Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH net-next v6 05/15] ethtool: helper functions for netlink interface
From: Jiri Pirko @ 2019-07-02 13:05 UTC (permalink / raw)
  To: Michal Kubecek
  Cc: David Miller, netdev, Jakub Kicinski, Andrew Lunn,
	Florian Fainelli, John Linville, Stephen Hemminger, Johannes Berg,
	linux-kernel
In-Reply-To: <44957b13e8edbced71aca893908d184eb9e57341.1562067622.git.mkubecek@suse.cz>

Tue, Jul 02, 2019 at 01:50:04PM CEST, mkubecek@suse.cz wrote:
>Add common request/reply header definition and helpers to parse request
>header and fill reply header. Provide ethnl_update_* helpers to update
>structure members from request attributes (to be used for *_SET requests).
>
>Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
>---
> include/uapi/linux/ethtool_netlink.h |  23 ++++
> net/ethtool/netlink.c                | 173 +++++++++++++++++++++++++++
> net/ethtool/netlink.h                | 145 ++++++++++++++++++++++
> 3 files changed, 341 insertions(+)
>
>diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
>index 9a0fbd4f85d9..ffd7db0848ef 100644
>--- a/include/uapi/linux/ethtool_netlink.h
>+++ b/include/uapi/linux/ethtool_netlink.h
>@@ -29,6 +29,29 @@ enum {
> 	ETHTOOL_MSG_KERNEL_MAX = (__ETHTOOL_MSG_KERNEL_CNT - 1)
> };
> 
>+/* request header */
>+
>+/* use compact bitsets in reply */
>+#define ETHTOOL_RF_COMPACT		(1 << 0)

"COMPACT_BITSETS"?


>+/* provide optional reply for SET or ACT requests */
>+#define ETHTOOL_RF_REPLY		(1 << 1)

"OPTIONAL_REPLY"?


>+
>+#define ETHTOOL_RF_ALL (ETHTOOL_RF_COMPACT | \
>+			ETHTOOL_RF_REPLY)
>+
>+enum {
>+	ETHTOOL_A_HEADER_UNSPEC,
>+	ETHTOOL_A_HEADER_DEV_INDEX,		/* u32 */
>+	ETHTOOL_A_HEADER_DEV_NAME,		/* string */
>+	ETHTOOL_A_HEADER_INFOMASK,		/* u32 */
>+	ETHTOOL_A_HEADER_GFLAGS,		/* u32 - ETHTOOL_RF_* */
>+	ETHTOOL_A_HEADER_RFLAGS,		/* u32 */
>+
>+	/* add new constants above here */
>+	__ETHTOOL_A_HEADER_CNT,
>+	ETHTOOL_A_HEADER_MAX = (__ETHTOOL_A_HEADER_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 3c98b41f04e5..e13f29bbd625 100644
>--- a/net/ethtool/netlink.c
>+++ b/net/ethtool/netlink.c
>@@ -1,8 +1,181 @@
> // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
> 
>+#include <net/sock.h>
> #include <linux/ethtool_netlink.h>
> #include "netlink.h"
> 
>+static struct genl_family ethtool_genl_family;
>+
>+static const struct nla_policy dflt_header_policy[ETHTOOL_A_HEADER_MAX + 1] = {
>+	[ETHTOOL_A_HEADER_UNSPEC]	= { .type = NLA_REJECT },
>+	[ETHTOOL_A_HEADER_DEV_INDEX]	= { .type = NLA_U32 },
>+	[ETHTOOL_A_HEADER_DEV_NAME]	= { .type = NLA_NUL_STRING,
>+					    .len = IFNAMSIZ - 1 },
>+	[ETHTOOL_A_HEADER_INFOMASK]	= { .type = NLA_U32 },
>+	[ETHTOOL_A_HEADER_GFLAGS]	= { .type = NLA_U32 },
>+	[ETHTOOL_A_HEADER_RFLAGS]	= { .type = NLA_U32 },
>+};
>+
>+/**
>+ * ethnl_parse_header() - parse request header
>+ * @req_info:    structure to put results into
>+ * @nest:        nest attribute with request header
>+ * @net:         request netns
>+ * @extack:      netlink extack for error reporting
>+ * @policy:      netlink attribute policy to validate header; use
>+ *               @dflt_header_policy (all attributes allowed) if null
>+ * @require_dev: fail if no device identiified in header
>+ *
>+ * Parse request header in nested attribute @nest and puts results into
>+ * the structure pointed to by @req_info. Extack from @info is used for error
>+ * reporting. If req_info->dev is not null on return, reference to it has
>+ * been taken. If error is returned, *req_info is null initialized and no
>+ * reference is held.
>+ *
>+ * Return: 0 on success or negative error code
>+ */
>+int ethnl_parse_header(struct ethnl_req_info *req_info,
>+		       const struct nlattr *nest, struct net *net,

s/nest/header/ ? Nest is way too generic and really tells nothing :/


>+		       struct netlink_ext_ack *extack,
>+		       const struct nla_policy *policy, bool require_dev)
>+{
>+	struct nlattr *tb[ETHTOOL_A_HEADER_MAX + 1];
>+	const struct nlattr *devname_attr;
>+	struct net_device *dev = NULL;
>+	int ret;
>+
>+	if (!nest) {
>+		NL_SET_ERR_MSG(extack, "request header missing");
>+		return -EINVAL;
>+	}
>+	ret = nla_parse_nested(tb, ETHTOOL_A_HEADER_MAX, nest,
>+			       policy ?: dflt_header_policy, extack);
>+	if (ret < 0)

if (ret)

Same remark goes to the rest of the code (also the rest of the patches),
in case called function cannot return positive values.


>+		return ret;
>+	devname_attr = tb[ETHTOOL_A_HEADER_DEV_NAME];
>+
>+	if (tb[ETHTOOL_A_HEADER_DEV_INDEX]) {
>+		u32 ifindex = nla_get_u32(tb[ETHTOOL_A_HEADER_DEV_INDEX]);
>+
>+		dev = dev_get_by_index(net, ifindex);
>+		if (!dev) {
>+			NL_SET_ERR_MSG_ATTR(extack,
>+					    tb[ETHTOOL_A_HEADER_DEV_INDEX],
>+					    "no device matches ifindex");
>+			return -ENODEV;
>+		}
>+		/* if both ifindex and ifname are passed, they must match */
>+		if (devname_attr &&
>+		    strncmp(dev->name, nla_data(devname_attr), IFNAMSIZ)) {
>+			dev_put(dev);
>+			NL_SET_ERR_MSG_ATTR(extack, nest,
>+					    "ifindex and name do not match");
>+			return -ENODEV;
>+		}
>+	} else if (devname_attr) {
>+		dev = dev_get_by_name(net, nla_data(devname_attr));
>+		if (!dev) {
>+			NL_SET_ERR_MSG_ATTR(extack, devname_attr,
>+					    "no device matches name");
>+			return -ENODEV;
>+		}
>+	} else if (require_dev) {
>+		NL_SET_ERR_MSG_ATTR(extack, nest,
>+				    "neither ifindex nor name specified");
>+		return -EINVAL;
>+	}
>+
>+	if (dev && !netif_device_present(dev)) {
>+		dev_put(dev);
>+		NL_SET_ERR_MSG(extack, "device not present");
>+		return -ENODEV;
>+	}
>+
>+	req_info->dev = dev;
>+	ethnl_update_u32(&req_info->req_mask, tb[ETHTOOL_A_HEADER_INFOMASK]);
>+	ethnl_update_u32(&req_info->global_flags, tb[ETHTOOL_A_HEADER_GFLAGS]);
>+	ethnl_update_u32(&req_info->req_flags, tb[ETHTOOL_A_HEADER_RFLAGS]);

Just:
	req_info->req_mask = nla_get_u32(tb[ETHTOOL_A_HEADER_INFOMASK];
	...

Not sure what ethnl_update_u32() is good for, but it is not needed here.


>+
>+	return 0;
>+}
>+
>+/**
>+ * ethnl_fill_reply_header() - Put standard header into a reply message
>+ * @skb:      skb with the message
>+ * @dev:      network device to describe in header
>+ * @attrtype: attribute type to use for the nest
>+ *
>+ * Create a nested attribute with attributes describing given network device.
>+ * Clean up on error.

Cleanup is obvious, no need to mention it in API docs.


>+ *
>+ * Return: 0 on success, error value (-EMSGSIZE only) on error
>+ */
>+int ethnl_fill_reply_header(struct sk_buff *skb, struct net_device *dev,
>+			    u16 attrtype)
>+{
>+	struct nlattr *nest;
>+
>+	if (!dev)
>+		return 0;
>+	nest = nla_nest_start(skb, attrtype);
>+	if (!nest)
>+		return -EMSGSIZE;
>+
>+	if (nla_put_u32(skb, ETHTOOL_A_HEADER_DEV_INDEX, (u32)dev->ifindex) ||
>+	    nla_put_string(skb, ETHTOOL_A_HEADER_DEV_NAME, dev->name))
>+		goto nla_put_failure;
>+	/* If more attributes are put into reply header, ethnl_header_size()
>+	 * must be updated to account for them.
>+	 */
>+
>+	nla_nest_end(skb, nest);
>+	return 0;
>+
>+nla_put_failure:
>+	nla_nest_cancel(skb, nest);
>+	return -EMSGSIZE;
>+}
>+
>+/**
>+ * ethnl_reply_init() - 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:     ETHTOOL_MSG_* message type for reply
>+ * @info:    genetlink info of the received packet we respond to
>+ * @ehdrp:   place to store payload pointer returned by genlmsg_new()
>+ *
>+ * Return: pointer to allocated skb on success, NULL on error
>+ */
>+struct sk_buff *ethnl_reply_init(size_t payload, struct net_device *dev, u8 cmd,
>+				 u16 hdr_attrtype, struct genl_info *info,
>+				 void **ehdrp)
>+{
>+	struct sk_buff *skb;
>+
>+	skb = genlmsg_new(payload, GFP_KERNEL);
>+	if (!skb)
>+		goto err;
>+	*ehdrp = genlmsg_put_reply(skb, info, &ethtool_genl_family, 0, cmd);
>+	if (!*ehdrp)
>+		goto err_free;
>+
>+	if (dev) {
>+		int ret;
>+
>+		ret = ethnl_fill_reply_header(skb, dev, hdr_attrtype);
>+		if (ret < 0)
>+			goto err;
>+	}
>+	return skb;
>+
>+err_free:
>+	nlmsg_free(skb);
>+	if (info)
>+		GENL_SET_ERR_MSG(info, "failed to setup reply message");
>+err:

Why also not fillup extack msg here?


>+	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 257ae55ccc82..5510eb7054b3 100644
>--- a/net/ethtool/netlink.h
>+++ b/net/ethtool/netlink.h
>@@ -6,5 +6,150 @@
> #include <linux/ethtool_netlink.h>
> #include <linux/netdevice.h>
> #include <net/genetlink.h>
>+#include <net/sock.h>
>+
>+struct ethnl_req_info;
>+
>+int ethnl_parse_header(struct ethnl_req_info *req_info,
>+		       const struct nlattr *nest, struct net *net,
>+		       struct netlink_ext_ack *extack,
>+		       const struct nla_policy *policy, bool require_dev);
>+int ethnl_fill_reply_header(struct sk_buff *skb, struct net_device *dev,
>+			    u16 attrtype);
>+struct sk_buff *ethnl_reply_init(size_t payload, struct net_device *dev, u8 cmd,
>+				 u16 hdr_attrtype, struct genl_info *info,
>+				 void **ehdrp);
>+
>+static inline int ethnl_str_size(const char *s)

If you really need this helper, put it into netlink code. There's nothing
ethtool-specific about this.


>+{
>+	return nla_total_size(strlen(s) + 1);
>+}
>+
>+/* The ethnl_update_* helpers set value pointed to by @dst to the value of
>+ * netlink attribute @attr (if attr is not null). They return true if *dst
>+ * value was changed, false if not.
>+ */
>+static inline bool ethnl_update_u32(u32 *dst, struct nlattr *attr)

I'm still not sure I'm convinced about these "update helpers" :)


>+{
>+	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 attribute */
>+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,

void *dst


>+				       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;
>+}
>+
>+/**
>+ * ethnl_is_privileged() - check if request has sufficient privileges
>+ * @skb: skb with client request
>+ *
>+ * Checks if client request has CAP_NET_ADMIN in its netns. Unlike the flags
>+ * in genl_ops, this allows finer access control, e.g. allowing or denying
>+ * the request based on its contents or witholding only part of the data
>+ * from unprivileged users.
>+ *
>+ * Return: true if request is privileged, false if not
>+ */
>+static inline bool ethnl_is_privileged(struct sk_buff *skb)

I wonder why you need this helper. Genetlink uses
ops->flags & GENL_ADMIN_PERM for this. 


>+{
>+	struct net *net = sock_net(skb->sk);
>+
>+	return netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN);
>+}
>+
>+/**
>+ * ethnl_reply_header_size() - total size of reply header
>+ *
>+ * This is an upper estimate so that we do not need to hold RTNL lock longer
>+ * than necessary (to prevent rename between size estimate and composing the

I guess this description is not relevant anymore. I don't see why to
hold rtnl mutex for this function...


>+ * message). Accounts only for device ifindex and name as those are the only
>+ * attributes ethnl_fill_reply_header() puts into the reply header.
>+ */
>+static inline unsigned int ethnl_reply_header_size(void)
>+{
>+	return nla_total_size(nla_total_size(sizeof(u32)) +
>+			      nla_total_size(IFNAMSIZ));
>+}
>+
>+/**
>+ * struct ethnl_req_info - base type of request information for GET requests
>+ * @dev:          network device the request is for (may be null)
>+ * @req_mask:     request mask, bitmap of requested information
>+ * @global_flags: request flags common for all request types
>+ * @req_flags:    request flags specific for each request type
>+ * @privileged:   privileged request (CAP_NET_ADMIN in netns)
>+ *
>+ * This is a common base, additional members may follow after this structure.
>+ */
>+struct ethnl_req_info {
>+	struct net_device		*dev;
>+	u32				req_mask;
>+	u32				global_flags;
>+	u32				req_flags;
>+	bool				privileged;
>+};
> 
> #endif /* _NET_ETHTOOL_NETLINK_H */
>-- 
>2.22.0
>

^ permalink raw reply

* Re: [PATCH net-next 5/5] ipv4: use indirect call wrappers for {tcp,udp}_{recv,send}msg()
From: Paolo Abeni @ 2019-07-02 13:03 UTC (permalink / raw)
  To: Willem de Bruijn; +Cc: Network Development, David S. Miller
In-Reply-To: <CA+FuTSfHF_LRuZeW3ZiX5a662=fdAu9zmmpa67WpOkZqkt8Srw@mail.gmail.com>

On Mon, 2019-07-01 at 15:07 -0400, Willem de Bruijn wrote:
> On Mon, Jul 1, 2019 at 1:10 PM Paolo Abeni <pabeni@redhat.com> wrote:
> > This avoids an indirect call per syscall for common ipv4 transports
> > 
> > Signed-off-by: Paolo Abeni <pabeni@redhat.com>
> > ---
> >  net/ipv4/af_inet.c | 12 +++++++++---
> >  1 file changed, 9 insertions(+), 3 deletions(-)
> > 
> > diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
> > index 8421e2f5bbb3..9a2f17d0c5f5 100644
> > --- a/net/ipv4/af_inet.c
> > +++ b/net/ipv4/af_inet.c
> > @@ -797,6 +797,8 @@ int inet_send_prepare(struct sock *sk)
> >  }
> >  EXPORT_SYMBOL_GPL(inet_send_prepare);
> > 
> > +INDIRECT_CALLABLE_DECLARE(int udp_sendmsg(struct sock *, struct msghdr *,
> > +                                         size_t));
> 
> Small nit: this is already defined in include/net/udp.h, which is
> included. So like tcp_sendmsg, probably no need to declare.

Thank you for the review!

You are right, that declaration can be dropped.
> 
> If defining inet6_sendmsg and inet6_recvmsg in include/net/ipv6.h,
> perhaps do the same for the other missing functions, instead of these
> indirect declarations at the callsite?

Uhm... since inet6_{send,recv}msg exists only for retpoline sake and
are not exported, I think is probably better move their declaration to
socket.c via INDIRECT_CALLABLE_DECLARE(), to that ICWs are all self-
contained.

Unless there are objections about spamming, I can repost the series
with the above changes.

Cheers,

Paolo


^ permalink raw reply

* [PATCH] User mode linux bump maximum MTU tuntap interface [RESAND]
From: Алексей @ 2019-07-02 12:55 UTC (permalink / raw)
  To: netdev
In-Reply-To: <54cee375-f1c3-a2b3-ea89-919b0af60433@yandex.ru>

Hello, the parameter  ETH_MAX_PACKET limited to 1500 bytes is the not
support jumbo frames.

This patch change ETH_MAX_PACKET the 65535 bytes to jumbo frame support
with user mode linux tuntap driver.


PATCH:

-------------------


diff -ruNP ../linux_orig/linux-5.1/arch/um/include/shared/net_user.h
./arch/um/include/shared/net_user.h
--- a/arch/um/include/shared/net_user.h    2019-05-06 00:42:58.000000000
+0000
+++ b/arch/um/include/shared/net_user.h    2019-07-02 07:14:13.593333356
+0000
@@ -9,7 +9,7 @@
 #define ETH_ADDR_LEN (6)
 #define ETH_HEADER_ETHERTAP (16)
 #define ETH_HEADER_OTHER (26) /* 14 for ethernet + VLAN + MPLS for
crazy people */
-#define ETH_MAX_PACKET (1500)
+#define ETH_MAX_PACKET (65535)
 
 #define UML_NET_VERSION (4)
 
-------------------
 


^ permalink raw reply

* suspicious RCU usage (was: Re: [PATCHv3 next 1/3] loopback: create blackhole net device similar to loopack.)
From: Geert Uytterhoeven @ 2019-07-02 12:54 UTC (permalink / raw)
  To: Mahesh Bandewar
  Cc: Netdev, Eric Dumazet, David Miller, Michael Chan, Daniel Axtens,
	Mahesh Bandewar, Paul E. McKenney, linux-arm-kernel, linux-kernel
In-Reply-To: <20190701213849.102759-1-maheshb@google.com>

 	Hi Mahesh,

On Mon, 1 Jul 2019, Mahesh Bandewar wrote:
> Create a blackhole net device that can be used for "dead"
> dst entries instead of loopback device. This blackhole device differs
> from loopback in few aspects: (a) It's not per-ns. (b)  MTU on this
> device is ETH_MIN_MTU (c) The xmit function is essentially kfree_skb().
> and (d) since it's not registered it won't have ifindex.
>
> Lower MTU effectively make the device not pass the MTU check during
> the route check when a dst associated with the skb is dead.
>
> Signed-off-by: Mahesh Bandewar <maheshb@google.com>

This is now commit 4de83b88c66a1e4d ("loopback: create blackhole net
device similar to loopack.") in net-next, and causes the following
warning on arm64:

     WARNING: suspicious RCU usage
     5.2.0-rc6-arm64-renesas-01699-g4de83b88c66a1e4d #263 Not tainted
     -----------------------------
     include/linux/rtnetlink.h:85 suspicious rcu_dereference_protected() usage!

     other info that might help us debug this:


     rcu_scheduler_active = 2, debug_locks = 1
     no locks held by swapper/0/1.

     stack backtrace:
     CPU: 2 PID: 1 Comm: swapper/0 Not tainted 5.2.0-rc6-arm64-renesas-01699-g4de83b88c66a1e4d #263
     Hardware name: Renesas Salvator-X 2nd version board based on r8a7795 ES2.0+ (DT)
     Call trace:
      dump_backtrace+0x0/0x148
      show_stack+0x14/0x20
      dump_stack+0xd4/0x11c
      lockdep_rcu_suspicious+0xcc/0x110
      dev_init_scheduler+0x114/0x150
      blackhole_netdev_init+0x40/0x80
      do_one_initcall+0x178/0x37c
      kernel_init_freeable+0x490/0x530
      kernel_init+0x10/0x100
      ret_from_fork+0x10/0x1c


> ---
> v1->v2->v3
>  no change
>
> drivers/net/loopback.c    | 76 ++++++++++++++++++++++++++++++++++-----
> include/linux/netdevice.h |  2 ++
> 2 files changed, 69 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
> index 87d361666cdd..3b39def5471e 100644
> --- a/drivers/net/loopback.c
> +++ b/drivers/net/loopback.c
> @@ -55,6 +55,13 @@
> #include <net/net_namespace.h>
> #include <linux/u64_stats_sync.h>
>
> +/* blackhole_netdev - a device used for dsts that are marked expired!
> + * This is global device (instead of per-net-ns) since it's not needed
> + * to be per-ns and gets initialized at boot time.
> + */
> +struct net_device *blackhole_netdev;
> +EXPORT_SYMBOL(blackhole_netdev);
> +
> /* The higher levels take care of making this non-reentrant (it's
>  * called with bh's disabled).
>  */
> @@ -150,12 +157,14 @@ static const struct net_device_ops loopback_ops = {
> 	.ndo_set_mac_address = eth_mac_addr,
> };
>
> -/* The loopback device is special. There is only one instance
> - * per network namespace.
> - */
> -static void loopback_setup(struct net_device *dev)
> +static void gen_lo_setup(struct net_device *dev,
> +			 unsigned int mtu,
> +			 const struct ethtool_ops *eth_ops,
> +			 const struct header_ops *hdr_ops,
> +			 const struct net_device_ops *dev_ops,
> +			 void (*dev_destructor)(struct net_device *dev))
> {
> -	dev->mtu		= 64 * 1024;
> +	dev->mtu		= mtu;
> 	dev->hard_header_len	= ETH_HLEN;	/* 14	*/
> 	dev->min_header_len	= ETH_HLEN;	/* 14	*/
> 	dev->addr_len		= ETH_ALEN;	/* 6	*/
> @@ -174,11 +183,20 @@ static void loopback_setup(struct net_device *dev)
> 		| NETIF_F_NETNS_LOCAL
> 		| NETIF_F_VLAN_CHALLENGED
> 		| NETIF_F_LOOPBACK;
> -	dev->ethtool_ops	= &loopback_ethtool_ops;
> -	dev->header_ops		= &eth_header_ops;
> -	dev->netdev_ops		= &loopback_ops;
> +	dev->ethtool_ops	= eth_ops;
> +	dev->header_ops		= hdr_ops;
> +	dev->netdev_ops		= dev_ops;
> 	dev->needs_free_netdev	= true;
> -	dev->priv_destructor	= loopback_dev_free;
> +	dev->priv_destructor	= dev_destructor;
> +}
> +
> +/* The loopback device is special. There is only one instance
> + * per network namespace.
> + */
> +static void loopback_setup(struct net_device *dev)
> +{
> +	gen_lo_setup(dev, (64 * 1024), &loopback_ethtool_ops, &eth_header_ops,
> +		     &loopback_ops, loopback_dev_free);
> }
>
> /* Setup and register the loopback device. */
> @@ -213,3 +231,43 @@ static __net_init int loopback_net_init(struct net *net)
> struct pernet_operations __net_initdata loopback_net_ops = {
> 	.init = loopback_net_init,
> };
> +
> +/* blackhole netdevice */
> +static netdev_tx_t blackhole_netdev_xmit(struct sk_buff *skb,
> +					 struct net_device *dev)
> +{
> +	kfree_skb(skb);
> +	net_warn_ratelimited("%s(): Dropping skb.\n", __func__);
> +	return NETDEV_TX_OK;
> +}
> +
> +static const struct net_device_ops blackhole_netdev_ops = {
> +	.ndo_start_xmit = blackhole_netdev_xmit,
> +};
> +
> +/* This is a dst-dummy device used specifically for invalidated
> + * DSTs and unlike loopback, this is not per-ns.
> + */
> +static void blackhole_netdev_setup(struct net_device *dev)
> +{
> +	gen_lo_setup(dev, ETH_MIN_MTU, NULL, NULL, &blackhole_netdev_ops, NULL);
> +}
> +
> +/* Setup and register the blackhole_netdev. */
> +static int __init blackhole_netdev_init(void)
> +{
> +	blackhole_netdev = alloc_netdev(0, "blackhole_dev", NET_NAME_UNKNOWN,
> +					blackhole_netdev_setup);
> +	if (!blackhole_netdev)
> +		return -ENOMEM;
> +
> +	dev_init_scheduler(blackhole_netdev);
> +	dev_activate(blackhole_netdev);
> +
> +	blackhole_netdev->flags |= IFF_UP | IFF_RUNNING;
> +	dev_net_set(blackhole_netdev, &init_net);
> +
> +	return 0;
> +}
> +
> +device_initcall(blackhole_netdev_init);
> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> index eeacebd7debb..88292953aa6f 100644
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -4870,4 +4870,6 @@ do {								\
> #define PTYPE_HASH_SIZE	(16)
> #define PTYPE_HASH_MASK	(PTYPE_HASH_SIZE - 1)
>
> +extern struct net_device *blackhole_netdev;
> +
> #endif	/* _LINUX_NETDEVICE_H */
>
Gr{oetje,eeting}s,

 						Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
 							    -- Linus Torvalds


^ permalink raw reply

* Re: [PATCH] rtl8xxxu: Fix wifi low signal strength issue of RTL8723BU
From: Jes Sorensen @ 2019-07-02 12:44 UTC (permalink / raw)
  To: Chris Chiu, kvalo, davem; +Cc: linux-wireless, netdev, linux-kernel, linux
In-Reply-To: <20190627095247.8792-1-chiu@endlessm.com>

On 6/27/19 5:52 AM, Chris Chiu wrote:
> The WiFi tx power of RTL8723BU is extremely low after booting. So
> the WiFi scan gives very limited AP list and it always fails to
> connect to the selected AP. This module only supports 1x1 antenna
> and the antenna is switched to bluetooth due to some incorrect
> register settings.
> 
> This commit hand over the antenna control to PTA, the wifi signal
> will be back to normal and the bluetooth scan can also work at the
> same time. However, the btcoexist still needs to be handled under
> different circumstances. If there's a BT connection established,
> the wifi still fails to connect until disconneting the BT.
> 
> Signed-off-by: Chris Chiu <chiu@endlessm.com>
> ---
>  drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c | 9 ++++++---
>  drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c  | 3 ++-
>  2 files changed, 8 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c
> index 3adb1d3d47ac..6c3c70d93ac1 100644
> --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c
> +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c
> @@ -1525,7 +1525,7 @@ static void rtl8723b_enable_rf(struct rtl8xxxu_priv *priv)
>  	/*
>  	 * WLAN action by PTA
>  	 */
> -	rtl8xxxu_write8(priv, REG_WLAN_ACT_CONTROL_8723B, 0x04);
> +	rtl8xxxu_write8(priv, REG_WLAN_ACT_CONTROL_8723B, 0x0c);
>  
>  	/*
>  	 * BT select S0/S1 controlled by WiFi
> @@ -1568,9 +1568,12 @@ static void rtl8723b_enable_rf(struct rtl8xxxu_priv *priv)
>  	rtl8xxxu_gen2_h2c_cmd(priv, &h2c, sizeof(h2c.ant_sel_rsv));
>  
>  	/*
> -	 * 0x280, 0x00, 0x200, 0x80 - not clear
> +	 * Different settings per different antenna position.
> +	 * Antenna switch to BT: 0x280, 0x00 (inverse)
> +	 * Antenna switch to WiFi: 0x0, 0x280 (inverse)
> +	 * Antenna controlled by PTA: 0x200, 0x80 (inverse)
>  	 */
> -	rtl8xxxu_write32(priv, REG_S0S1_PATH_SWITCH, 0x00);
> +	rtl8xxxu_write32(priv, REG_S0S1_PATH_SWITCH, 0x80);
>  
>  	/*
>  	 * Software control, antenna at WiFi side
> diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
> index 8136e268b4e6..87b2179a769e 100644
> --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
> +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
> @@ -3891,12 +3891,13 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw)
>  
>  	/* Check if MAC is already powered on */
>  	val8 = rtl8xxxu_read8(priv, REG_CR);
> +	val16 = rtl8xxxu_read16(priv, REG_SYS_CLKR);
>  
>  	/*
>  	 * Fix 92DU-VC S3 hang with the reason is that secondary mac is not
>  	 * initialized. First MAC returns 0xea, second MAC returns 0x00
>  	 */
> -	if (val8 == 0xea)
> +	if (val8 == 0xea || !(val16 & BIT(11)))
>  		macpower = false;
>  	else
>  		macpower = true;

This part I would like to ask you take a good look at the other chips to
make sure you don't break support for 8192cu, 8723au, 8188eu with this.

Cheers,
Jes

^ permalink raw reply

* Re: [PATCH] rtl8xxxu: Fix wifi low signal strength issue of RTL8723BU
From: Jes Sorensen @ 2019-07-02 12:42 UTC (permalink / raw)
  To: Daniel Drake, Chris Chiu
  Cc: Kalle Valo, David Miller, linux-wireless, netdev, Linux Kernel,
	Linux Upstreaming Team, Larry Finger
In-Reply-To: <CAD8Lp44R0a1=fVi=fGv69w1ppdcaFV01opkdkhaX-eJ=K=tYeA@mail.gmail.com>

On 7/1/19 4:27 AM, Daniel Drake wrote:
> Hi Chris,
> 
> On Thu, Jun 27, 2019 at 5:53 PM Chris Chiu <chiu@endlessm.com> wrote:
>> The WiFi tx power of RTL8723BU is extremely low after booting. So
>> the WiFi scan gives very limited AP list and it always fails to
>> connect to the selected AP. This module only supports 1x1 antenna
>> and the antenna is switched to bluetooth due to some incorrect
>> register settings.
>>
>> This commit hand over the antenna control to PTA, the wifi signal
>> will be back to normal and the bluetooth scan can also work at the
>> same time. However, the btcoexist still needs to be handled under
>> different circumstances. If there's a BT connection established,
>> the wifi still fails to connect until disconneting the BT.
>>
>> Signed-off-by: Chris Chiu <chiu@endlessm.com>
> 
> Really nice work finding this!
> 
> I know that after this change, you plan to bring over the btcoexist
> code from the vendor driver (or at least the minimum required code)
> for a more complete fix, but I'm curious how you found these magic
> register values and how they compare to the values used by the vendor
> driver with btcoexist?

We definitely don't want to bring over the vendor code, since it's a
pile of spaghetti, but we probably need to get something sorted. This
went down the drain when the bluetooth driver was added without taking
it into account - long after this driver was merged.

Cheers,
Jes


^ permalink raw reply

* [PATCH][next] ath: fix various spelling mistakes
From: Colin King @ 2019-07-02 12:39 UTC (permalink / raw)
  To: Kalle Valo, David S . Miller, Maya Erez, ath10k, linux-wireless,
	netdev, wil6210
  Cc: kernel-janitors, linux-kernel

From: Colin Ian King <colin.king@canonical.com>

There are a bunch of spelling mistakes in two ath drivers, fix
these.

Signed-off-by: Colin Ian King <colin.king@canonical.com>
---
 drivers/net/wireless/ath/ath10k/core.c | 2 +-
 drivers/net/wireless/ath/ath10k/mac.c  | 2 +-
 drivers/net/wireless/ath/ath10k/qmi.c  | 4 ++--
 drivers/net/wireless/ath/wil6210/wmi.c | 2 +-
 4 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index dc45d16e8d21..a7c25d49683b 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -2784,7 +2784,7 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
 
 	status = ath10k_hif_set_target_log_mode(ar, fw_diag_log);
 	if (status && status != -EOPNOTSUPP) {
-		ath10k_warn(ar, "set traget log mode faileds: %d\n", status);
+		ath10k_warn(ar, "set target log mode failed: %d\n", status);
 		goto err_hif_stop;
 	}
 
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index e43a566eef77..20f72ec95b28 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -7417,7 +7417,7 @@ static bool ath10k_mac_set_vht_bitrate_mask_fixup(struct ath10k *ar,
 	err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
 					WMI_PEER_PARAM_FIXED_RATE, rate);
 	if (err)
-		ath10k_warn(ar, "failed to eanble STA %pM peer fixed rate: %d\n",
+		ath10k_warn(ar, "failed to enable STA %pM peer fixed rate: %d\n",
 			    sta->addr, err);
 
 	return true;
diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c
index 3b63b6257c43..d28daa2d9449 100644
--- a/drivers/net/wireless/ath/ath10k/qmi.c
+++ b/drivers/net/wireless/ath/ath10k/qmi.c
@@ -643,7 +643,7 @@ int ath10k_qmi_set_fw_log_mode(struct ath10k *ar, u8 fw_log_mode)
 			       wlfw_ini_req_msg_v01_ei, &req);
 	if (ret < 0) {
 		qmi_txn_cancel(&txn);
-		ath10k_err(ar, "fail to send fw log reqest: %d\n", ret);
+		ath10k_err(ar, "failed to send fw log request: %d\n", ret);
 		goto out;
 	}
 
@@ -652,7 +652,7 @@ int ath10k_qmi_set_fw_log_mode(struct ath10k *ar, u8 fw_log_mode)
 		goto out;
 
 	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
-		ath10k_err(ar, "fw log request rejectedr: %d\n",
+		ath10k_err(ar, "fw log request rejected: %d\n",
 			   resp.resp.error);
 		ret = -EINVAL;
 		goto out;
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 475b1a233cc9..e1704cdfc03e 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -2688,7 +2688,7 @@ int wmi_get_all_temperatures(struct wil6210_priv *wil,
 		return rc;
 
 	if (reply.evt.status == WMI_FW_STATUS_FAILURE) {
-		wil_err(wil, "Failed geting TEMP_SENSE_ALL\n");
+		wil_err(wil, "Failed getting TEMP_SENSE_ALL\n");
 		return -EINVAL;
 	}
 
-- 
2.20.1


^ permalink raw reply related

* Re: [PATCH net 2/4] net: bridge: mcast: fix stale ipv6 hdr pointer when handling v6 query
From: Martin Weinelt @ 2019-07-02 12:37 UTC (permalink / raw)
  To: Nikolay Aleksandrov, netdev; +Cc: roopa, davem, bridge, yoshfuji
In-Reply-To: <20190702120021.13096-3-nikolay@cumulusnetworks.com>


[-- Attachment #1.1: Type: text/plain, Size: 1382 bytes --]

Tested-by: Martin Weinelt <martin@linuxlounge.net>

On 7/2/19 2:00 PM, Nikolay Aleksandrov wrote:
> We get a pointer to the ipv6 hdr in br_ip6_multicast_query but we may
> call pskb_may_pull afterwards and end up using a stale pointer.
> So use the header directly, it's just 1 place where it's needed.
> 
> Fixes: 08b202b67264 ("bridge br_multicast: IPv6 MLD support.")
> Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
> ---
>  net/bridge/br_multicast.c | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)
> 
> diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
> index f37897e7b97b..3d8deac2353d 100644
> --- a/net/bridge/br_multicast.c
> +++ b/net/bridge/br_multicast.c
> @@ -1279,7 +1279,6 @@ static int br_ip6_multicast_query(struct net_bridge *br,
>  				  u16 vid)
>  {
>  	unsigned int transport_len = ipv6_transport_len(skb);
> -	const struct ipv6hdr *ip6h = ipv6_hdr(skb);
>  	struct mld_msg *mld;
>  	struct net_bridge_mdb_entry *mp;
>  	struct mld2_query *mld2q;
> @@ -1323,7 +1322,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
>  
>  	if (is_general_query) {
>  		saddr.proto = htons(ETH_P_IPV6);
> -		saddr.u.ip6 = ip6h->saddr;
> +		saddr.u.ip6 = ipv6_hdr(skb)->saddr;
>  
>  		br_multicast_query_received(br, port, &br->ip6_other_query,
>  					    &saddr, max_delay);
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* [PATCH ipsec] xfrm interface: fix memory leak on creation
From: Nicolas Dichtel @ 2019-07-02  7:38 UTC (permalink / raw)
  To: steffen.klassert, davem
  Cc: netdev, Nicolas Dichtel, Lorenzo Colitti, Benedict Wong,
	Shannon Nelson, Antony Antony, Eyal Birger, Julien Floret

The following commands produce a backtrace and returns an error but the
xfrm interface is created (in the wrong netns):
$ ip netns add foo
$ ip netns add bar
$ ip -n foo netns set bar 0
$ ip -n foo link add xfrmi0 link-netnsid 0 type xfrm dev lo if_id 23
RTNETLINK answers: Invalid argument
$ ip -n bar link ls xfrmi0
2: xfrmi0@lo: <NOARP,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/none 00:00:00:00:00:00 brd 00:00:00:00:00:00

Here is the backtrace:
[   79.879174] WARNING: CPU: 0 PID: 1178 at net/core/dev.c:8172 rollback_registered_many+0x86/0x3c1
[   79.880260] Modules linked in: xfrm_interface nfsv3 nfs_acl auth_rpcgss nfsv4 nfs lockd grace sunrpc fscache button parport_pc parport serio_raw evdev pcspkr loop ext4 crc16 mbcache jbd2 crc32c_generic ide_cd_mod ide_gd_mod cdrom ata_$
eneric ata_piix libata scsi_mod 8139too piix psmouse i2c_piix4 ide_core 8139cp mii i2c_core floppy
[   79.883698] CPU: 0 PID: 1178 Comm: ip Not tainted 5.2.0-rc6+ #106
[   79.884462] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014
[   79.885447] RIP: 0010:rollback_registered_many+0x86/0x3c1
[   79.886120] Code: 01 e8 d7 7d c6 ff 0f 0b 48 8b 45 00 4c 8b 20 48 8d 58 90 49 83 ec 70 48 8d 7b 70 48 39 ef 74 44 8a 83 d0 04 00 00 84 c0 75 1f <0f> 0b e8 61 cd ff ff 48 b8 00 01 00 00 00 00 ad de 48 89 43 70 66
[   79.888667] RSP: 0018:ffffc900015ab740 EFLAGS: 00010246
[   79.889339] RAX: ffff8882353e5700 RBX: ffff8882353e56a0 RCX: ffff8882353e5710
[   79.890174] RDX: ffffc900015ab7e0 RSI: ffffc900015ab7e0 RDI: ffff8882353e5710
[   79.891029] RBP: ffffc900015ab7e0 R08: ffffc900015ab7e0 R09: ffffc900015ab7e0
[   79.891866] R10: ffffc900015ab7a0 R11: ffffffff82233fec R12: ffffc900015ab770
[   79.892728] R13: ffffffff81eb7ec0 R14: ffff88822ed6cf00 R15: 00000000ffffffea
[   79.893557] FS:  00007ff350f31740(0000) GS:ffff888237a00000(0000) knlGS:0000000000000000
[   79.894581] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   79.895317] CR2: 00000000006c8580 CR3: 000000022c272000 CR4: 00000000000006f0
[   79.896137] Call Trace:
[   79.896464]  unregister_netdevice_many+0x12/0x6c
[   79.896998]  __rtnl_newlink+0x6e2/0x73b
[   79.897446]  ? __kmalloc_node_track_caller+0x15e/0x185
[   79.898039]  ? pskb_expand_head+0x5f/0x1fe
[   79.898556]  ? stack_access_ok+0xd/0x2c
[   79.899009]  ? deref_stack_reg+0x12/0x20
[   79.899462]  ? stack_access_ok+0xd/0x2c
[   79.899927]  ? stack_access_ok+0xd/0x2c
[   79.900404]  ? __module_text_address+0x9/0x4f
[   79.900910]  ? is_bpf_text_address+0x5/0xc
[   79.901390]  ? kernel_text_address+0x67/0x7b
[   79.901884]  ? __kernel_text_address+0x1a/0x25
[   79.902397]  ? unwind_get_return_address+0x12/0x23
[   79.903122]  ? __cmpxchg_double_slab.isra.37+0x46/0x77
[   79.903772]  rtnl_newlink+0x43/0x56
[   79.904217]  rtnetlink_rcv_msg+0x200/0x24c

In fact, each time an xfrm interface was created, a netdev was allocated
by __rtnl_newlink()/rtnl_create_link() and then another one by
xfrmi_newlink()/xfrmi_create(). Only the second one was registered, it's
why the previous commands produce a backtrace: dev_change_net_namespace()
was called on a netdev with reg_state set to NETREG_UNINITIALIZED (the
first one).

CC: Lorenzo Colitti <lorenzo@google.com>
CC: Benedict Wong <benedictwong@google.com>
CC: Steffen Klassert <steffen.klassert@secunet.com>
CC: Shannon Nelson <shannon.nelson@oracle.com>
CC: Antony Antony <antony@phenome.org>
CC: Eyal Birger <eyal.birger@gmail.com>
Fixes: f203b76d7809 ("xfrm: Add virtual xfrm interfaces")
Reported-by: Julien Floret <julien.floret@6wind.com>
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
 net/xfrm/xfrm_interface.c | 98 +++++++++++----------------------------
 1 file changed, 28 insertions(+), 70 deletions(-)

diff --git a/net/xfrm/xfrm_interface.c b/net/xfrm/xfrm_interface.c
index ad3a2555c517..7dbe0c608df5 100644
--- a/net/xfrm/xfrm_interface.c
+++ b/net/xfrm/xfrm_interface.c
@@ -133,7 +133,7 @@ static void xfrmi_dev_free(struct net_device *dev)
 	free_percpu(dev->tstats);
 }
 
-static int xfrmi_create2(struct net_device *dev)
+static int xfrmi_create(struct net_device *dev)
 {
 	struct xfrm_if *xi = netdev_priv(dev);
 	struct net *net = dev_net(dev);
@@ -156,54 +156,7 @@ static int xfrmi_create2(struct net_device *dev)
 	return err;
 }
 
-static struct xfrm_if *xfrmi_create(struct net *net, struct xfrm_if_parms *p)
-{
-	struct net_device *dev;
-	struct xfrm_if *xi;
-	char name[IFNAMSIZ];
-	int err;
-
-	if (p->name[0]) {
-		strlcpy(name, p->name, IFNAMSIZ);
-	} else {
-		err = -EINVAL;
-		goto failed;
-	}
-
-	dev = alloc_netdev(sizeof(*xi), name, NET_NAME_UNKNOWN, xfrmi_dev_setup);
-	if (!dev) {
-		err = -EAGAIN;
-		goto failed;
-	}
-
-	dev_net_set(dev, net);
-
-	xi = netdev_priv(dev);
-	xi->p = *p;
-	xi->net = net;
-	xi->dev = dev;
-	xi->phydev = dev_get_by_index(net, p->link);
-	if (!xi->phydev) {
-		err = -ENODEV;
-		goto failed_free;
-	}
-
-	err = xfrmi_create2(dev);
-	if (err < 0)
-		goto failed_dev_put;
-
-	return xi;
-
-failed_dev_put:
-	dev_put(xi->phydev);
-failed_free:
-	free_netdev(dev);
-failed:
-	return ERR_PTR(err);
-}
-
-static struct xfrm_if *xfrmi_locate(struct net *net, struct xfrm_if_parms *p,
-				   int create)
+static struct xfrm_if *xfrmi_locate(struct net *net, struct xfrm_if_parms *p)
 {
 	struct xfrm_if __rcu **xip;
 	struct xfrm_if *xi;
@@ -211,17 +164,11 @@ static struct xfrm_if *xfrmi_locate(struct net *net, struct xfrm_if_parms *p,
 
 	for (xip = &xfrmn->xfrmi[0];
 	     (xi = rtnl_dereference(*xip)) != NULL;
-	     xip = &xi->next) {
-		if (xi->p.if_id == p->if_id) {
-			if (create)
-				return ERR_PTR(-EEXIST);
-
+	     xip = &xi->next)
+		if (xi->p.if_id == p->if_id)
 			return xi;
-		}
-	}
-	if (!create)
-		return ERR_PTR(-ENODEV);
-	return xfrmi_create(net, p);
+
+	return NULL;
 }
 
 static void xfrmi_dev_uninit(struct net_device *dev)
@@ -686,21 +633,33 @@ static int xfrmi_newlink(struct net *src_net, struct net_device *dev,
 			struct netlink_ext_ack *extack)
 {
 	struct net *net = dev_net(dev);
-	struct xfrm_if_parms *p;
+	struct xfrm_if_parms p;
 	struct xfrm_if *xi;
+	int err;
 
-	xi = netdev_priv(dev);
-	p = &xi->p;
-
-	xfrmi_netlink_parms(data, p);
+	xfrmi_netlink_parms(data, &p);
 
 	if (!tb[IFLA_IFNAME])
 		return -EINVAL;
 
-	nla_strlcpy(p->name, tb[IFLA_IFNAME], IFNAMSIZ);
+	nla_strlcpy(p.name, tb[IFLA_IFNAME], IFNAMSIZ);
 
-	xi = xfrmi_locate(net, p, 1);
-	return PTR_ERR_OR_ZERO(xi);
+	xi = xfrmi_locate(net, &p);
+	if (xi)
+		return -EEXIST;
+
+	xi = netdev_priv(dev);
+	xi->p = p;
+	xi->net = net;
+	xi->dev = dev;
+	xi->phydev = dev_get_by_index(net, p.link);
+	if (!xi->phydev)
+		return -ENODEV;
+
+	err = xfrmi_create(dev);
+	if (err < 0)
+		dev_put(xi->phydev);
+	return err;
 }
 
 static void xfrmi_dellink(struct net_device *dev, struct list_head *head)
@@ -717,9 +676,8 @@ static int xfrmi_changelink(struct net_device *dev, struct nlattr *tb[],
 
 	xfrmi_netlink_parms(data, &xi->p);
 
-	xi = xfrmi_locate(net, &xi->p, 0);
-
-	if (IS_ERR_OR_NULL(xi)) {
+	xi = xfrmi_locate(net, &xi->p);
+	if (!xi) {
 		xi = netdev_priv(dev);
 	} else {
 		if (xi->dev != dev)
-- 
2.21.0


^ permalink raw reply related

* Re: [PATCH net 1/4] net: bridge: mcast: fix stale nsrcs pointer in igmp3/mld2 report handling
From: Martin Weinelt @ 2019-07-02 12:29 UTC (permalink / raw)
  To: Nikolay Aleksandrov, netdev; +Cc: roopa, davem, bridge, yoshfuji
In-Reply-To: <20190702120021.13096-2-nikolay@cumulusnetworks.com>


[-- Attachment #1.1: Type: text/plain, Size: 6601 bytes --]

Tested-by: Martin Weinelt <martin@linuxlounge.net>

On 7/2/19 2:00 PM, Nikolay Aleksandrov wrote:
> We take a pointer to grec prior to calling pskb_may_pull and use it
> afterwards to get nsrcs so record nsrcs before the pull when handling
> igmp3 and we get a pointer to nsrcs and call pskb_may_pull when handling
> mld2 which again could lead to reading 2 bytes out-of-bounds.
> 
>  ==================================================================
>  BUG: KASAN: use-after-free in br_multicast_rcv+0x480c/0x4ad0 [bridge]
>  Read of size 2 at addr ffff8880421302b4 by task ksoftirqd/1/16
> 
>  CPU: 1 PID: 16 Comm: ksoftirqd/1 Tainted: G           OE     5.2.0-rc6+ #1
>  Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014
>  Call Trace:
>   dump_stack+0x71/0xab
>   print_address_description+0x6a/0x280
>   ? br_multicast_rcv+0x480c/0x4ad0 [bridge]
>   __kasan_report+0x152/0x1aa
>   ? br_multicast_rcv+0x480c/0x4ad0 [bridge]
>   ? br_multicast_rcv+0x480c/0x4ad0 [bridge]
>   kasan_report+0xe/0x20
>   br_multicast_rcv+0x480c/0x4ad0 [bridge]
>   ? br_multicast_disable_port+0x150/0x150 [bridge]
>   ? ktime_get_with_offset+0xb4/0x150
>   ? __kasan_kmalloc.constprop.6+0xa6/0xf0
>   ? __netif_receive_skb+0x1b0/0x1b0
>   ? br_fdb_update+0x10e/0x6e0 [bridge]
>   ? br_handle_frame_finish+0x3c6/0x11d0 [bridge]
>   br_handle_frame_finish+0x3c6/0x11d0 [bridge]
>   ? br_pass_frame_up+0x3a0/0x3a0 [bridge]
>   ? virtnet_probe+0x1c80/0x1c80 [virtio_net]
>   br_handle_frame+0x731/0xd90 [bridge]
>   ? select_idle_sibling+0x25/0x7d0
>   ? br_handle_frame_finish+0x11d0/0x11d0 [bridge]
>   __netif_receive_skb_core+0xced/0x2d70
>   ? virtqueue_get_buf_ctx+0x230/0x1130 [virtio_ring]
>   ? do_xdp_generic+0x20/0x20
>   ? virtqueue_napi_complete+0x39/0x70 [virtio_net]
>   ? virtnet_poll+0x94d/0xc78 [virtio_net]
>   ? receive_buf+0x5120/0x5120 [virtio_net]
>   ? __netif_receive_skb_one_core+0x97/0x1d0
>   __netif_receive_skb_one_core+0x97/0x1d0
>   ? __netif_receive_skb_core+0x2d70/0x2d70
>   ? _raw_write_trylock+0x100/0x100
>   ? __queue_work+0x41e/0xbe0
>   process_backlog+0x19c/0x650
>   ? _raw_read_lock_irq+0x40/0x40
>   net_rx_action+0x71e/0xbc0
>   ? __switch_to_asm+0x40/0x70
>   ? napi_complete_done+0x360/0x360
>   ? __switch_to_asm+0x34/0x70
>   ? __switch_to_asm+0x40/0x70
>   ? __schedule+0x85e/0x14d0
>   __do_softirq+0x1db/0x5f9
>   ? takeover_tasklets+0x5f0/0x5f0
>   run_ksoftirqd+0x26/0x40
>   smpboot_thread_fn+0x443/0x680
>   ? sort_range+0x20/0x20
>   ? schedule+0x94/0x210
>   ? __kthread_parkme+0x78/0xf0
>   ? sort_range+0x20/0x20
>   kthread+0x2ae/0x3a0
>   ? kthread_create_worker_on_cpu+0xc0/0xc0
>   ret_from_fork+0x35/0x40
> 
>  The buggy address belongs to the page:
>  page:ffffea0001084c00 refcount:0 mapcount:-128 mapping:0000000000000000 index:0x0
>  flags: 0xffffc000000000()
>  raw: 00ffffc000000000 ffffea0000cfca08 ffffea0001098608 0000000000000000
>  raw: 0000000000000000 0000000000000003 00000000ffffff7f 0000000000000000
>  page dumped because: kasan: bad access detected
> 
>  Memory state around the buggy address:
>  ffff888042130180: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
>  ffff888042130200: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
>  > ffff888042130280: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
>                                      ^
>  ffff888042130300: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
>  ffff888042130380: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
>  ==================================================================
>  Disabling lock debugging due to kernel taint
> 
> Fixes: bc8c20acaea1 ("bridge: multicast: treat igmpv3 report with INCLUDE and no sources as a leave")
> Reported-by: Martin Weinelt <martin@linuxlounge.net>
> Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
> ---
>  net/bridge/br_multicast.c | 20 ++++++++++++--------
>  1 file changed, 12 insertions(+), 8 deletions(-)
> 
> diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
> index de22c8fbbb15..f37897e7b97b 100644
> --- a/net/bridge/br_multicast.c
> +++ b/net/bridge/br_multicast.c
> @@ -911,6 +911,7 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
>  	int type;
>  	int err = 0;
>  	__be32 group;
> +	u16 nsrcs;
>  
>  	ih = igmpv3_report_hdr(skb);
>  	num = ntohs(ih->ngrec);
> @@ -924,8 +925,9 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
>  		grec = (void *)(skb->data + len - sizeof(*grec));
>  		group = grec->grec_mca;
>  		type = grec->grec_type;
> +		nsrcs = ntohs(grec->grec_nsrcs);
>  
> -		len += ntohs(grec->grec_nsrcs) * 4;
> +		len += nsrcs * 4;
>  		if (!ip_mc_may_pull(skb, len))
>  			return -EINVAL;
>  
> @@ -946,7 +948,7 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
>  		src = eth_hdr(skb)->h_source;
>  		if ((type == IGMPV3_CHANGE_TO_INCLUDE ||
>  		     type == IGMPV3_MODE_IS_INCLUDE) &&
> -		    ntohs(grec->grec_nsrcs) == 0) {
> +		    nsrcs == 0) {
>  			br_ip4_multicast_leave_group(br, port, group, vid, src);
>  		} else {
>  			err = br_ip4_multicast_add_group(br, port, group, vid,
> @@ -983,7 +985,8 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
>  	len = skb_transport_offset(skb) + sizeof(*icmp6h);
>  
>  	for (i = 0; i < num; i++) {
> -		__be16 *nsrcs, _nsrcs;
> +		__be16 *_nsrcs, __nsrcs;
> +		u16 nsrcs;
>  
>  		nsrcs_offset = len + offsetof(struct mld2_grec, grec_nsrcs);
>  
> @@ -991,12 +994,13 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
>  		    nsrcs_offset + sizeof(_nsrcs))
>  			return -EINVAL;
>  
> -		nsrcs = skb_header_pointer(skb, nsrcs_offset,
> -					   sizeof(_nsrcs), &_nsrcs);
> -		if (!nsrcs)
> +		_nsrcs = skb_header_pointer(skb, nsrcs_offset,
> +					    sizeof(__nsrcs), &__nsrcs);
> +		if (!_nsrcs)
>  			return -EINVAL;
>  
> -		grec_len = struct_size(grec, grec_src, ntohs(*nsrcs));
> +		nsrcs = ntohs(*_nsrcs);
> +		grec_len = struct_size(grec, grec_src, nsrcs);
>  
>  		if (!ipv6_mc_may_pull(skb, len + grec_len))
>  			return -EINVAL;
> @@ -1021,7 +1025,7 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
>  		src = eth_hdr(skb)->h_source;
>  		if ((grec->grec_type == MLD2_CHANGE_TO_INCLUDE ||
>  		     grec->grec_type == MLD2_MODE_IS_INCLUDE) &&
> -		    ntohs(*nsrcs) == 0) {
> +		    nsrcs == 0) {
>  			br_ip6_multicast_leave_group(br, port, &grec->grec_mca,
>  						     vid, src);
>  		} else {
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* Re: [PATCH net-next v6 04/15] ethtool: introduce ethtool netlink interface
From: Jiri Pirko @ 2019-07-02 12:25 UTC (permalink / raw)
  To: Michal Kubecek
  Cc: David Miller, netdev, Jakub Kicinski, Andrew Lunn,
	Florian Fainelli, John Linville, Stephen Hemminger, Johannes Berg,
	linux-kernel
In-Reply-To: <e7fa3ad7e9cf4d7a8f9a2085e3166f7260845b0a.1562067622.git.mkubecek@suse.cz>

Tue, Jul 02, 2019 at 01:49:59PM CEST, mkubecek@suse.cz wrote:
>Basic genetlink and init infrastructure for the netlink interface, register
>genetlink family "ethtool". Add CONFIG_ETHTOOL_NETLINK Kconfig option to
>make the build optional. Add initial overall interface description into
>Documentation/networking/ethtool-netlink.txt, further patches will add more
>detailed information.
>
>Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
>---
> Documentation/networking/ethtool-netlink.txt | 208 +++++++++++++++++++
> include/linux/ethtool_netlink.h              |   9 +
> include/uapi/linux/ethtool_netlink.h         |  36 ++++
> net/Kconfig                                  |   8 +
> net/ethtool/Makefile                         |   6 +-
> net/ethtool/netlink.c                        |  33 +++
> net/ethtool/netlink.h                        |  10 +
> 7 files changed, 309 insertions(+), 1 deletion(-)
> create mode 100644 Documentation/networking/ethtool-netlink.txt
> create mode 100644 include/linux/ethtool_netlink.h
> create mode 100644 include/uapi/linux/ethtool_netlink.h
> create mode 100644 net/ethtool/netlink.c
> create mode 100644 net/ethtool/netlink.h
>
>diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
>new file mode 100644
>index 000000000000..97c369aa290b
>--- /dev/null
>+++ b/Documentation/networking/ethtool-netlink.txt
>@@ -0,0 +1,208 @@
>+                        Netlink interface for ethtool
>+                        =============================
>+
>+
>+Basic information
>+-----------------
>+
>+Netlink interface for ethtool uses generic netlink family "ethtool" (userspace
>+application should use macros ETHTOOL_GENL_NAME and ETHTOOL_GENL_VERSION
>+defined in <linux/ethtool_netlink.h> uapi header). This family does not use
>+a specific header, all information in requests and replies is passed using
>+netlink attributes.
>+
>+The ethtool netlink interface uses extended ACK for error and warning
>+reporting, userspace application developers are encouraged to make these
>+messages available to user in a suitable way.
>+
>+Requests can be divided into three categories: "get" (retrieving information),
>+"set" (setting parameters) and "action" (invoking an action).
>+
>+All "set" and "action" type requests require admin privileges (CAP_NET_ADMIN
>+in the namespace). Most "get" type requests are allowed for anyone but there
>+are exceptions (where the response contains sensitive information). In some
>+cases, the request as such is allowed for anyone but unprivileged users have
>+attributes with sensitive information (e.g. wake-on-lan password) omitted.
>+
>+
>+Conventions
>+-----------
>+
>+Attributes which represent a boolean value usually use u8 type so that we can
>+distinguish three states: "on", "off" and "not present" (meaning the
>+information is not available in "get" requests or value is not to be changed
>+in "set" requests). For these attributes, the "true" value should be passed as
>+number 1 but any non-zero value should be understood as "true" by recipient.
>+
>+In the message structure descriptions below, if an attribute name is suffixed
>+with "+", parent nest can contain multiple attributes of the same type. This
>+implements an array of entries.
>+
>+
>+Request header
>+--------------
>+
>+Each request or reply message contains a nested attribute with common header.
>+Structure of this header is

Missing ":"


>+
>+    ETHTOOL_A_HEADER_DEV_INDEX	(u32)		device ifindex
>+    ETHTOOL_A_HEADER_DEV_NAME	(string)	device name
>+    ETHTOOL_A_HEADER_INFOMASK	(u32)		info mask
>+    ETHTOOL_A_HEADER_GFLAGS	(u32)		flags common for all requests
>+    ETHTOOL_A_HEADER_RFLAGS	(u32)		request specific flags
>+
>+ETHTOOL_A_HEADER_DEV_INDEX and ETHTOOL_A_HEADER_DEV_NAME identify the device
>+message relates to. One of them is sufficient in requests, if both are used,
>+they must identify the same device. Some requests, e.g. global string sets, do
>+not require device identification. Most GET requests also allow dump requests
>+without device identification to query the same information for all devices
>+providing it (each device in a separate message).
>+
>+Optional info mask allows to ask only for a part of data provided by GET

How this "infomask" works? What are the bits related to? Is that request
specific?


>+request types. If omitted or zero, all data is returned. The two flag bitmaps
>+allow enabling requestoptions; ETHTOOL_A_HEADER_GFLAGS are global flags common

s/requestoptions;/request options./  ?


>+for all request types, flags recognized in ETHTOOL_A_HEADER_RFLAGS and their
>+interpretation are specific for each request type. Global flags are
>+
>+    ETHTOOL_RF_COMPACT		use compact format bitsets in reply

Why "RF"? Isn't this "GF"? I would like "ETHTOOL_GFLAG_COMPACT" better.


>+    ETHTOOL_RF_REPLY		send optional reply (SET and ACT requests)
>+
>+Request specific flags are described with each request type. For both flag
>+attributes, new flags should follow the general idea that if the flag is not
>+set, the behaviour is the same as (or closer to) the behaviour before it was

"closer to" ? That would be unfortunate I believe...


>+introduced.
>+
>+
>+List of message types
>+---------------------
>+
>+All constants identifying message types use ETHTOOL_CMD_ prefix and suffix
>+according to message purpose:
>+
>+    _GET	userspace request to retrieve data
>+    _SET	userspace request to set data
>+    _ACT	userspace request to perform an action
>+    _GET_REPLY	kernel reply to a GET request
>+    _SET_REPLY	kernel reply to a SET request
>+    _ACT_REPLY  kernel reply to an ACT request
>+    _NTF	kernel notification
>+
>+"GET" requests are sent by userspace applications to retrieve device
>+information. They usually do not contain any message specific attributes.
>+Kernel replies with corresponding "GET_REPLY" message. For most types, "GET"
>+request with NLM_F_DUMP and no device identification can be used to query the
>+information for all devices supporting the request.
>+
>+If the data can be also modified, corresponding "SET" message with the same
>+layout as "GET" reply is used to request changes. Only attributes where

s/"GET" reply"/"GET_REPLY" ?
Maybe better to emphasize that the "GET_REPLY" is the one corresponding
with "SET". But perhaps I got this sentence all wrong :/


>+a change is requested are included in such request (also, not all attributes
>+may be changed). Replies to most "SET" request consist only of error code and
>+extack; if kernel provides additional data, it is sent in the form of
>+corresponding "SET_REPLY" message (if ETHTOOL_RF_REPLY flag was set in request
>+header).
>+
>+Data modification also triggers sending a "NTF" message with a notification.
>+These usually bear only a subset of attributes which was affected by the
>+change. The same notification is issued if the data is modified using other
>+means (mostly ioctl ethtool interface). Unlike notifications from ethtool
>+netlink code which are only sent if something actually changed, notifications
>+triggered by ioctl interface may be sent even if the request did not actually
>+change any data.

Interesting. What's the reason for that?


>+
>+"ACT" messages request kernel (driver) to perform a specific action. If some
>+information is reported by kernel (as requested by ETHTOOL_RF_REPLY flag in
>+request header), the reply takes form of an "ACT_REPLY" message. Performing an
>+action also triggers a notification ("NTF" message).
>+
>+Later sections describe the format and semantics of these messages.
>+
>+
>+Request translation
>+-------------------
>+
>+The following table maps ioctl commands to netlink commands providing their
>+functionality. Entries with "n/a" in right column are commands which do not
>+have their netlink replacement yet.
>+
>+ioctl command			netlink command
>+---------------------------------------------------------------------
>+ETHTOOL_GSET			n/a
>+ETHTOOL_SSET			n/a
>+ETHTOOL_GDRVINFO		n/a
>+ETHTOOL_GREGS			n/a
>+ETHTOOL_GWOL			n/a
>+ETHTOOL_SWOL			n/a
>+ETHTOOL_GMSGLVL			n/a
>+ETHTOOL_SMSGLVL			n/a
>+ETHTOOL_NWAY_RST		n/a
>+ETHTOOL_GLINK			n/a
>+ETHTOOL_GEEPROM			n/a
>+ETHTOOL_SEEPROM			n/a
>+ETHTOOL_GCOALESCE		n/a
>+ETHTOOL_SCOALESCE		n/a
>+ETHTOOL_GRINGPARAM		n/a
>+ETHTOOL_SRINGPARAM		n/a
>+ETHTOOL_GPAUSEPARAM		n/a
>+ETHTOOL_SPAUSEPARAM		n/a
>+ETHTOOL_GRXCSUM			n/a
>+ETHTOOL_SRXCSUM			n/a
>+ETHTOOL_GTXCSUM			n/a
>+ETHTOOL_STXCSUM			n/a
>+ETHTOOL_GSG			n/a
>+ETHTOOL_SSG			n/a
>+ETHTOOL_TEST			n/a
>+ETHTOOL_GSTRINGS		n/a
>+ETHTOOL_PHYS_ID			n/a
>+ETHTOOL_GSTATS			n/a
>+ETHTOOL_GTSO			n/a
>+ETHTOOL_STSO			n/a
>+ETHTOOL_GPERMADDR		rtnetlink RTM_GETLINK
>+ETHTOOL_GUFO			n/a
>+ETHTOOL_SUFO			n/a
>+ETHTOOL_GGSO			n/a
>+ETHTOOL_SGSO			n/a
>+ETHTOOL_GFLAGS			n/a
>+ETHTOOL_SFLAGS			n/a
>+ETHTOOL_GPFLAGS			n/a
>+ETHTOOL_SPFLAGS			n/a
>+ETHTOOL_GRXFH			n/a
>+ETHTOOL_SRXFH			n/a
>+ETHTOOL_GGRO			n/a
>+ETHTOOL_SGRO			n/a
>+ETHTOOL_GRXRINGS		n/a
>+ETHTOOL_GRXCLSRLCNT		n/a
>+ETHTOOL_GRXCLSRULE		n/a
>+ETHTOOL_GRXCLSRLALL		n/a
>+ETHTOOL_SRXCLSRLDEL		n/a
>+ETHTOOL_SRXCLSRLINS		n/a
>+ETHTOOL_FLASHDEV		n/a
>+ETHTOOL_RESET			n/a
>+ETHTOOL_SRXNTUPLE		n/a
>+ETHTOOL_GRXNTUPLE		n/a
>+ETHTOOL_GSSET_INFO		n/a
>+ETHTOOL_GRXFHINDIR		n/a
>+ETHTOOL_SRXFHINDIR		n/a
>+ETHTOOL_GFEATURES		n/a
>+ETHTOOL_SFEATURES		n/a
>+ETHTOOL_GCHANNELS		n/a
>+ETHTOOL_SCHANNELS		n/a
>+ETHTOOL_SET_DUMP		n/a
>+ETHTOOL_GET_DUMP_FLAG		n/a
>+ETHTOOL_GET_DUMP_DATA		n/a
>+ETHTOOL_GET_TS_INFO		n/a
>+ETHTOOL_GMODULEINFO		n/a
>+ETHTOOL_GMODULEEEPROM		n/a
>+ETHTOOL_GEEE			n/a
>+ETHTOOL_SEEE			n/a
>+ETHTOOL_GRSSH			n/a
>+ETHTOOL_SRSSH			n/a
>+ETHTOOL_GTUNABLE		n/a
>+ETHTOOL_STUNABLE		n/a
>+ETHTOOL_GPHYSTATS		n/a
>+ETHTOOL_PERQUEUE		n/a
>+ETHTOOL_GLINKSETTINGS		n/a
>+ETHTOOL_SLINKSETTINGS		n/a
>+ETHTOOL_PHY_GTUNABLE		n/a
>+ETHTOOL_PHY_STUNABLE		n/a
>+ETHTOOL_GFECPARAM		n/a
>+ETHTOOL_SFECPARAM		n/a
>diff --git a/include/linux/ethtool_netlink.h b/include/linux/ethtool_netlink.h
>new file mode 100644
>index 000000000000..0412adb4f42f
>--- /dev/null
>+++ b/include/linux/ethtool_netlink.h
>@@ -0,0 +1,9 @@
>+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
>+
>+#ifndef _LINUX_ETHTOOL_NETLINK_H_
>+#define _LINUX_ETHTOOL_NETLINK_H_
>+
>+#include <uapi/linux/ethtool_netlink.h>
>+#include <linux/ethtool.h>
>+
>+#endif /* _LINUX_ETHTOOL_NETLINK_H_ */
>diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
>new file mode 100644
>index 000000000000..9a0fbd4f85d9
>--- /dev/null
>+++ b/include/uapi/linux/ethtool_netlink.h
>@@ -0,0 +1,36 @@
>+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
>+/*
>+ * include/uapi/linux/ethtool_netlink.h - netlink interface for ethtool
>+ *
>+ * See Documentation/networking/ethtool-netlink.txt in kernel source tree for
>+ * doucumentation of the interface.
>+ */
>+
>+#ifndef _UAPI_LINUX_ETHTOOL_NETLINK_H_
>+#define _UAPI_LINUX_ETHTOOL_NETLINK_H_
>+
>+#include <linux/ethtool.h>
>+
>+/* message types - userspace to kernel */
>+enum {
>+	ETHTOOL_MSG_USER_NONE,
>+
>+	/* add new constants above here */
>+	__ETHTOOL_MSG_USER_CNT,
>+	ETHTOOL_MSG_USER_MAX = (__ETHTOOL_MSG_USER_CNT - 1)
>+};
>+
>+/* message types - kernel to userspace */
>+enum {
>+	ETHTOOL_MSG_KERNEL_NONE,
>+
>+	/* add new constants above here */
>+	__ETHTOOL_MSG_KERNEL_CNT,
>+	ETHTOOL_MSG_KERNEL_MAX = (__ETHTOOL_MSG_KERNEL_CNT - 1)
>+};
>+
>+/* generic netlink info */
>+#define ETHTOOL_GENL_NAME "ethtool"
>+#define ETHTOOL_GENL_VERSION 1
>+
>+#endif /* _UAPI_LINUX_ETHTOOL_NETLINK_H_ */
>diff --git a/net/Kconfig b/net/Kconfig
>index 57f51a279ad6..65b760d26eec 100644
>--- a/net/Kconfig
>+++ b/net/Kconfig
>@@ -447,6 +447,14 @@ config FAILOVER
> 	  migration of VMs with direct attached VFs by failing over to the
> 	  paravirtual datapath when the VF is unplugged.
> 
>+config ETHTOOL_NETLINK
>+	bool "Netlink interface for ethtool"
>+	default y
>+	help
>+	  An alternative userspace interface for ethtool based on generic
>+	  netlink. It provides better extensibility and some new features,
>+	  e.g. notification messages.
>+
> endif   # if NET
> 
> # Used by archs to tell that they support BPF JIT compiler plus which flavour.
>diff --git a/net/ethtool/Makefile b/net/ethtool/Makefile
>index 3ebfab2bca66..f30e0da88be5 100644
>--- a/net/ethtool/Makefile
>+++ b/net/ethtool/Makefile
>@@ -1,3 +1,7 @@
> # SPDX-License-Identifier: GPL-2.0
> 
>-obj-y		+= ioctl.o
>+obj-y				+= ioctl.o
>+
>+obj-$(CONFIG_ETHTOOL_NETLINK)	+= ethtool_nl.o

Hmm, I wonder, why not to make this always on? We want users to use
it, memory savings in case it is off would be minimal. RTNetlink is also
always on. Ethtool ioctl is also always on.


>+
>+ethtool_nl-y	:= netlink.o
>diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
>new file mode 100644
>index 000000000000..3c98b41f04e5
>--- /dev/null
>+++ b/net/ethtool/netlink.c
>@@ -0,0 +1,33 @@
>+// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
>+
>+#include <linux/ethtool_netlink.h>
>+#include "netlink.h"
>+
>+/* genetlink setup */
>+
>+static const struct genl_ops ethtool_genl_ops[] = {
>+};
>+
>+static struct genl_family ethtool_genl_family = {
>+	.name		= ETHTOOL_GENL_NAME,
>+	.version	= ETHTOOL_GENL_VERSION,
>+	.netnsok	= true,
>+	.parallel_ops	= true,
>+	.ops		= ethtool_genl_ops,
>+	.n_ops		= ARRAY_SIZE(ethtool_genl_ops),
>+};
>+
>+/* module setup */
>+
>+static int __init ethnl_init(void)
>+{
>+	int ret;
>+
>+	ret = genl_register_family(&ethtool_genl_family);
>+	if (WARN(ret < 0, "ethtool: genetlink family registration failed"))

WARN(ret, ...)


>+		return ret;
>+
>+	return 0;
>+}
>+
>+subsys_initcall(ethnl_init);
>diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h
>new file mode 100644
>index 000000000000..257ae55ccc82
>--- /dev/null
>+++ b/net/ethtool/netlink.h
>@@ -0,0 +1,10 @@
>+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
>+
>+#ifndef _NET_ETHTOOL_NETLINK_H
>+#define _NET_ETHTOOL_NETLINK_H
>+
>+#include <linux/ethtool_netlink.h>
>+#include <linux/netdevice.h>
>+#include <net/genetlink.h>
>+
>+#endif /* _NET_ETHTOOL_NETLINK_H */
>-- 
>2.22.0
>

^ permalink raw reply

* Re: [PATCH][next] iwlwifi: mvm: fix comparison of u32 variable with less than zero
From: Luca Coelho @ 2019-07-02 11:54 UTC (permalink / raw)
  To: Colin King, Haim Dreyfuss, Johannes Berg, Emmanuel Grumbach,
	Intel Linux Wireless, Kalle Valo, David S . Miller,
	linux-wireless, netdev
  Cc: kernel-janitors, linux-kernel
In-Reply-To: <20190701162657.15174-1-colin.king@canonical.com>

On Mon, 2019-07-01 at 17:26 +0100, Colin King wrote:
> From: Colin Ian King <colin.king@canonical.com>
> 
> The comparison of the u32 variable wgds_tbl_idx with less than zero is
> always going to be false because it is unsigned.  Fix this by making
> wgds_tbl_idx a plain signed int.
> 
> Addresses-Coverity: ("Unsigned compared against 0")
> Fixes: 4fd445a2c855 ("iwlwifi: mvm: Add log information about SAR status")
> Signed-off-by: Colin Ian King <colin.king@canonical.com>
> ---
>  drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
> index 719f793b3487..a9bb43a2f27b 100644
> --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
> +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
> @@ -620,7 +620,7 @@ void iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm,
>  	enum iwl_mcc_source src;
>  	char mcc[3];
>  	struct ieee80211_regdomain *regd;
> -	u32 wgds_tbl_idx;
> +	int wgds_tbl_idx;
>  
>  	lockdep_assert_held(&mvm->mutex);

Thanks, Colin!

I applied this to our internal tree and it will reach the mainline
following our normal upstreaming process.

--
Cheers,
Luca.


^ permalink raw reply

* Re: [PATCH bpf-next v2 1/6] xsk: replace ndo_xsk_async_xmit with ndo_xsk_wakeup
From: Magnus Karlsson @ 2019-07-02 12:15 UTC (permalink / raw)
  To: Maxim Mikityanskiy
  Cc: Magnus Karlsson, ast@kernel.org, bjorn.topel@intel.com,
	daniel@iogearbox.net, netdev@vger.kernel.org, brouer@redhat.com,
	bpf@vger.kernel.org, bruce.richardson@intel.com,
	ciara.loftus@intel.com, jakub.kicinski@netronome.com,
	xiaolong.ye@intel.com, qi.z.zhang@intel.com,
	sridhar.samudrala@intel.com, kevin.laatz@intel.com,
	ilias.apalodimas@linaro.org, kiran.patil@intel.com,
	axboe@kernel.dk, maciej.fijalkowski@intel.com,
	maciejromanfijalkowski@gmail.com,
	intel-wired-lan@lists.osuosl.org
In-Reply-To: <a57b5b49-bd03-92af-cc5d-fe11d1d0e437@mellanox.com>

On Tue, Jul 2, 2019 at 1:43 PM Maxim Mikityanskiy <maximmi@mellanox.com> wrote:
>
> On 2019-07-02 12:21, Magnus Karlsson wrote:
> > This commit replaces ndo_xsk_async_xmit with ndo_xsk_wakeup. This new
> > ndo provides the same functionality as before but with the addition of
> > a new flags field that is used to specifiy if Rx, Tx or both should be
> > woken up. The previous ndo only woke up Tx, as implied by the
> > name. The i40e and ixgbe drivers (which are all the supported ones)
> > are updated with this new interface.
>
> This API change will break build of mlx5 - XSK support for mlx5 was merged.

Yes, that will definitely break it. But I am glad your support is in
:-). Do you have any other comments on this patch set before I make a
v3?

/Magnus

> > This new ndo will be used by the new need_wakeup functionality of XDP
> > sockets that need to be able to wake up both Rx and Tx driver
> > processing.
> >
> > Signed-off-by: Magnus Karlsson <magnus.karlsson@intel.com>
>

^ permalink raw reply

* Re: [PATCH net-next v6 02/15] netlink: rename nl80211_validate_nested() to nla_validate_nested()
From: Johannes Berg @ 2019-07-02 12:15 UTC (permalink / raw)
  To: Michal Kubecek, David Miller, netdev
  Cc: Jakub Kicinski, Jiri Pirko, Andrew Lunn, Florian Fainelli,
	John Linville, Stephen Hemminger, linux-kernel
In-Reply-To: <d0c23ac629c4a0343acc9f09484e078962c55402.1562067622.git.mkubecek@suse.cz>

On Tue, 2019-07-02 at 13:49 +0200, Michal Kubecek wrote:
> Function nl80211_validate_nested() is not specific to nl80211, it's
> a counterpart to nla_validate_nested_deprecated() with strict validation.
> For consistency with other validation and parse functions, rename it to
> nla_validate_nested().

Umm, right, not sure how that happened. Sorry about that.

Reviewed-by: Johannes Berg <johannes@sipsolutions.net?

johannes


^ permalink raw reply

* Re: [PATCH net-next v6 02/15] netlink: rename nl80211_validate_nested() to nla_validate_nested()
From: Johannes Berg @ 2019-07-02 12:15 UTC (permalink / raw)
  To: Michal Kubecek, David Miller, netdev
  Cc: Jakub Kicinski, Jiri Pirko, Andrew Lunn, Florian Fainelli,
	John Linville, Stephen Hemminger, linux-kernel
In-Reply-To: <d0c23ac629c4a0343acc9f09484e078962c55402.1562067622.git.mkubecek@suse.cz>

On Tue, 2019-07-02 at 13:49 +0200, Michal Kubecek wrote:
> Function nl80211_validate_nested() is not specific to nl80211, it's
> a counterpart to nla_validate_nested_deprecated() with strict validation.
> For consistency with other validation and parse functions, rename it to
> nla_validate_nested().

Umm, right, not sure how that happened. Sorry about that.

Reviewed-by: Johannes Berg <johannes@sipsolutions.net>

johannes


^ permalink raw reply

* [PATCH net 1/4] net: bridge: mcast: fix stale nsrcs pointer in igmp3/mld2 report handling
From: Nikolay Aleksandrov @ 2019-07-02 12:00 UTC (permalink / raw)
  To: netdev; +Cc: roopa, davem, martin, bridge, yoshfuji, Nikolay Aleksandrov
In-Reply-To: <20190702120021.13096-1-nikolay@cumulusnetworks.com>

We take a pointer to grec prior to calling pskb_may_pull and use it
afterwards to get nsrcs so record nsrcs before the pull when handling
igmp3 and we get a pointer to nsrcs and call pskb_may_pull when handling
mld2 which again could lead to reading 2 bytes out-of-bounds.

 ==================================================================
 BUG: KASAN: use-after-free in br_multicast_rcv+0x480c/0x4ad0 [bridge]
 Read of size 2 at addr ffff8880421302b4 by task ksoftirqd/1/16

 CPU: 1 PID: 16 Comm: ksoftirqd/1 Tainted: G           OE     5.2.0-rc6+ #1
 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014
 Call Trace:
  dump_stack+0x71/0xab
  print_address_description+0x6a/0x280
  ? br_multicast_rcv+0x480c/0x4ad0 [bridge]
  __kasan_report+0x152/0x1aa
  ? br_multicast_rcv+0x480c/0x4ad0 [bridge]
  ? br_multicast_rcv+0x480c/0x4ad0 [bridge]
  kasan_report+0xe/0x20
  br_multicast_rcv+0x480c/0x4ad0 [bridge]
  ? br_multicast_disable_port+0x150/0x150 [bridge]
  ? ktime_get_with_offset+0xb4/0x150
  ? __kasan_kmalloc.constprop.6+0xa6/0xf0
  ? __netif_receive_skb+0x1b0/0x1b0
  ? br_fdb_update+0x10e/0x6e0 [bridge]
  ? br_handle_frame_finish+0x3c6/0x11d0 [bridge]
  br_handle_frame_finish+0x3c6/0x11d0 [bridge]
  ? br_pass_frame_up+0x3a0/0x3a0 [bridge]
  ? virtnet_probe+0x1c80/0x1c80 [virtio_net]
  br_handle_frame+0x731/0xd90 [bridge]
  ? select_idle_sibling+0x25/0x7d0
  ? br_handle_frame_finish+0x11d0/0x11d0 [bridge]
  __netif_receive_skb_core+0xced/0x2d70
  ? virtqueue_get_buf_ctx+0x230/0x1130 [virtio_ring]
  ? do_xdp_generic+0x20/0x20
  ? virtqueue_napi_complete+0x39/0x70 [virtio_net]
  ? virtnet_poll+0x94d/0xc78 [virtio_net]
  ? receive_buf+0x5120/0x5120 [virtio_net]
  ? __netif_receive_skb_one_core+0x97/0x1d0
  __netif_receive_skb_one_core+0x97/0x1d0
  ? __netif_receive_skb_core+0x2d70/0x2d70
  ? _raw_write_trylock+0x100/0x100
  ? __queue_work+0x41e/0xbe0
  process_backlog+0x19c/0x650
  ? _raw_read_lock_irq+0x40/0x40
  net_rx_action+0x71e/0xbc0
  ? __switch_to_asm+0x40/0x70
  ? napi_complete_done+0x360/0x360
  ? __switch_to_asm+0x34/0x70
  ? __switch_to_asm+0x40/0x70
  ? __schedule+0x85e/0x14d0
  __do_softirq+0x1db/0x5f9
  ? takeover_tasklets+0x5f0/0x5f0
  run_ksoftirqd+0x26/0x40
  smpboot_thread_fn+0x443/0x680
  ? sort_range+0x20/0x20
  ? schedule+0x94/0x210
  ? __kthread_parkme+0x78/0xf0
  ? sort_range+0x20/0x20
  kthread+0x2ae/0x3a0
  ? kthread_create_worker_on_cpu+0xc0/0xc0
  ret_from_fork+0x35/0x40

 The buggy address belongs to the page:
 page:ffffea0001084c00 refcount:0 mapcount:-128 mapping:0000000000000000 index:0x0
 flags: 0xffffc000000000()
 raw: 00ffffc000000000 ffffea0000cfca08 ffffea0001098608 0000000000000000
 raw: 0000000000000000 0000000000000003 00000000ffffff7f 0000000000000000
 page dumped because: kasan: bad access detected

 Memory state around the buggy address:
 ffff888042130180: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
 ffff888042130200: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
 > ffff888042130280: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
                                     ^
 ffff888042130300: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
 ffff888042130380: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
 ==================================================================
 Disabling lock debugging due to kernel taint

Fixes: bc8c20acaea1 ("bridge: multicast: treat igmpv3 report with INCLUDE and no sources as a leave")
Reported-by: Martin Weinelt <martin@linuxlounge.net>
Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
---
 net/bridge/br_multicast.c | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index de22c8fbbb15..f37897e7b97b 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -911,6 +911,7 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
 	int type;
 	int err = 0;
 	__be32 group;
+	u16 nsrcs;
 
 	ih = igmpv3_report_hdr(skb);
 	num = ntohs(ih->ngrec);
@@ -924,8 +925,9 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
 		grec = (void *)(skb->data + len - sizeof(*grec));
 		group = grec->grec_mca;
 		type = grec->grec_type;
+		nsrcs = ntohs(grec->grec_nsrcs);
 
-		len += ntohs(grec->grec_nsrcs) * 4;
+		len += nsrcs * 4;
 		if (!ip_mc_may_pull(skb, len))
 			return -EINVAL;
 
@@ -946,7 +948,7 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
 		src = eth_hdr(skb)->h_source;
 		if ((type == IGMPV3_CHANGE_TO_INCLUDE ||
 		     type == IGMPV3_MODE_IS_INCLUDE) &&
-		    ntohs(grec->grec_nsrcs) == 0) {
+		    nsrcs == 0) {
 			br_ip4_multicast_leave_group(br, port, group, vid, src);
 		} else {
 			err = br_ip4_multicast_add_group(br, port, group, vid,
@@ -983,7 +985,8 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
 	len = skb_transport_offset(skb) + sizeof(*icmp6h);
 
 	for (i = 0; i < num; i++) {
-		__be16 *nsrcs, _nsrcs;
+		__be16 *_nsrcs, __nsrcs;
+		u16 nsrcs;
 
 		nsrcs_offset = len + offsetof(struct mld2_grec, grec_nsrcs);
 
@@ -991,12 +994,13 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
 		    nsrcs_offset + sizeof(_nsrcs))
 			return -EINVAL;
 
-		nsrcs = skb_header_pointer(skb, nsrcs_offset,
-					   sizeof(_nsrcs), &_nsrcs);
-		if (!nsrcs)
+		_nsrcs = skb_header_pointer(skb, nsrcs_offset,
+					    sizeof(__nsrcs), &__nsrcs);
+		if (!_nsrcs)
 			return -EINVAL;
 
-		grec_len = struct_size(grec, grec_src, ntohs(*nsrcs));
+		nsrcs = ntohs(*_nsrcs);
+		grec_len = struct_size(grec, grec_src, nsrcs);
 
 		if (!ipv6_mc_may_pull(skb, len + grec_len))
 			return -EINVAL;
@@ -1021,7 +1025,7 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
 		src = eth_hdr(skb)->h_source;
 		if ((grec->grec_type == MLD2_CHANGE_TO_INCLUDE ||
 		     grec->grec_type == MLD2_MODE_IS_INCLUDE) &&
-		    ntohs(*nsrcs) == 0) {
+		    nsrcs == 0) {
 			br_ip6_multicast_leave_group(br, port, &grec->grec_mca,
 						     vid, src);
 		} else {
-- 
2.21.0


^ permalink raw reply related

* [PATCH net 3/4] net: bridge: don't cache ether dest pointer on input
From: Nikolay Aleksandrov @ 2019-07-02 12:00 UTC (permalink / raw)
  To: netdev; +Cc: roopa, davem, martin, bridge, yoshfuji, Nikolay Aleksandrov
In-Reply-To: <20190702120021.13096-1-nikolay@cumulusnetworks.com>

We would cache ether dst pointer on input in br_handle_frame_finish but
after the neigh suppress code that could lead to a stale pointer since
both ipv4 and ipv6 suppress code do pskb_may_pull. This means we have to
always reload it after the suppress code so there's no point in having
it cached just retrieve it directly.

Fixes: 057658cb33fbf ("bridge: suppress arp pkts on BR_NEIGH_SUPPRESS ports")
Fixes: ed842faeb2bd ("bridge: suppress nd pkts on BR_NEIGH_SUPPRESS ports")
Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
---
 net/bridge/br_input.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 21b74e7a7b2f..52c712984cc7 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -74,7 +74,6 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
 	struct net_bridge_fdb_entry *dst = NULL;
 	struct net_bridge_mdb_entry *mdst;
 	bool local_rcv, mcast_hit = false;
-	const unsigned char *dest;
 	struct net_bridge *br;
 	u16 vid = 0;
 
@@ -92,10 +91,9 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
 		br_fdb_update(br, p, eth_hdr(skb)->h_source, vid, false);
 
 	local_rcv = !!(br->dev->flags & IFF_PROMISC);
-	dest = eth_hdr(skb)->h_dest;
-	if (is_multicast_ether_addr(dest)) {
+	if (is_multicast_ether_addr(eth_hdr(skb)->h_dest)) {
 		/* by definition the broadcast is also a multicast address */
-		if (is_broadcast_ether_addr(dest)) {
+		if (is_broadcast_ether_addr(eth_hdr(skb)->h_dest)) {
 			pkt_type = BR_PKT_BROADCAST;
 			local_rcv = true;
 		} else {
@@ -145,7 +143,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
 		}
 		break;
 	case BR_PKT_UNICAST:
-		dst = br_fdb_find_rcu(br, dest, vid);
+		dst = br_fdb_find_rcu(br, eth_hdr(skb)->h_dest, vid);
 	default:
 		break;
 	}
-- 
2.21.0


^ permalink raw reply related

* [PATCH net 4/4] net: bridge: stp: don't cache eth dest pointer before skb pull
From: Nikolay Aleksandrov @ 2019-07-02 12:00 UTC (permalink / raw)
  To: netdev; +Cc: roopa, davem, martin, bridge, yoshfuji, Nikolay Aleksandrov
In-Reply-To: <20190702120021.13096-1-nikolay@cumulusnetworks.com>

Don't cache eth dest pointer before calling pskb_may_pull.

Fixes: cf0f02d04a83 ("[BRIDGE]: use llc for receiving STP packets")
Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
---
 net/bridge/br_stp_bpdu.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c
index 68a6922b4141..7796dd9d42d7 100644
--- a/net/bridge/br_stp_bpdu.c
+++ b/net/bridge/br_stp_bpdu.c
@@ -143,7 +143,6 @@ void br_send_tcn_bpdu(struct net_bridge_port *p)
 void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb,
 		struct net_device *dev)
 {
-	const unsigned char *dest = eth_hdr(skb)->h_dest;
 	struct net_bridge_port *p;
 	struct net_bridge *br;
 	const unsigned char *buf;
@@ -172,7 +171,7 @@ void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb,
 	if (p->state == BR_STATE_DISABLED)
 		goto out;
 
-	if (!ether_addr_equal(dest, br->group_addr))
+	if (!ether_addr_equal(eth_hdr(skb)->h_dest, br->group_addr))
 		goto out;
 
 	if (p->flags & BR_BPDU_GUARD) {
-- 
2.21.0


^ permalink raw reply related

* [PATCH net 2/4] net: bridge: mcast: fix stale ipv6 hdr pointer when handling v6 query
From: Nikolay Aleksandrov @ 2019-07-02 12:00 UTC (permalink / raw)
  To: netdev; +Cc: roopa, davem, martin, bridge, yoshfuji, Nikolay Aleksandrov
In-Reply-To: <20190702120021.13096-1-nikolay@cumulusnetworks.com>

We get a pointer to the ipv6 hdr in br_ip6_multicast_query but we may
call pskb_may_pull afterwards and end up using a stale pointer.
So use the header directly, it's just 1 place where it's needed.

Fixes: 08b202b67264 ("bridge br_multicast: IPv6 MLD support.")
Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
---
 net/bridge/br_multicast.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index f37897e7b97b..3d8deac2353d 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1279,7 +1279,6 @@ static int br_ip6_multicast_query(struct net_bridge *br,
 				  u16 vid)
 {
 	unsigned int transport_len = ipv6_transport_len(skb);
-	const struct ipv6hdr *ip6h = ipv6_hdr(skb);
 	struct mld_msg *mld;
 	struct net_bridge_mdb_entry *mp;
 	struct mld2_query *mld2q;
@@ -1323,7 +1322,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
 
 	if (is_general_query) {
 		saddr.proto = htons(ETH_P_IPV6);
-		saddr.u.ip6 = ip6h->saddr;
+		saddr.u.ip6 = ipv6_hdr(skb)->saddr;
 
 		br_multicast_query_received(br, port, &br->ip6_other_query,
 					    &saddr, max_delay);
-- 
2.21.0


^ permalink raw reply related

* [PATCH net 0/4] net: bridge: fix possible stale skb pointers
From: Nikolay Aleksandrov @ 2019-07-02 12:00 UTC (permalink / raw)
  To: netdev; +Cc: roopa, davem, martin, bridge, yoshfuji, Nikolay Aleksandrov

Hi,
In the bridge driver we have a couple of places which call pskb_may_pull
but we've cached skb pointers before that and use them after which can
lead to out-of-bounds/stale pointer use. I've had these in my "to fix"
list for some time and now we got a report (patch 01) so here they are.
Patches 02-04 are fixes based on code inspection. Also patch 01 was
tested by Martin Weinelt, Martin if you don't mind please add your
tested-by tag to it by replying with Tested-by: name <email>.
I've also briefly tested the set by trying to exercise those code paths.

Thanks,
 Nik

Nikolay Aleksandrov (4):
  net: bridge: mcast: fix stale nsrcs pointer in igmp3/mld2 report
    handling
  net: bridge: mcast: fix stale ipv6 hdr pointer when handling v6 query
  net: bridge: don't cache ether dest pointer on input
  net: bridge: stp: don't cache eth dest pointer before skb pull

 net/bridge/br_input.c     |  8 +++-----
 net/bridge/br_multicast.c | 23 +++++++++++++----------
 net/bridge/br_stp_bpdu.c  |  3 +--
 3 files changed, 17 insertions(+), 17 deletions(-)

-- 
2.21.0


^ permalink raw reply

* Re: [PATCH net-next v6 02/15] netlink: rename nl80211_validate_nested() to nla_validate_nested()
From: Jiri Pirko @ 2019-07-02 12:03 UTC (permalink / raw)
  To: Michal Kubecek
  Cc: David Miller, netdev, Jakub Kicinski, Andrew Lunn,
	Florian Fainelli, John Linville, Stephen Hemminger, Johannes Berg,
	linux-kernel
In-Reply-To: <d0c23ac629c4a0343acc9f09484e078962c55402.1562067622.git.mkubecek@suse.cz>

Tue, Jul 02, 2019 at 01:49:49PM CEST, mkubecek@suse.cz wrote:
>Function nl80211_validate_nested() is not specific to nl80211, it's
>a counterpart to nla_validate_nested_deprecated() with strict validation.
>For consistency with other validation and parse functions, rename it to
>nla_validate_nested().
>
>Signed-off-by: Michal Kubecek <mkubecek@suse.cz>

Acked-by: Jiri Pirko <jiri@mellanox.com>

^ permalink raw reply

* Re: [PATCH net-next v6 01/15] rtnetlink: provide permanent hardware address in RTM_NEWLINK
From: Jiri Pirko @ 2019-07-02 11:57 UTC (permalink / raw)
  To: Michal Kubecek
  Cc: David Miller, netdev, Jakub Kicinski, Andrew Lunn,
	Florian Fainelli, John Linville, Stephen Hemminger, Johannes Berg,
	linux-kernel
In-Reply-To: <b6e0aefbcb58297b3ec0a12ee4be8e5194eee61a.1562067622.git.mkubecek@suse.cz>

Tue, Jul 02, 2019 at 01:49:44PM CEST, mkubecek@suse.cz wrote:
>Permanent hardware address of a network device was traditionally provided
>via ethtool ioctl interface but as Jiri Pirko pointed out in a review of
>ethtool netlink interface, rtnetlink is much more suitable for it so let's
>add it to the RTM_NEWLINK message.
>
>Add IFLA_PERM_ADDRESS attribute to RTM_NEWLINK messages unless the
>permanent address is all zeros (i.e. device driver did not fill it). As
>permanent address is not modifiable, reject userspace requests containing
>IFLA_PERM_ADDRESS attribute.
>
>Note: we already provide permanent hardware address for bond slaves;
>unfortunately we cannot drop that attribute for backward compatibility
>reasons.
>
>v5 -> v6: only add the attribute if permanent address is not zero
>
>Signed-off-by: Michal Kubecek <mkubecek@suse.cz>

Acked-by: Jiri Pirko <jiri@mellanox.com>

^ permalink raw reply

* [PATCH net-next v6 01/15] rtnetlink: provide permanent hardware address in RTM_NEWLINK
From: Michal Kubecek @ 2019-07-02 11:49 UTC (permalink / raw)
  To: David Miller, netdev
  Cc: Jakub Kicinski, Jiri Pirko, Andrew Lunn, Florian Fainelli,
	John Linville, Stephen Hemminger, Johannes Berg, linux-kernel
In-Reply-To: <cover.1562067622.git.mkubecek@suse.cz>

Permanent hardware address of a network device was traditionally provided
via ethtool ioctl interface but as Jiri Pirko pointed out in a review of
ethtool netlink interface, rtnetlink is much more suitable for it so let's
add it to the RTM_NEWLINK message.

Add IFLA_PERM_ADDRESS attribute to RTM_NEWLINK messages unless the
permanent address is all zeros (i.e. device driver did not fill it). As
permanent address is not modifiable, reject userspace requests containing
IFLA_PERM_ADDRESS attribute.

Note: we already provide permanent hardware address for bond slaves;
unfortunately we cannot drop that attribute for backward compatibility
reasons.

v5 -> v6: only add the attribute if permanent address is not zero

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 include/uapi/linux/if_link.h | 1 +
 net/core/rtnetlink.c         | 5 +++++
 2 files changed, 6 insertions(+)

diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 6f75bda2c2d7..1c79d6283a4d 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -167,6 +167,7 @@ enum {
 	IFLA_NEW_IFINDEX,
 	IFLA_MIN_MTU,
 	IFLA_MAX_MTU,
+	IFLA_PERM_ADDRESS,
 	__IFLA_MAX
 };
 
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 1ee6460f8275..9aae53e8914e 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -1027,6 +1027,7 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev,
 	       + nla_total_size(4)  /* IFLA_CARRIER_DOWN_COUNT */
 	       + nla_total_size(4)  /* IFLA_MIN_MTU */
 	       + nla_total_size(4)  /* IFLA_MAX_MTU */
+	       + nla_total_size(MAX_ADDR_LEN) /* IFLA_PERM_ADDRESS */
 	       + 0;
 }
 
@@ -1691,6 +1692,9 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb,
 	    nla_put_s32(skb, IFLA_NEW_IFINDEX, new_ifindex) < 0)
 		goto nla_put_failure;
 
+	if (memchr_inv(dev->perm_addr, '\0', dev->addr_len) &&
+	    nla_put(skb, IFLA_PERM_ADDRESS, dev->addr_len, dev->perm_addr))
+		goto nla_put_failure;
 
 	rcu_read_lock();
 	if (rtnl_fill_link_af(skb, dev, ext_filter_mask))
@@ -1750,6 +1754,7 @@ static const struct nla_policy ifla_policy[IFLA_MAX+1] = {
 	[IFLA_CARRIER_DOWN_COUNT] = { .type = NLA_U32 },
 	[IFLA_MIN_MTU]		= { .type = NLA_U32 },
 	[IFLA_MAX_MTU]		= { .type = NLA_U32 },
+	[IFLA_PERM_ADDRESS]	= { .type = NLA_REJECT },
 };
 
 static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
-- 
2.22.0


^ permalink raw reply related

* [PATCH net-next v6 15/15] ethtool: provide link state in SETTINGS_GET request
From: Michal Kubecek @ 2019-07-02 11:50 UTC (permalink / raw)
  To: David Miller, netdev
  Cc: Jakub Kicinski, Jiri Pirko, Andrew Lunn, Florian Fainelli,
	John Linville, Stephen Hemminger, Johannes Berg, linux-kernel
In-Reply-To: <cover.1562067622.git.mkubecek@suse.cz>

Add information about device link state (as provided by ETHTOOL_GLINK ioctl
command) into the SETTINGS_GET reply when ETHTOOL_IM_SETTINGS_LINKSTATE
bit is set in the request info mask.

We cannot use NLA_FLAG for link state as we need three states: off, on and
unknown. The attribute is encapsulated in a nest to allow future extensions
(e.g. link down reason or more detailed link state information).

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 Documentation/networking/ethtool-netlink.txt |  5 ++-
 include/uapi/linux/ethtool_netlink.h         | 14 +++++++-
 net/ethtool/common.c                         |  8 +++++
 net/ethtool/common.h                         |  3 ++
 net/ethtool/ioctl.c                          |  8 ++---
 net/ethtool/settings.c                       | 37 ++++++++++++++++++++
 6 files changed, 69 insertions(+), 6 deletions(-)

diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index 05bc8f5f8654..dc06e33329a4 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -250,6 +250,7 @@ Info mask bits meaning:
 
     ETHTOOL_IM_SETTINGS_LINKINFO	link settings
     ETHTOOL_IM_SETTINGS_LINKMODES	link modes and related
+    ETHTOOL_IM_SETTINGS_LINKSTATE	link state
 
 Response contents:
 
@@ -266,6 +267,8 @@ Response contents:
         ETHTOOL_A_LINKMODES_PEER	    (bitset)	    partner link modes
         ETHTOOL_A_LINKMODES_SPEED	    (u32)	    link speed (Mb/s)
         ETHTOOL_A_LINKMODES_DUPLEX	    (u8)	    duplex mode
+    ETHTOOL_A_SETTINGS_LINK_STATE	(nested)	link state
+        ETHTOOL_A_LINKSTATE_LINK	    (u8)	    link on/off/unknown
 
 Most of the attributes and their values have the same meaning as matching
 members of the corresponding ioctl structures. For ETHTOOL_A_LINKMODES_OURS,
@@ -323,7 +326,7 @@ ETHTOOL_SWOL			n/a
 ETHTOOL_GMSGLVL			n/a
 ETHTOOL_SMSGLVL			n/a
 ETHTOOL_NWAY_RST		n/a
-ETHTOOL_GLINK			n/a
+ETHTOOL_GLINK			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_GEEPROM			n/a
 ETHTOOL_SEEPROM			n/a
 ETHTOOL_GCOALESCE		n/a
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index 8ccf66ed3f58..46c13455246f 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -158,6 +158,7 @@ enum {
 	ETHTOOL_A_SETTINGS_HEADER,		/* nest - _A_HEADER_* */
 	ETHTOOL_A_SETTINGS_LINK_INFO,		/* nest - _A_LINKINFO_* */
 	ETHTOOL_A_SETTINGS_LINK_MODES,		/* nest - _A_LINKMODES_* */
+	ETHTOOL_A_SETTINGS_LINK_STATE,		/* nest - _A_LINKSTATE_* */
 
 	/* add new constants above here */
 	__ETHTOOL_A_SETTINGS_CNT,
@@ -166,9 +167,11 @@ enum {
 
 #define ETHTOOL_IM_SETTINGS_LINKINFO		(1U << 0)
 #define ETHTOOL_IM_SETTINGS_LINKMODES		(1U << 1)
+#define ETHTOOL_IM_SETTINGS_LINKSTATE		(1U << 2)
 
 #define ETHTOOL_IM_SETTINGS_ALL (ETHTOOL_IM_SETTINGS_LINKINFO | \
-				 ETHTOOL_IM_SETTINGS_LINKMODES)
+				 ETHTOOL_IM_SETTINGS_LINKMODES | \
+				 ETHTOOL_IM_SETTINGS_LINKSTATE)
 
 #define ETHTOOL_RF_SETTINGS_ALL 0
 
@@ -198,6 +201,15 @@ enum {
 	ETHTOOL_A_LINKMODES_MAX = (__ETHTOOL_A_LINKMODES_CNT - 1)
 };
 
+enum {
+	ETHTOOL_A_LINKSTATE_UNSPEC,
+	ETHTOOL_A_LINKSTATE_LINK,		/* u8 */
+
+	/* add new constants above here */
+	__ETHTOOL_A_LINKSTATE_CNT,
+	ETHTOOL_A_LINKSTATE_MAX = (__ETHTOOL_A_LINKSTATE_CNT - 1)
+};
+
 /* generic netlink info */
 #define ETHTOOL_GENL_NAME "ethtool"
 #define ETHTOOL_GENL_VERSION 1
diff --git a/net/ethtool/common.c b/net/ethtool/common.c
index abb00b3a7e77..b06635ad2620 100644
--- a/net/ethtool/common.c
+++ b/net/ethtool/common.c
@@ -130,3 +130,11 @@ convert_legacy_settings_to_link_ksettings(
 		= legacy_settings->eth_tp_mdix_ctrl;
 	return retval;
 }
+
+int __ethtool_get_link(struct net_device *dev)
+{
+	if (!dev->ethtool_ops->get_link)
+		return -EOPNOTSUPP;
+
+	return netif_running(dev) && dev->ethtool_ops->get_link(dev);
+}
diff --git a/net/ethtool/common.h b/net/ethtool/common.h
index 0381936d8e1e..a2c1504576c2 100644
--- a/net/ethtool/common.h
+++ b/net/ethtool/common.h
@@ -3,6 +3,7 @@
 #ifndef _ETHTOOL_COMMON_H
 #define _ETHTOOL_COMMON_H
 
+#include <linux/netdevice.h>
 #include <linux/ethtool.h>
 
 extern const char
@@ -14,6 +15,8 @@ tunable_strings[__ETHTOOL_TUNABLE_COUNT][ETH_GSTRING_LEN];
 extern const char
 phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN];
 
+int __ethtool_get_link(struct net_device *dev);
+
 bool convert_legacy_settings_to_link_ksettings(
 	struct ethtool_link_ksettings *link_ksettings,
 	const struct ethtool_cmd *legacy_settings);
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index 504ab2f7009c..853b8c21a5e5 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -1359,12 +1359,12 @@ static int ethtool_nway_reset(struct net_device *dev)
 static int ethtool_get_link(struct net_device *dev, char __user *useraddr)
 {
 	struct ethtool_value edata = { .cmd = ETHTOOL_GLINK };
+	int link = __ethtool_get_link(dev);
 
-	if (!dev->ethtool_ops->get_link)
-		return -EOPNOTSUPP;
-
-	edata.data = netif_running(dev) && dev->ethtool_ops->get_link(dev);
+	if (link < 0)
+		return link;
 
+	edata.data = link;
 	if (copy_to_user(useraddr, &edata, sizeof(edata)))
 		return -EFAULT;
 	return 0;
diff --git a/net/ethtool/settings.c b/net/ethtool/settings.c
index 2fc961297076..079d3776df71 100644
--- a/net/ethtool/settings.c
+++ b/net/ethtool/settings.c
@@ -11,6 +11,7 @@ struct settings_data {
 	struct ethnl_reply_data		repdata_base;
 	struct ethtool_link_ksettings	ksettings;
 	struct ethtool_link_settings	*lsettings;
+	int				link;
 	bool				lpm_empty;
 };
 
@@ -113,6 +114,7 @@ settings_get_policy[ETHTOOL_A_SETTINGS_MAX + 1] = {
 	[ETHTOOL_A_SETTINGS_HEADER]	= { .type = NLA_NESTED },
 	[ETHTOOL_A_SETTINGS_LINK_INFO]	= { .type = NLA_REJECT },
 	[ETHTOOL_A_SETTINGS_LINK_MODES]	= { .type = NLA_REJECT },
+	[ETHTOOL_A_SETTINGS_LINK_STATE]	= { .type = NLA_REJECT },
 };
 
 static int ethnl_get_link_ksettings(struct genl_info *info,
@@ -140,6 +142,7 @@ static int settings_prepare(struct ethnl_req_info *req_info,
 
 	data->lsettings = &data->ksettings.base;
 	data->lpm_empty = true;
+	data->link = -EOPNOTSUPP;
 
 	ret = ethnl_before_ops(dev);
 	if (ret < 0)
@@ -162,6 +165,8 @@ static int settings_prepare(struct ethnl_req_info *req_info,
 		ethnl_bitmap_to_u32(data->ksettings.link_modes.lp_advertising,
 				    __ETHTOOL_LINK_MODE_MASK_NWORDS);
 	}
+	if (req_mask & ETHTOOL_IM_SETTINGS_LINKSTATE)
+		data->link = __ethtool_get_link(dev);
 	ethnl_after_ops(dev);
 
 	data->repdata_base.info_mask = req_mask;
@@ -212,6 +217,13 @@ settings_linkmodes_size(const struct ethtool_link_ksettings *ksettings,
 	return nla_total_size(len);
 }
 
+static int settings_linkstate_size(int link)
+{
+	if (link < 0)
+		return nla_total_size(0);
+	return nla_total_size(nla_total_size(sizeof(u8)));
+}
+
 /* reply_size() handler
  *
  * To keep things simple, reserve space for some attributes which may not
@@ -235,6 +247,8 @@ static int settings_size(const struct ethnl_req_info *req_info)
 			return ret;
 		len += ret;
 	}
+	if (info_mask & ETHTOOL_IM_SETTINGS_LINKSTATE)
+		len += settings_linkstate_size(data->link);
 
 	return len;
 }
@@ -310,6 +324,23 @@ settings_fill_linkmodes(struct sk_buff *skb,
 	return -EMSGSIZE;
 }
 
+static int settings_fill_linkstate(struct sk_buff *skb, int link)
+{
+	struct nlattr *nest;
+
+	nest = nla_nest_start(skb, ETHTOOL_A_SETTINGS_LINK_STATE);
+	if (!nest)
+		return -EMSGSIZE;
+	if (link >= 0 && nla_put_u8(skb, ETHTOOL_A_LINKSTATE_LINK, !!link))
+		goto nla_put_failure;
+	nla_nest_end(skb, nest);
+	return 0;
+
+nla_put_failure:
+	nla_nest_cancel(skb, nest);
+	return -EMSGSIZE;
+}
+
 /* fill_reply() handler */
 static int settings_fill(struct sk_buff *skb,
 			 const struct ethnl_req_info *req_info)
@@ -331,6 +362,11 @@ static int settings_fill(struct sk_buff *skb,
 		if (ret < 0)
 			return ret;
 	}
+	if (info_mask & ETHTOOL_IM_SETTINGS_LINKSTATE) {
+		ret = settings_fill_linkstate(skb, data->link);
+		if (ret < 0)
+			return ret;
+	}
 
 	return 0;
 }
@@ -389,6 +425,7 @@ settings_set_policy[ETHTOOL_A_SETTINGS_MAX + 1] = {
 	[ETHTOOL_A_SETTINGS_HEADER]		= { .type = NLA_NESTED },
 	[ETHTOOL_A_SETTINGS_LINK_INFO]		= { .type = NLA_NESTED },
 	[ETHTOOL_A_SETTINGS_LINK_MODES]		= { .type = NLA_NESTED },
+	[ETHTOOL_A_SETTINGS_LINK_STATE]		= { .type = NLA_REJECT },
 };
 
 static int ethnl_set_link_ksettings(struct genl_info *info,
-- 
2.22.0


^ permalink raw reply related

* [PATCH net-next v6 14/15] ethtool: set link settings and link modes with SETTINGS_SET request
From: Michal Kubecek @ 2019-07-02 11:50 UTC (permalink / raw)
  To: David Miller, netdev
  Cc: Jakub Kicinski, Jiri Pirko, Andrew Lunn, Florian Fainelli,
	John Linville, Stephen Hemminger, Johannes Berg, linux-kernel
In-Reply-To: <cover.1562067622.git.mkubecek@suse.cz>

Implement SETTINGS_SET netlink request allowing to set link settings and
advertised link modes as an alternative to ETHTOOL_SLINKSETTINGS and
ETHTOOL_SSET ioctl commands.

Only values which are intended to be set are to be included in the request.
Omitted attributes will be left at current values.

ETHTOOL_A_SETTINGS_LINK_MODES nested attribute is used to set (or modify)
advertised link modes and related settings (autonegotiation, speed and
duplex). Kernel implements logic which was already partially implemented in
ethtool for ioctl interface: if autonegotiation is on (either it was on
already or the request turns it on), no link mode change is requested (no
ETHTOOL_A_LINKMODES_OURS attribute) and speed or duplex are provided,
advertised link modes are set to supported modes matching requested speed
and/or duplex.

ETHTOOL_A_SETTINGS_LINK_INFO nested attribute is used to set physical port,
phy MDIO address and MDI(-X) control. An attempt to modify other attributes
provided by corresponding GET request is rejected.

When any data is modified, ETHTOOL_MSG_SETTINGS_NTF message in the same
format as a reply to GET request is sent to notify userspace about the
changes. The same notification is also sent when these settings are
modified using the ioctl interface.

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 Documentation/networking/ethtool-netlink.txt |  34 +-
 include/uapi/linux/ethtool_netlink.h         |   2 +
 net/ethtool/ioctl.c                          |  18 +-
 net/ethtool/netlink.c                        |  11 +
 net/ethtool/netlink.h                        |   2 +
 net/ethtool/settings.c                       | 332 +++++++++++++++++++
 6 files changed, 395 insertions(+), 4 deletions(-)

diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index 1d803488e02c..05bc8f5f8654 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -152,11 +152,13 @@ Userspace to kernel:
 
     ETHTOOL_MSG_STRSET_GET		get string set
     ETHTOOL_MSG_SETTINGS_GET		get device settings
+    ETHTOOL_MSG_SETTINGS_SET		set device settings
 
 Kernel to userspace:
 
     ETHTOOL_MSG_STRSET_GET_REPLY	string set contents
     ETHTOOL_MSG_SETTINGS_GET_REPLY	device settings
+    ETHTOOL_MSG_SETTINGS_NTF		device settings notification
 
 "GET" requests are sent by userspace applications to retrieve device
 information. They usually do not contain any message specific attributes.
@@ -275,6 +277,34 @@ to them are broadcasted as notifications on change of these settings using
 netlink or ioctl ethtool interface.
 
 
+SETTINGS_SET
+------------
+
+SETTINGS_SET request allows setting some of the data reported by SETTINGS_GET.
+Request flags, info_mask and index are ignored. These attributes are allowed
+to be passed with SETTINGS_SET request:
+
+    ETHTOOL_A_SETTINGS_HEADER		(nested)	request header
+    ETHTOOL_A_SETTINGS_LINK_INFO	(nested)	link settings
+        ETHTOOL_A_LINKINFO_PORT		    (u8)	    physical port
+        ETHTOOL_A_LINKINFO_PHYADDR	    (u8)	    MDIO address of phy
+        ETHTOOL_A_LINKINFO_TP_MDIX_CTRL	    (u8)	    MDI(-X) control
+    ETHTOOL_A_SETTINGS_LINK_MODES	(nested)	link modes
+        ETHTOOL_A_LINKMODES_AUTONEG	    (u8)	    autonegotiation
+        ETHTOOL_A_LINKMODES_OURS	    (bitset)	    advertised link modes
+        ETHTOOL_A_LINKMODES_SPEED	    (u32)	    link speed (Mb/s)
+        ETHTOOL_A_LINKMODES_DUPLEX	    (u8)	    duplex mode
+
+ETHTOOL_A_LINKMODES_OURS bit set allows setting advertised link modes. If
+autonegotiation is on (either set now or kept from before), advertised modes
+are not changed (no ETHTOOL_A_LINKMODES_OURS attribute) and at least one of
+speed and duplex is specified, kernel adjusts advertised modes to all
+supported modes matching speed, duplex or both (whatever is specified). This
+autoselection is done on ethtool side with ioctl interface, netlink interface
+is supposed to allow requesting changes without knowing what exactly kernel
+supports.
+
+
 Request translation
 -------------------
 
@@ -285,7 +315,7 @@ have their netlink replacement yet.
 ioctl command			netlink command
 ---------------------------------------------------------------------
 ETHTOOL_GSET			ETHTOOL_MSG_SETTINGS_GET
-ETHTOOL_SSET			n/a
+ETHTOOL_SSET			ETHTOOL_MSG_SETTINGS_SET
 ETHTOOL_GDRVINFO		n/a
 ETHTOOL_GREGS			n/a
 ETHTOOL_GWOL			n/a
@@ -359,7 +389,7 @@ ETHTOOL_STUNABLE		n/a
 ETHTOOL_GPHYSTATS		n/a
 ETHTOOL_PERQUEUE		n/a
 ETHTOOL_GLINKSETTINGS		ETHTOOL_MSG_SETTINGS_GET
-ETHTOOL_SLINKSETTINGS		n/a
+ETHTOOL_SLINKSETTINGS		ETHTOOL_MSG_SETTINGS_SET
 ETHTOOL_PHY_GTUNABLE		n/a
 ETHTOOL_PHY_STUNABLE		n/a
 ETHTOOL_GFECPARAM		n/a
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index a046dd8da50e..8ccf66ed3f58 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -16,6 +16,7 @@ enum {
 	ETHTOOL_MSG_USER_NONE,
 	ETHTOOL_MSG_STRSET_GET,
 	ETHTOOL_MSG_SETTINGS_GET,
+	ETHTOOL_MSG_SETTINGS_SET,
 
 	/* add new constants above here */
 	__ETHTOOL_MSG_USER_CNT,
@@ -27,6 +28,7 @@ enum {
 	ETHTOOL_MSG_KERNEL_NONE,
 	ETHTOOL_MSG_STRSET_GET_REPLY,
 	ETHTOOL_MSG_SETTINGS_GET_REPLY,
+	ETHTOOL_MSG_SETTINGS_NTF,
 
 	/* add new constants above here */
 	__ETHTOOL_MSG_KERNEL_CNT,
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index ed53e07d619e..504ab2f7009c 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -26,6 +26,7 @@
 #include <net/devlink.h>
 #include <net/xdp_sock.h>
 #include <net/flow_offload.h>
+#include <linux/ethtool_netlink.h>
 
 #include "common.h"
 
@@ -565,7 +566,13 @@ static int ethtool_set_link_ksettings(struct net_device *dev,
 	    != link_ksettings.base.link_mode_masks_nwords)
 		return -EINVAL;
 
-	return dev->ethtool_ops->set_link_ksettings(dev, &link_ksettings);
+	err = dev->ethtool_ops->set_link_ksettings(dev, &link_ksettings);
+	if (err >= 0)
+		ethtool_notify(dev, NULL, ETHTOOL_MSG_SETTINGS_NTF,
+			       ETHTOOL_IM_SETTINGS_LINKINFO |
+			       ETHTOOL_IM_SETTINGS_LINKMODES,
+			       NULL);
+	return err;
 }
 
 /* Query device for its ethtool_cmd settings.
@@ -614,6 +621,7 @@ static int ethtool_set_settings(struct net_device *dev, void __user *useraddr)
 {
 	struct ethtool_link_ksettings link_ksettings;
 	struct ethtool_cmd cmd;
+	int ret;
 
 	ASSERT_RTNL();
 
@@ -626,7 +634,13 @@ static int ethtool_set_settings(struct net_device *dev, void __user *useraddr)
 		return -EINVAL;
 	link_ksettings.base.link_mode_masks_nwords =
 		__ETHTOOL_LINK_MODE_MASK_NU32;
-	return dev->ethtool_ops->set_link_ksettings(dev, &link_ksettings);
+	ret = dev->ethtool_ops->set_link_ksettings(dev, &link_ksettings);
+	if (ret >= 0)
+		ethtool_notify(dev, NULL, ETHTOOL_MSG_SETTINGS_NTF,
+			       ETHTOOL_IM_SETTINGS_LINKINFO |
+			       ETHTOOL_IM_SETTINGS_LINKMODES,
+			       NULL);
+	return ret;
 }
 
 static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index 9ff17ef05023..69b6dfe2a1c8 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -612,6 +612,11 @@ static int ethnl_get_done(struct netlink_callback *cb)
 
 static const struct get_request_ops *ethnl_std_notify_to_ops(unsigned int cmd)
 {
+	switch (cmd) {
+	case ETHTOOL_MSG_SETTINGS_NTF:
+		return &settings_request_ops;
+	};
+
 	WARN_ONCE(1, "unexpected notification type %u\n", cmd);
 	return NULL;
 }
@@ -679,6 +684,7 @@ typedef void (*ethnl_notify_handler_t)(struct net_device *dev,
 				       const void *data);
 
 static const ethnl_notify_handler_t ethnl_notify_handlers[] = {
+	[ETHTOOL_MSG_SETTINGS_NTF]	= ethnl_std_notify,
 };
 
 void ethtool_notify(struct net_device *dev, struct netlink_ext_ack *extack,
@@ -714,6 +720,11 @@ static const struct genl_ops ethtool_genl_ops[] = {
 		.dumpit	= ethnl_get_dumpit,
 		.done	= ethnl_get_done,
 	},
+	{
+		.cmd	= ETHTOOL_MSG_SETTINGS_SET,
+		.flags	= GENL_UNS_ADMIN_PERM,
+		.doit	= ethnl_set_settings,
+	},
 };
 
 static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h
index 6512d9d508bf..43fdf11cfc6d 100644
--- a/net/ethtool/netlink.h
+++ b/net/ethtool/netlink.h
@@ -297,4 +297,6 @@ struct get_request_ops {
 extern const struct get_request_ops strset_request_ops;
 extern const struct get_request_ops settings_request_ops;
 
+int ethnl_set_settings(struct sk_buff *skb, struct genl_info *info);
+
 #endif /* _NET_ETHTOOL_NETLINK_H */
diff --git a/net/ethtool/settings.c b/net/ethtool/settings.c
index 11ec30b9d48b..2fc961297076 100644
--- a/net/ethtool/settings.c
+++ b/net/ethtool/settings.c
@@ -14,6 +14,99 @@ struct settings_data {
 	bool				lpm_empty;
 };
 
+struct link_mode_info {
+	int				speed;
+	u8				duplex;
+};
+
+#define __DEFINE_LINK_MODE_PARAMS(_speed, _type, _duplex) \
+	[ETHTOOL_LINK_MODE(_speed, _type, _duplex)] = { \
+		.speed	= SPEED_ ## _speed, \
+		.duplex	= __DUPLEX_ ## _duplex \
+	}
+#define __DUPLEX_Half DUPLEX_HALF
+#define __DUPLEX_Full DUPLEX_FULL
+#define __DEFINE_SPECIAL_MODE_PARAMS(_mode) \
+	[ETHTOOL_LINK_MODE_ ## _mode ## _BIT] = { \
+		.speed	= SPEED_UNKNOWN, \
+		.duplex	= DUPLEX_UNKNOWN, \
+	}
+
+static const struct link_mode_info link_mode_params[] = {
+	__DEFINE_LINK_MODE_PARAMS(10, T, Half),
+	__DEFINE_LINK_MODE_PARAMS(10, T, Full),
+	__DEFINE_LINK_MODE_PARAMS(100, T, Half),
+	__DEFINE_LINK_MODE_PARAMS(100, T, Full),
+	__DEFINE_LINK_MODE_PARAMS(1000, T, Half),
+	__DEFINE_LINK_MODE_PARAMS(1000, T, Full),
+	__DEFINE_SPECIAL_MODE_PARAMS(Autoneg),
+	__DEFINE_SPECIAL_MODE_PARAMS(TP),
+	__DEFINE_SPECIAL_MODE_PARAMS(AUI),
+	__DEFINE_SPECIAL_MODE_PARAMS(MII),
+	__DEFINE_SPECIAL_MODE_PARAMS(FIBRE),
+	__DEFINE_SPECIAL_MODE_PARAMS(BNC),
+	__DEFINE_LINK_MODE_PARAMS(10000, T, Full),
+	__DEFINE_SPECIAL_MODE_PARAMS(Pause),
+	__DEFINE_SPECIAL_MODE_PARAMS(Asym_Pause),
+	__DEFINE_LINK_MODE_PARAMS(2500, X, Full),
+	__DEFINE_SPECIAL_MODE_PARAMS(Backplane),
+	__DEFINE_LINK_MODE_PARAMS(1000, KX, Full),
+	__DEFINE_LINK_MODE_PARAMS(10000, KX4, Full),
+	__DEFINE_LINK_MODE_PARAMS(10000, KR, Full),
+	[ETHTOOL_LINK_MODE_10000baseR_FEC_BIT] = {
+		.speed	= SPEED_10000,
+		.duplex = DUPLEX_FULL,
+	},
+	__DEFINE_LINK_MODE_PARAMS(20000, MLD2, Full),
+	__DEFINE_LINK_MODE_PARAMS(20000, KR2, Full),
+	__DEFINE_LINK_MODE_PARAMS(40000, KR4, Full),
+	__DEFINE_LINK_MODE_PARAMS(40000, CR4, Full),
+	__DEFINE_LINK_MODE_PARAMS(40000, SR4, Full),
+	__DEFINE_LINK_MODE_PARAMS(40000, LR4, Full),
+	__DEFINE_LINK_MODE_PARAMS(56000, KR4, Full),
+	__DEFINE_LINK_MODE_PARAMS(56000, CR4, Full),
+	__DEFINE_LINK_MODE_PARAMS(56000, SR4, Full),
+	__DEFINE_LINK_MODE_PARAMS(56000, LR4, Full),
+	__DEFINE_LINK_MODE_PARAMS(25000, CR, Full),
+	__DEFINE_LINK_MODE_PARAMS(25000, KR, Full),
+	__DEFINE_LINK_MODE_PARAMS(25000, SR, Full),
+	__DEFINE_LINK_MODE_PARAMS(50000, CR2, Full),
+	__DEFINE_LINK_MODE_PARAMS(50000, KR2, Full),
+	__DEFINE_LINK_MODE_PARAMS(100000, KR4, Full),
+	__DEFINE_LINK_MODE_PARAMS(100000, SR4, Full),
+	__DEFINE_LINK_MODE_PARAMS(100000, CR4, Full),
+	__DEFINE_LINK_MODE_PARAMS(100000, LR4_ER4, Full),
+	__DEFINE_LINK_MODE_PARAMS(50000, SR2, Full),
+	__DEFINE_LINK_MODE_PARAMS(1000, X, Full),
+	__DEFINE_LINK_MODE_PARAMS(10000, CR, Full),
+	__DEFINE_LINK_MODE_PARAMS(10000, SR, Full),
+	__DEFINE_LINK_MODE_PARAMS(10000, LR, Full),
+	__DEFINE_LINK_MODE_PARAMS(10000, LRM, Full),
+	__DEFINE_LINK_MODE_PARAMS(10000, ER, Full),
+	__DEFINE_LINK_MODE_PARAMS(2500, T, Full),
+	__DEFINE_LINK_MODE_PARAMS(5000, T, Full),
+	__DEFINE_SPECIAL_MODE_PARAMS(FEC_NONE),
+	__DEFINE_SPECIAL_MODE_PARAMS(FEC_RS),
+	__DEFINE_SPECIAL_MODE_PARAMS(FEC_BASER),
+	__DEFINE_LINK_MODE_PARAMS(50000, KR, Full),
+	__DEFINE_LINK_MODE_PARAMS(50000, SR, Full),
+	__DEFINE_LINK_MODE_PARAMS(50000, CR, Full),
+	__DEFINE_LINK_MODE_PARAMS(50000, LR_ER_FR, Full),
+	__DEFINE_LINK_MODE_PARAMS(50000, DR, Full),
+	__DEFINE_LINK_MODE_PARAMS(100000, KR2, Full),
+	__DEFINE_LINK_MODE_PARAMS(100000, SR2, Full),
+	__DEFINE_LINK_MODE_PARAMS(100000, CR2, Full),
+	__DEFINE_LINK_MODE_PARAMS(100000, LR2_ER2_FR2, Full),
+	__DEFINE_LINK_MODE_PARAMS(100000, DR2, Full),
+	__DEFINE_LINK_MODE_PARAMS(200000, KR4, Full),
+	__DEFINE_LINK_MODE_PARAMS(200000, SR4, Full),
+	__DEFINE_LINK_MODE_PARAMS(200000, LR4_ER4_FR4, Full),
+	__DEFINE_LINK_MODE_PARAMS(200000, DR4, Full),
+	__DEFINE_LINK_MODE_PARAMS(200000, CR4, Full),
+	__DEFINE_LINK_MODE_PARAMS(100, T1, Full),
+	__DEFINE_LINK_MODE_PARAMS(1000, T1, Full),
+};
+
 static const struct nla_policy
 settings_get_policy[ETHTOOL_A_SETTINGS_MAX + 1] = {
 	[ETHTOOL_A_SETTINGS_UNSPEC]	= { .type = NLA_REJECT },
@@ -257,3 +350,242 @@ const struct get_request_ops settings_request_ops = {
 	.reply_size		= settings_size,
 	.fill_reply		= settings_fill,
 };
+
+/* SET_SETTINGS */
+
+static const struct nla_policy settings_hdr_policy[ETHTOOL_A_HEADER_MAX + 1] = {
+	[ETHTOOL_A_HEADER_UNSPEC]		= { .type = NLA_REJECT },
+	[ETHTOOL_A_HEADER_DEV_INDEX]		= { .type = NLA_U32 },
+	[ETHTOOL_A_HEADER_DEV_NAME]		= { .type = NLA_NUL_STRING,
+						    .len = IFNAMSIZ - 1 },
+	[ETHTOOL_A_HEADER_INFOMASK]		= { .type = NLA_REJECT },
+	[ETHTOOL_A_HEADER_GFLAGS]		= { .type = NLA_U32 },
+	[ETHTOOL_A_HEADER_RFLAGS]		= { .type = NLA_REJECT },
+};
+
+static const struct nla_policy
+linkinfo_set_policy[ETHTOOL_A_LINKINFO_MAX + 1] = {
+	[ETHTOOL_A_LINKINFO_UNSPEC]		= { .type = NLA_REJECT },
+	[ETHTOOL_A_LINKINFO_PORT]		= { .type = NLA_U8 },
+	[ETHTOOL_A_LINKINFO_PHYADDR]		= { .type = NLA_U8 },
+	[ETHTOOL_A_LINKINFO_TP_MDIX]		= { .type = NLA_REJECT },
+	[ETHTOOL_A_LINKINFO_TP_MDIX_CTRL]	= { .type = NLA_U8 },
+	[ETHTOOL_A_LINKINFO_TRANSCEIVER]	= { .type = NLA_REJECT },
+};
+
+static const struct nla_policy
+linkmodes_set_policy[ETHTOOL_A_LINKMODES_MAX + 1] = {
+	[ETHTOOL_A_LINKMODES_UNSPEC]		= { .type = NLA_REJECT },
+	[ETHTOOL_A_LINKMODES_AUTONEG]		= { .type = NLA_U8 },
+	[ETHTOOL_A_LINKMODES_OURS]		= { .type = NLA_NESTED },
+	[ETHTOOL_A_LINKMODES_PEER]		= { .type = NLA_REJECT },
+	[ETHTOOL_A_LINKMODES_SPEED]		= { .type = NLA_U32 },
+	[ETHTOOL_A_LINKMODES_DUPLEX]		= { .type = NLA_U8 },
+};
+
+static const struct nla_policy
+settings_set_policy[ETHTOOL_A_SETTINGS_MAX + 1] = {
+	[ETHTOOL_A_SETTINGS_UNSPEC]		= { .type = NLA_REJECT },
+	[ETHTOOL_A_SETTINGS_HEADER]		= { .type = NLA_NESTED },
+	[ETHTOOL_A_SETTINGS_LINK_INFO]		= { .type = NLA_NESTED },
+	[ETHTOOL_A_SETTINGS_LINK_MODES]		= { .type = NLA_NESTED },
+};
+
+static int ethnl_set_link_ksettings(struct genl_info *info,
+				    struct net_device *dev,
+				    struct ethtool_link_ksettings *ksettings)
+{
+	int ret = dev->ethtool_ops->set_link_ksettings(dev, ksettings);
+
+	if (ret < 0)
+		GENL_SET_ERR_MSG(info, "link settings update failed");
+	return ret;
+}
+
+/* Set advertised link modes to all supported modes matching requested speed
+ * and duplex values. Called when autonegotiation is on, speed or duplex is
+ * requested but no link mode change. This is done in userspace with ioctl()
+ * interface, move it into kernel for netlink.
+ * Returns true if advertised modes bitmap was modified.
+ */
+static bool settings_auto_linkmodes(struct ethtool_link_ksettings *ksettings,
+				    bool req_speed, bool req_duplex)
+{
+	unsigned long *advertising = ksettings->link_modes.advertising;
+	unsigned long *supported = ksettings->link_modes.supported;
+	DECLARE_BITMAP(old_adv, __ETHTOOL_LINK_MODE_MASK_NBITS);
+	unsigned int i;
+
+	BUILD_BUG_ON(ARRAY_SIZE(link_mode_params) !=
+		     __ETHTOOL_LINK_MODE_MASK_NBITS);
+
+	bitmap_copy(old_adv, advertising, __ETHTOOL_LINK_MODE_MASK_NBITS);
+
+	for (i = 0; i < __ETHTOOL_LINK_MODE_MASK_NBITS; i++) {
+		const struct link_mode_info *info = &link_mode_params[i];
+
+		if (info->speed == SPEED_UNKNOWN)
+			continue;
+		if (test_bit(i, supported) &&
+		    (!req_speed || info->speed == ksettings->base.speed) &&
+		    (!req_duplex || info->duplex == ksettings->base.duplex))
+			set_bit(i, advertising);
+		else
+			clear_bit(i, advertising);
+	}
+
+	return !bitmap_equal(old_adv, advertising,
+			     __ETHTOOL_LINK_MODE_MASK_NBITS);
+}
+
+static int settings_update_linkinfo(struct genl_info *info, struct nlattr *nest,
+				    struct ethtool_link_settings *lsettings)
+{
+	struct nlattr *tb[ETHTOOL_A_LINKINFO_MAX + 1];
+	int ret;
+
+	if (!nest)
+		return 0;
+	ret = nla_parse_nested(tb, ETHTOOL_A_LINKINFO_MAX, nest,
+			       linkinfo_set_policy, info->extack);
+	if (ret < 0)
+		return ret;
+
+	ret = 0;
+	if (ethnl_update_u8(&lsettings->port, tb[ETHTOOL_A_LINKINFO_PORT]))
+		ret = 1;
+	if (ethnl_update_u8(&lsettings->phy_address,
+			    tb[ETHTOOL_A_LINKINFO_PHYADDR]))
+		ret = 1;
+	if (ethnl_update_u8(&lsettings->eth_tp_mdix_ctrl,
+			    tb[ETHTOOL_A_LINKINFO_TP_MDIX_CTRL]))
+		ret = 1;
+
+	return ret;
+}
+
+static int settings_update_linkmodes(struct genl_info *info,
+				     const struct nlattr *nest,
+				     struct ethtool_link_ksettings *ksettings)
+{
+	struct ethtool_link_settings *lsettings = &ksettings->base;
+	struct nlattr *tb[ETHTOOL_A_LINKMODES_MAX + 1];
+	bool req_speed, req_duplex;
+	bool mod = false;
+	int ret;
+
+	if (!nest)
+		return 0;
+	ret = nla_parse_nested(tb, ETHTOOL_A_LINKMODES_MAX, nest,
+			       linkmodes_set_policy, info->extack);
+	if (ret < 0)
+		return ret;
+	req_speed = tb[ETHTOOL_A_LINKMODES_SPEED];
+	req_duplex = tb[ETHTOOL_A_LINKMODES_DUPLEX];
+
+	if (ethnl_update_u8(&lsettings->autoneg,
+			    tb[ETHTOOL_A_LINKMODES_AUTONEG]))
+		mod = true;
+	if (ethnl_update_bitset(ksettings->link_modes.advertising, NULL,
+				__ETHTOOL_LINK_MODE_MASK_NBITS,
+				tb[ETHTOOL_A_LINKMODES_OURS],
+				&ret, link_mode_names, false, info))
+		mod = true;
+	if (ret < 0)
+		return ret;
+	if (ethnl_update_u32(&lsettings->speed, tb[ETHTOOL_A_LINKMODES_SPEED]))
+		mod = true;
+	if (ethnl_update_u8(&lsettings->duplex, tb[ETHTOOL_A_LINKMODES_DUPLEX]))
+		mod = true;
+
+	if (!tb[ETHTOOL_A_LINKMODES_OURS] && lsettings->autoneg &&
+	    (req_speed || req_duplex) &&
+	    settings_auto_linkmodes(ksettings, req_speed, req_duplex))
+		mod = true;
+
+	return mod;
+}
+
+/* Update device settings using ->set_link_ksettings() callback */
+static int ethnl_update_ksettings(struct genl_info *info, struct nlattr **tb,
+				  struct net_device *dev, u32 *req_mask)
+{
+	struct ethtool_link_ksettings ksettings = {};
+	struct ethtool_link_settings *lsettings;
+	u32 mod_mask = 0;
+	int ret;
+
+	ret = ethnl_get_link_ksettings(info, dev, &ksettings);
+	if (ret < 0)
+		return ret;
+	lsettings = &ksettings.base;
+
+	ret = settings_update_linkinfo(info, tb[ETHTOOL_A_SETTINGS_LINK_INFO],
+				       lsettings);
+	if (ret < 0)
+		return ret;
+	if (ret)
+		mod_mask |= ETHTOOL_IM_SETTINGS_LINKINFO;
+
+	ret = settings_update_linkmodes(info, tb[ETHTOOL_A_SETTINGS_LINK_MODES],
+					&ksettings);
+	if (ret < 0)
+		return ret;
+	if (ret)
+		mod_mask |= ETHTOOL_IM_SETTINGS_LINKMODES;
+
+	if (mod_mask) {
+		ret = ethnl_set_link_ksettings(info, dev, &ksettings);
+		if (ret < 0)
+			return ret;
+		*req_mask |= mod_mask;
+	}
+
+	return 0;
+}
+
+int ethnl_set_settings(struct sk_buff *skb, struct genl_info *info)
+{
+	struct nlattr *tb[ETHTOOL_A_SETTINGS_MAX + 1];
+	struct ethnl_req_info req_info = {};
+	struct net_device *dev;
+	u32 req_mask = 0;
+	int ret;
+
+	ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb,
+			  ETHTOOL_A_SETTINGS_MAX, settings_set_policy,
+			  info->extack);
+	if (ret < 0)
+		return ret;
+	ret = ethnl_parse_header(&req_info, tb[ETHTOOL_A_SETTINGS_HEADER],
+				 genl_info_net(info), info->extack,
+				 settings_hdr_policy, true);
+	if (ret < 0)
+		return ret;
+	dev = req_info.dev;
+
+	rtnl_lock();
+	ret = ethnl_before_ops(dev);
+	if (ret < 0)
+		goto out_rtnl;
+	if (tb[ETHTOOL_A_SETTINGS_LINK_INFO] ||
+	    tb[ETHTOOL_A_SETTINGS_LINK_MODES]) {
+		ret = -EOPNOTSUPP;
+		if (!dev->ethtool_ops->get_link_ksettings)
+			goto out_ops;
+		ret = ethnl_update_ksettings(info, tb, dev, &req_mask);
+		if (ret < 0)
+			goto out_ops;
+	}
+	ret = 0;
+
+out_ops:
+	if (req_mask)
+		ethtool_notify(dev, NULL, ETHTOOL_MSG_SETTINGS_NTF, req_mask,
+			       NULL);
+	ethnl_after_ops(dev);
+out_rtnl:
+	rtnl_unlock();
+	dev_put(dev);
+	return ret;
+}
-- 
2.22.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox