All of lore.kernel.org
 help / color / mirror / Atom feed
From: Michal Kubecek <mkubecek@suse.cz>
To: netdev@vger.kernel.org
Cc: David Miller <davem@davemloft.net>, Andrew Lunn <andrew@lunn.ch>,
	Jakub Kicinski <jakub.kicinski@netronome.com>,
	Jiri Pirko <jiri@resnulli.us>,
	linux-kernel@vger.kernel.org
Subject: [RFC PATCH net-next v3 04/21] ethtool: helper functions for netlink interface
Date: Mon, 18 Feb 2019 19:21:44 +0100 (CET)	[thread overview]
Message-ID: <266b4ea3596de134329f8bbd5d13e282d1d27442.1550513384.git.mkubecek@suse.cz> (raw)
In-Reply-To: <cover.1550513384.git.mkubecek@suse.cz>

Various helpers used by ethtool netlink code.

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 include/uapi/linux/ethtool_netlink.h |  11 +++
 net/ethtool/netlink.c                | 119 +++++++++++++++++++++++
 net/ethtool/netlink.h                | 135 +++++++++++++++++++++++++++
 3 files changed, 265 insertions(+)

diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index d8a8d3c72c2f..01896a1ee21a 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -12,6 +12,17 @@ enum {
 	ETHNL_CMD_MAX = (__ETHNL_CMD_CNT - 1)
 };
 
+/* device specification */
+
+enum {
+	ETHA_DEV_UNSPEC,
+	ETHA_DEV_INDEX,				/* u32 */
+	ETHA_DEV_NAME,				/* string */
+
+	__ETHA_DEV_CNT,
+	ETHA_DEV_MAX = (__ETHA_DEV_CNT - 1)
+};
+
 /* generic netlink info */
 #define ETHTOOL_GENL_NAME "ethtool"
 #define ETHTOOL_GENL_VERSION 1
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index 5fe3e5b68e81..ffdcc7c9d4bc 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -1,8 +1,127 @@
 // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
 
+#include <net/sock.h>
 #include <linux/ethtool_netlink.h>
 #include "netlink.h"
 
+static const struct nla_policy dev_policy[ETHA_DEV_MAX + 1] = {
+	[ETHA_DEV_UNSPEC]	= { .type = NLA_REJECT },
+	[ETHA_DEV_INDEX]	= { .type = NLA_U32 },
+	[ETHA_DEV_NAME]		= { .type = NLA_NUL_STRING,
+				    .len = IFNAMSIZ - 1 },
+};
+
+struct net_device *ethnl_dev_get(struct genl_info *info, struct nlattr *nest)
+{
+	struct net *net = genl_info_net(info);
+	struct nlattr *tb[ETHA_DEV_MAX + 1];
+	struct net_device *dev;
+	int ret;
+
+	if (!nest) {
+		ETHNL_SET_ERRMSG(info,
+				 "mandatory device identification missing");
+		return ERR_PTR(-EINVAL);
+	}
+	ret = nla_parse_nested(tb, ETHA_DEV_MAX, nest, dev_policy,
+			       info->extack);
+	if (ret < 0)
+		return ERR_PTR(ret);
+
+	if (tb[ETHA_DEV_INDEX]) {
+		dev = dev_get_by_index(net, nla_get_u32(tb[ETHA_DEV_INDEX]));
+		if (!dev)
+			return ERR_PTR(-ENODEV);
+		/* if both ifindex and ifname are passed, they must match */
+		if (tb[ETHA_DEV_NAME]) {
+			const char *nl_name = nla_data(tb[ETHA_DEV_NAME]);
+
+			if (strncmp(dev->name, nl_name, IFNAMSIZ)) {
+				dev_put(dev);
+				ETHNL_SET_ERRMSG(info,
+						 "ifindex and ifname do not match");
+				return ERR_PTR(-ENODEV);
+			}
+		}
+		return dev;
+	} else if (tb[ETHA_DEV_NAME]) {
+		dev = dev_get_by_name(net, nla_data(tb[ETHA_DEV_NAME]));
+		if (!dev)
+			return ERR_PTR(-ENODEV);
+	} else {
+		ETHNL_SET_ERRMSG(info, "either ifindex or ifname required");
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (!netif_device_present(dev)) {
+		dev_put(dev);
+		ETHNL_SET_ERRMSG(info, "device not present");
+		return ERR_PTR(-ENODEV);
+	}
+	return dev;
+}
+
+int ethnl_fill_dev(struct sk_buff *msg, struct net_device *dev, u16 attrtype)
+{
+	struct nlattr *nest;
+	int ret = -EMSGSIZE;
+
+	nest = ethnl_nest_start(msg, attrtype);
+	if (!nest)
+		return -EMSGSIZE;
+
+	if (nla_put_u32(msg, ETHA_DEV_INDEX, (u32)dev->ifindex))
+		goto err;
+	if (nla_put_string(msg, ETHA_DEV_NAME, dev->name))
+		goto err;
+
+	nla_nest_end(msg, nest);
+	return 0;
+err:
+	nla_nest_cancel(msg, nest);
+	return ret;
+}
+
+/* create skb for a reply and fill device identification
+ * payload: payload length (without netlink and genetlink header)
+ * dev:     device the reply is about (may be null)
+ * cmd:     ETHNL_CMD_* command for reply
+ * info:    info for the received packet we respond to
+ * ehdrp:   place to store payload pointer returned by genlmsg_new()
+ * returns: skb or null on error
+ */
+struct sk_buff *ethnl_reply_init(size_t payload, struct net_device *dev, u8 cmd,
+				 u16 dev_attrtype, struct genl_info *info,
+				 void **ehdrp)
+{
+	void *ehdr;
+	struct sk_buff *rskb;
+
+	rskb = genlmsg_new(payload, GFP_KERNEL);
+	if (!rskb) {
+		ETHNL_SET_ERRMSG(info,
+				 "failed to allocate reply message");
+		return NULL;
+	}
+
+	ehdr = genlmsg_put_reply(rskb, info, &ethtool_genl_family, 0, cmd);
+	if (!ehdr)
+		goto err;
+	if (ehdrp)
+		*ehdrp = ehdr;
+	if (dev) {
+		int ret = ethnl_fill_dev(rskb, dev, dev_attrtype);
+
+		if (ret < 0)
+			goto err;
+	}
+
+	return rskb;
+err:
+	nlmsg_free(rskb);
+	return NULL;
+}
+
 /* genetlink setup */
 
 static const struct genl_ops ethtool_genl_ops[] = {
diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h
index 63063b582ca2..36a397656127 100644
--- a/net/ethtool/netlink.h
+++ b/net/ethtool/netlink.h
@@ -6,7 +6,142 @@
 #include <linux/ethtool_netlink.h>
 #include <linux/netdevice.h>
 #include <net/genetlink.h>
+#include <net/sock.h>
+
+#define ETHNL_SET_ERRMSG(info, msg) \
+	do { if (info) GENL_SET_ERR_MSG(info, msg); } while (0)
 
 extern struct genl_family ethtool_genl_family;
 
+struct net_device *ethnl_dev_get(struct genl_info *info, struct nlattr *nest);
+int ethnl_fill_dev(struct sk_buff *msg, struct net_device *dev, u16 attrtype);
+
+struct sk_buff *ethnl_reply_init(size_t payload, struct net_device *dev, u8 cmd,
+				 u16 dev_attrtype, struct genl_info *info,
+				 void **ehdrp);
+
+static inline int ethnl_str_size(const char *s)
+{
+	return nla_total_size(strlen(s) + 1);
+}
+
+static inline int ethnl_str_ifne_size(const char *s)
+{
+	return s[0] ? ethnl_str_size(s) : 0;
+}
+
+static inline int ethnl_put_str_ifne(struct sk_buff *skb, int attrtype,
+				     const char *s)
+{
+	if (!s[0])
+		return 0;
+	return nla_put_string(skb, attrtype, s);
+}
+
+static inline struct nlattr *ethnl_nest_start(struct sk_buff *skb,
+					      int attrtype)
+{
+	return nla_nest_start(skb, attrtype | NLA_F_NESTED);
+}
+
+/* ethnl_update_* return true if the value is changed */
+static inline bool ethnl_update_u32(u32 *dst, struct nlattr *attr)
+{
+	u32 val;
+
+	if (!attr)
+		return false;
+	val = nla_get_u32(attr);
+	if (*dst == val)
+		return false;
+
+	*dst = val;
+	return true;
+}
+
+static inline bool ethnl_update_u8(u8 *dst, struct nlattr *attr)
+{
+	u8 val;
+
+	if (!attr)
+		return false;
+	val = nla_get_u8(attr);
+	if (*dst == val)
+		return false;
+
+	*dst = val;
+	return true;
+}
+
+/* update u32 value used as bool from NLA_U8 */
+static inline bool ethnl_update_bool32(u32 *dst, struct nlattr *attr)
+{
+	u8 val;
+
+	if (!attr)
+		return false;
+	val = !!nla_get_u8(attr);
+	if (!!*dst == val)
+		return false;
+
+	*dst = val;
+	return true;
+}
+
+static inline bool ethnl_update_binary(u8 *dst, unsigned int len,
+				       struct nlattr *attr)
+{
+	if (!attr)
+		return false;
+	if (nla_len(attr) < len)
+		len = nla_len(attr);
+	if (!memcmp(dst, nla_data(attr), len))
+		return false;
+
+	memcpy(dst, nla_data(attr), len);
+	return true;
+}
+
+static inline bool ethnl_update_bitfield32(u32 *dst, struct nlattr *attr)
+{
+	struct nla_bitfield32 change;
+	u32 newval;
+
+	if (!attr)
+		return false;
+	change = nla_get_bitfield32(attr);
+	newval = (*dst & ~change.selector) | (change.value & change.selector);
+	if (*dst == newval)
+		return false;
+
+	*dst = newval;
+	return true;
+}
+
+static inline void warn_partial_info(struct genl_info *info)
+{
+	ETHNL_SET_ERRMSG(info, "not all requested data could be retrieved");
+}
+
+/* Check user privileges explicitly to allow finer access control based on
+ * context of the request or hiding part of the information from unprivileged
+ * users
+ */
+static inline bool ethnl_is_privileged(struct sk_buff *skb)
+{
+	struct net *net = sock_net(skb->sk);
+
+	return netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN);
+}
+
+/* total size of ETHA_*_DEV nested attribute; this is an upper estimate so that
+ * we do not need to hold RTNL longer than necessary to prevent rename between
+ * estimating the size and composing the message
+ */
+static inline unsigned int dev_ident_size(void)
+{
+	return nla_total_size(nla_total_size(sizeof(u32)) +
+			      nla_total_size(IFNAMSIZ));
+}
+
 #endif /* _NET_ETHTOOL_NETLINK_H */
-- 
2.20.1


  parent reply	other threads:[~2019-02-18 18:21 UTC|newest]

Thread overview: 47+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-02-18 18:21 [RFC PATCH net-next v3 00/21] ethtool netlink interface, part 1 Michal Kubecek
2019-02-18 18:21 ` [RFC PATCH net-next v3 01/21] netlink: introduce nla_put_bitfield32() Michal Kubecek
2019-02-18 18:21 ` [RFC PATCH net-next v3 02/21] ethtool: move to its own directory Michal Kubecek
2019-02-18 20:01   ` Jakub Kicinski
2019-02-18 18:21 ` [RFC PATCH net-next v3 03/21] ethtool: introduce ethtool netlink interface Michal Kubecek
2019-02-18 18:21 ` Michal Kubecek [this message]
2019-02-18 20:15   ` [RFC PATCH net-next v3 04/21] ethtool: helper functions for " Jakub Kicinski
2019-02-19 13:07     ` Michal Kubecek
2019-02-18 18:21 ` [RFC PATCH net-next v3 05/21] ethtool: netlink bitset handling Michal Kubecek
2019-02-20  2:27   ` Jakub Kicinski
2019-02-20  8:16     ` Michal Kubecek
2019-02-18 18:21 ` [RFC PATCH net-next v3 06/21] ethtool: support for netlink notifications Michal Kubecek
2019-02-18 18:21 ` [RFC PATCH net-next v3 07/21] ethtool: implement EVENT notifications Michal Kubecek
2019-02-18 23:46   ` Andrew Lunn
2019-02-19  7:02     ` Michal Kubecek
2019-02-18 18:22 ` [RFC PATCH net-next v3 08/21] ethtool: generic handlers for GET requests Michal Kubecek
2019-02-20  2:42   ` Jakub Kicinski
2019-02-18 18:22 ` [RFC PATCH net-next v3 09/21] ethtool: move string arrays into common file Michal Kubecek
2019-02-18 18:22 ` [RFC PATCH net-next v3 10/21] ethtool: provide string sets with GET_STRSET request Michal Kubecek
2019-02-20  2:56   ` Jakub Kicinski
2019-02-20 12:34     ` Michal Kubecek
2019-02-18 18:22 ` [RFC PATCH net-next v3 11/21] ethtool: provide driver/device information in GET_INFO request Michal Kubecek
2019-02-18 18:22 ` [RFC PATCH net-next v3 12/21] ethtool: provide permanent hardware address " Michal Kubecek
2019-02-19 10:24   ` Jiri Pirko
2019-02-19 11:36     ` Michal Kubecek
2019-02-18 18:22 ` [RFC PATCH net-next v3 13/21] ethtool: provide timestamping information " Michal Kubecek
2019-02-20  3:00   ` Jakub Kicinski
2019-02-20 13:00     ` Michal Kubecek
2019-02-20 18:37       ` Jakub Kicinski
2019-02-18 18:22 ` [RFC PATCH net-next v3 14/21] ethtool: provide link mode names as a string set Michal Kubecek
2019-02-21  3:21   ` Florian Fainelli
2019-02-21  9:57     ` Michal Kubecek
2019-02-18 18:22 ` [RFC PATCH net-next v3 15/21] ethtool: provide link settings and link modes in GET_SETTINGS request Michal Kubecek
2019-02-21  3:14   ` Florian Fainelli
2019-02-21 10:14     ` Michal Kubecek
2019-02-21 17:40       ` Florian Fainelli
2019-02-18 18:22 ` [RFC PATCH net-next v3 16/21] ethtool: provide WoL information " Michal Kubecek
2019-02-18 18:22 ` [RFC PATCH net-next v3 17/21] ethtool: provide message level " Michal Kubecek
2019-02-18 18:22 ` [RFC PATCH net-next v3 18/21] ethtool: provide link state " Michal Kubecek
2019-02-18 18:23 ` [RFC PATCH net-next v3 19/21] ethtool: provide device features " Michal Kubecek
2019-02-18 18:23 ` [RFC PATCH net-next v3 20/21] ethtool: provide private flags " Michal Kubecek
2019-02-18 18:23 ` [RFC PATCH net-next v3 21/21] ethtool: send netlink notifications about setting changes Michal Kubecek
2019-02-19 10:35 ` [RFC PATCH net-next v3 00/21] ethtool netlink interface, part 1 Jiri Pirko
2019-02-19 11:57   ` Michal Kubecek
2019-02-19 12:27     ` Jiri Pirko
2019-02-21  3:21 ` Florian Fainelli
2019-02-21  9:54   ` Michal Kubecek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=266b4ea3596de134329f8bbd5d13e282d1d27442.1550513384.git.mkubecek@suse.cz \
    --to=mkubecek@suse.cz \
    --cc=andrew@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=jakub.kicinski@netronome.com \
    --cc=jiri@resnulli.us \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.