(root)/
strace-6.5/
tests-m32/
nlattr_inet_diag_msg.c
       1  /*
       2   * Copyright (c) 2017 JingPiao Chen <chenjingpiao@gmail.com>
       3   * Copyright (c) 2017-2022 The strace developers.
       4   * All rights reserved.
       5   *
       6   * SPDX-License-Identifier: GPL-2.0-or-later
       7   */
       8  
       9  #include "tests.h"
      10  
      11  #include <stdio.h>
      12  #include <string.h>
      13  #include <arpa/inet.h>
      14  #include <linux/atalk.h>
      15  #include <linux/mptcp.h>
      16  #include <linux/tls.h>
      17  #include <net/if.h>
      18  #include <netinet/in.h>
      19  #include <netinet/tcp.h>
      20  #include "test_nlattr.h"
      21  #include <linux/inet_diag.h>
      22  #include <linux/sock_diag.h>
      23  
      24  
      25  #ifndef HAVE_STRUCT_TCP_DIAG_MD5SIG
      26  struct tcp_diag_md5sig {
      27  	__u8	tcpm_family;
      28  	__u8	tcpm_prefixlen;
      29  	__u16	tcpm_keylen;
      30  	__be32	tcpm_addr[4];
      31  	__u8	tcpm_key[80 /* TCP_MD5SIG_MAXKEYLEN */];
      32  };
      33  #endif
      34  
      35  static const char * const sk_meminfo_strs[] = {
      36  	"SK_MEMINFO_RMEM_ALLOC",
      37  	"SK_MEMINFO_RCVBUF",
      38  	"SK_MEMINFO_WMEM_ALLOC",
      39  	"SK_MEMINFO_SNDBUF",
      40  	"SK_MEMINFO_FWD_ALLOC",
      41  	"SK_MEMINFO_WMEM_QUEUED",
      42  	"SK_MEMINFO_OPTMEM",
      43  	"SK_MEMINFO_BACKLOG",
      44  	"SK_MEMINFO_DROPS",
      45  };
      46  
      47  static const char address[] = "10.11.12.13";
      48  static const unsigned int hdrlen = sizeof(struct inet_diag_msg);
      49  static uint16_t  attr1;
      50  static const char *attr1_str = NULL;
      51  static uint16_t  attr2;
      52  static const char *attr2_str = NULL;
      53  
      54  
      55  static void
      56  init_inet_diag_msg(struct nlmsghdr *const nlh, const unsigned int msg_len)
      57  {
      58  	SET_STRUCT(struct nlmsghdr, nlh,
      59  		.nlmsg_len = msg_len,
      60  		.nlmsg_type = SOCK_DIAG_BY_FAMILY,
      61  		.nlmsg_flags = NLM_F_DUMP
      62  	);
      63  
      64  	struct inet_diag_msg *const msg = NLMSG_DATA(nlh);
      65  	SET_STRUCT(struct inet_diag_msg, msg,
      66  		.idiag_family = AF_INET,
      67  		.idiag_state = TCP_LISTEN,
      68  		.id.idiag_if = ifindex_lo()
      69  	);
      70  
      71  	if (!inet_pton(AF_INET, address, msg->id.idiag_src) ||
      72  	    !inet_pton(AF_INET, address, msg->id.idiag_dst))
      73  		perror_msg_and_skip("inet_pton");
      74  }
      75  
      76  static void
      77  print_inet_diag_msg(const unsigned int msg_len)
      78  {
      79  	printf("{nlmsg_len=%u, nlmsg_type=SOCK_DIAG_BY_FAMILY"
      80  	       ", nlmsg_flags=NLM_F_DUMP, nlmsg_seq=0, nlmsg_pid=0}"
      81  	       ", {idiag_family=AF_INET, idiag_state=TCP_LISTEN"
      82  	       ", idiag_timer=0, idiag_retrans=0"
      83  	       ", id={idiag_sport=htons(0), idiag_dport=htons(0)"
      84  	       ", idiag_src=inet_addr(\"%s\")"
      85  	       ", idiag_dst=inet_addr(\"%s\")"
      86  	       ", idiag_if=" IFINDEX_LO_STR
      87  	       ", idiag_cookie=[0, 0]}"
      88  	       ", idiag_expires=0, idiag_rqueue=0, idiag_wqueue=0"
      89  	       ", idiag_uid=0, idiag_inode=0}",
      90  	       msg_len, address, address);
      91  }
      92  
      93  static void
      94  init_inet_diag_nest_1(struct nlmsghdr *const nlh, const unsigned int msg_len)
      95  {
      96  	init_inet_diag_msg(nlh, msg_len);
      97  
      98  	struct nlattr *nla = NLMSG_ATTR(nlh, hdrlen);
      99  	SET_STRUCT(struct nlattr, nla,
     100  		.nla_len = msg_len - NLMSG_SPACE(hdrlen),
     101  		.nla_type = attr1,
     102  	);
     103  }
     104  
     105  static void
     106  print_inet_diag_nest_1(const unsigned int msg_len)
     107  {
     108  	print_inet_diag_msg(msg_len);
     109  	printf(", [{nla_len=%u, nla_type=%s}",
     110  	       msg_len - NLMSG_SPACE(hdrlen), attr1_str);
     111  }
     112  
     113  static void
     114  init_inet_diag_nest_2(struct nlmsghdr *const nlh, const unsigned int msg_len)
     115  {
     116  	init_inet_diag_nest_1(nlh, msg_len);
     117  
     118  	struct nlattr *nla = NLMSG_ATTR(nlh, hdrlen);
     119  	nla += 1;
     120  	SET_STRUCT(struct nlattr, nla,
     121  		.nla_len = msg_len - NLMSG_SPACE(hdrlen) - NLA_HDRLEN,
     122  		.nla_type = attr2,
     123  	);
     124  }
     125  
     126  static void
     127  print_inet_diag_nest_2(const unsigned int msg_len)
     128  {
     129  	print_inet_diag_nest_1(msg_len);
     130  	printf(", [{nla_len=%u, nla_type=%s}",
     131  	       msg_len - NLMSG_SPACE(hdrlen) - NLA_HDRLEN, attr2_str);
     132  }
     133  
     134  static void
     135  print_uint(const unsigned int *p, size_t i)
     136  {
     137  	if (i >= ARRAY_SIZE(sk_meminfo_strs))
     138  		printf("[%zu /* SK_MEMINFO_??? */", i);
     139  	else
     140  		printf("[%s", sk_meminfo_strs[i]);
     141  
     142  	printf("]=%u", *p);
     143  }
     144  
     145  static const struct {
     146  	struct tcp_diag_md5sig val;
     147  	const char *str;
     148  } md5sig_vecs[] = {
     149  	{ { 0 },
     150  	  "{tcpm_family=AF_UNSPEC, tcpm_prefixlen=0, tcpm_keylen=0"
     151  	  ", tcpm_addr=\"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00"
     152  	  "\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\", tcpm_key=\"\"}" },
     153  	{ { AF_INET, 0x42, 1, { BE_LE(0xdeadface, 0xcefaadde) } },
     154  	  "{tcpm_family=AF_INET, tcpm_prefixlen=66, tcpm_keylen=1"
     155  	  ", tcpm_addr=inet_addr(\"222.173.250.206\")"
     156  	  ", tcpm_key=\"\\x00\"}" },
     157  	{ { AF_INET6, 0xbe, 42,
     158  	    { BE_LE(0xdeadface, 0xcefaadde), BE_LE(0xcafe0000, 0xfeca),
     159  	      BE_LE(0xface, 0xcefa0000), BE_LE(0xbadc0ded, 0xed0ddcba) },
     160  	    "OH HAI THAR\0\1\2\3\4\5\6\7\3779876543210abcdefghijklmnopqrstuv" },
     161  	  "{tcpm_family=AF_INET6, tcpm_prefixlen=190, tcpm_keylen=42"
     162  	  ", inet_pton(AF_INET6, \"dead:face:cafe::face:badc:ded\", &tcpm_addr)"
     163  	  ", tcpm_key=\"\\x4f\\x48\\x20\\x48\\x41\\x49\\x20\\x54\\x48\\x41"
     164  	  "\\x52\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\xff\\x39\\x38\\x37"
     165  	  "\\x36\\x35\\x34\\x33\\x32\\x31\\x30\\x61\\x62\\x63\\x64\\x65\\x66"
     166  	  "\\x67\\x68\\x69\\x6a\\x6b\\x6c\"}" },
     167  	{ { 46, 0, 45067,
     168  	    { BE_LE(0xdeadface, 0xcefaadde), BE_LE(0xcafe0000, 0xfeca),
     169  	      BE_LE(0xface, 0xcefa0000), BE_LE(0xbadc0ded, 0xed0ddcba) },
     170  	    "OH HAI THAR\0\1\2\3\4\5\6\7\3779876543210abcdefghijklmnopqrstuv"
     171  	    "xyz0123456789ABCDEFGHIJKLMNO" },
     172  	  "{tcpm_family=0x2e /* AF_??? */, tcpm_prefixlen=0, tcpm_keylen=45067"
     173  	  ", tcpm_addr=\"\\xde\\xad\\xfa\\xce\\xca\\xfe\\x00\\x00"
     174  	  "\\x00\\x00\\xfa\\xce\\xba\\xdc\\x0d\\xed\""
     175  	  ", tcpm_key=\"\\x4f\\x48\\x20\\x48\\x41\\x49\\x20\\x54\\x48\\x41"
     176  	  "\\x52\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\xff\\x39\\x38\\x37"
     177  	  "\\x36\\x35\\x34\\x33\\x32\\x31\\x30\\x61\\x62\\x63\\x64\\x65\\x66"
     178  	  "\\x67\\x68\\x69\\x6a\\x6b\\x6c\\x6d\\x6e\\x6f\\x70\\x71\\x72\\x73"
     179  	  "\\x74\\x75\\x76\\x78\\x79\\x7a\\x30\\x31\\x32\\x33\\x34\\x35\\x36"
     180  	  "\\x37\\x38\\x39\\x41\\x42\\x43\\x44\\x45\\x46\\x47\\x48\\x49\\x4a"
     181  	  "\\x4b\\x4c\\x4d\\x4e\\x4f\"}" },
     182  };
     183  
     184  static void
     185  print_md5sig(const struct tcp_diag_md5sig *p, size_t i)
     186  {
     187  	printf("%s", md5sig_vecs[i].str);
     188  }
     189  
     190  static void
     191  print_sa(const struct sockaddr_storage *p, size_t i)
     192  {
     193  	static const char *strs[] = {
     194  		"{sa_family=AF_INET, sin_port=htons(42069)"
     195  		", sin_addr=inet_addr(\"18.52.86.120\")}",
     196  		"{sa_family=AF_INET6, sin6_port=htons(23456)"
     197  		", sin6_flowinfo=htonl(324508639)"
     198  		", inet_pton(AF_INET6, \"1234:5678::9abc:def0\", &sin6_addr)"
     199  		", sin6_scope_id=610839776}",
     200  		"{sa_family=AF_APPLETALK"
     201  		", sa_data=\"i\\0" BE_LE("\\207e", "e\\207") "B\\0\\0\\0\\0\\0"
     202  		"\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0"
     203  		"\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0"
     204  		"\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0"
     205  		"\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0"
     206  		"\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0"
     207  		"\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\"}"
     208  	};
     209  
     210  	printf("%s", strs[i]);
     211  }
     212  
     213  int
     214  main(void)
     215  {
     216  	skip_if_unavailable("/proc/self/fd/");
     217  
     218  	static const struct inet_diag_meminfo minfo = {
     219  		.idiag_rmem = 0xfadcacdb,
     220  		.idiag_wmem = 0xbdabcada,
     221  		.idiag_fmem = 0xbadbfafb,
     222  		.idiag_tmem = 0xfdacdadf
     223  	};
     224  	static const struct tcpvegas_info vegas = {
     225  		.tcpv_enabled = 0xfadcacdb,
     226  		.tcpv_rttcnt = 0xbdabcada,
     227  		.tcpv_rtt = 0xbadbfafb,
     228  		.tcpv_minrtt = 0xfdacdadf
     229  	};
     230  	static const struct tcp_dctcp_info dctcp = {
     231  		.dctcp_enabled = 0xfdac,
     232  		.dctcp_ce_state = 0xfadc,
     233  		.dctcp_alpha = 0xbdabcada,
     234  		.dctcp_ab_ecn = 0xbadbfafb,
     235  		.dctcp_ab_tot = 0xfdacdadf
     236  	};
     237  	static const struct tcp_bbr_info bbr = {
     238  		.bbr_bw_lo = 0xfdacdadf,
     239  		.bbr_bw_hi = 0xfadcacdb,
     240  		.bbr_min_rtt = 0xbdabcada,
     241  		.bbr_pacing_gain = 0xbadbfafb,
     242  		.bbr_cwnd_gain = 0xfdacdadf
     243  	};
     244  	static const uint32_t mem[] = { 0xaffacbad, 0xffadbcab };
     245  	static uint32_t bigmem[SK_MEMINFO_VARS + 1];
     246  	static const uint32_t mark = 0xabdfadca;
     247  
     248  	const int fd = create_nl_socket(NETLINK_SOCK_DIAG);
     249  	void *const nlh0 = midtail_alloc(NLMSG_SPACE(hdrlen),
     250  					 NLA_HDRLEN +
     251  					 MAX(sizeof(bigmem), DEFAULT_STRLEN));
     252  
     253  	static char pattern[4096];
     254  	fill_memory_ex(pattern, sizeof(pattern), 'a', 'z' - 'a' + 1);
     255  
     256  	TEST_NLATTR_OBJECT(fd, nlh0, hdrlen,
     257  			   init_inet_diag_msg, print_inet_diag_msg,
     258  			   INET_DIAG_MEMINFO, pattern, minfo,
     259  			   printf("{");
     260  			   PRINT_FIELD_U(minfo, idiag_rmem);
     261  			   printf(", ");
     262  			   PRINT_FIELD_U(minfo, idiag_wmem);
     263  			   printf(", ");
     264  			   PRINT_FIELD_U(minfo, idiag_fmem);
     265  			   printf(", ");
     266  			   PRINT_FIELD_U(minfo, idiag_tmem);
     267  			   printf("}"));
     268  
     269  	TEST_NLATTR_OBJECT(fd, nlh0, hdrlen,
     270  			   init_inet_diag_msg, print_inet_diag_msg,
     271  			   INET_DIAG_VEGASINFO, pattern, vegas,
     272  			   printf("{");
     273  			   PRINT_FIELD_U(vegas, tcpv_enabled);
     274  			   printf(", ");
     275  			   PRINT_FIELD_U(vegas, tcpv_rttcnt);
     276  			   printf(", ");
     277  			   PRINT_FIELD_U(vegas, tcpv_rtt);
     278  			   printf(", ");
     279  			   PRINT_FIELD_U(vegas, tcpv_minrtt);
     280  			   printf("}"));
     281  
     282  
     283  	TEST_NLATTR_OBJECT(fd, nlh0, hdrlen,
     284  			   init_inet_diag_msg, print_inet_diag_msg,
     285  			   INET_DIAG_DCTCPINFO, pattern, dctcp,
     286  			   printf("{");
     287  			   PRINT_FIELD_U(dctcp, dctcp_enabled);
     288  			   printf(", ");
     289  			   PRINT_FIELD_U(dctcp, dctcp_ce_state);
     290  			   printf(", ");
     291  			   PRINT_FIELD_U(dctcp, dctcp_alpha);
     292  			   printf(", ");
     293  			   PRINT_FIELD_U(dctcp, dctcp_ab_ecn);
     294  			   printf(", ");
     295  			   PRINT_FIELD_U(dctcp, dctcp_ab_tot);
     296  			   printf("}"));
     297  
     298  	TEST_NLATTR_OBJECT(fd, nlh0, hdrlen,
     299  			   init_inet_diag_msg, print_inet_diag_msg,
     300  			   INET_DIAG_BBRINFO, pattern, bbr,
     301  			   printf("{");
     302  			   PRINT_FIELD_X(bbr, bbr_bw_lo);
     303  			   printf(", ");
     304  			   PRINT_FIELD_X(bbr, bbr_bw_hi);
     305  			   printf(", ");
     306  			   PRINT_FIELD_U(bbr, bbr_min_rtt);
     307  			   printf(", ");
     308  			   PRINT_FIELD_U(bbr, bbr_pacing_gain);
     309  			   printf(", ");
     310  			   PRINT_FIELD_U(bbr, bbr_cwnd_gain);
     311  			   printf("}"));
     312  
     313  	TEST_NLATTR_ARRAY(fd, nlh0, hdrlen,
     314  			  init_inet_diag_msg, print_inet_diag_msg,
     315  			  INET_DIAG_SKMEMINFO, pattern, mem, print_uint);
     316  
     317  	memcpy(bigmem, pattern, sizeof(bigmem));
     318  
     319  	TEST_NLATTR_ARRAY(fd, nlh0, hdrlen,
     320  			  init_inet_diag_msg, print_inet_diag_msg,
     321  			  INET_DIAG_SKMEMINFO, pattern, bigmem, print_uint);
     322  
     323  	TEST_NLATTR_OBJECT(fd, nlh0, hdrlen,
     324  			   init_inet_diag_msg, print_inet_diag_msg,
     325  			   INET_DIAG_MARK, pattern, mark,
     326  			   printf("%u", mark));
     327  
     328  	TEST_NLATTR_OBJECT(fd, nlh0, hdrlen,
     329  			   init_inet_diag_msg, print_inet_diag_msg,
     330  			   INET_DIAG_CLASS_ID, pattern, mark,
     331  			   printf("%u", mark));
     332  
     333  	static const struct strval8 shutdown_vecs[] = {
     334  		{ ARG_STR(0) },
     335  		{ 1, "0x1 /* RCV_SHUTDOWN */" },
     336  		{ 2, "0x2 /* SEND_SHUTDOWN */" },
     337  		{ 3, "0x3 /* RCV_SHUTDOWN|SEND_SHUTDOWN */" },
     338  		{ 4, "0x4 /* ???_SHUTDOWN */" },
     339  		{ 23, "0x17 /* RCV_SHUTDOWN|SEND_SHUTDOWN|0x14 */" },
     340  		{ 252, "0xfc /* ???_SHUTDOWN */" },
     341  	};
     342  	TAIL_ALLOC_OBJECT_CONST_PTR(uint8_t, shutdown);
     343  	for (size_t i = 0; i < ARRAY_SIZE(shutdown_vecs); i++) {
     344  		*shutdown = shutdown_vecs[i].val;
     345  		TEST_NLATTR(fd, nlh0, hdrlen,
     346  			    init_inet_diag_msg, print_inet_diag_msg,
     347  			    INET_DIAG_SHUTDOWN,
     348  			    sizeof(*shutdown), shutdown, sizeof(*shutdown),
     349  			    printf("%s", shutdown_vecs[i].str));
     350  	}
     351  
     352  	char *const str = tail_alloc(DEFAULT_STRLEN);
     353  	fill_memory_ex(str, DEFAULT_STRLEN, '0', 10);
     354  	TEST_NLATTR(fd, nlh0, hdrlen,
     355  		    init_inet_diag_msg, print_inet_diag_msg, INET_DIAG_CONG,
     356  		    DEFAULT_STRLEN, str, DEFAULT_STRLEN,
     357  		    printf("\"%.*s\"...", DEFAULT_STRLEN, str));
     358  	str[DEFAULT_STRLEN - 1] = '\0';
     359  	TEST_NLATTR(fd, nlh0, hdrlen,
     360  		    init_inet_diag_msg, print_inet_diag_msg, INET_DIAG_CONG,
     361  		    DEFAULT_STRLEN, str, DEFAULT_STRLEN,
     362  		    printf("\"%s\"", str));
     363  
     364  	/* u8 INET_DIAG_* attrs */
     365  	static const struct strval16 u8_attrs[] = {
     366  		{ ENUM_KNOWN(0x5, INET_DIAG_TOS) },
     367  		{ ENUM_KNOWN(0x6, INET_DIAG_TCLASS) },
     368  		{ ENUM_KNOWN(0xb, INET_DIAG_SKV6ONLY) },
     369  	};
     370  	void *nlh_u8 = midtail_alloc(NLMSG_SPACE(hdrlen), sizeof(uint8_t));
     371  
     372  	for (size_t i = 0; i < ARRAY_SIZE(u8_attrs); i++) {
     373  		check_u8_nlattr(fd, nlh_u8, hdrlen,
     374  				init_inet_diag_msg, print_inet_diag_msg,
     375  				u8_attrs[i].val, u8_attrs[i].str, pattern, 0);
     376  	}
     377  
     378  	/* u32 INET_DIAG_* attrs */
     379  	static const struct strval16 u32_attrs[] = {
     380  		{ ENUM_KNOWN(0xf, INET_DIAG_MARK) },
     381  		{ ENUM_KNOWN(0x11, INET_DIAG_CLASS_ID) },
     382  	};
     383  	void *nlh_u32 = midtail_alloc(NLMSG_SPACE(hdrlen), sizeof(uint32_t));
     384  
     385  	for (size_t i = 0; i < ARRAY_SIZE(u32_attrs); i++) {
     386  		check_u32_nlattr(fd, nlh_u32, hdrlen,
     387  				 init_inet_diag_msg, print_inet_diag_msg,
     388  				 u32_attrs[i].val, u32_attrs[i].str,
     389  				 pattern, 0);
     390  	}
     391  
     392  	/* u64 INET_DIAG_* attrs */
     393  	static const struct strval16 u64_attrs[] = {
     394  		{ ENUM_KNOWN(0x15, INET_DIAG_CGROUP_ID) },
     395  	};
     396  	void *nlh_u64 = midtail_alloc(NLMSG_SPACE(hdrlen), sizeof(uint64_t));
     397  
     398  	for (size_t i = 0; i < ARRAY_SIZE(u64_attrs); i++) {
     399  		check_u64_nlattr(fd, nlh_u64, hdrlen,
     400  				 init_inet_diag_msg, print_inet_diag_msg,
     401  				 u64_attrs[i].val, u64_attrs[i].str,
     402  				 pattern, 0);
     403  	}
     404  
     405  	/* INET_DIAG_PROTOCOL */
     406  	static const struct strval8 protos[] = {
     407  		{ 0, "IPPROTO_IP" },
     408  		{ 2, "IPPROTO_IGMP" },
     409  		{ 5, "0x5 /* IPPROTO_??? */" },
     410  		{ 6, "IPPROTO_TCP" },
     411  		{ 190, "0xbe /* IPPROTO_??? */" },
     412  		{ 255, "IPPROTO_RAW" },
     413  	};
     414  
     415  	for (size_t i = 0; i < ARRAY_SIZE(protos); i++) {
     416  		TEST_NLATTR(fd, nlh0, hdrlen,
     417  			    init_inet_diag_msg, print_inet_diag_msg,
     418  			    INET_DIAG_PROTOCOL,
     419  			    sizeof(uint8_t), &protos[i].val, sizeof(uint8_t),
     420  			    printf("%s", protos[i].str));
     421  	}
     422  
     423  	/* INET_DIAG_MD5SIG */
     424  	struct tcp_diag_md5sig md5s_arr[ARRAY_SIZE(md5sig_vecs)];
     425  
     426  	for (size_t i = 0; i < ARRAY_SIZE(md5sig_vecs); i++) {
     427  		memcpy(md5s_arr + i, &md5sig_vecs[i].val, sizeof(md5s_arr[0]));
     428  
     429  		TEST_NLATTR_OBJECT(fd, nlh0, hdrlen,
     430  				   init_inet_diag_msg, print_inet_diag_msg,
     431  				   INET_DIAG_MD5SIG, pattern,
     432  				   md5sig_vecs[i].val,
     433  				   printf("[%s]", md5sig_vecs[i].str));
     434  	}
     435  
     436  	TEST_NLATTR_ARRAY(fd, nlh0, hdrlen,
     437  			  init_inet_diag_msg, print_inet_diag_msg,
     438  			  INET_DIAG_MD5SIG, pattern, md5s_arr, print_md5sig);
     439  
     440  	/* INET_DIAG_ULP_INFO */
     441  	attr1 = INET_DIAG_ULP_INFO;
     442  	attr1_str = "INET_DIAG_ULP_INFO";
     443  
     444  	/* INET_DIAG_ULP_INFO: unknown, undecoded */
     445  	static const struct strval16 ulp_unk_attrs[] = {
     446  		{ ENUM_KNOWN(0, INET_ULP_INFO_UNSPEC) },
     447  		{ ARG_XLAT_UNKNOWN(0x4, "INET_ULP_INFO_???") },
     448  		{ ARG_XLAT_UNKNOWN(0x1ace, "INET_ULP_INFO_???") },
     449  	};
     450  	static const uint32_t dummy = BE_LE(0xdeadc0de, 0xdec0adde);
     451  
     452  	for (size_t i = 0; i < ARRAY_SIZE(ulp_unk_attrs); i++) {
     453  		TEST_NESTED_NLATTR_(fd, nlh0, hdrlen,
     454  				    init_inet_diag_nest_1,
     455  				    print_inet_diag_nest_1,
     456  				    ulp_unk_attrs[i].val,
     457  				    ulp_unk_attrs[i].str,
     458  				    sizeof(dummy), &dummy, sizeof(dummy), 1,
     459  				    printf("\"\\xde\\xad\\xc0\\xde\""));
     460  	}
     461  
     462  	/* INET_DIAG_ULP_INFO: INET_ULP_INFO_NAME */
     463  	static const struct {
     464  		const char *val;
     465  		const char *str;
     466  		ssize_t sz;
     467  	} ulp_names[] = {
     468  		{ "OH HAI", "\"OH HAI\"", 7 },
     469  		{ "\0\0\0", "\"\\0\\0\\0\"", 4 },
     470  		{ "\1\2\3\4\5\6\7\10\11\12\13\14",
     471  		  "\"\\1\\2\\3\\4\\5\\6\\7\\10\\t\\n\\v\\f\"...", 12 },
     472  	};
     473  
     474  	for (size_t i = 0; i < ARRAY_SIZE(ulp_names); i++) {
     475  		TEST_NESTED_NLATTR_(fd, nlh0, hdrlen,
     476  				    init_inet_diag_nest_1,
     477  				    print_inet_diag_nest_1,
     478  				    INET_ULP_INFO_NAME, "INET_ULP_INFO_NAME",
     479  				    ulp_names[i].sz, ulp_names[i].val,
     480  				    ulp_names[i].sz, 1,
     481  				    printf("%s", ulp_names[i].str));
     482  	}
     483  
     484  	/* INET_DIAG_ULP_INFO: INET_ULP_INFO_TLS */
     485  	attr2 = INET_ULP_INFO_TLS;
     486  	attr2_str = "INET_ULP_INFO_TLS";
     487  
     488  	/* INET_DIAG_ULP_INFO: INET_ULP_INFO_TLS: unknown, undecoded */
     489  	static const struct strval16 tls_unk_attrs[] = {
     490  		{ ENUM_KNOWN(0, TLS_INFO_UNSPEC) },
     491  		{ ENUM_KNOWN(0x6, TLS_INFO_RX_NO_PAD) },
     492  		{ ARG_XLAT_UNKNOWN(0x7, "TLS_INFO_???") },
     493  		{ ARG_XLAT_UNKNOWN(0x1ace, "TLS_INFO_???") },
     494  	};
     495  
     496  	for (size_t i = 0; i < ARRAY_SIZE(tls_unk_attrs); i++) {
     497  		TEST_NESTED_NLATTR_(fd, nlh0, hdrlen,
     498  				    init_inet_diag_nest_2,
     499  				    print_inet_diag_nest_2,
     500  				    tls_unk_attrs[i].val,
     501  				    tls_unk_attrs[i].str,
     502  				    sizeof(dummy), &dummy, sizeof(dummy), 2,
     503  				    printf("\"\\xde\\xad\\xc0\\xde\""));
     504  	}
     505  
     506  	/* INET_DIAG_ULP_INFO: INET_ULP_INFO_TLS: TLS_INFO_VERSION */
     507  	static const struct strval16 tls_vers[] = {
     508  		{ ARG_XLAT_UNKNOWN(0, "TLS_???_VERSION") },
     509  		{ ARG_XLAT_UNKNOWN(0x200, "TLS_???_VERSION") },
     510  		{ ARG_XLAT_UNKNOWN(0x300, "TLS_???_VERSION") },
     511  		{ ARG_XLAT_UNKNOWN(0x301, "TLS_???_VERSION") },
     512  		{ ARG_XLAT_UNKNOWN(0x302, "TLS_???_VERSION") },
     513  		{ ENUM_KNOWN(0x303, TLS_1_2_VERSION) },
     514  		{ ENUM_KNOWN(0x304, TLS_1_3_VERSION) },
     515  		{ ARG_XLAT_UNKNOWN(0x305, "TLS_???_VERSION") },
     516  		{ ARG_XLAT_UNKNOWN(0xdead, "TLS_???_VERSION") },
     517  	};
     518  
     519  	for (size_t i = 0; i < ARRAY_SIZE(tls_vers); i++) {
     520  		TEST_NESTED_NLATTR_(fd, nlh0, hdrlen,
     521  				    init_inet_diag_nest_2,
     522  				    print_inet_diag_nest_2,
     523  				    TLS_INFO_VERSION, "TLS_INFO_VERSION",
     524  				    2, &tls_vers[i].val, 2, 2,
     525  				    printf("%s", tls_vers[i].str));
     526  	}
     527  
     528  	/* INET_DIAG_ULP_INFO: INET_ULP_INFO_TLS: TLS_INFO_CIPHER */
     529  	static const struct strval16 tls_ciphers[] = {
     530  		{ ARG_XLAT_UNKNOWN(0, "TLS_CIPHER_???") },
     531  		{ ARG_XLAT_UNKNOWN(0x32, "TLS_CIPHER_???") },
     532  		{ ENUM_KNOWN(0x33, TLS_CIPHER_AES_GCM_128) },
     533  		{ ENUM_KNOWN(0x34, TLS_CIPHER_AES_GCM_256) },
     534  		{ ENUM_KNOWN(0x35, TLS_CIPHER_AES_CCM_128) },
     535  		{ ENUM_KNOWN(0x36, TLS_CIPHER_CHACHA20_POLY1305) },
     536  		{ ENUM_KNOWN(0x37, TLS_CIPHER_SM4_GCM) },
     537  		{ ENUM_KNOWN(0x38, TLS_CIPHER_SM4_CCM) },
     538  		{ ENUM_KNOWN(0x39, TLS_CIPHER_ARIA_GCM_128) },
     539  		{ ENUM_KNOWN(0x3a, TLS_CIPHER_ARIA_GCM_256) },
     540  		{ ARG_XLAT_UNKNOWN(0x3b, "TLS_CIPHER_???") },
     541  		{ ARG_XLAT_UNKNOWN(0xcafe, "TLS_CIPHER_???") },
     542  	};
     543  
     544  	for (size_t i = 0; i < ARRAY_SIZE(tls_ciphers); i++) {
     545  		TEST_NESTED_NLATTR_(fd, nlh0, hdrlen,
     546  				    init_inet_diag_nest_2,
     547  				    print_inet_diag_nest_2,
     548  				    TLS_INFO_CIPHER, "TLS_INFO_CIPHER",
     549  				    2, &tls_ciphers[i].val, 2, 2,
     550  				    printf("%s", tls_ciphers[i].str));
     551  	}
     552  
     553  	/* INET_DIAG_ULP_INFO: INET_ULP_INFO_TLS: TLS_INFO_[RT]XCONF */
     554  	static const struct strval16 tls_cfg_attrs[] = {
     555  		{ ENUM_KNOWN(0, TLS_INFO_TXCONF) },
     556  		{ ENUM_KNOWN(0, TLS_INFO_RXCONF) },
     557  	};
     558  	static const struct strval16 tls_cfgs[] = {
     559  		{ ARG_XLAT_UNKNOWN(0, "TLS_CONF_???") },
     560  		{ ENUM_KNOWN(0x1, TLS_CONF_BASE) },
     561  		{ ENUM_KNOWN(0x2, TLS_CONF_SW) },
     562  		{ ENUM_KNOWN(0x3, TLS_CONF_HW) },
     563  		{ ENUM_KNOWN(0x4, TLS_CONF_HW_RECORD) },
     564  		{ ARG_XLAT_UNKNOWN(0x5, "TLS_CONF_???") },
     565  		{ ARG_XLAT_UNKNOWN(0xface, "TLS_CONF_???") },
     566  	};
     567  
     568  	for (size_t i = 0; i < ARRAY_SIZE(tls_cfg_attrs); i++) {
     569  		for (size_t j = 0; j < ARRAY_SIZE(tls_cfgs); j++) {
     570  			TEST_NESTED_NLATTR_(fd, nlh0, hdrlen,
     571  					    init_inet_diag_nest_2,
     572  					    print_inet_diag_nest_2,
     573  					    tls_cfg_attrs[i].val,
     574  					    tls_cfg_attrs[i].str,
     575  					    2, &tls_cfgs[i].val, 2, 2,
     576  					    printf("%s", tls_cfgs[i].str));
     577  		}
     578  	}
     579  
     580  	/* INET_DIAG_ULP_INFO: INET_ULP_INFO_MPTCP */
     581  	attr2 = INET_ULP_INFO_MPTCP;
     582  	attr2_str = "INET_ULP_INFO_MPTCP";
     583  
     584  	/* INET_DIAG_ULP_INFO: INET_ULP_INFO_MPTCP: unknown, undecoded */
     585  	static const struct strval16 mptcp_unk_attrs[] = {
     586  		{ ENUM_KNOWN(0, MPTCP_SUBFLOW_ATTR_UNSPEC) },
     587  		{ ENUM_KNOWN(0xb, MPTCP_SUBFLOW_ATTR_PAD) },
     588  		{ ARG_XLAT_UNKNOWN(0xc, "MPTCP_SUBFLOW_ATTR_???") },
     589  		{ ARG_XLAT_UNKNOWN(0x1ace, "MPTCP_SUBFLOW_ATTR_???") },
     590  	};
     591  
     592  	for (size_t i = 0; i < ARRAY_SIZE(mptcp_unk_attrs); i++) {
     593  		TEST_NESTED_NLATTR_(fd, nlh0, hdrlen,
     594  				    init_inet_diag_nest_2,
     595  				    print_inet_diag_nest_2,
     596  				    mptcp_unk_attrs[i].val,
     597  				    mptcp_unk_attrs[i].str,
     598  				    sizeof(dummy), &dummy, sizeof(dummy), 2,
     599  				    printf("\"\\xde\\xad\\xc0\\xde\""));
     600  	}
     601  
     602  	/* INET_DIAG_ULP_INFO: INET_ULP_INFO_MPTCP: u8 */
     603  	static const struct strval16 mptcp_u8_attrs[] = {
     604  		{ ENUM_KNOWN(0x9, MPTCP_SUBFLOW_ATTR_ID_REM) },
     605  		{ ENUM_KNOWN(0xa, MPTCP_SUBFLOW_ATTR_ID_LOC) },
     606  	};
     607  	void *nlh_n2_u8 = midtail_alloc(NLMSG_SPACE(hdrlen),
     608  					NLA_HDRLEN * 2 + sizeof(uint8_t));
     609  
     610  	for (size_t i = 0; i < ARRAY_SIZE(mptcp_u8_attrs); i++) {
     611  		check_u8_nlattr(fd, nlh_n2_u8, hdrlen,
     612  				init_inet_diag_nest_2,
     613  				print_inet_diag_nest_2,
     614  				mptcp_u8_attrs[i].val, mptcp_u8_attrs[i].str,
     615  				pattern, 2);
     616  	}
     617  
     618  	/* INET_DIAG_ULP_INFO: INET_ULP_INFO_MPTCP: u16 */
     619  	static const struct strval16 mptcp_u16_attrs[] = {
     620  		{ ENUM_KNOWN(0x7, MPTCP_SUBFLOW_ATTR_MAP_DATALEN) },
     621  	};
     622  	void *nlh_n2_u16 = midtail_alloc(NLMSG_SPACE(hdrlen),
     623  					 NLA_HDRLEN * 2 + sizeof(uint16_t));
     624  
     625  	for (size_t i = 0; i < ARRAY_SIZE(mptcp_u16_attrs); i++) {
     626  		check_u16_nlattr(fd, nlh_n2_u16, hdrlen,
     627  				init_inet_diag_nest_2,
     628  				print_inet_diag_nest_2,
     629  				mptcp_u16_attrs[i].val, mptcp_u16_attrs[i].str,
     630  				pattern, 2);
     631  	}
     632  
     633  	/* INET_DIAG_ULP_INFO: INET_ULP_INFO_MPTCP: u32 */
     634  	static const struct strval16 mptcp_u32_attrs[] = {
     635  		{ ENUM_KNOWN(0x3, MPTCP_SUBFLOW_ATTR_RELWRITE_SEQ) },
     636  		{ ENUM_KNOWN(0x5, MPTCP_SUBFLOW_ATTR_MAP_SFSEQ) },
     637  		{ ENUM_KNOWN(0x6, MPTCP_SUBFLOW_ATTR_SSN_OFFSET) },
     638  	};
     639  	void *nlh_n2_u32 = midtail_alloc(NLMSG_SPACE(hdrlen),
     640  					 NLA_HDRLEN * 2 + sizeof(uint32_t));
     641  
     642  	for (size_t i = 0; i < ARRAY_SIZE(mptcp_u32_attrs); i++) {
     643  		check_u32_nlattr(fd, nlh_n2_u32, hdrlen,
     644  				init_inet_diag_nest_2,
     645  				print_inet_diag_nest_2,
     646  				mptcp_u32_attrs[i].val, mptcp_u32_attrs[i].str,
     647  				pattern, 2);
     648  	}
     649  
     650  	/* INET_DIAG_ULP_INFO: INET_ULP_INFO_MPTCP: u64 */
     651  	static const struct strval16 mptcp_u64_attrs[] = {
     652  		{ ENUM_KNOWN(0x4, MPTCP_SUBFLOW_ATTR_MAP_SEQ) },
     653  	};
     654  	void *nlh_n2_u64 = midtail_alloc(NLMSG_SPACE(hdrlen),
     655  					 NLA_HDRLEN * 2 + sizeof(uint64_t));
     656  
     657  	for (size_t i = 0; i < ARRAY_SIZE(mptcp_u64_attrs); i++) {
     658  		check_u64_nlattr(fd, nlh_n2_u64, hdrlen,
     659  				init_inet_diag_nest_2,
     660  				print_inet_diag_nest_2,
     661  				mptcp_u64_attrs[i].val, mptcp_u64_attrs[i].str,
     662  				pattern, 2);
     663  	}
     664  
     665  	/* INET_DIAG_ULP_INFO: INET_ULP_INFO_MPTCP: x32 */
     666  	static const struct strval16 mptcp_x32_attrs[] = {
     667  		{ ENUM_KNOWN(0x1, MPTCP_SUBFLOW_ATTR_TOKEN_REM) },
     668  		{ ENUM_KNOWN(0x2, MPTCP_SUBFLOW_ATTR_TOKEN_LOC) },
     669  	};
     670  
     671  	for (size_t i = 0; i < ARRAY_SIZE(mptcp_x32_attrs); i++) {
     672  		check_x32_nlattr(fd, nlh_u32, hdrlen,
     673  				init_inet_diag_nest_2,
     674  				print_inet_diag_nest_2,
     675  				mptcp_x32_attrs[i].val, mptcp_x32_attrs[i].str,
     676  				pattern, 2);
     677  	}
     678  
     679  	/* INET_DIAG_ULP_INFO: INET_ULP_INFO_MPTCP: MPTCP_SUBFLOW_ATTR_FLAGS */
     680  	static const struct strval32 mptcp_flags[] = {
     681  		{ ARG_STR(0) },
     682  		{ ARG_XLAT_KNOWN(0x1, "MPTCP_SUBFLOW_FLAG_MCAP_REM") },
     683  		{ ARG_XLAT_KNOWN(0xdecaffed,
     684  				 "MPTCP_SUBFLOW_FLAG_MCAP_REM"
     685  				 "|MPTCP_SUBFLOW_FLAG_JOIN_REM"
     686  				 "|MPTCP_SUBFLOW_FLAG_JOIN_LOC"
     687  				 "|MPTCP_SUBFLOW_FLAG_BKUP_LOC"
     688  				 "|MPTCP_SUBFLOW_FLAG_FULLY_ESTABLISHED"
     689  				 "|MPTCP_SUBFLOW_FLAG_CONNECTED"
     690  				 "|MPTCP_SUBFLOW_FLAG_MAPVALID|0xdecafe00") },
     691  		{ ARG_XLAT_UNKNOWN(0xfffffe00, "MPTCP_SUBFLOW_FLAG_???") },
     692  	};
     693  
     694  	for (size_t i = 0; i < ARRAY_SIZE(mptcp_flags); i++) {
     695  		TEST_NESTED_NLATTR_(fd, nlh0, hdrlen,
     696  				    init_inet_diag_nest_2,
     697  				    print_inet_diag_nest_2,
     698  				    MPTCP_SUBFLOW_ATTR_FLAGS,
     699  				    "MPTCP_SUBFLOW_ATTR_FLAGS",
     700  				    4, &mptcp_flags[i].val, 4, 2,
     701  				    printf("%s", mptcp_flags[i].str));
     702  	}
     703  
     704  	/* INET_DIAG_SK_BPF_STORAGES */
     705  	attr1 = INET_DIAG_SK_BPF_STORAGES;
     706  	attr1_str = "INET_DIAG_SK_BPF_STORAGES";
     707  
     708  	/* INET_DIAG_SK_BPF_STORAGES: unknown, undecoded */
     709  	static const struct strval16 bpfsts_unk_attrs[] = {
     710  		{ ENUM_KNOWN(0, SK_DIAG_BPF_STORAGE_REP_NONE) },
     711  		{ ARG_XLAT_UNKNOWN(0x2, "SK_DIAG_BPF_STORAGE_???") },
     712  		{ ARG_XLAT_UNKNOWN(0x1ace, "SK_DIAG_BPF_STORAGE_???") },
     713  	};
     714  
     715  	for (size_t i = 0; i < ARRAY_SIZE(bpfsts_unk_attrs); i++) {
     716  		TEST_NESTED_NLATTR_(fd, nlh0, hdrlen,
     717  				    init_inet_diag_nest_1,
     718  				    print_inet_diag_nest_1,
     719  				    bpfsts_unk_attrs[i].val,
     720  				    bpfsts_unk_attrs[i].str,
     721  				    sizeof(dummy), &dummy, sizeof(dummy), 1,
     722  				    printf("\"\\xde\\xad\\xc0\\xde\""));
     723  	}
     724  
     725  	/* INET_DIAG_SK_BPF_STORAGES: SK_DIAG_BPF_STORAGE */
     726  	attr2 = SK_DIAG_BPF_STORAGE;
     727  	attr2_str = "SK_DIAG_BPF_STORAGE";
     728  
     729  	/* INET_DIAG_SK_BPF_STORAGES: SK_DIAG_BPF_STORAGE: unknown, undecoded */
     730  	static const struct strval16 bpfst_unk_attrs[] = {
     731  		{ ENUM_KNOWN(0, SK_DIAG_BPF_STORAGE_NONE) },
     732  		{ ENUM_KNOWN(0x1, SK_DIAG_BPF_STORAGE_NONE) },
     733  		{ ARG_XLAT_UNKNOWN(0x4, "SK_DIAG_BPF_STORAGE_???") },
     734  		{ ARG_XLAT_UNKNOWN(0x1ace, "SK_DIAG_BPF_STORAGE_???") },
     735  	};
     736  
     737  	for (size_t i = 0; i < ARRAY_SIZE(bpfst_unk_attrs); i++) {
     738  		TEST_NESTED_NLATTR_(fd, nlh0, hdrlen,
     739  				    init_inet_diag_nest_2,
     740  				    print_inet_diag_nest_2,
     741  				    bpfst_unk_attrs[i].val,
     742  				    bpfst_unk_attrs[i].str,
     743  				    sizeof(dummy), &dummy, sizeof(dummy), 2,
     744  				    printf("\"\\xde\\xad\\xc0\\xde\""));
     745  	}
     746  
     747  	/* INET_DIAG_SK_BPF_STORAGES: SK_DIAG_BPF_STORAGE: u32 */
     748  	static const struct strval16 bpfst_u32_attrs[] = {
     749  		{ ENUM_KNOWN(0x2, SK_DIAG_BPF_STORAGE_MAP_ID) },
     750  	};
     751  
     752  	for (size_t i = 0; i < ARRAY_SIZE(bpfst_u32_attrs); i++) {
     753  		check_u32_nlattr(fd, nlh_u32, hdrlen,
     754  				init_inet_diag_nest_2,
     755  				print_inet_diag_nest_2,
     756  				bpfst_u32_attrs[i].val, bpfst_u32_attrs[i].str,
     757  				pattern, 2);
     758  	}
     759  
     760  	/*
     761  	 * INET_DIAG_SK_BPF_STORAGES: SK_DIAG_BPF_STORAGE:
     762  	 *                            SK_DIAG_BPF_STORAGE_MAP_VALUE
     763  	 */
     764  	static const struct {
     765  		ssize_t sz;
     766  		const char *val;
     767  		const char *str;
     768  	} bpfst_vals[] = {
     769  		{ 1, "\xbe", "0xbe" },
     770  		{ 2, BE_LE("\xde\xad", "\xad\xde"), "0xdead" },
     771  		{ 3, "\xca\xff\xee", "\"\\xca\\xff\\xee\"" },
     772  		{ 4, BE_LE("\xba\xdc\x0d\xed", "\xed\x0d\xdc\xba"),
     773  		     "0xbadc0ded" },
     774  		{ 5, "\x00\x09\x0a\x0b\x0c",
     775  		     "\"\\x00\\x09\\x0a\\x0b\\x0c\"" },
     776  		{ 6, "012345",
     777  		     "\"\\x30\\x31\\x32\\x33\\x34\\x35\"" },
     778  		{ 7, "abcdefg",
     779  		     "\"\\x61\\x62\\x63\\x64\\x65\\x66\\x67\"" },
     780  		{ 8, BE_LE("\xbe\xef\xfa\xce\xde\xad\xc0\xde",
     781  			   "\xde\xc0\xad\xde\xce\xfa\xef\xbe"),
     782  		     "0xbeeffacedeadc0de" },
     783  		{ 9, "ABCDEFGHI",
     784  		     "\"\\x41\\x42\\x43\\x44\\x45\\x46\\x47\\x48\\x49\"" },
     785  		{ 10, "1234567890",
     786  		      "\"\\x31\\x32\\x33\\x34\\x35"
     787  		      "\\x36\\x37\\x38\\x39\\x30\"" },
     788  		{ 12, "a1b2c3d4e5f6",
     789  		      "\"\\x61\\x31\\x62\\x32\\x63\\x33"
     790  		      "\\x64\\x34\\x65\\x35\\x66\\x36\"" },
     791  		{ 16, "A1B2C3D4E5F6G7H8",
     792  		      "\"\\x41\\x31\\x42\\x32\\x43\\x33\\x44\\x34"
     793  		      "\\x45\\x35\\x46\\x36\\x47\\x37\\x48\\x38\"" },
     794  		{ 36, "abcdefghijklmnopqrstuvwxyz0123456789",
     795  		      "\"\\x61\\x62\\x63\\x64\\x65\\x66\\x67\\x68\\x69\\x6a"
     796  		      "\\x6b\\x6c\\x6d\\x6e\\x6f\\x70\\x71\\x72\\x73\\x74\\x75"
     797  		      "\\x76\\x77\\x78\\x79\\x7a\\x30\\x31\\x32\\x33\\x34\\x35"
     798  		      "\"..." },
     799  	};
     800  
     801  	for (size_t i = 0; i < ARRAY_SIZE(bpfst_vals); i++) {
     802  		TEST_NESTED_NLATTR_(fd, nlh0, hdrlen,
     803  				    init_inet_diag_nest_2,
     804  				    print_inet_diag_nest_2,
     805  				    SK_DIAG_BPF_STORAGE_MAP_VALUE,
     806  				    "SK_DIAG_BPF_STORAGE_MAP_VALUE",
     807  				    bpfst_vals[i].sz, bpfst_vals[i].val,
     808  				    bpfst_vals[i].sz, 2,
     809  				    printf("%s", bpfst_vals[i].str));
     810  	}
     811  
     812  	/* INET_DIAG_SOCKOPT */
     813  	static const struct {
     814  		ssize_t sz;
     815  		const char *val;
     816  		const char *str;
     817  	} sockopts[] = {
     818  		{ 1, "\xbe", "\"\\xbe\"" },
     819  		{ 2, "\x00\x00", "{}" },
     820  		{ 2, BE_LE("\xca\xa0", "\x53\x05"),
     821  		  "{recverr=1, is_icsk=1, mc_loop=1, mc_all=1"
     822  		  ", bind_address_no_port=1, defer_connect=1}" },
     823  		{ 3, BE_LE("\x1e\xad", "\x78\xb5"),
     824  		  "{hdrincl=1, mc_loop=1, transparent=1, mc_all=1"
     825  		  ", bind_address_no_port=1, defer_connect=1"
     826  		  ", unused=" BE_LE("0xd", "0x16") " /* bits 3..8 */}" },
     827  		{ 4, "\xff\xff\x00\xff",
     828  		  "{recverr=1, is_icsk=1, freebind=1, hdrincl=1, mc_loop=1"
     829  		  ", transparent=1, mc_all=1, nodefrag=1"
     830  		  ", bind_address_no_port=1, recverr_rfc4884=1, defer_connect=1"
     831  		  ", unused=0x1f /* bits 3..8 */}"
     832  		  ", /* bytes 2..3 */ \"\\x00\\xff\"" },
     833  	};
     834  
     835  	for (size_t i = 0; i < ARRAY_SIZE(sockopts); i++) {
     836  		TEST_NLATTR(fd, nlh0, hdrlen,
     837  			    init_inet_diag_msg, print_inet_diag_msg,
     838  			    INET_DIAG_SOCKOPT,
     839  			    sockopts[i].sz, sockopts[i].val, sockopts[i].sz,
     840  			    printf("%s", sockopts[i].str));
     841  	}
     842  
     843  	/* INET_DIAG_LOCALS, INET_DIAG_PEERS */
     844  	static const struct strval16 sa_attrs[] = {
     845  		{ ENUM_KNOWN(0xc, INET_DIAG_LOCALS) },
     846  		{ ENUM_KNOWN(0xd, INET_DIAG_PEERS) },
     847  	};
     848  	enum {
     849  		SA_CNT = 3,
     850  		SA_SZ  = sizeof(struct sockaddr_storage) * SA_CNT,
     851  	};
     852  	void *nlh_sa = midtail_alloc(NLMSG_SPACE(hdrlen), SA_SZ);
     853  	struct sockaddr_storage buf[SA_CNT] = { { 0 } };
     854  
     855  	struct sockaddr_in *sa_in = (struct sockaddr_in *) (buf);
     856  	sa_in->sin_family = AF_INET;
     857  	sa_in->sin_port = htons(42069);
     858  	sa_in->sin_addr.s_addr = htonl(0x12345678);
     859  
     860  	struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *) (buf + 1);
     861  	sa_in6->sin6_family = AF_INET6;
     862  	sa_in6->sin6_port = htons(23456);
     863  	sa_in6->sin6_flowinfo = htonl(0x13579bdf);
     864  	sa_in6->sin6_scope_id = 0x2468ace0;
     865  	memcpy(sa_in6->sin6_addr.s6_addr,
     866  	       "\x12\x34\x56\x78\0\0\0\0\0\0\0\0\x9a\xbc\xde\xf0",
     867  	       sizeof(sa_in6->sin6_addr.s6_addr));
     868  
     869  	struct sockaddr_at *sa_at = (struct sockaddr_at *) (buf + 2);
     870  	sa_at->sat_family = AF_APPLETALK;
     871  	sa_at->sat_port = 0x69;
     872  	sa_at->sat_addr.s_net = 0x8765;
     873  	sa_at->sat_addr.s_node = 0x42;
     874  
     875  	for (size_t i = 0; i < ARRAY_SIZE(sa_attrs); i++) {
     876  		TEST_NLATTR_ARRAY_(fd, nlh_sa, hdrlen,
     877  				   init_inet_diag_msg, print_inet_diag_msg,
     878  				   sa_attrs[i].val, sa_attrs[i].str,
     879  				   pattern, buf, print_sa);
     880  	}
     881  
     882  	puts("+++ exited with 0 +++");
     883  	return 0;
     884  }