/*
* IFLA_LINKINFO netlink attribute decoding check.
*
* Copyright (c) 2018 The strace developers.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "tests.h"
#include <inttypes.h>
#include <stdio.h>
#include <stddef.h>
#include <arpa/inet.h>
#include "test_nlattr.h"
#include <linux/if.h>
#include <linux/if_arp.h>
#ifdef HAVE_LINUX_IF_LINK_H
# include <linux/if_link.h>
#endif
#include <linux/rtnetlink.h>
#define XLAT_MACROS_ONLY
# include <xlat/rtnl_link_attrs.h>
# include <xlat/rtnl_ifla_info_attrs.h>
#undef XLAT_MACROS_ONLY
#define IFLA_ATTR IFLA_LINKINFO
#include "nlattr_ifla.h"
#define COMMA ,
#define TEST_UNKNOWN_TUNNELS(fd_, nlh0_, objtype_, objtype_str_, \
obj_, objsz_, arrstrs_, ...) \
do { \
/* 64 is guestimate for maximum unknown type len */ \
char buf[8 * 2 + 64 + objsz_]; \
const char **arrstrs[] = arrstrs_; \
const char ***arrstrs_pos = arrstrs; \
const char **arrstr = *arrstrs_pos; \
const char *type = NULL; \
\
for (type = arrstr ? arrstr[0] : NULL; type && arrstr; \
type = (++arrstr)[0] ? arrstr[0] \
: (++arrstrs_pos)[0] \
? (arrstr = arrstrs_pos[0])[0] \
: NULL) \
{ \
size_t type_len = strlen(type) + 1; \
\
if (type_len > 64) \
error_msg_and_fail("Unexpectedly long " \
"unknown type: \"%s\" " \
"(length is %zu)", \
type, type_len); \
\
struct nlattr obj_nla = { \
.nla_len = NLA_HDRLEN + (objsz_), \
.nla_type = (objtype_), \
}; \
\
char *pos = buf; \
memcpy(pos, type, type_len); \
pos += NLA_ALIGN(type_len); \
memcpy(pos, &obj_nla, sizeof(obj_nla)); \
pos += sizeof(obj_nla); \
memcpy(pos, (obj_), (objsz_)); \
\
TEST_NLATTR_EX_((fd_), \
(nlh0_) - hdrlen - (pos - buf), \
hdrlen + NLA_HDRLEN, \
init_ifinfomsg, print_ifinfomsg, \
IFLA_INFO_KIND, "IFLA_INFO_KIND", \
type_len, objsz_ + (pos - buf), \
buf, objsz_ + (pos - buf), \
printf("\"%s\"}", type); \
printf(", {{nla_len=%zu" \
", nla_type=%s}, ", \
(objsz_) + NLA_HDRLEN, \
(objtype_str_)); \
\
{ __VA_ARGS__; } \
\
printf("}")); \
} \
} while (0)
#define TEST_LINKINFO_(fd_, nlh0_, nla_type_, nla_type_str_, tuntype_, \
obj_, objsz_, pattern_, fallback_func_, ...) \
do { \
size_t tuntype_len = strlen(tuntype_) + 1; \
char *buf = tail_alloc(NLA_ALIGN(tuntype_len) \
+ NLA_HDRLEN + (objsz_)); \
char *pos = buf; \
\
struct nlattr obj_nla = { \
.nla_len = NLA_HDRLEN + (objsz_), \
.nla_type = (nla_type_), \
}; \
\
memcpy(pos, (tuntype_), tuntype_len); \
pos += NLA_ALIGN(tuntype_len); \
memcpy(pos, &obj_nla, sizeof(obj_nla)); \
pos += sizeof(obj_nla); \
memcpy(pos, &(obj_), (objsz_)); \
\
if (fallback_func_ == print_quoted_hex) { \
TEST_NLATTR_EX_((fd_), \
(nlh0_) - NLA_HDRLEN, \
hdrlen + NLA_HDRLEN, \
init_ifinfomsg, print_ifinfomsg, \
IFLA_INFO_KIND, "IFLA_INFO_KIND", \
tuntype_len, \
objsz_ + (pos - buf) - 1, \
buf, objsz_ + (pos - buf) - 1, \
printf("\"%s\"}", (tuntype_)); \
printf(", {{nla_len=%zu" \
", nla_type=%s}, ", \
(objsz_) + NLA_HDRLEN, \
(nla_type_str_)); \
(fallback_func_)((obj_), \
(objsz_) - 1); \
printf("}")); \
} \
\
TEST_NLATTR_EX_((fd_), (nlh0_) - NLA_HDRLEN, \
hdrlen + NLA_HDRLEN, \
init_ifinfomsg, print_ifinfomsg, \
IFLA_INFO_KIND, "IFLA_INFO_KIND", \
tuntype_len, objsz_ + (pos - buf), \
buf, objsz_ + (pos - buf) - 1, \
printf("\"%s\"}", (tuntype_)); \
printf(", {{nla_len=%zu, nla_type=%s}, ", \
(objsz_) + NLA_HDRLEN, \
(nla_type_str_)); \
printf("%p}", \
RTA_DATA(NLMSG_ATTR(nlh, \
(hdrlen + NLA_HDRLEN + (pos - buf)))) \
) \
); \
\
TEST_NLATTR_EX_((fd_), (nlh0_) - NLA_HDRLEN, \
hdrlen + NLA_HDRLEN, \
init_ifinfomsg, print_ifinfomsg, \
IFLA_INFO_KIND, "IFLA_INFO_KIND", \
tuntype_len, objsz_ + (pos - buf), \
buf, objsz_ + (pos - buf), \
printf("\"%s\"}", (tuntype_)); \
printf(", {{nla_len=%zu, nla_type=%s}, ", \
(objsz_) + NLA_HDRLEN, \
(nla_type_str_)); \
\
{ __VA_ARGS__; } \
\
printf("}")); \
} while (0)
#define TEST_LINKINFO(fd_, nlh0_, nla_type_, tuntype_, \
obj_, pattern_, fallback_func_, ...) \
TEST_LINKINFO_((fd_), (nlh0_), nla_type_, #nla_type_, (tuntype_), \
(obj_), sizeof(obj_), pattern_, fallback_func_, \
__VA_ARGS__)
#define TEST_NESTED_LINKINFO(fd_, nlh0_, \
nla_type_, nla_type_str_, tuntype_, \
subnla_type_, subnla_type_str_, \
obj_, pattern_, ...) \
do { \
size_t tuntype_len = strlen(tuntype_) + 1; \
struct { \
size_t sz; \
const char *str; \
} attrs[] = { __VA_ARGS__ }; \
size_t tunhdrlen; \
size_t buflen = NLA_ALIGN(tuntype_len) + NLA_HDRLEN; \
size_t attrsz = 0; \
\
for (size_t i = 0; i < ARRAY_SIZE(attrs); i++) \
attrsz += NLA_HDRLEN + NLA_ALIGN(attrs[i].sz); \
\
buflen += attrsz; \
\
char *buf = tail_alloc(buflen); \
char *pos = buf; \
\
struct nlattr nla = { \
.nla_len = NLA_HDRLEN + attrsz, \
.nla_type = (nla_type_), \
}; \
\
memcpy(pos, (tuntype_), tuntype_len); \
pos += NLA_ALIGN(tuntype_len); \
memcpy(pos, &nla, sizeof(nla)); \
pos += sizeof(nla); \
\
tunhdrlen = pos - buf; \
\
nla.nla_type = subnla_type_; \
\
for (size_t i = 0; i < ARRAY_SIZE(attrs); i++) { \
nla.nla_len = NLA_HDRLEN + attrs[i].sz; \
memcpy(pos, &nla, sizeof(nla)); \
pos += sizeof(nla); \
\
memcpy(pos, &(obj_), MIN(sizeof(obj_), attrs[i].sz)); \
\
if (attrs[i].sz > sizeof(obj_)) \
memcpy(pos + sizeof(obj_), \
&(pattern_), \
attrs[i].sz - sizeof(obj_)); \
\
pos += NLA_ALIGN(attrs[i].sz); \
} \
\
TEST_NLATTR_EX_((fd_), (nlh0_) - hdrlen - tunhdrlen, \
hdrlen + NLA_HDRLEN, \
init_ifinfomsg, print_ifinfomsg, \
IFLA_INFO_KIND, "IFLA_INFO_KIND", \
tuntype_len, buflen, \
buf, buflen, \
printf("\"%s\"}", (tuntype_)); \
printf(", {{nla_len=%zu, nla_type=%s}, [", \
attrsz + NLA_HDRLEN, \
(nla_type_str_)); \
\
for (size_t i = 0; i < ARRAY_SIZE(attrs); i++) \
printf("%s%s{nla_len=%zu" \
", nla_type=%s}%s%s%s", \
i ? ", " : "", \
attrs[i].str ? "{": "", \
attrs[i].sz + NLA_HDRLEN, \
subnla_type_str_, \
attrs[i].str ? ", ": "", \
attrs[i].str ?: "", \
attrs[i].str ? "}" : ""); \
\
printf("]}")); \
} while (0)
int
main(void)
{
static const uint8_t unknown_msg[] = { 0xab, 0xac, 0xdb, 0xcd };
static const char *unsupported_tunnel_types[] = {
"batadv", "bond",
"caif", "cfhsi",
"dummy",
"erspan",
"geneve", "gre", "gretap", "gtp",
"hsr",
"ifb", "ip6erspan", "ip6gre", "ip6gretap", "ip6tnl",
"ipip", "ipoib", "ipvlan", "ipvtap",
"lowpan",
"macsec", "macvlan", "macvtap",
"netdevsim", "nlmon",
"openvswitch",
"ppp",
"rmnet",
"sit",
"team",
"vcan", "veth", "vlan", "vrf", "vsockmon",
"vti", "vti6", "vxcan", "vxlan",
NULL
};
static const char *unsupported_xstats_types[] = {
"bridge",
"tun",
NULL
};
static const char *unsupported_data_types[] = {
"can",
NULL
};
skip_if_unavailable("/proc/self/fd/");
const int fd = create_nl_socket(NETLINK_ROUTE);
const unsigned int hdrlen = sizeof(struct ifinfomsg);
void *nlh0 = midtail_alloc(NLMSG_SPACE(hdrlen), 2 * NLA_HDRLEN + 256);
static char pattern[4096];
fill_memory_ex(pattern, sizeof(pattern), 'a', 'z' - 'a' + 1);
/* unknown AF_INFO_* type */
TEST_NESTED_NLATTR_OBJECT(fd, nlh0, hdrlen,
init_ifinfomsg, print_ifinfomsg,
IFLA_INFO_UNSPEC, pattern, unknown_msg,
printf("\"\\xab\\xac\\xdb\\xcd\""));
TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen,
init_ifinfomsg, print_ifinfomsg,
6, "0x6 /* IFLA_INFO_??? */", pattern,
unknown_msg, print_quoted_hex, 1,
printf("\"\\xab\\xac\\xdb\\xcd\""));
/* IFLA_INFO_KIND */
TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen,
init_ifinfomsg, print_ifinfomsg,
IFLA_INFO_KIND, "IFLA_INFO_KIND", pattern,
unknown_msg, print_quoted_stringn, 1,
printf("\"\\253\\254\\333\\315\"..."));
/* IFLA_INFO_KIND + IFLA_INFO_UNSPEC */
TEST_UNKNOWN_TUNNELS(fd, nlh0, IFLA_INFO_UNSPEC, "IFLA_INFO_UNSPEC",
unknown_msg, sizeof(unknown_msg),
{unsupported_tunnel_types COMMA
unsupported_xstats_types COMMA
unsupported_data_types COMMA
NULL},
printf("\"\\xab\\xac\\xdb\\xcd\""));
/* IFLA_INFO_KIND + IFLA_INFO_KIND */
TEST_UNKNOWN_TUNNELS(fd, nlh0, IFLA_INFO_KIND, "IFLA_INFO_KIND",
unknown_msg, sizeof(unknown_msg),
{unsupported_tunnel_types COMMA
unsupported_xstats_types COMMA
unsupported_data_types COMMA
NULL},
printf("\"\\253\\254\\333\\315\"..."));
/* IFLA_INFO_KIND + IFLA_INFO_DATA */
TEST_UNKNOWN_TUNNELS(fd, nlh0, IFLA_INFO_DATA, "IFLA_INFO_DATA",
unknown_msg, sizeof(unknown_msg),
{unsupported_tunnel_types COMMA
unsupported_data_types COMMA
NULL},
printf("\"\\xab\\xac\\xdb\\xcd\""));
struct val_name {
unsigned int val;
const char *name;
};
static const uint64_t u64_val = 0xdeadc0defacefeedULL;
static const uint32_t u32_val = 0xbadc0dedU;
static const uint16_t u16_val = 0xdeed;
static const uint8_t u8_val = 0xa1;
/* bridge attrs */
static const struct val_name und_br_attrs[] = {
{ 0, "IFLA_BR_UNSPEC" },
{ 20, "IFLA_BR_GROUP_ADDR" },
{ 21, "IFLA_BR_FDB_FLUSH" },
{ 40, "IFLA_BR_PAD" },
{ 45, "0x2d /* IFLA_BR_??? */" },
};
for (size_t k = 0; k < ARRAY_SIZE(und_br_attrs); k++) {
TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "bridge",
und_br_attrs[k].val, und_br_attrs[k].name,
unknown_msg, pattern,
{ 2, "\"\\xab\\xac\"" },
{ 4, "\"\\xab\\xac\\xdb\\xcd\"" },
{ 6,
"\"\\xab\\xac\\xdb\\xcd\\x61\\x62\"" },
{ 8, "\"\\xab\\xac\\xdb\\xcd\\x61\\x62"
"\\x63\\x64\"" },
{ 10, "\"\\xab\\xac\\xdb\\xcd\\x61\\x62"
"\\x63\\x64\\x65\\x66\"" });
}
static const struct val_name u64_br_attrs[] = {
{ 16, "IFLA_BR_HELLO_TIMER" },
{ 17, "IFLA_BR_TCN_TIMER" },
{ 18, "IFLA_BR_TOPOLOGY_CHANGE_TIMER" },
{ 19, "IFLA_BR_GC_TIMER" },
{ 30, "IFLA_BR_MCAST_LAST_MEMBER_INTVL" },
{ 31, "IFLA_BR_MCAST_MEMBERSHIP_INTVL" },
{ 32, "IFLA_BR_MCAST_QUERIER_INTVL" },
{ 33, "IFLA_BR_MCAST_QUERY_INTVL" },
{ 34, "IFLA_BR_MCAST_QUERY_RESPONSE_INTVL" },
{ 35, "IFLA_BR_MCAST_STARTUP_QUERY_INTVL" },
};
for (size_t k = 0; k < ARRAY_SIZE(u64_br_attrs); k++) {
TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "bridge",
u64_br_attrs[k].val, u64_br_attrs[k].name,
u64_val, pattern,
{ 7, "\""
#if WORDS_BIGENDIAN
"\\xde\\xad\\xc0\\xde\\xfa\\xce\\xfe"
#else
"\\xed\\xfe\\xce\\xfa\\xde\\xc0\\xad"
#endif
"\"" },
{ 8, "16045693111314087661" },
{ 9, "16045693111314087661" });
}
static const struct val_name u32_br_attrs[] = {
{ 1, "IFLA_BR_FORWARD_DELAY" },
{ 2, "IFLA_BR_HELLO_TIME" },
{ 3, "IFLA_BR_MAX_AGE" },
{ 4, "IFLA_BR_AGEING_TIME" },
{ 5, "IFLA_BR_STP_STATE" },
{ 13, "IFLA_BR_ROOT_PATH_COST" },
{ 26, "IFLA_BR_MCAST_HASH_ELASTICITY" },
{ 27, "IFLA_BR_MCAST_HASH_MAX" },
{ 28, "IFLA_BR_MCAST_LAST_MEMBER_CNT" },
{ 29, "IFLA_BR_MCAST_STARTUP_QUERY_CNT" },
};
for (size_t k = 0; k < ARRAY_SIZE(u32_br_attrs); k++) {
TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "bridge",
u32_br_attrs[k].val, u32_br_attrs[k].name,
u32_val, pattern,
{ 3, "\""
#if WORDS_BIGENDIAN
"\\xba\\xdc\\x0d"
#else
"\\xed\\x0d\\xdc"
#endif
"\"" },
{ 4, "3134983661" },
{ 5, "3134983661" });
}
static const struct val_name u16_br_attrs[] = {
{ 6, "IFLA_BR_PRIORITY" },
{ 12, "IFLA_BR_ROOT_PORT" },
{ 39, "IFLA_BR_VLAN_DEFAULT_PVID" },
};
for (size_t k = 0; k < ARRAY_SIZE(u16_br_attrs); k++) {
TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "bridge",
u16_br_attrs[k].val, u16_br_attrs[k].name,
u16_val, pattern,
{ 1, "\""
#if WORDS_BIGENDIAN
"\\xde"
#else
"\\xed"
#endif
"\"" },
{ 2, "57069" },
{ 3, "57069" });
}
static const struct val_name x16_br_attrs[] = {
{ 9, "IFLA_BR_GROUP_FWD_MASK" },
};
for (size_t k = 0; k < ARRAY_SIZE(x16_br_attrs); k++) {
TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "bridge",
x16_br_attrs[k].val, x16_br_attrs[k].name,
u16_val, pattern,
{ 1, "\""
#if WORDS_BIGENDIAN
"\\xde"
#else
"\\xed"
#endif
"\"" },
{ 2, "0xdeed" },
{ 3, "0xdeed" });
}
static const struct val_name u8_br_attrs[] = {
{ 7, "IFLA_BR_VLAN_FILTERING" },
{ 14, "IFLA_BR_TOPOLOGY_CHANGE" },
{ 15, "IFLA_BR_TOPOLOGY_CHANGE_DETECTED" },
{ 22, "IFLA_BR_MCAST_ROUTER" },
{ 23, "IFLA_BR_MCAST_SNOOPING" },
{ 24, "IFLA_BR_MCAST_QUERY_USE_IFADDR" },
{ 25, "IFLA_BR_MCAST_QUERIER" },
{ 36, "IFLA_BR_NF_CALL_IPTABLES" },
{ 37, "IFLA_BR_NF_CALL_IP6TABLES" },
{ 38, "IFLA_BR_NF_CALL_ARPTABLES" },
{ 41, "IFLA_BR_VLAN_STATS_ENABLED" },
{ 42, "IFLA_BR_MCAST_STATS_ENABLED" },
{ 43, "IFLA_BR_MCAST_IGMP_VERSION" },
{ 44, "IFLA_BR_MCAST_MLD_VERSION" },
};
for (size_t k = 0; k < ARRAY_SIZE(u8_br_attrs); k++) {
TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "bridge",
u8_br_attrs[k].val, u8_br_attrs[k].name,
u8_val, pattern,
{ 0, NULL },
{ 1, "161" },
{ 2, "161" });
}
unsigned short eth_p = htons(0x88C7);
TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "bridge",
8, "IFLA_BR_VLAN_PROTOCOL",
eth_p, pattern,
{ 1, "\"\\x88\"" },
{ 2, "htons(ETH_P_PREAUTH)" },
{ 2, "htons(ETH_P_PREAUTH)" });
static const uint8_t bridge_id[]
= { 0xbe, 0xef, 0xfa, 0xce, 0xde, 0xc0, 0xde, 0xad };
static const struct val_name br_id_attrs[] = {
{ 10, "IFLA_BR_ROOT_ID" },
{ 11, "IFLA_BR_BRIDGE_ID" },
};
for (size_t k = 0; k < ARRAY_SIZE(br_id_attrs); k++) {
TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "bridge",
br_id_attrs[k].val, br_id_attrs[k].name,
bridge_id, pattern,
{ 7, "\"\\xbe\\xef\\xfa\\xce"
"\\xde\\xc0\\xde\"" },
{ 8, "{prio=[190, 239]"
", addr=fa:ce:de:c0:de:ad}" },
{ 9, "{prio=[190, 239]"
", addr=fa:ce:de:c0:de:ad}" });
}
/* tun attrs */
static const struct val_name u8_tun_attrs[] = {
{ 4, "IFLA_TUN_PI" },
{ 5, "IFLA_TUN_VNET_HDR" },
{ 6, "IFLA_TUN_PERSIST" },
{ 7, "IFLA_TUN_MULTI_QUEUE" },
};
for (size_t k = 0; k < ARRAY_SIZE(u8_tun_attrs); k++) {
TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "tun",
u8_tun_attrs[k].val, u8_tun_attrs[k].name,
u8_val, pattern,
{ 0, NULL },
{ 1, "161" },
{ 2, "161" });
}
static const struct val_name u32_tun_attrs[] = {
{ 8, "IFLA_TUN_NUM_QUEUES" },
{ 9, "IFLA_TUN_NUM_DISABLED_QUEUES" },
};
for (size_t k = 0; k < ARRAY_SIZE(u32_tun_attrs); k++) {
TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "tun",
u32_tun_attrs[k].val,
u32_tun_attrs[k].name,
u32_val, pattern,
{ 3, "\""
#if WORDS_BIGENDIAN
"\\xba\\xdc\\x0d"
#else
"\\xed\\x0d\\xdc"
#endif
"\"" },
{ 4, "3134983661" },
{ 5, "3134983661" });
}
static const struct val_name und_tun_attrs[] = {
{ 0, "IFLA_TUN_UNSPEC" },
{ 10, "0xa /* IFLA_TUN_??? */" },
};
for (size_t k = 0; k < ARRAY_SIZE(und_tun_attrs); k++) {
TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "tun",
und_tun_attrs[k].val,
und_tun_attrs[k].name,
unknown_msg, pattern,
{ 2, "\"\\xab\\xac\"" },
{ 4, "\"\\xab\\xac\\xdb\\xcd\"" },
{ 6,
"\"\\xab\\xac\\xdb\\xcd\\x61\\x62\"" },
{ 8, "\"\\xab\\xac\\xdb\\xcd\\x61\\x62"
"\\x63\\x64\"" },
{ 10, "\"\\xab\\xac\\xdb\\xcd\\x61\\x62"
"\\x63\\x64\\x65\\x66\"" });
}
static const uint32_t minus_one = 0xffffffffU;
static const struct val_name uid_tun_attrs[] = {
{ 1, "IFLA_TUN_OWNER" },
{ 2, "IFLA_TUN_GROUP" },
};
for (size_t k = 0; k < ARRAY_SIZE(uid_tun_attrs); k++) {
TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "tun",
uid_tun_attrs[k].val,
uid_tun_attrs[k].name,
u32_val, pattern,
{ 3, "\""
#if WORDS_BIGENDIAN
"\\xba\\xdc\\x0d"
#else
"\\xed\\x0d\\xdc"
#endif
"\"" },
{ 4, "3134983661" },
{ 5, "3134983661" });
TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "tun",
uid_tun_attrs[k].val,
uid_tun_attrs[k].name,
minus_one, pattern,
{ 3, "\"\\xff\\xff\\xff\"" },
{ 4, "-1" },
{ 5, "-1" });
}
static const struct {
uint8_t val;
const char *str;
} tun_types[] = {
{ 0, "0 /* IFF_??? */"},
{ 1, "IFF_TUN"},
{ 2, "IFF_TAP"},
{ 3, "0x3 /* IFF_??? */"},
{ 0xda, "0xda /* IFF_??? */"},
};
for (size_t k = 0; k < ARRAY_SIZE(tun_types); k++) {
TEST_NESTED_LINKINFO(fd, nlh0, 2, "IFLA_INFO_DATA", "tun",
3, "IFLA_TUN_TYPE",
tun_types[k].val, pattern,
{ 0, NULL },
{ 1, tun_types[k].str },
{ 2, tun_types[k].str });
}
/* IFLA_INFO_KIND + IFLA_INFO_XSTATS */
TEST_UNKNOWN_TUNNELS(fd, nlh0, IFLA_INFO_XSTATS, "IFLA_INFO_XSTATS",
unknown_msg, sizeof(unknown_msg),
{unsupported_tunnel_types COMMA
/*
* can decoder decodes its data only if it's big
* enough.
*/
unsupported_xstats_types COMMA
unsupported_data_types COMMA
NULL},
printf("\"\\xab\\xac\\xdb\\xcd\""));
uint32_t can_stats_data[] = {
0xbadc0de0, 0xbadc0de1, 0xbadc0de2, 0xbadc0de3,
0xbadc0de4, 0xbadc0de5,
};
TEST_LINKINFO(fd, nlh0, IFLA_INFO_XSTATS, "can",
can_stats_data, pattern, print_quoted_hex,
printf("{bus_error=3134983648"
", error_warning=3134983649"
", error_passive=3134983650"
", bus_off=3134983651"
", arbitration_lost=3134983652"
", restarts=3134983653}"));
/* IFLA_INFO_KIND + IFLA_INFO_SLVAE_KIND */
TEST_UNKNOWN_TUNNELS(fd, nlh0,
IFLA_INFO_SLAVE_KIND, "IFLA_INFO_SLAVE_KIND",
unknown_msg, sizeof(unknown_msg),
{unsupported_tunnel_types COMMA
unsupported_xstats_types COMMA
unsupported_data_types COMMA
NULL},
printf("\"\\253\\254\\333\\315\"..."));
/* IFLA_INFO_KIND + IFLA_INFO_SLAVE_DATA */
TEST_UNKNOWN_TUNNELS(fd, nlh0,
IFLA_INFO_SLAVE_DATA, "IFLA_INFO_SLAVE_DATA",
unknown_msg, sizeof(unknown_msg),
{unsupported_tunnel_types COMMA
unsupported_xstats_types COMMA
unsupported_data_types COMMA
NULL},
printf("\"\\xab\\xac\\xdb\\xcd\""));
/* IFLA_INFO_KIND + unknown type */
TEST_UNKNOWN_TUNNELS(fd, nlh0, 6, "0x6 /* IFLA_INFO_??? */",
unknown_msg, sizeof(unknown_msg),
{unsupported_tunnel_types COMMA
unsupported_xstats_types COMMA
unsupported_data_types COMMA
NULL},
printf("\"\\xab\\xac\\xdb\\xcd\""));
puts("+++ exited with 0 +++");
return 0;
}