net/ethtool/privflags.c

Source file repositories/reference/linux-study-clean/net/ethtool/privflags.c

File Facts

System
Linux kernel
Corpus path
net/ethtool/privflags.c
Extension
.c
Size
5430 bytes
Lines
196
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: implementation source
Status
source implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

struct privflags_req_info {
	struct ethnl_req_info		base;
};

struct privflags_reply_data {
	struct ethnl_reply_data		base;
	const char			(*priv_flag_names)[ETH_GSTRING_LEN];
	unsigned int			n_priv_flags;
	u32				priv_flags;
};

#define PRIVFLAGS_REPDATA(__reply_base) \
	container_of(__reply_base, struct privflags_reply_data, base)

const struct nla_policy ethnl_privflags_get_policy[] = {
	[ETHTOOL_A_PRIVFLAGS_HEADER]		=
		NLA_POLICY_NESTED(ethnl_header_policy),
};

static int ethnl_get_priv_flags_info(struct net_device *dev,
				     unsigned int *count,
				     const char (**names)[ETH_GSTRING_LEN])
{
	const struct ethtool_ops *ops = dev->ethtool_ops;
	int nflags;

	nflags = ops->get_sset_count(dev, ETH_SS_PRIV_FLAGS);
	if (nflags < 0)
		return nflags;

	if (names) {
		*names = kcalloc(nflags, ETH_GSTRING_LEN, GFP_KERNEL);
		if (!*names)
			return -ENOMEM;
		ops->get_strings(dev, ETH_SS_PRIV_FLAGS, (u8 *)*names);
	}

	/* We can pass more than 32 private flags to userspace via netlink but
	 * we cannot get more with ethtool_ops::get_priv_flags(). Note that we
	 * must not adjust nflags before allocating the space for flag names
	 * as the buffer must be large enough for all flags.
	 */
	if (WARN_ONCE(nflags > 32,
		      "device %s reports more than 32 private flags (%d)\n",
		      netdev_name(dev), nflags))
		nflags = 32;
	*count = nflags;

	return 0;
}

static int privflags_prepare_data(const struct ethnl_req_info *req_base,
				  struct ethnl_reply_data *reply_base,
				  const struct genl_info *info)
{
	struct privflags_reply_data *data = PRIVFLAGS_REPDATA(reply_base);
	struct net_device *dev = reply_base->dev;
	const char (*names)[ETH_GSTRING_LEN];
	const struct ethtool_ops *ops;
	unsigned int nflags;
	int ret;

	ops = dev->ethtool_ops;
	if (!ops->get_priv_flags || !ops->get_sset_count || !ops->get_strings)
		return -EOPNOTSUPP;
	ret = ethnl_ops_begin(dev);
	if (ret < 0)
		return ret;

	ret = ethnl_get_priv_flags_info(dev, &nflags, &names);
	if (ret < 0)
		goto out_ops;
	data->priv_flags = ops->get_priv_flags(dev);
	data->priv_flag_names = names;
	data->n_priv_flags = nflags;

out_ops:
	ethnl_ops_complete(dev);
	return ret;
}

static int privflags_reply_size(const struct ethnl_req_info *req_base,
				const struct ethnl_reply_data *reply_base)
{
	const struct privflags_reply_data *data = PRIVFLAGS_REPDATA(reply_base);
	bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
	const u32 all_flags = ~(u32)0 >> (32 - data->n_priv_flags);

	return ethnl_bitset32_size(&data->priv_flags, &all_flags,
				   data->n_priv_flags,

Annotation

Implementation Notes