diff mbox series

[net-next,v14,12/13] net: ethtool: strset: Allow querying phy stats by index

Message ID 20240701131801.1227740-13-maxime.chevallier@bootlin.com (mailing list archive)
State Under Review
Delegated to: Netdev Maintainers
Headers show
Series Introduce PHY listing and link_topology tracking | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next, async
netdev/ynl success Generated files up to date; no warnings/errors; GEN HAS DIFF 2 files changed, 919 insertions(+);
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 839 this patch: 839
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers success CCed 5 of 5 maintainers
netdev/build_clang success Errors and warnings before: 846 this patch: 846
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 846 this patch: 846
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 70 lines checked
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 1 this patch: 1
netdev/source_inline success Was 0 now: 0
netdev/contest success net-next-2024-07-03--12-00 (tests: 666)

Commit Message

Maxime Chevallier July 1, 2024, 1:17 p.m. UTC
The ETH_SS_PHY_STATS command gets PHY statistics. Use the phydev pointer
from the ethnl request to allow query phy stats from each PHY on the
link.

Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
 net/ethtool/strset.c | 24 +++++++++++++++++-------
 1 file changed, 17 insertions(+), 7 deletions(-)

Comments

Simon Horman July 2, 2024, 10:54 a.m. UTC | #1
On Mon, Jul 01, 2024 at 03:17:58PM +0200, Maxime Chevallier wrote:
> The ETH_SS_PHY_STATS command gets PHY statistics. Use the phydev pointer
> from the ethnl request to allow query phy stats from each PHY on the
> link.
> 
> Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
> ---
>  net/ethtool/strset.c | 24 +++++++++++++++++-------
>  1 file changed, 17 insertions(+), 7 deletions(-)
> 
> diff --git a/net/ethtool/strset.c b/net/ethtool/strset.c

...

> @@ -279,6 +280,8 @@ static int strset_prepare_data(const struct ethnl_req_info *req_base,
>  	const struct strset_req_info *req_info = STRSET_REQINFO(req_base);
>  	struct strset_reply_data *data = STRSET_REPDATA(reply_base);
>  	struct net_device *dev = reply_base->dev;
> +	struct nlattr **tb = info->attrs;

Hi Maxime,

Elsewhere in this function it is assumed that info may be NULL.
But here it is dereferenced unconditionally.

Flagged by Smatch.

> +	struct phy_device *phydev;
>  	unsigned int i;
>  	int ret;
>  

...
Maxime Chevallier July 3, 2024, 6:55 a.m. UTC | #2
Hello Simon,

On Tue, 2 Jul 2024 11:54:11 +0100
Simon Horman <horms@kernel.org> wrote:

> On Mon, Jul 01, 2024 at 03:17:58PM +0200, Maxime Chevallier wrote:
> > The ETH_SS_PHY_STATS command gets PHY statistics. Use the phydev pointer
> > from the ethnl request to allow query phy stats from each PHY on the
> > link.
> > 
> > Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
> > ---
> >  net/ethtool/strset.c | 24 +++++++++++++++++-------
> >  1 file changed, 17 insertions(+), 7 deletions(-)
> > 
> > diff --git a/net/ethtool/strset.c b/net/ethtool/strset.c  
> 
> ...
> 
> > @@ -279,6 +280,8 @@ static int strset_prepare_data(const struct ethnl_req_info *req_base,
> >  	const struct strset_req_info *req_info = STRSET_REQINFO(req_base);
> >  	struct strset_reply_data *data = STRSET_REPDATA(reply_base);
> >  	struct net_device *dev = reply_base->dev;
> > +	struct nlattr **tb = info->attrs;  
> 
> Hi Maxime,
> 
> Elsewhere in this function it is assumed that info may be NULL.
> But here it is dereferenced unconditionally.

Hmm in almst all netlink commands we do dereference the genl_info *info
pointer without checks.

I've looked into net/netlink/genetlink.c to backtrack call-sites and it
looks to be that indeed info can't be NULL (either populated from
genl_start() or genl_family_rcv_msg_doit(). Maybe Jakub can confirm
this ?

If what I say above is correct, I can include a small patch to remove
the un-necessary check that makes smatch think the genl_info pointer can
be NULL.

Thanks for the report,

Maxime
diff mbox series

Patch

diff --git a/net/ethtool/strset.c b/net/ethtool/strset.c
index c678b484a079..ebc3a7ad0558 100644
--- a/net/ethtool/strset.c
+++ b/net/ethtool/strset.c
@@ -126,7 +126,7 @@  struct strset_reply_data {
 
 const struct nla_policy ethnl_strset_get_policy[] = {
 	[ETHTOOL_A_STRSET_HEADER]	=
-		NLA_POLICY_NESTED(ethnl_header_policy),
+		NLA_POLICY_NESTED(ethnl_header_policy_phy),
 	[ETHTOOL_A_STRSET_STRINGSETS]	= { .type = NLA_NESTED },
 	[ETHTOOL_A_STRSET_COUNTS_ONLY]	= { .type = NLA_FLAG },
 };
@@ -233,17 +233,18 @@  static void strset_cleanup_data(struct ethnl_reply_data *reply_base)
 }
 
 static int strset_prepare_set(struct strset_info *info, struct net_device *dev,
-			      unsigned int id, bool counts_only)
+			      struct phy_device *phydev, unsigned int id,
+			      bool counts_only)
 {
 	const struct ethtool_phy_ops *phy_ops = ethtool_phy_ops;
 	const struct ethtool_ops *ops = dev->ethtool_ops;
 	void *strings;
 	int count, ret;
 
-	if (id == ETH_SS_PHY_STATS && dev->phydev &&
+	if (id == ETH_SS_PHY_STATS && phydev &&
 	    !ops->get_ethtool_phy_stats && phy_ops &&
 	    phy_ops->get_sset_count)
-		ret = phy_ops->get_sset_count(dev->phydev);
+		ret = phy_ops->get_sset_count(phydev);
 	else if (ops->get_sset_count && ops->get_strings)
 		ret = ops->get_sset_count(dev, id);
 	else
@@ -258,10 +259,10 @@  static int strset_prepare_set(struct strset_info *info, struct net_device *dev,
 		strings = kcalloc(count, ETH_GSTRING_LEN, GFP_KERNEL);
 		if (!strings)
 			return -ENOMEM;
-		if (id == ETH_SS_PHY_STATS && dev->phydev &&
+		if (id == ETH_SS_PHY_STATS && phydev &&
 		    !ops->get_ethtool_phy_stats && phy_ops &&
 		    phy_ops->get_strings)
-			phy_ops->get_strings(dev->phydev, strings);
+			phy_ops->get_strings(phydev, strings);
 		else
 			ops->get_strings(dev, id, strings);
 		info->strings = strings;
@@ -279,6 +280,8 @@  static int strset_prepare_data(const struct ethnl_req_info *req_base,
 	const struct strset_req_info *req_info = STRSET_REQINFO(req_base);
 	struct strset_reply_data *data = STRSET_REPDATA(reply_base);
 	struct net_device *dev = reply_base->dev;
+	struct nlattr **tb = info->attrs;
+	struct phy_device *phydev;
 	unsigned int i;
 	int ret;
 
@@ -297,6 +300,13 @@  static int strset_prepare_data(const struct ethnl_req_info *req_base,
 		return 0;
 	}
 
+	phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_HEADER_FLAGS],
+				      info->extack);
+
+	/* phydev can be NULL, check for errors only */
+	if (IS_ERR(phydev))
+		return PTR_ERR(phydev);
+
 	ret = ethnl_ops_begin(dev);
 	if (ret < 0)
 		goto err_strset;
@@ -305,7 +315,7 @@  static int strset_prepare_data(const struct ethnl_req_info *req_base,
 		    !data->sets[i].per_dev)
 			continue;
 
-		ret = strset_prepare_set(&data->sets[i], dev, i,
+		ret = strset_prepare_set(&data->sets[i], dev, phydev, i,
 					 req_info->counts_only);
 		if (ret < 0)
 			goto err_ops;