Home | History | Annotate | Download | only in tests-m32
      1 /*
      2  * IFLA_LINKINFO netlink attribute decoding check.
      3  *
      4  * Copyright (c) 2018 The strace developers.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. The name of the author may not be used to endorse or promote products
     16  *    derived from this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 #include "tests.h"
     31 
     32 #include <inttypes.h>
     33 #include <stdio.h>
     34 #include <stddef.h>
     35 #include <arpa/inet.h>
     36 
     37 #include "test_nlattr.h"
     38 
     39 #include <linux/if.h>
     40 #include <linux/if_arp.h>
     41 #ifdef HAVE_LINUX_IF_LINK_H
     42 # include <linux/if_link.h>
     43 #endif
     44 #include <linux/rtnetlink.h>
     45 
     46 #define XLAT_MACROS_ONLY
     47 # include <xlat/rtnl_link_attrs.h>
     48 # include <xlat/rtnl_ifla_info_attrs.h>
     49 #undef XLAT_MACROS_ONLY
     50 
     51 #define IFLA_ATTR IFLA_LINKINFO
     52 #include "nlattr_ifla.h"
     53 
     54 #define COMMA ,
     55 #define TEST_UNKNOWN_TUNNELS(fd_, nlh0_, objtype_, objtype_str_,	\
     56 			     obj_, objsz_, arrstrs_, ...)		\
     57 	do {								\
     58 		/* 64 is guestimate for maximum unknown type len */	\
     59 		char buf[8 * 2 + 64 + objsz_];				\
     60 		const char **arrstrs[] = arrstrs_;			\
     61 		const char ***arrstrs_pos = arrstrs;			\
     62 		const char **arrstr = *arrstrs_pos;			\
     63 		const char *type = NULL;				\
     64 									\
     65 		for (type = arrstr ? arrstr[0] : NULL; type && arrstr;	\
     66 		     type = (++arrstr)[0] ? arrstr[0]			\
     67 					  : (++arrstrs_pos)[0]		\
     68 				             ? (arrstr = arrstrs_pos[0])[0] \
     69 					     : NULL)			\
     70 		{							\
     71 			size_t type_len = strlen(type) + 1;		\
     72 									\
     73 			if (type_len > 64)				\
     74 				error_msg_and_fail("Unexpectedly long "	\
     75 						   "unknown type: \"%s\" " \
     76 						   "(length is %zu)",	\
     77 						   type, type_len);	\
     78 									\
     79 			struct nlattr obj_nla = {			\
     80 				.nla_len = NLA_HDRLEN + (objsz_),	\
     81 				.nla_type = (objtype_),			\
     82 			};						\
     83 									\
     84 			char *pos = buf;				\
     85 			memcpy(pos, type, type_len);			\
     86 			pos += NLA_ALIGN(type_len);			\
     87 			memcpy(pos, &obj_nla, sizeof(obj_nla));		\
     88 			pos += sizeof(obj_nla);				\
     89 			memcpy(pos, (obj_), (objsz_));			\
     90 									\
     91 			TEST_NLATTR_EX_((fd_),				\
     92 					(nlh0_) - hdrlen - (pos - buf),	\
     93 					hdrlen + NLA_HDRLEN,		\
     94 					init_ifinfomsg, print_ifinfomsg, \
     95 					IFLA_INFO_KIND, "IFLA_INFO_KIND", \
     96 					type_len, objsz_ + (pos - buf),	\
     97 					buf, objsz_ + (pos - buf),	\
     98 					printf("\"%s\"}", type);	\
     99 					printf(", {{nla_len=%zu"	\
    100 				               ", nla_type=%s}, ",	\
    101 					       (objsz_) + NLA_HDRLEN,	\
    102 					       (objtype_str_));		\
    103 									\
    104 					{ __VA_ARGS__; }		\
    105 									\
    106 					printf("}"));			\
    107 		}							\
    108 	} while (0)
    109 
    110 #define TEST_LINKINFO_(fd_, nlh0_, nla_type_, nla_type_str_, tuntype_,	\
    111 		       obj_, objsz_, pattern_, fallback_func_, ...)	\
    112 	do {								\
    113 		size_t tuntype_len = strlen(tuntype_) + 1;		\
    114 		char *buf = tail_alloc(NLA_ALIGN(tuntype_len)		\
    115 				       + NLA_HDRLEN + (objsz_));	\
    116 		char *pos = buf;					\
    117 									\
    118 		struct nlattr obj_nla = {				\
    119 			.nla_len = NLA_HDRLEN + (objsz_),		\
    120 			.nla_type = (nla_type_),			\
    121 		};							\
    122 									\
    123 		memcpy(pos, (tuntype_), tuntype_len);			\
    124 		pos += NLA_ALIGN(tuntype_len);				\
    125 		memcpy(pos, &obj_nla, sizeof(obj_nla));			\
    126 		pos += sizeof(obj_nla);					\
    127 		memcpy(pos, &(obj_), (objsz_));				\
    128 									\
    129 		if (fallback_func_ == print_quoted_hex) {		\
    130 			TEST_NLATTR_EX_((fd_),				\
    131 					(nlh0_) - NLA_HDRLEN,		\
    132 					hdrlen + NLA_HDRLEN,		\
    133 					init_ifinfomsg, print_ifinfomsg, \
    134 					IFLA_INFO_KIND, "IFLA_INFO_KIND", \
    135 					tuntype_len,			\
    136 					objsz_ + (pos - buf) - 1,	\
    137 					buf, objsz_ + (pos - buf) - 1,	\
    138 					printf("\"%s\"}", (tuntype_));	\
    139 					printf(", {{nla_len=%zu"	\
    140 					       ", nla_type=%s}, ",	\
    141 					       (objsz_) + NLA_HDRLEN,	\
    142 					       (nla_type_str_));	\
    143 					(fallback_func_)((obj_),	\
    144 							 (objsz_) - 1);	\
    145 					printf("}"));			\
    146 		}							\
    147 									\
    148 		TEST_NLATTR_EX_((fd_), (nlh0_) - NLA_HDRLEN,		\
    149 				hdrlen + NLA_HDRLEN,			\
    150 				init_ifinfomsg, print_ifinfomsg,	\
    151 				IFLA_INFO_KIND, "IFLA_INFO_KIND",	\
    152 				tuntype_len, objsz_ + (pos - buf),	\
    153 				buf, objsz_ + (pos - buf) - 1,		\
    154 				printf("\"%s\"}", (tuntype_));		\
    155 				printf(", {{nla_len=%zu, nla_type=%s}, ", \
    156 				       (objsz_) + NLA_HDRLEN,		\
    157 				       (nla_type_str_));		\
    158 				printf("%p}",				\
    159 				       RTA_DATA(NLMSG_ATTR(nlh,		\
    160 				       (hdrlen + NLA_HDRLEN + (pos - buf)))) \
    161 				       )				\
    162 				);					\
    163 									\
    164 		TEST_NLATTR_EX_((fd_), (nlh0_) - NLA_HDRLEN,		\
    165 				hdrlen + NLA_HDRLEN,			\
    166 				init_ifinfomsg, print_ifinfomsg,	\
    167 				IFLA_INFO_KIND, "IFLA_INFO_KIND",	\
    168 				tuntype_len, objsz_ + (pos - buf),	\
    169 				buf, objsz_ + (pos - buf),		\
    170 				printf("\"%s\"}", (tuntype_));		\
    171 				printf(", {{nla_len=%zu, nla_type=%s}, ", \
    172 				       (objsz_) + NLA_HDRLEN,		\
    173 				       (nla_type_str_));		\
    174 									\
    175 				{ __VA_ARGS__; }			\
    176 									\
    177 				printf("}"));				\
    178 	} while (0)
    179 
    180 #define TEST_LINKINFO(fd_, nlh0_, nla_type_, tuntype_,	\
    181 		      obj_, pattern_, fallback_func_, ...)	\
    182 	TEST_LINKINFO_((fd_), (nlh0_), nla_type_, #nla_type_, (tuntype_), \
    183 		       (obj_), sizeof(obj_), pattern_, fallback_func_,	\
    184 		       __VA_ARGS__)
    185 
    186 #define TEST_NESTED_LINKINFO(fd_, nlh0_,				\
    187 			     nla_type_, nla_type_str_, tuntype_,	\
    188 			     subnla_type_, subnla_type_str_,		\
    189 			     obj_, pattern_, ...)			\
    190 	do {								\
    191 		size_t tuntype_len = strlen(tuntype_) + 1;		\
    192 		struct {						\
    193 			size_t sz;					\
    194 			const char *str;				\
    195 		} attrs[] = { __VA_ARGS__ };				\
    196 		size_t tunhdrlen;					\
    197 		size_t buflen = NLA_ALIGN(tuntype_len) + NLA_HDRLEN;	\
    198 		size_t attrsz = 0;					\
    199 									\
    200 		for (size_t i = 0; i < ARRAY_SIZE(attrs); i++)		\
    201 			attrsz += NLA_HDRLEN + NLA_ALIGN(attrs[i].sz);	\
    202 									\
    203 		buflen += attrsz;					\
    204 									\
    205 		char *buf = tail_alloc(buflen);				\
    206 		char *pos = buf;					\
    207 									\
    208 		struct nlattr nla = {					\
    209 			.nla_len = NLA_HDRLEN + attrsz,			\
    210 			.nla_type = (nla_type_),			\
    211 		};							\
    212 									\
    213 		memcpy(pos, (tuntype_), tuntype_len);			\
    214 		pos += NLA_ALIGN(tuntype_len);				\
    215 		memcpy(pos, &nla, sizeof(nla));				\
    216 		pos += sizeof(nla);					\
    217 									\
    218 		tunhdrlen = pos - buf;					\
    219 									\
    220 		nla.nla_type = subnla_type_;				\
    221 									\
    222 		for (size_t i = 0; i < ARRAY_SIZE(attrs); i++) {	\
    223 			nla.nla_len = NLA_HDRLEN + attrs[i].sz;		\
    224 			memcpy(pos, &nla, sizeof(nla));			\
    225 			pos += sizeof(nla);				\
    226 									\
    227 			memcpy(pos, &(obj_), MIN(sizeof(obj_), attrs[i].sz)); \
    228 									\
    229 			if (attrs[i].sz > sizeof(obj_))			\
    230 				memcpy(pos + sizeof(obj_),		\
    231 				       &(pattern_),			\
    232 				       attrs[i].sz - sizeof(obj_));	\
    233 									\
    234 			pos += NLA_ALIGN(attrs[i].sz);			\
    235 		}							\
    236 									\
    237 		TEST_NLATTR_EX_((fd_), (nlh0_) - hdrlen - tunhdrlen,	\
    238 				hdrlen + NLA_HDRLEN,			\
    239 				init_ifinfomsg, print_ifinfomsg,	\
    240 				IFLA_INFO_KIND, "IFLA_INFO_KIND",	\
    241 				tuntype_len, buflen,			\
    242 				buf, buflen,				\
    243 				printf("\"%s\"}", (tuntype_));		\
    244 				printf(", {{nla_len=%zu, nla_type=%s}, [", \
    245 				       attrsz + NLA_HDRLEN,		\
    246 				       (nla_type_str_));		\
    247 									\
    248 				for (size_t i = 0; i < ARRAY_SIZE(attrs); i++) \
    249 					printf("%s%s{nla_len=%zu"	\
    250 					       ", nla_type=%s}%s%s%s",	\
    251 					       i ? ", " : "",		\
    252 					       attrs[i].str ? "{": "",	\
    253 					       attrs[i].sz + NLA_HDRLEN, \
    254 					       subnla_type_str_,	\
    255 					       attrs[i].str ? ", ": "", \
    256 					       attrs[i].str ?: "",	\
    257 					       attrs[i].str ? "}" : ""); \
    258 									\
    259 				printf("]}"));				\
    260 	} while (0)
    261 
    262 int
    263 main(void)
    264 {
    265 	static const uint8_t unknown_msg[] = { 0xab, 0xac, 0xdb, 0xcd };
    266 	static const char *unsupported_tunnel_types[] = {
    267 		"batadv", "bond",
    268 		"caif", "cfhsi",
    269 		"dummy",
    270 		"erspan",
    271 		"geneve", "gre", "gretap", "gtp",
    272 		"hsr",
    273 		"ifb", "ip6erspan", "ip6gre", "ip6gretap", "ip6tnl",
    274 		"ipip", "ipoib", "ipvlan", "ipvtap",
    275 		"lowpan",
    276 		"macsec", "macvlan", "macvtap",
    277 		"netdevsim", "nlmon",
    278 		"openvswitch",
    279 		"ppp",
    280 		"rmnet",
    281 		"sit",
    282 		"team",
    283 		"vcan", "veth", "vlan", "vrf", "vsockmon",
    284 		"vti", "vti6", "vxcan", "vxlan",
    285 		NULL
    286 	};
    287 	static const char *unsupported_xstats_types[] = {
    288 		"bridge",
    289 		"tun",
    290 		NULL
    291 	};
    292 	static const char *unsupported_data_types[] = {
    293 		"can",
    294 		NULL
    295 	};
    296 
    297 	skip_if_unavailable("/proc/self/fd/");
    298 
    299 	const int fd = create_nl_socket(NETLINK_ROUTE);
    300 
    301 	const unsigned int hdrlen = sizeof(struct ifinfomsg);
    302 	void *nlh0 = midtail_alloc(NLMSG_SPACE(hdrlen), 2 * NLA_HDRLEN + 256);
    303 
    304 	static char pattern[4096];
    305 	fill_memory_ex(pattern, sizeof(pattern), 'a', 'z' - 'a' + 1);
    306 
    307 
    308 	/* unknown AF_INFO_* type */
    309 	TEST_NESTED_NLATTR_OBJECT(fd, nlh0, hdrlen,
    310 			   init_ifinfomsg, print_ifinfomsg,
    311 			   IFLA_INFO_UNSPEC, pattern, unknown_msg,
    312 			   printf("\"\\xab\\xac\\xdb\\xcd\""));
    313 
    314 	TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen,
    315 			       init_ifinfomsg, print_ifinfomsg,
    316 			       6, "0x6 /* IFLA_INFO_??? */", pattern,
    317 			       unknown_msg, print_quoted_hex, 1,
    318 			       printf("\"\\xab\\xac\\xdb\\xcd\""));
    319 
    320 
    321 	/* IFLA_INFO_KIND */
    322 	TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen,
    323 				      init_ifinfomsg, print_ifinfomsg,
    324 				      IFLA_INFO_KIND, "IFLA_INFO_KIND", pattern,
    325 				      unknown_msg, print_quoted_stringn, 1,
    326 				      printf("\"\\253\\254\\333\\315\"..."));
    327 
    328 
    329 	/* IFLA_INFO_KIND + IFLA_INFO_UNSPEC */
    330 	TEST_UNKNOWN_TUNNELS(fd, nlh0, IFLA_INFO_UNSPEC, "IFLA_INFO_UNSPEC",
    331 			     unknown_msg, sizeof(unknown_msg),
    332 			     {unsupported_tunnel_types COMMA
    333 			      unsupported_xstats_types COMMA
    334 			      unsupported_data_types COMMA
    335 			      NULL},
    336 			     printf("\"\\xab\\xac\\xdb\\xcd\""));
    337 
    338 
    339 	/* IFLA_INFO_KIND + IFLA_INFO_KIND */
    340 	TEST_UNKNOWN_TUNNELS(fd, nlh0, IFLA_INFO_KIND, "IFLA_INFO_KIND",
    341 			     unknown_msg, sizeof(unknown_msg),
    342 			     {unsupported_tunnel_types COMMA
    343 			      unsupported_xstats_types COMMA
    344 			      unsupported_data_types COMMA
    345 			      NULL},
    346 			     printf("\"\\253\\254\\333\\315\"..."));
    347 
    348 
    349 	/* IFLA_INFO_KIND + IFLA_INFO_DATA */
    350 	TEST_UNKNOWN_TUNNELS(fd, nlh0, IFLA_INFO_DATA, "IFLA_INFO_DATA",
    351 			     unknown_msg, sizeof(unknown_msg),
    352 			     {unsupported_tunnel_types COMMA
    353 			      unsupported_data_types COMMA
    354 			      NULL},
    355 			     printf("\"\\xab\\xac\\xdb\\xcd\""));
    356 
    357 	struct val_name {
    358 		unsigned int val;
    359 		const char *name;
    360 	};
    361 
    362 	static const uint64_t u64_val = 0xdeadc0defacefeedULL;
    363 	static const uint32_t u32_val = 0xbadc0dedU;
    364 	static const uint16_t u16_val = 0xdeed;
    365 	static const uint8_t  u8_val  = 0xa1;
    366 
    367 	/* bridge attrs */
    368 	static const struct val_name und_br_attrs[] = {
    369 		{ 0, "IFLA_BR_UNSPEC" },
    370 		{ 20, "IFLA_BR_GROUP_ADDR" },
    371 		{ 21, "IFLA_BR_FDB_FLUSH" },
    372 		{ 40, "IFLA_BR_PAD" },
    373 		{ 45, "0x2d /* IFLA_BR_??? */" },
    374 	};
    375 
    376 	for (size_t k = 0; k < ARRAY_SIZE(und_br_attrs); k++) {
    377 		TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "bridge",
    378 				     und_br_attrs[k].val, und_br_attrs[k].name,
    379 				     unknown_msg, pattern,
    380 				     { 2, "\"\\xab\\xac\"" },
    381 				     { 4, "\"\\xab\\xac\\xdb\\xcd\"" },
    382 				     { 6,
    383 					"\"\\xab\\xac\\xdb\\xcd\\x61\\x62\"" },
    384 				     { 8, "\"\\xab\\xac\\xdb\\xcd\\x61\\x62"
    385 					"\\x63\\x64\"" },
    386 				     { 10, "\"\\xab\\xac\\xdb\\xcd\\x61\\x62"
    387 					"\\x63\\x64\\x65\\x66\"" });
    388 	}
    389 
    390 	static const struct val_name u64_br_attrs[] = {
    391 		{ 16, "IFLA_BR_HELLO_TIMER" },
    392 		{ 17, "IFLA_BR_TCN_TIMER" },
    393 		{ 18, "IFLA_BR_TOPOLOGY_CHANGE_TIMER" },
    394 		{ 19, "IFLA_BR_GC_TIMER" },
    395 		{ 30, "IFLA_BR_MCAST_LAST_MEMBER_INTVL" },
    396 		{ 31, "IFLA_BR_MCAST_MEMBERSHIP_INTVL" },
    397 		{ 32, "IFLA_BR_MCAST_QUERIER_INTVL" },
    398 		{ 33, "IFLA_BR_MCAST_QUERY_INTVL" },
    399 		{ 34, "IFLA_BR_MCAST_QUERY_RESPONSE_INTVL" },
    400 		{ 35, "IFLA_BR_MCAST_STARTUP_QUERY_INTVL" },
    401 	};
    402 
    403 	for (size_t k = 0; k < ARRAY_SIZE(u64_br_attrs); k++) {
    404 		TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "bridge",
    405 				     u64_br_attrs[k].val, u64_br_attrs[k].name,
    406 				     u64_val, pattern,
    407 				     { 7, "\""
    408 #if WORDS_BIGENDIAN
    409 					"\\xde\\xad\\xc0\\xde\\xfa\\xce\\xfe"
    410 #else
    411 					"\\xed\\xfe\\xce\\xfa\\xde\\xc0\\xad"
    412 #endif
    413 					"\"" },
    414 				     { 8, "16045693111314087661" },
    415 				     { 9, "16045693111314087661" });
    416 	}
    417 
    418 	static const struct val_name u32_br_attrs[] = {
    419 		{  1, "IFLA_BR_FORWARD_DELAY" },
    420 		{  2, "IFLA_BR_HELLO_TIME" },
    421 		{  3, "IFLA_BR_MAX_AGE" },
    422 		{  4, "IFLA_BR_AGEING_TIME" },
    423 		{  5, "IFLA_BR_STP_STATE" },
    424 		{ 13, "IFLA_BR_ROOT_PATH_COST" },
    425 		{ 26, "IFLA_BR_MCAST_HASH_ELASTICITY" },
    426 		{ 27, "IFLA_BR_MCAST_HASH_MAX" },
    427 		{ 28, "IFLA_BR_MCAST_LAST_MEMBER_CNT" },
    428 		{ 29, "IFLA_BR_MCAST_STARTUP_QUERY_CNT" },
    429 	};
    430 
    431 	for (size_t k = 0; k < ARRAY_SIZE(u32_br_attrs); k++) {
    432 		TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "bridge",
    433 				     u32_br_attrs[k].val, u32_br_attrs[k].name,
    434 				     u32_val, pattern,
    435 				     { 3, "\""
    436 #if WORDS_BIGENDIAN
    437 					"\\xba\\xdc\\x0d"
    438 #else
    439 					"\\xed\\x0d\\xdc"
    440 #endif
    441 					"\"" },
    442 				     { 4, "3134983661" },
    443 				     { 5, "3134983661" });
    444 	}
    445 
    446 	static const struct val_name u16_br_attrs[] = {
    447 		{  6, "IFLA_BR_PRIORITY" },
    448 		{ 12, "IFLA_BR_ROOT_PORT" },
    449 		{ 39, "IFLA_BR_VLAN_DEFAULT_PVID" },
    450 	};
    451 
    452 	for (size_t k = 0; k < ARRAY_SIZE(u16_br_attrs); k++) {
    453 		TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "bridge",
    454 				     u16_br_attrs[k].val, u16_br_attrs[k].name,
    455 				     u16_val, pattern,
    456 				     { 1, "\""
    457 #if WORDS_BIGENDIAN
    458 					"\\xde"
    459 #else
    460 					"\\xed"
    461 #endif
    462 					"\"" },
    463 				     { 2, "57069" },
    464 				     { 3, "57069" });
    465 	}
    466 
    467 
    468 	static const struct val_name x16_br_attrs[] = {
    469 		{  9, "IFLA_BR_GROUP_FWD_MASK" },
    470 	};
    471 
    472 	for (size_t k = 0; k < ARRAY_SIZE(x16_br_attrs); k++) {
    473 		TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "bridge",
    474 				     x16_br_attrs[k].val, x16_br_attrs[k].name,
    475 				     u16_val, pattern,
    476 				     { 1, "\""
    477 #if WORDS_BIGENDIAN
    478 					"\\xde"
    479 #else
    480 					"\\xed"
    481 #endif
    482 					"\"" },
    483 				     { 2, "0xdeed" },
    484 				     { 3, "0xdeed" });
    485 	}
    486 
    487 	static const struct val_name u8_br_attrs[] = {
    488 		{  7, "IFLA_BR_VLAN_FILTERING" },
    489 		{ 14, "IFLA_BR_TOPOLOGY_CHANGE" },
    490 		{ 15, "IFLA_BR_TOPOLOGY_CHANGE_DETECTED" },
    491 		{ 22, "IFLA_BR_MCAST_ROUTER" },
    492 		{ 23, "IFLA_BR_MCAST_SNOOPING" },
    493 		{ 24, "IFLA_BR_MCAST_QUERY_USE_IFADDR" },
    494 		{ 25, "IFLA_BR_MCAST_QUERIER" },
    495 		{ 36, "IFLA_BR_NF_CALL_IPTABLES" },
    496 		{ 37, "IFLA_BR_NF_CALL_IP6TABLES" },
    497 		{ 38, "IFLA_BR_NF_CALL_ARPTABLES" },
    498 		{ 41, "IFLA_BR_VLAN_STATS_ENABLED" },
    499 		{ 42, "IFLA_BR_MCAST_STATS_ENABLED" },
    500 		{ 43, "IFLA_BR_MCAST_IGMP_VERSION" },
    501 		{ 44, "IFLA_BR_MCAST_MLD_VERSION" },
    502 	};
    503 
    504 	for (size_t k = 0; k < ARRAY_SIZE(u8_br_attrs); k++) {
    505 		TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "bridge",
    506 				     u8_br_attrs[k].val, u8_br_attrs[k].name,
    507 				     u8_val, pattern,
    508 				     { 0, NULL },
    509 				     { 1, "161" },
    510 				     { 2, "161" });
    511 	}
    512 
    513 	unsigned short eth_p = htons(0x88C7);
    514 	TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "bridge",
    515 			     8, "IFLA_BR_VLAN_PROTOCOL",
    516 			     eth_p, pattern,
    517 			     { 1, "\"\\x88\"" },
    518 			     { 2, "htons(ETH_P_PREAUTH)" },
    519 			     { 2, "htons(ETH_P_PREAUTH)" });
    520 
    521 	static const uint8_t bridge_id[]
    522 		= { 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xc0, 0xde, 0xad };
    523 	static const struct val_name br_id_attrs[] = {
    524 		{ 10, "IFLA_BR_ROOT_ID" },
    525 		{ 11, "IFLA_BR_BRIDGE_ID" },
    526 	};
    527 
    528 	for (size_t k = 0; k < ARRAY_SIZE(br_id_attrs); k++) {
    529 		TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "bridge",
    530 				     br_id_attrs[k].val, br_id_attrs[k].name,
    531 				     bridge_id, pattern,
    532 				     { 7, "\"\\xbe\\xef\\xfa\\xce"
    533 					  "\\xde\\xc0\\xde\"" },
    534 				     { 8, "{prio=[190, 239]"
    535 					  ", addr=fa:ce:de:c0:de:ad}" },
    536 				     { 9, "{prio=[190, 239]"
    537 					  ", addr=fa:ce:de:c0:de:ad}" });
    538 	}
    539 
    540 	/* tun attrs */
    541 	static const struct val_name u8_tun_attrs[] = {
    542 		{ 4, "IFLA_TUN_PI" },
    543 		{ 5, "IFLA_TUN_VNET_HDR" },
    544 		{ 6, "IFLA_TUN_PERSIST" },
    545 		{ 7, "IFLA_TUN_MULTI_QUEUE" },
    546 	};
    547 
    548 	for (size_t k = 0; k < ARRAY_SIZE(u8_tun_attrs); k++) {
    549 		TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "tun",
    550 				     u8_tun_attrs[k].val, u8_tun_attrs[k].name,
    551 				     u8_val, pattern,
    552 				     { 0, NULL },
    553 				     { 1, "161" },
    554 				     { 2, "161" });
    555 	}
    556 
    557 	static const struct val_name u32_tun_attrs[] = {
    558 		{ 8, "IFLA_TUN_NUM_QUEUES" },
    559 		{ 9, "IFLA_TUN_NUM_DISABLED_QUEUES" },
    560 	};
    561 
    562 	for (size_t k = 0; k < ARRAY_SIZE(u32_tun_attrs); k++) {
    563 		TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "tun",
    564 				     u32_tun_attrs[k].val,
    565 				     u32_tun_attrs[k].name,
    566 				     u32_val, pattern,
    567 				     { 3, "\""
    568 #if WORDS_BIGENDIAN
    569 					"\\xba\\xdc\\x0d"
    570 #else
    571 					"\\xed\\x0d\\xdc"
    572 #endif
    573 					"\"" },
    574 				     { 4, "3134983661" },
    575 				     { 5, "3134983661" });
    576 	}
    577 
    578 	static const struct val_name und_tun_attrs[] = {
    579 		{ 0,  "IFLA_TUN_UNSPEC" },
    580 		{ 10, "0xa /* IFLA_TUN_??? */" },
    581 	};
    582 
    583 	for (size_t k = 0; k < ARRAY_SIZE(und_tun_attrs); k++) {
    584 		TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "tun",
    585 				     und_tun_attrs[k].val,
    586 				     und_tun_attrs[k].name,
    587 				     unknown_msg, pattern,
    588 				     { 2, "\"\\xab\\xac\"" },
    589 				     { 4, "\"\\xab\\xac\\xdb\\xcd\"" },
    590 				     { 6,
    591 					"\"\\xab\\xac\\xdb\\xcd\\x61\\x62\"" },
    592 				     { 8, "\"\\xab\\xac\\xdb\\xcd\\x61\\x62"
    593 					"\\x63\\x64\"" },
    594 				     { 10, "\"\\xab\\xac\\xdb\\xcd\\x61\\x62"
    595 					"\\x63\\x64\\x65\\x66\"" });
    596 	}
    597 
    598 	static const uint32_t minus_one = 0xffffffffU;
    599 	static const struct val_name uid_tun_attrs[] = {
    600 		{ 1, "IFLA_TUN_OWNER" },
    601 		{ 2, "IFLA_TUN_GROUP" },
    602 	};
    603 
    604 	for (size_t k = 0; k < ARRAY_SIZE(uid_tun_attrs); k++) {
    605 		TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "tun",
    606 				     uid_tun_attrs[k].val,
    607 				     uid_tun_attrs[k].name,
    608 				     u32_val, pattern,
    609 				     { 3, "\""
    610 #if WORDS_BIGENDIAN
    611 					"\\xba\\xdc\\x0d"
    612 #else
    613 					"\\xed\\x0d\\xdc"
    614 #endif
    615 					"\"" },
    616 				     { 4, "3134983661" },
    617 				     { 5, "3134983661" });
    618 
    619 		TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "tun",
    620 				     uid_tun_attrs[k].val,
    621 				     uid_tun_attrs[k].name,
    622 				     minus_one, pattern,
    623 				     { 3, "\"\\xff\\xff\\xff\"" },
    624 				     { 4, "-1" },
    625 				     { 5, "-1" });
    626 	}
    627 
    628 	static const struct {
    629 		uint8_t val;
    630 		const char *str;
    631 	} tun_types[] = {
    632 		{ 0, "0 /* IFF_??? */"},
    633 		{ 1, "IFF_TUN"},
    634 		{ 2, "IFF_TAP"},
    635 		{ 3, "0x3 /* IFF_??? */"},
    636 		{ 0xda, "0xda /* IFF_??? */"},
    637 	};
    638 
    639 	for (size_t k = 0; k < ARRAY_SIZE(tun_types); k++) {
    640 		TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "tun",
    641 				     3, "IFLA_TUN_TYPE",
    642 				     tun_types[k].val, pattern,
    643 				     { 0, NULL },
    644 				     { 1, tun_types[k].str },
    645 				     { 2, tun_types[k].str });
    646 	}
    647 
    648 
    649 	/* IFLA_INFO_KIND + IFLA_INFO_XSTATS */
    650 	TEST_UNKNOWN_TUNNELS(fd, nlh0, IFLA_INFO_XSTATS, "IFLA_INFO_XSTATS",
    651 			     unknown_msg, sizeof(unknown_msg),
    652 			     {unsupported_tunnel_types COMMA
    653 			     /*
    654 			      * can decoder decodes its data only if it's big
    655 			      * enough.
    656 			      */
    657 			      unsupported_xstats_types COMMA
    658 			      unsupported_data_types COMMA
    659 			      NULL},
    660 			     printf("\"\\xab\\xac\\xdb\\xcd\""));
    661 
    662 	uint32_t can_stats_data[] = {
    663 		0xbadc0de0, 0xbadc0de1, 0xbadc0de2, 0xbadc0de3,
    664 		0xbadc0de4, 0xbadc0de5,
    665 	};
    666 
    667 	TEST_LINKINFO(fd, nlh0, IFLA_INFO_XSTATS, "can",
    668 		      can_stats_data, pattern, print_quoted_hex,
    669 		      printf("{bus_error=3134983648"
    670 			     ", error_warning=3134983649"
    671 			     ", error_passive=3134983650"
    672 			     ", bus_off=3134983651"
    673 			     ", arbitration_lost=3134983652"
    674 			     ", restarts=3134983653}"));
    675 
    676 
    677 	/* IFLA_INFO_KIND + IFLA_INFO_SLVAE_KIND */
    678 	TEST_UNKNOWN_TUNNELS(fd, nlh0,
    679 			     IFLA_INFO_SLAVE_KIND, "IFLA_INFO_SLAVE_KIND",
    680 			     unknown_msg, sizeof(unknown_msg),
    681 			     {unsupported_tunnel_types COMMA
    682 			      unsupported_xstats_types COMMA
    683 			      unsupported_data_types COMMA
    684 			      NULL},
    685 			     printf("\"\\253\\254\\333\\315\"..."));
    686 
    687 
    688 	/* IFLA_INFO_KIND + IFLA_INFO_SLAVE_DATA */
    689 	TEST_UNKNOWN_TUNNELS(fd, nlh0,
    690 			     IFLA_INFO_SLAVE_DATA, "IFLA_INFO_SLAVE_DATA",
    691 			     unknown_msg, sizeof(unknown_msg),
    692 			     {unsupported_tunnel_types COMMA
    693 			      unsupported_xstats_types COMMA
    694 			      unsupported_data_types COMMA
    695 			      NULL},
    696 			     printf("\"\\xab\\xac\\xdb\\xcd\""));
    697 
    698 
    699 	/* IFLA_INFO_KIND + unknown type */
    700 	TEST_UNKNOWN_TUNNELS(fd, nlh0, 6, "0x6 /* IFLA_INFO_??? */",
    701 			     unknown_msg, sizeof(unknown_msg),
    702 			     {unsupported_tunnel_types COMMA
    703 			      unsupported_xstats_types COMMA
    704 			      unsupported_data_types COMMA
    705 			      NULL},
    706 			     printf("\"\\xab\\xac\\xdb\\xcd\""));
    707 
    708 
    709 	puts("+++ exited with 0 +++");
    710 	return 0;
    711 }
    712