# Copyright 2020 syzkaller project authors. All rights reserved.
# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

include <linux/net.h>
include <uapi/linux/netlink.h>
include <uapi/linux/genetlink.h>
include <uapi/linux/ethtool_netlink.h>

resource genl_ethtool_family_id[int16]
type msghdr_ethtool[CMD, POLICY] msghdr_netlink[netlink_msg_t[genl_ethtool_family_id, genlmsghdr_t[CMD], POLICY]]

syz_genetlink_get_family_id$ethtool(name ptr[in, string["ethtool"]], fd sock_nl_generic) genl_ethtool_family_id

sendmsg$ETHTOOL_MSG_STRSET_GET(fd sock_nl_generic, msg ptr[in, msghdr_ethtool[ETHTOOL_MSG_STRSET_GET, ethnl_strset_get_policy]], f flags[send_flags])
sendmsg$ETHTOOL_MSG_LINKINFO_GET(fd sock_nl_generic, msg ptr[in, msghdr_ethtool[ETHTOOL_MSG_LINKINFO_GET, header_only_ethnl_policy[ETHTOOL_A_LINKINFO_HEADER]]], f flags[send_flags])
sendmsg$ETHTOOL_MSG_LINKINFO_SET(fd sock_nl_generic, msg ptr[in, msghdr_ethtool[ETHTOOL_MSG_LINKINFO_SET, ethnl_linkinfo_set_policy]], f flags[send_flags])
sendmsg$ETHTOOL_MSG_LINKMODES_GET(fd sock_nl_generic, msg ptr[in, msghdr_ethtool[ETHTOOL_MSG_LINKMODES_GET, header_only_ethnl_policy[ETHTOOL_A_LINKMODES_HEADER]]], f flags[send_flags])
sendmsg$ETHTOOL_MSG_LINKMODES_SET(fd sock_nl_generic, msg ptr[in, msghdr_ethtool[ETHTOOL_MSG_LINKMODES_SET, ethnl_linkmodes_set_policy]], f flags[send_flags])
sendmsg$ETHTOOL_MSG_LINKSTATE_GET(fd sock_nl_generic, msg ptr[in, msghdr_ethtool[ETHTOOL_MSG_LINKSTATE_GET, header_only_ethnl_policy[ETHTOOL_A_LINKSTATE_HEADER]]], f flags[send_flags])
sendmsg$ETHTOOL_MSG_DEBUG_GET(fd sock_nl_generic, msg ptr[in, msghdr_ethtool[ETHTOOL_MSG_DEBUG_GET, header_only_ethnl_policy[ETHTOOL_A_DEBUG_HEADER]]], f flags[send_flags])
sendmsg$ETHTOOL_MSG_DEBUG_SET(fd sock_nl_generic, msg ptr[in, msghdr_ethtool[ETHTOOL_MSG_DEBUG_SET, ethnl_debug_set_policy]], f flags[send_flags])
sendmsg$ETHTOOL_MSG_WOL_GET(fd sock_nl_generic, msg ptr[in, msghdr_ethtool[ETHTOOL_MSG_WOL_GET, header_only_ethnl_policy[ETHTOOL_A_WOL_HEADER]]], f flags[send_flags])
sendmsg$ETHTOOL_MSG_WOL_SET(fd sock_nl_generic, msg ptr[in, msghdr_ethtool[ETHTOOL_MSG_WOL_SET, ethnl_wol_set_policy]], f flags[send_flags])
sendmsg$ETHTOOL_MSG_FEATURES_GET(fd sock_nl_generic, msg ptr[in, msghdr_ethtool[ETHTOOL_MSG_FEATURES_GET, header_only_ethnl_policy[ETHTOOL_A_FEATURES_HEADER]]], f flags[send_flags])
sendmsg$ETHTOOL_MSG_FEATURES_SET(fd sock_nl_generic, msg ptr[in, msghdr_ethtool[ETHTOOL_MSG_FEATURES_SET, ethnl_features_set_policy]], f flags[send_flags])
sendmsg$ETHTOOL_MSG_PRIVFLAGS_GET(fd sock_nl_generic, msg ptr[in, msghdr_ethtool[ETHTOOL_MSG_PRIVFLAGS_GET, header_only_ethnl_policy[ETHTOOL_A_PRIVFLAGS_HEADER]]], f flags[send_flags])
sendmsg$ETHTOOL_MSG_PRIVFLAGS_SET(fd sock_nl_generic, msg ptr[in, msghdr_ethtool[ETHTOOL_MSG_PRIVFLAGS_SET, ethnl_privflags_set_policy]], f flags[send_flags])
sendmsg$ETHTOOL_MSG_RINGS_GET(fd sock_nl_generic, msg ptr[in, msghdr_ethtool[ETHTOOL_MSG_RINGS_GET, header_only_ethnl_policy[ETHTOOL_A_RINGS_HEADER]]], f flags[send_flags])
sendmsg$ETHTOOL_MSG_RINGS_SET(fd sock_nl_generic, msg ptr[in, msghdr_ethtool[ETHTOOL_MSG_RINGS_SET, ethnl_rings_set_policy]], f flags[send_flags])
sendmsg$ETHTOOL_MSG_CHANNELS_GET(fd sock_nl_generic, msg ptr[in, msghdr_ethtool[ETHTOOL_MSG_CHANNELS_GET, header_only_ethnl_policy[ETHTOOL_A_CHANNELS_HEADER]]], f flags[send_flags])
sendmsg$ETHTOOL_MSG_CHANNELS_SET(fd sock_nl_generic, msg ptr[in, msghdr_ethtool[ETHTOOL_MSG_CHANNELS_SET, ethnl_channels_set_policy]], f flags[send_flags])
sendmsg$ETHTOOL_MSG_COALESCE_GET(fd sock_nl_generic, msg ptr[in, msghdr_ethtool[ETHTOOL_MSG_COALESCE_GET, header_only_ethnl_policy[ETHTOOL_A_COALESCE_HEADER]]], f flags[send_flags])
sendmsg$ETHTOOL_MSG_COALESCE_SET(fd sock_nl_generic, msg ptr[in, msghdr_ethtool[ETHTOOL_MSG_COALESCE_SET, ethnl_coalesce_set_policy]], f flags[send_flags])
sendmsg$ETHTOOL_MSG_PAUSE_GET(fd sock_nl_generic, msg ptr[in, msghdr_ethtool[ETHTOOL_MSG_PAUSE_GET, header_only_ethnl_policy[ETHTOOL_A_PAUSE_HEADER]]], f flags[send_flags])
sendmsg$ETHTOOL_MSG_PAUSE_SET(fd sock_nl_generic, msg ptr[in, msghdr_ethtool[ETHTOOL_MSG_PAUSE_SET, ethnl_pause_set_policy]], f flags[send_flags])
sendmsg$ETHTOOL_MSG_EEE_GET(fd sock_nl_generic, msg ptr[in, msghdr_ethtool[ETHTOOL_MSG_EEE_GET, header_only_ethnl_policy[ETHTOOL_A_EEE_HEADER]]], f flags[send_flags])
sendmsg$ETHTOOL_MSG_EEE_SET(fd sock_nl_generic, msg ptr[in, msghdr_ethtool[ETHTOOL_MSG_EEE_SET, ethnl_eee_set_policy]], f flags[send_flags])
sendmsg$ETHTOOL_MSG_TSINFO_GET(fd sock_nl_generic, msg ptr[in, msghdr_ethtool[ETHTOOL_MSG_TSINFO_GET, header_only_ethnl_policy[ETHTOOL_A_TSINFO_HEADER]]], f flags[send_flags])
sendmsg$ETHTOOL_MSG_STATS_GET(fd sock_nl_generic, msg ptr[in, msghdr_ethtool[ETHTOOL_MSG_STATS_GET, ethnl_stats_get_policy]], f flags[send_flags])

ethnl_stats_get_policy [
	ETHTOOL_A_STATS_HEADER	nlnest[ETHTOOL_A_STATS_HEADER, array[ethnl_header_policy]]
	ETHTOOL_A_STATS_GROUPS	nlnest[ETHTOOL_A_STATS_GROUPS, array[bitset_policy]]
	ETHTOOL_A_STATS_SRC	nlattr[ETHTOOL_A_STATS_SRC, flags[ethtool_mac_stats_src, int32]]
] [varlen]

ethtool_mac_stats_src = ETHTOOL_MAC_STATS_SRC_AGGREGATE, ETHTOOL_MAC_STATS_SRC_EMAC, ETHTOOL_MAC_STATS_SRC_PMAC

ethnl_header_policy [
	ETHTOOL_A_HEADER_DEV_INDEX	nlattr[ETHTOOL_A_HEADER_DEV_INDEX, ifindex]
	ETHTOOL_A_HEADER_DEV_NAME	nlattr[ETHTOOL_A_HEADER_DEV_NAME, devname]
	ETHTOOL_A_HEADER_FLAGS		nlattr[ETHTOOL_A_HEADER_FLAGS, flags[ethnl_flags, int32]]
] [varlen]

ethnl_flags = ETHTOOL_FLAG_COMPACT_BITSETS, ETHTOOL_FLAG_OMIT_REPLY

type header_only_ethnl_policy[HEADER_TYPE] [
	HEADER	nlnest[HEADER_TYPE, array[ethnl_header_policy]]
] [varlen]

bitset_policy [
	ETHTOOL_A_BITSET_NOMASK	nlattr[ETHTOOL_A_BITSET_NOMASK, void]
	ETHTOOL_A_BITSET_SIZE	nlattr[ETHTOOL_A_BITSET_SIZE, int32]
	ETHTOOL_A_BITSET_BITS	nlnest[ETHTOOL_A_BITSET_BITS, array[nlnest[ETHTOOL_A_BITSET_BITS_BIT, array[bit_policy]]]]
	ETHTOOL_A_BITSET_VALUE	nlattr[ETHTOOL_A_BITSET_VALUE, array[int8]]
	ETHTOOL_A_BITSET_MASK	nlattr[ETHTOOL_A_BITSET_MASK, array[int8]]
] [varlen]

bit_policy [
	ETHTOOL_A_BITSET_BIT_INDEX	nlattr[ETHTOOL_A_BITSET_BIT_INDEX, int32]
	ETHTOOL_A_BITSET_BIT_VALUE	nlattr[ETHTOOL_A_BITSET_BIT_VALUE, void]
	ETHTOOL_A_BITSET_BIT_NAME	nlattr[ETHTOOL_A_BITSET_BIT_NAME, string]
] [varlen]

ethnl_strset_get_policy [
	ETHTOOL_A_STRSET_HEADER		nlnest[ETHTOOL_A_STRSET_HEADER, array[ethnl_header_policy]]
	ETHTOOL_A_STRSET_STRINGSETS	nlnest[ETHTOOL_A_STRSET_STRINGSETS, array[nlnest[ETHTOOL_A_STRINGSETS_STRINGSET, array[get_stringset_policy]]]]
	ETHTOOL_A_STRSET_COUNTS_ONLY	nlattr[ETHTOOL_A_STRSET_COUNTS_ONLY, void]
] [varlen]

get_stringset_policy [
	ETHTOOL_A_STRINGSET_ID	nlattr[ETHTOOL_A_STRINGSET_ID, flags[ethtool_stringset, int32]]
] [varlen]

ethnl_linkinfo_set_policy [
	ETHTOOL_A_LINKINFO_HEADER	nlnest[ETHTOOL_A_LINKINFO_HEADER, array[ethnl_header_policy]]
	ETHTOOL_A_LINKINFO_PORT		nlattr[ETHTOOL_A_LINKINFO_PORT, int8]
	ETHTOOL_A_LINKINFO_PHYADDR	nlattr[ETHTOOL_A_LINKINFO_PHYADDR, int8]
	ETHTOOL_A_LINKINFO_TP_MDIX_CTRL	nlattr[ETHTOOL_A_LINKINFO_TP_MDIX_CTRL, int8]
] [varlen]

ethnl_linkmodes_set_policy [
	ETHTOOL_A_LINKMODES_HEADER		nlnest[ETHTOOL_A_LINKMODES_HEADER, array[ethnl_header_policy]]
	ETHTOOL_A_LINKMODES_AUTONEG		nlattr[ETHTOOL_A_LINKMODES_AUTONEG, int8]
	ETHTOOL_A_LINKMODES_DUPLEX		nlattr[ETHTOOL_A_LINKMODES_DUPLEX, int8]
	ETHTOOL_A_LINKMODES_SPEED		nlattr[ETHTOOL_A_LINKMODES_SPEED, int32]
	ETHTOOL_A_LINKMODES_OURS		nlnest[ETHTOOL_A_LINKMODES_OURS, array[bitset_policy]]
	ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG	nlattr[ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG, flags[eth_master_slave_cfg, int8]]
	ETHTOOL_A_LINKMODES_LANES		nlattr[ETHTOOL_A_LINKMODES_LANES, flags[eth_link_lanes, int32]]
] [varlen]

eth_master_slave_cfg = MASTER_SLAVE_CFG_MASTER_PREFERRED, MASTER_SLAVE_CFG_SLAVE_PREFERRED, MASTER_SLAVE_CFG_MASTER_FORCE, MASTER_SLAVE_CFG_SLAVE_FORCE
eth_link_lanes = 1, 2, 4, 8

ethnl_debug_set_policy [
	ETHTOOL_A_DEBUG_HEADER	nlnest[ETHTOOL_A_DEBUG_HEADER, array[ethnl_header_policy]]
	ETHTOOL_A_DEBUG_MSGMASK	nlnest[ETHTOOL_A_DEBUG_MSGMASK, array[bitset_policy]]
] [varlen]

ethnl_wol_set_policy [
	ETHTOOL_A_WOL_HEADER	nlnest[ETHTOOL_A_WOL_HEADER, array[ethnl_header_policy]]
	ETHTOOL_A_WOL_MODES	nlnest[ETHTOOL_A_WOL_MODES, array[bitset_policy]]
	ETHTOOL_A_WOL_SOPASS	nlattr[ETHTOOL_A_WOL_SOPASS, array[int8]]
] [varlen]

ethnl_features_set_policy [
	ETHTOOL_A_FEATURES_HEADER	nlnest[ETHTOOL_A_FEATURES_HEADER, array[ethnl_header_policy]]
	ETHTOOL_A_FEATURES_WANTED	nlnest[ETHTOOL_A_FEATURES_WANTED, array[bitset_policy]]
] [varlen]

ethnl_privflags_set_policy [
	ETHTOOL_A_PRIVFLAGS_HEADER	nlnest[ETHTOOL_A_PRIVFLAGS_HEADER, array[ethnl_header_policy]]
	ETHTOOL_A_PRIVFLAGS_FLAGS	nlnest[ETHTOOL_A_PRIVFLAGS_FLAGS, array[bitset_policy]]
] [varlen]

ethnl_rings_set_policy [
	ETHTOOL_A_RINGS_HEADER		nlnest[ETHTOOL_A_RINGS_HEADER, array[ethnl_header_policy]]
	ETHTOOL_A_RINGS_RX		nlattr[ETHTOOL_A_RINGS_RX, int32]
	ETHTOOL_A_RINGS_RX_MINI		nlattr[ETHTOOL_A_RINGS_RX_MINI, int32]
	ETHTOOL_A_RINGS_RX_JUMBO	nlattr[ETHTOOL_A_RINGS_RX_JUMBO, int32]
	ETHTOOL_A_RINGS_TX		nlattr[ETHTOOL_A_RINGS_TX, int32]
] [varlen]

ethnl_channels_set_policy [
	ETHTOOL_A_CHANNELS_HEADER		nlnest[ETHTOOL_A_CHANNELS_HEADER, array[ethnl_header_policy]]
	ETHTOOL_A_CHANNELS_RX_COUNT		nlattr[ETHTOOL_A_CHANNELS_RX_COUNT, int32]
	ETHTOOL_A_CHANNELS_TX_COUNT		nlattr[ETHTOOL_A_CHANNELS_TX_COUNT, int32]
	ETHTOOL_A_CHANNELS_OTHER_COUNT		nlattr[ETHTOOL_A_CHANNELS_OTHER_COUNT, int32]
	ETHTOOL_A_CHANNELS_COMBINED_COUNT	nlattr[ETHTOOL_A_CHANNELS_COMBINED_COUNT, int32]
] [varlen]

ethnl_coalesce_set_policy [
	ETHTOOL_A_COALESCE_HEADER		nlnest[ETHTOOL_A_COALESCE_HEADER, array[ethnl_header_policy]]
	ETHTOOL_A_COALESCE_RX_USECS		nlattr[ETHTOOL_A_COALESCE_RX_USECS, int32]
	ETHTOOL_A_COALESCE_RX_MAX_FRAMES	nlattr[ETHTOOL_A_COALESCE_RX_MAX_FRAMES, int32]
	ETHTOOL_A_COALESCE_RX_USECS_IRQ		nlattr[ETHTOOL_A_COALESCE_RX_USECS_IRQ, int32]
	ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ	nlattr[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ, int32]
	ETHTOOL_A_COALESCE_TX_USECS		nlattr[ETHTOOL_A_COALESCE_TX_USECS, int32]
	ETHTOOL_A_COALESCE_TX_MAX_FRAMES	nlattr[ETHTOOL_A_COALESCE_TX_MAX_FRAMES, int32]
	ETHTOOL_A_COALESCE_TX_USECS_IRQ		nlattr[ETHTOOL_A_COALESCE_TX_USECS_IRQ, int32]
	ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ	nlattr[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ, int32]
	ETHTOOL_A_COALESCE_STATS_BLOCK_USECS	nlattr[ETHTOOL_A_COALESCE_STATS_BLOCK_USECS, int32]
	ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX	nlattr[ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX, bool8]
	ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX	nlattr[ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX, bool8]
	ETHTOOL_A_COALESCE_PKT_RATE_LOW		nlattr[ETHTOOL_A_COALESCE_PKT_RATE_LOW, int32]
	ETHTOOL_A_COALESCE_RX_USECS_LOW		nlattr[ETHTOOL_A_COALESCE_RX_USECS_LOW, int32]
	ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW	nlattr[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW, int32]
	ETHTOOL_A_COALESCE_TX_USECS_LOW		nlattr[ETHTOOL_A_COALESCE_TX_USECS_LOW, int32]
	ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW	nlattr[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW, int32]
	ETHTOOL_A_COALESCE_PKT_RATE_HIGH	nlattr[ETHTOOL_A_COALESCE_PKT_RATE_HIGH, int32]
	ETHTOOL_A_COALESCE_RX_USECS_HIGH	nlattr[ETHTOOL_A_COALESCE_RX_USECS_HIGH, int32]
	ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH	nlattr[ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH, int32]
	ETHTOOL_A_COALESCE_TX_USECS_HIGH	nlattr[ETHTOOL_A_COALESCE_TX_USECS_HIGH, int32]
	ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH	nlattr[ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH, int32]
	ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL	nlattr[ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL, int32]
	ETHTOOL_A_COALESCE_USE_CQE_MODE_TX	nlattr[ETHTOOL_A_COALESCE_USE_CQE_MODE_TX, bool8]
	ETHTOOL_A_COALESCE_USE_CQE_MODE_RX	nlattr[ETHTOOL_A_COALESCE_USE_CQE_MODE_RX, bool8]
] [varlen]

ethnl_pause_set_policy [
	ETHTOOL_A_PAUSE_HEADER	nlnest[ETHTOOL_A_PAUSE_HEADER, array[ethnl_header_policy]]
	ETHTOOL_A_PAUSE_AUTONEG	nlattr[ETHTOOL_A_PAUSE_AUTONEG, bool8]
	ETHTOOL_A_PAUSE_RX	nlattr[ETHTOOL_A_PAUSE_RX, bool8]
	ETHTOOL_A_PAUSE_TX	nlattr[ETHTOOL_A_PAUSE_TX, bool8]
] [varlen]

ethnl_eee_set_policy [
	ETHTOOL_A_EEE_HEADER		nlnest[ETHTOOL_A_EEE_HEADER, array[ethnl_header_policy]]
	ETHTOOL_A_EEE_MODES_OURS	nlnest[ETHTOOL_A_EEE_MODES_OURS, array[bitset_policy]]
	ETHTOOL_A_EEE_ENABLED		nlattr[ETHTOOL_A_EEE_ENABLED, bool8]
	ETHTOOL_A_EEE_TX_LPI_ENABLED	nlattr[ETHTOOL_A_EEE_TX_LPI_ENABLED, bool8]
	ETHTOOL_A_EEE_TX_LPI_TIMER	nlattr[ETHTOOL_A_EEE_TX_LPI_TIMER, int32]
] [varlen]
