Received: by 2002:ac0:bc90:0:0:0:0:0 with SMTP id a16csp673534img; Thu, 21 Mar 2019 06:42:33 -0700 (PDT) X-Google-Smtp-Source: APXvYqxTlzYenKojwQhrHW7dJdjkG6Vs5cTKlTGASzTnIs+o662ThtcyqCRYyCR8rZY3fxwTE3aD X-Received: by 2002:a17:902:801:: with SMTP id 1mr3527821plk.299.1553175753658; Thu, 21 Mar 2019 06:42:33 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1553175753; cv=none; d=google.com; s=arc-20160816; b=yAHexxbdpyYxooRfJEJo2KGjBksXg2ilib4GdgcXKa2nI9ELQ/0xVCti7mPJPVo2WB RNXJwD2XL0yHFJKlvag/kh8Vqx77Rkgrz3SbybrvfkOAGOYpVA3LIg/v6BEEFLJVW8xi lRtQjgCgSNPYWfeoM2FEzI+Q+HYooTsx6X51a6ThUnuK0qB8d7EBsg+b9EAU5dXQO2I3 jAHlO+vtZm1m85AeFXDe2GkYqzEQCK7XCswXy/Y34xiAL20FL6FFIfunpVVlycQcmBGM 9UkE/lcYvAflANBiObXcpzIlQDSnqxmoR3xJEhx3Lofub7AAw6irJboQCu2rOuK9bzp+ o+4g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:date:cc:to:subject:from:references :in-reply-to:message-id; bh=glq+Es9JA8jsD7CSRDk/dWYqqTRbqbM0HecYcFfOtKg=; b=EKwHdPofudVU5zZcvkiCIg5Fry8vcP9JPE9E+Fp7SgjzsKcALSesdntZ8B3kjtGGvZ fkGSCjAPMwnzgFI4aex6HBRKZpPzeALvoN1vwaWlcD/pV5OpIkpokDAb6PV79xkZNiG5 Cszqh3NAVTjAOL6HUXTYXbYTVLgW3WNhkLV4x01y9JEFvD+J6pnAdgCfpkI7qhGmgZ1m yNAdoOjomKU9tnzkQmZWmf7EhElp/qmXj5xXs8XkvP4+pfx2aD18QaLbwEAWQ6BQvLj8 MJn5oCJN03syXlXWQVDVEZXZwzrbOzAtFhB8EV2b1a1E0mHXu3YKiN92kg91pRNArd3S m8/w== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id n23si4344027plp.182.2019.03.21.06.42.19; Thu, 21 Mar 2019 06:42:33 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728651AbfCUNlT (ORCPT + 99 others); Thu, 21 Mar 2019 09:41:19 -0400 Received: from mx2.suse.de ([195.135.220.15]:36618 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1728623AbfCUNlS (ORCPT ); Thu, 21 Mar 2019 09:41:18 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id D833FAE60; Thu, 21 Mar 2019 13:41:15 +0000 (UTC) Received: by unicorn.suse.cz (Postfix, from userid 1000) id 819B2E00BF; Thu, 21 Mar 2019 14:41:15 +0100 (CET) Message-Id: <188ad7a2d52fe87525781fcd103427347c5e4ecf.1553170807.git.mkubecek@suse.cz> In-Reply-To: References: From: Michal Kubecek Subject: [PATCH net-next v4 19/22] ethtool: provide WoL information in GET_SETTINGS request To: David Miller , netdev@vger.kernel.org Cc: Jakub Kicinski , Jiri Pirko , Andrew Lunn , Florian Fainelli , John Linville , linux-kernel@vger.kernel.org Date: Thu, 21 Mar 2019 14:41:15 +0100 (CET) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add information about supported and enabled wake on LAN modes into the GET_SETTINGS reply when ETH_SETTINGS_IM_WOL flag is set in the request. The GET_SETTINGS request can be still sent by unprivileged users but in such case the SecureOn password (if any) is not included in the reply. Send notification in the same format as reply SET_SETTINGS message when wake on LAN settings are modified using ioctl interface (ETHTOOL_SWOL command). Signed-off-by: Michal Kubecek --- Documentation/networking/ethtool-netlink.txt | 13 +++- include/uapi/linux/ethtool_netlink.h | 14 ++++- net/ethtool/common.c | 10 ++++ net/ethtool/common.h | 1 + net/ethtool/ioctl.c | 10 ++-- net/ethtool/settings.c | 63 ++++++++++++++++++++ 6 files changed, 105 insertions(+), 6 deletions(-) diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt index ebd1a0404828..bc7f28f0182f 100644 --- a/Documentation/networking/ethtool-netlink.txt +++ b/Documentation/networking/ethtool-netlink.txt @@ -278,6 +278,7 @@ Info mask bits meaning: ETH_SETTINGS_IM_LINKINFO link settings ETH_SETTINGS_IM_LINKMODES link modes and related ETH_SETTINGS_IM_LINKSTATE link state + ETH_SETTINGS_IM_WOL struct ethtool_wolinfo Response contents: @@ -296,12 +297,22 @@ Response contents: ETHA_LINKMODES_DUPLEX (u8) duplex mode ETHA_SETTINGS_LINK_STATE (nested) link state ETHA_LINKSTATE_LINK (u8) link on/off/unknown + ETHA_SETTINGS_WOL (nested) wake on LAN settings + ETHA_WOL_MODES (bitfield32) wake on LAN modes + ETHA_WOL_SOPASS (binary) SecureOn(tm) password Most of the attributes and their values have the same meaning as matching members of the corresponding ioctl structures. For ETHA_LINKMODES_OURS, value represents advertised modes and mask represents supported modes. ETHA_LINKMODES_PEER in the reply is a bit list. +For ETHA_WOL_MODES, selector reports wake on LAN modes supported by the +device and value enabled modes. + +GET_SETTINGS request is allowed for unprivileged user but ETHA_WOL_SOPASS +is only provided by kernel in response to privileged (netns CAP_NET_ADMIN) +requests. + GET_SETTINGS requests allow dumps and messages in the same format as response to them are broadcasted as notifications on change of these settings using netlink or ioctl ethtool interface. @@ -348,7 +359,7 @@ ETHTOOL_GSET ETHNL_CMD_GET_SETTINGS ETHTOOL_SSET ETHNL_CMD_SET_SETTINGS ETHTOOL_GDRVINFO ETHNL_CMD_GET_INFO ETHTOOL_GREGS n/a -ETHTOOL_GWOL n/a +ETHTOOL_GWOL ETHNL_CMD_GET_SETTINGS ETHTOOL_SWOL n/a ETHTOOL_GMSGLVL n/a ETHTOOL_SMSGLVL n/a diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h index 45c27c7291d0..532ad11ae87c 100644 --- a/include/uapi/linux/ethtool_netlink.h +++ b/include/uapi/linux/ethtool_netlink.h @@ -197,6 +197,7 @@ enum { ETHA_SETTINGS_LINK_INFO, /* nest - ETHA_LINKINFO_* */ ETHA_SETTINGS_LINK_MODES, /* nest - ETHA_LINKMODES_* */ ETHA_SETTINGS_LINK_STATE, /* nest - ETHA_LINKSTATE_* */ + ETHA_SETTINGS_WOL, /* nest - ETHA_WOL_* */ __ETHA_SETTINGS_CNT, ETHA_SETTINGS_MAX = (__ETHA_SETTINGS_CNT - 1) @@ -205,10 +206,12 @@ enum { #define ETH_SETTINGS_IM_LINKINFO (1U << 0) #define ETH_SETTINGS_IM_LINKMODES (1U << 1) #define ETH_SETTINGS_IM_LINKSTATE (1U << 2) +#define ETH_SETTINGS_IM_WOL (1U << 3) #define ETH_SETTINGS_IM_ALL (ETH_SETTINGS_IM_LINKINFO | \ ETH_SETTINGS_IM_LINKMODES | \ - ETH_SETTINGS_IM_LINKSTATE) + ETH_SETTINGS_IM_LINKSTATE | \ + ETH_SETTINGS_IM_WOL) enum { ETHA_LINKINFO_UNSPEC, @@ -242,6 +245,15 @@ enum { ETHA_LINKSTATE_MAX = (__ETHA_LINKSTATE_CNT - 1) }; +enum { + ETHA_WOL_UNSPEC, + ETHA_WOL_MODES, /* bitfield32 */ + ETHA_WOL_SOPASS, /* binary */ + + __ETHA_WOL_CNT, + ETHA_WOL_MAX = (__ETHA_WOL_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 dc907d8b6e43..4b2f08da910a 100644 --- a/net/ethtool/common.c +++ b/net/ethtool/common.c @@ -213,3 +213,13 @@ int __ethtool_get_link(struct net_device *dev) return netif_running(dev) && dev->ethtool_ops->get_link(dev); } + +int __ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + if (!dev->ethtool_ops->get_wol) + return -EOPNOTSUPP; + + dev->ethtool_ops->get_wol(dev, wol); + + return 0; +} diff --git a/net/ethtool/common.h b/net/ethtool/common.h index a5ddd7f5cfce..bbe3e51f7308 100644 --- a/net/ethtool/common.h +++ b/net/ethtool/common.h @@ -18,6 +18,7 @@ phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN]; int __ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info); int __ethtool_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info); int __ethtool_get_link(struct net_device *dev); +int __ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol); bool convert_legacy_settings_to_link_ksettings( struct ethtool_link_ksettings *link_ksettings, diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c index 58669dafeaf9..bba02a218eea 100644 --- a/net/ethtool/ioctl.c +++ b/net/ethtool/ioctl.c @@ -1242,11 +1242,11 @@ static int ethtool_reset(struct net_device *dev, char __user *useraddr) static int ethtool_get_wol(struct net_device *dev, char __user *useraddr) { struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL }; + int rc; - if (!dev->ethtool_ops->get_wol) - return -EOPNOTSUPP; - - dev->ethtool_ops->get_wol(dev, &wol); + rc = __ethtool_get_wol(dev, &wol); + if (rc < 0) + return rc; if (copy_to_user(useraddr, &wol, sizeof(wol))) return -EFAULT; @@ -1269,6 +1269,8 @@ static int ethtool_set_wol(struct net_device *dev, char __user *useraddr) return ret; dev->wol_enabled = !!wol.wolopts; + ethtool_notify(dev, NULL, ETHNL_CMD_SET_SETTINGS, ETH_SETTINGS_IM_WOL, + NULL); return 0; } diff --git a/net/ethtool/settings.c b/net/ethtool/settings.c index 7a2729f01f79..56a045e5e916 100644 --- a/net/ethtool/settings.c +++ b/net/ethtool/settings.c @@ -6,10 +6,12 @@ struct settings_data { struct common_req_info reqinfo_base; + bool privileged; /* everything below here will be reset for each device in dumps */ struct common_reply_data repdata_base; struct ethtool_link_ksettings ksettings; + struct ethtool_wolinfo wolinfo; struct ethtool_link_settings *lsettings; int link; bool lpm_empty; @@ -114,15 +116,20 @@ static const struct nla_policy get_settings_policy[ETHA_SETTINGS_MAX + 1] = { [ETHA_SETTINGS_LINK_INFO] = { .type = NLA_REJECT }, [ETHA_SETTINGS_LINK_MODES] = { .type = NLA_REJECT }, [ETHA_SETTINGS_LINK_STATE] = { .type = NLA_REJECT }, + [ETHA_SETTINGS_WOL] = { .type = NLA_REJECT }, }; static int parse_settings(struct common_req_info *req_info, struct sk_buff *skb, struct genl_info *info, const struct nlmsghdr *nlhdr) { + struct settings_data *data = + container_of(req_info, struct settings_data, reqinfo_base); struct nlattr *tb[ETHA_SETTINGS_MAX + 1]; int ret; + data->privileged = ethnl_is_privileged(skb); + ret = ethnlmsg_parse(nlhdr, tb, ETHA_SETTINGS_MAX, get_settings_policy, info); if (ret < 0) @@ -159,6 +166,16 @@ static int ethnl_get_link_ksettings(struct genl_info *info, return ret; } +static int ethnl_get_wol(struct genl_info *info, struct net_device *dev, + struct ethtool_wolinfo *wolinfo) +{ + int ret = __ethtool_get_wol(dev, wolinfo); + + if (ret < 0) + ETHNL_SET_ERRMSG(info, "failed to retrieve wol info"); + return ret; +} + static int prepare_settings(struct common_req_info *req_info, struct genl_info *info) { @@ -194,6 +211,11 @@ static int prepare_settings(struct common_req_info *req_info, } if (req_mask & ETH_SETTINGS_IM_LINKSTATE) data->link = __ethtool_get_link(dev); + if (req_mask & ETH_SETTINGS_IM_WOL) { + ret = ethnl_get_wol(info, dev, &data->wolinfo); + if (ret < 0) + req_mask &= ~ETH_SETTINGS_IM_WOL; + } ethnl_after_ops(dev); data->repdata_base.info_mask = req_mask; @@ -249,6 +271,12 @@ static int link_state_size(int link) return nla_total_size(nla_total_size(sizeof(u8))); } +static int wol_size(void) +{ + return nla_total_size(nla_total_size(sizeof(struct nla_bitfield32)) + + nla_total_size(SOPASS_MAX)); +} + /* To keep things simple, reserve space for some attributes which may not * be added to the message (e.g. ETHA_SETTINGS_SOPASS); therefore the length * returned may be bigger than the actual length of the message sent @@ -272,6 +300,8 @@ static int settings_size(const struct common_req_info *req_info) } if (info_mask & ETH_SETTINGS_IM_LINKSTATE) len += link_state_size(data->link); + if (info_mask & ETH_SETTINGS_IM_WOL) + len += wol_size(); return len; } @@ -361,6 +391,33 @@ static int fill_link_state(struct sk_buff *skb, u8 link) return -EMSGSIZE; } +static int fill_wolinfo(struct sk_buff *skb, + const struct ethtool_wolinfo *wolinfo, bool privileged) +{ + struct nlattr *nest; + + nest = ethnl_nest_start(skb, ETHA_SETTINGS_WOL); + if (!nest) + return -EMSGSIZE; + if (nla_put_bitfield32(skb, ETHA_WOL_MODES, wolinfo->wolopts, + wolinfo->supported)) + goto err; + /* ioctl() restricts read access to wolinfo but the actual + * reason is to hide sopass from unprivileged users; netlink + * can show wol modes without sopass + */ + if (privileged && + nla_put(skb, ETHA_WOL_SOPASS, sizeof(wolinfo->sopass), + wolinfo->sopass)) + goto err; + nla_nest_end(skb, nest); + return 0; + +err: + nla_nest_cancel(skb, nest); + return -EMSGSIZE; +} + static int fill_settings(struct sk_buff *skb, const struct common_req_info *req_info) { @@ -386,6 +443,11 @@ static int fill_settings(struct sk_buff *skb, if (ret < 0) return ret; } + if (info_mask & ETH_SETTINGS_IM_WOL) { + ret = fill_wolinfo(skb, &data->wolinfo, data->privileged); + if (ret < 0) + return ret; + } return 0; } @@ -431,6 +493,7 @@ static const struct nla_policy set_settings_policy[ETHA_SETTINGS_MAX + 1] = { [ETHA_SETTINGS_LINK_INFO] = { .type = NLA_NESTED }, [ETHA_SETTINGS_LINK_MODES] = { .type = NLA_NESTED }, [ETHA_SETTINGS_LINK_STATE] = { .type = NLA_REJECT }, + [ETHA_SETTINGS_WOL] = { .type = NLA_REJECT }, }; static int ethnl_set_link_ksettings(struct genl_info *info, -- 2.21.0