/* * 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 #include #include #include #include "test_nlattr.h" #include #include #ifdef HAVE_LINUX_IF_LINK_H # include #endif #include #define XLAT_MACROS_ONLY # include # include #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; }