From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.0 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A8446C43381 for ; Mon, 25 Mar 2019 17:08:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 6BF5620896 for ; Mon, 25 Mar 2019 17:08:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730454AbfCYRI4 (ORCPT ); Mon, 25 Mar 2019 13:08:56 -0400 Received: from mx2.suse.de ([195.135.220.15]:51414 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1730424AbfCYRIy (ORCPT ); Mon, 25 Mar 2019 13:08:54 -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 65657B020; Mon, 25 Mar 2019 17:08:52 +0000 (UTC) Received: by unicorn.suse.cz (Postfix, from userid 1000) id 0FDFEE1404; Mon, 25 Mar 2019 18:08:52 +0100 (CET) Message-Id: In-Reply-To: References: From: Michal Kubecek Subject: [PATCH net-next v5 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 , Stephen Hemminger , linux-kernel@vger.kernel.org Date: Mon, 25 Mar 2019 18:08:52 +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