Currently, some ethtool link parameters, like speed, lanes and duplex, are derived from the link_mode parameter. These link parameters are only derived in __ethtool_get_link_ksettings(), but the ioctl path does not go through this function. This means that old ethtool (w/o netlink) won't get any reasonable values.
Add a function that derives the parameters from link_mode and use it in ioctl paths as well. Output before: $ ethtool --version ethtool version 5.4 $ ethtool swp13 Settings for swp13: Supported ports: [ FIBRE Backplane ] Supported link modes: 1000baseKX/Full 10000baseKR/Full 25000baseCR/Full 25000baseKR/Full 25000baseSR/Full Supported pause frame use: Symmetric Receive-only Supports auto-negotiation: Yes Supported FEC modes: Not reported Advertised link modes: 1000baseKX/Full 10000baseKR/Full 25000baseCR/Full 25000baseKR/Full 25000baseSR/Full Advertised pause frame use: No Advertised auto-negotiation: Yes Advertised FEC modes: Not reported Speed: Unknown! Duplex: Half Port: Direct Attach Copper PHYAD: 0 Transceiver: internal Auto-negotiation: on Link detected: yes Output after: $ ethtool swp13 Settings for swp13: Supported ports: [ FIBRE Backplane ] Supported link modes: 1000baseKX/Full 10000baseKR/Full 25000baseCR/Full 25000baseKR/Full 25000baseSR/Full Supported pause frame use: Symmetric Receive-only Supports auto-negotiation: Yes Supported FEC modes: Not reported Advertised link modes: 1000baseKX/Full 10000baseKR/Full 25000baseCR/Full 25000baseKR/Full 25000baseSR/Full Advertised pause frame use: No Advertised auto-negotiation: Yes Advertised FEC modes: Not reported Speed: 25000Mb/s Duplex: Full Port: Direct Attach Copper PHYAD: 0 Transceiver: internal Auto-negotiation: on Link detected: yes Fixes: c8907043c6ac9 ("ethtool: Get link mode in use instead of speed and duplex parameters") Signed-off-by: Danielle Ratson <daniel...@nvidia.com> Reported-by: Ido Schimmel <ido...@nvidia.com> Reviewed-by: Ido Schimmel <ido...@nvidia.com> --- net/ethtool/ioctl.c | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c index cebbf93b27a7..943162ef080c 100644 --- a/net/ethtool/ioctl.c +++ b/net/ethtool/ioctl.c @@ -422,11 +422,31 @@ struct ethtool_link_usettings { } link_modes; }; +static int +ethtool_params_from_link_mode(const struct net_device *dev, + struct ethtool_link_ksettings *link_ksettings) +{ + const struct link_mode_info *link_info; + + if (dev->ethtool_ops->cap_link_mode_supported && + link_ksettings->link_mode != -1) { + if (WARN_ON_ONCE(link_ksettings->link_mode >= + __ETHTOOL_LINK_MODE_MASK_NBITS)) + return -EINVAL; + + link_info = &link_mode_params[link_ksettings->link_mode]; + link_ksettings->base.speed = link_info->speed; + link_ksettings->lanes = link_info->lanes; + link_ksettings->base.duplex = link_info->duplex; + } + + return 0; +} + /* Internal kernel helper to query a device ethtool_link_settings. */ int __ethtool_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *link_ksettings) { - const struct link_mode_info *link_info; int err; ASSERT_RTNL(); @@ -440,17 +460,7 @@ int __ethtool_get_link_ksettings(struct net_device *dev, if (err) return err; - if (dev->ethtool_ops->cap_link_mode_supported && - link_ksettings->link_mode != -1) { - if (WARN_ON_ONCE(link_ksettings->link_mode >= - __ETHTOOL_LINK_MODE_MASK_NBITS)) - return -EINVAL; - - link_info = &link_mode_params[link_ksettings->link_mode]; - link_ksettings->base.speed = link_info->speed; - link_ksettings->lanes = link_info->lanes; - link_ksettings->base.duplex = link_info->duplex; - } + ethtool_params_from_link_mode(dev, link_ksettings); return 0; } @@ -572,6 +582,8 @@ static int ethtool_get_link_ksettings(struct net_device *dev, if (err < 0) return err; + ethtool_params_from_link_mode(dev, &link_ksettings); + /* make sure we tell the right values to user */ link_ksettings.base.cmd = ETHTOOL_GLINKSETTINGS; link_ksettings.base.link_mode_masks_nwords @@ -673,6 +685,8 @@ static int ethtool_get_settings(struct net_device *dev, void __user *useraddr) return err; convert_link_ksettings_to_legacy_settings(&cmd, &link_ksettings); + ethtool_params_from_link_mode(dev, &link_ksettings); + /* send a sensible cmd tag back to user */ cmd.cmd = ETHTOOL_GSET; -- 2.26.2