^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * net/core/ethtool.c - Ethtool ioctl handler
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (c) 2003 Matthew Wilcox <matthew@wil.cx>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * This file is where we call all the ethtool_ops commands to get
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * the information ethtool needs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/compat.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/capability.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/ethtool.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/netdevice.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/net_tstamp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/phy.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/bitops.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/vmalloc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/sfp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/rtnetlink.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/sched/signal.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/net.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <net/devlink.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <net/xdp_sock_drv.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <net/flow_offload.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/ethtool_netlink.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <generated/utsrelease.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include "common.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * Some useful ethtool_ops methods that're device independent.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * If we find that all drivers want to do the same thing here,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * we can turn these into dev_() function calls.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) u32 ethtool_op_get_link(struct net_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) return netif_carrier_ok(dev) ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) EXPORT_SYMBOL(ethtool_op_get_link);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) int ethtool_op_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) info->so_timestamping =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) SOF_TIMESTAMPING_TX_SOFTWARE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) SOF_TIMESTAMPING_RX_SOFTWARE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) SOF_TIMESTAMPING_SOFTWARE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) info->phc_index = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) EXPORT_SYMBOL(ethtool_op_get_ts_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) /* Handlers for each ethtool command */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) struct ethtool_gfeatures cmd = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) .cmd = ETHTOOL_GFEATURES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) .size = ETHTOOL_DEV_FEATURE_WORDS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) struct ethtool_get_features_block features[ETHTOOL_DEV_FEATURE_WORDS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) u32 __user *sizeaddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) u32 copy_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) /* in case feature bits run out again */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) BUILD_BUG_ON(ETHTOOL_DEV_FEATURE_WORDS * sizeof(u32) > sizeof(netdev_features_t));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) features[i].available = (u32)(dev->hw_features >> (32 * i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) features[i].requested = (u32)(dev->wanted_features >> (32 * i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) features[i].active = (u32)(dev->features >> (32 * i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) features[i].never_changed =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) (u32)(NETIF_F_NEVER_CHANGE >> (32 * i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) sizeaddr = useraddr + offsetof(struct ethtool_gfeatures, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) if (get_user(copy_size, sizeaddr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) if (copy_size > ETHTOOL_DEV_FEATURE_WORDS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) copy_size = ETHTOOL_DEV_FEATURE_WORDS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) useraddr += sizeof(cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (copy_to_user(useraddr, features, copy_size * sizeof(*features)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) static int ethtool_set_features(struct net_device *dev, void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) struct ethtool_sfeatures cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) struct ethtool_set_features_block features[ETHTOOL_DEV_FEATURE_WORDS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) netdev_features_t wanted = 0, valid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) int i, ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) useraddr += sizeof(cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) if (cmd.size != ETHTOOL_DEV_FEATURE_WORDS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) if (copy_from_user(features, useraddr, sizeof(features)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) valid |= (netdev_features_t)features[i].valid << (32 * i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) wanted |= (netdev_features_t)features[i].requested << (32 * i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) if (valid & ~NETIF_F_ETHTOOL_BITS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (valid & ~dev->hw_features) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) valid &= dev->hw_features;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) ret |= ETHTOOL_F_UNSUPPORTED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) dev->wanted_features &= ~valid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) dev->wanted_features |= wanted & valid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) __netdev_update_features(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if ((dev->wanted_features ^ dev->features) & valid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) ret |= ETHTOOL_F_WISH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) static int __ethtool_get_sset_count(struct net_device *dev, int sset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) const struct ethtool_phy_ops *phy_ops = ethtool_phy_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) const struct ethtool_ops *ops = dev->ethtool_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) if (sset == ETH_SS_FEATURES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) return ARRAY_SIZE(netdev_features_strings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (sset == ETH_SS_RSS_HASH_FUNCS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) return ARRAY_SIZE(rss_hash_func_strings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) if (sset == ETH_SS_TUNABLES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) return ARRAY_SIZE(tunable_strings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (sset == ETH_SS_PHY_TUNABLES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) return ARRAY_SIZE(phy_tunable_strings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) if (sset == ETH_SS_PHY_STATS && dev->phydev &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) !ops->get_ethtool_phy_stats &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) phy_ops && phy_ops->get_sset_count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) return phy_ops->get_sset_count(dev->phydev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) if (sset == ETH_SS_LINK_MODES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) return __ETHTOOL_LINK_MODE_MASK_NBITS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) if (ops->get_sset_count && ops->get_strings)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) return ops->get_sset_count(dev, sset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) static void __ethtool_get_strings(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) u32 stringset, u8 *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) const struct ethtool_phy_ops *phy_ops = ethtool_phy_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) const struct ethtool_ops *ops = dev->ethtool_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) if (stringset == ETH_SS_FEATURES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) memcpy(data, netdev_features_strings,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) sizeof(netdev_features_strings));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) else if (stringset == ETH_SS_RSS_HASH_FUNCS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) memcpy(data, rss_hash_func_strings,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) sizeof(rss_hash_func_strings));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) else if (stringset == ETH_SS_TUNABLES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) memcpy(data, tunable_strings, sizeof(tunable_strings));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) else if (stringset == ETH_SS_PHY_TUNABLES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) memcpy(data, phy_tunable_strings, sizeof(phy_tunable_strings));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) else if (stringset == ETH_SS_PHY_STATS && dev->phydev &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) !ops->get_ethtool_phy_stats && phy_ops &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) phy_ops->get_strings)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) phy_ops->get_strings(dev->phydev, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) else if (stringset == ETH_SS_LINK_MODES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) memcpy(data, link_mode_names,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) __ETHTOOL_LINK_MODE_MASK_NBITS * ETH_GSTRING_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) /* ops->get_strings is valid because checked earlier */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) ops->get_strings(dev, stringset, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) static netdev_features_t ethtool_get_feature_mask(u32 eth_cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) /* feature masks of legacy discrete ethtool ops */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) switch (eth_cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) case ETHTOOL_GTXCSUM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) case ETHTOOL_STXCSUM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) return NETIF_F_CSUM_MASK | NETIF_F_FCOE_CRC |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) NETIF_F_SCTP_CRC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) case ETHTOOL_GRXCSUM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) case ETHTOOL_SRXCSUM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) return NETIF_F_RXCSUM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) case ETHTOOL_GSG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) case ETHTOOL_SSG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) return NETIF_F_SG | NETIF_F_FRAGLIST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) case ETHTOOL_GTSO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) case ETHTOOL_STSO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) return NETIF_F_ALL_TSO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) case ETHTOOL_GGSO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) case ETHTOOL_SGSO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) return NETIF_F_GSO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) case ETHTOOL_GGRO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) case ETHTOOL_SGRO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) return NETIF_F_GRO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) BUG();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) static int ethtool_get_one_feature(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) char __user *useraddr, u32 ethcmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) netdev_features_t mask = ethtool_get_feature_mask(ethcmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) struct ethtool_value edata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) .cmd = ethcmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) .data = !!(dev->features & mask),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) if (copy_to_user(useraddr, &edata, sizeof(edata)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) static int ethtool_set_one_feature(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) void __user *useraddr, u32 ethcmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) struct ethtool_value edata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) netdev_features_t mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) if (copy_from_user(&edata, useraddr, sizeof(edata)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) mask = ethtool_get_feature_mask(ethcmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) mask &= dev->hw_features;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) if (!mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) if (edata.data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) dev->wanted_features |= mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) dev->wanted_features &= ~mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) __netdev_update_features(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) #define ETH_ALL_FLAGS (ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN | \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) ETH_FLAG_NTUPLE | ETH_FLAG_RXHASH)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) #define ETH_ALL_FEATURES (NETIF_F_LRO | NETIF_F_HW_VLAN_CTAG_RX | \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_NTUPLE | \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) NETIF_F_RXHASH)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) static u32 __ethtool_get_flags(struct net_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) u32 flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) if (dev->features & NETIF_F_LRO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) flags |= ETH_FLAG_LRO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) if (dev->features & NETIF_F_HW_VLAN_CTAG_RX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) flags |= ETH_FLAG_RXVLAN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) if (dev->features & NETIF_F_HW_VLAN_CTAG_TX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) flags |= ETH_FLAG_TXVLAN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) if (dev->features & NETIF_F_NTUPLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) flags |= ETH_FLAG_NTUPLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) if (dev->features & NETIF_F_RXHASH)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) flags |= ETH_FLAG_RXHASH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) return flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) static int __ethtool_set_flags(struct net_device *dev, u32 data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) netdev_features_t features = 0, changed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) if (data & ~ETH_ALL_FLAGS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) if (data & ETH_FLAG_LRO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) features |= NETIF_F_LRO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) if (data & ETH_FLAG_RXVLAN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) features |= NETIF_F_HW_VLAN_CTAG_RX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) if (data & ETH_FLAG_TXVLAN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) features |= NETIF_F_HW_VLAN_CTAG_TX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) if (data & ETH_FLAG_NTUPLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) features |= NETIF_F_NTUPLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) if (data & ETH_FLAG_RXHASH)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) features |= NETIF_F_RXHASH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) /* allow changing only bits set in hw_features */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) changed = (features ^ dev->features) & ETH_ALL_FEATURES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) if (changed & ~dev->hw_features)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) return (changed & dev->hw_features) ? -EINVAL : -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) dev->wanted_features =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) (dev->wanted_features & ~changed) | (features & changed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) __netdev_update_features(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) /* Given two link masks, AND them together and save the result in dst. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) void ethtool_intersect_link_masks(struct ethtool_link_ksettings *dst,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) struct ethtool_link_ksettings *src)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) unsigned int size = BITS_TO_LONGS(__ETHTOOL_LINK_MODE_MASK_NBITS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) unsigned int idx = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) for (; idx < size; idx++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) dst->link_modes.supported[idx] &=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) src->link_modes.supported[idx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) dst->link_modes.advertising[idx] &=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) src->link_modes.advertising[idx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) EXPORT_SYMBOL(ethtool_intersect_link_masks);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) void ethtool_convert_legacy_u32_to_link_mode(unsigned long *dst,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) u32 legacy_u32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) bitmap_zero(dst, __ETHTOOL_LINK_MODE_MASK_NBITS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) dst[0] = legacy_u32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) EXPORT_SYMBOL(ethtool_convert_legacy_u32_to_link_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) /* return false if src had higher bits set. lower bits always updated. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) bool ethtool_convert_link_mode_to_legacy_u32(u32 *legacy_u32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) const unsigned long *src)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) bool retval = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) /* TODO: following test will soon always be true */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) if (__ETHTOOL_LINK_MODE_MASK_NBITS > 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) __ETHTOOL_DECLARE_LINK_MODE_MASK(ext);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) bitmap_zero(ext, __ETHTOOL_LINK_MODE_MASK_NBITS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) bitmap_fill(ext, 32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) bitmap_complement(ext, ext, __ETHTOOL_LINK_MODE_MASK_NBITS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) if (bitmap_intersects(ext, src,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) __ETHTOOL_LINK_MODE_MASK_NBITS)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) /* src mask goes beyond bit 31 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) retval = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) *legacy_u32 = src[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) EXPORT_SYMBOL(ethtool_convert_link_mode_to_legacy_u32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) /* return false if ksettings link modes had higher bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) * set. legacy_settings always updated (best effort)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) static bool
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) convert_link_ksettings_to_legacy_settings(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) struct ethtool_cmd *legacy_settings,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) const struct ethtool_link_ksettings *link_ksettings)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) bool retval = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) memset(legacy_settings, 0, sizeof(*legacy_settings));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) /* this also clears the deprecated fields in legacy structure:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) * __u8 transceiver;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) * __u32 maxtxpkt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) * __u32 maxrxpkt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) retval &= ethtool_convert_link_mode_to_legacy_u32(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) &legacy_settings->supported,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) link_ksettings->link_modes.supported);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) retval &= ethtool_convert_link_mode_to_legacy_u32(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) &legacy_settings->advertising,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) link_ksettings->link_modes.advertising);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) retval &= ethtool_convert_link_mode_to_legacy_u32(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) &legacy_settings->lp_advertising,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) link_ksettings->link_modes.lp_advertising);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) ethtool_cmd_speed_set(legacy_settings, link_ksettings->base.speed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) legacy_settings->duplex
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) = link_ksettings->base.duplex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) legacy_settings->port
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) = link_ksettings->base.port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) legacy_settings->phy_address
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) = link_ksettings->base.phy_address;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) legacy_settings->autoneg
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) = link_ksettings->base.autoneg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) legacy_settings->mdio_support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) = link_ksettings->base.mdio_support;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) legacy_settings->eth_tp_mdix
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) = link_ksettings->base.eth_tp_mdix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) legacy_settings->eth_tp_mdix_ctrl
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) = link_ksettings->base.eth_tp_mdix_ctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) legacy_settings->transceiver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) = link_ksettings->base.transceiver;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) /* number of 32-bit words to store the user's link mode bitmaps */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) #define __ETHTOOL_LINK_MODE_MASK_NU32 \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) DIV_ROUND_UP(__ETHTOOL_LINK_MODE_MASK_NBITS, 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) /* layout of the struct passed from/to userland */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) struct ethtool_link_usettings {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) struct ethtool_link_settings base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) __u32 supported[__ETHTOOL_LINK_MODE_MASK_NU32];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) __u32 advertising[__ETHTOOL_LINK_MODE_MASK_NU32];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) __u32 lp_advertising[__ETHTOOL_LINK_MODE_MASK_NU32];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) } link_modes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) /* Internal kernel helper to query a device ethtool_link_settings. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) int __ethtool_get_link_ksettings(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) struct ethtool_link_ksettings *link_ksettings)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) ASSERT_RTNL();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) if (!dev->ethtool_ops->get_link_ksettings)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) memset(link_ksettings, 0, sizeof(*link_ksettings));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) return dev->ethtool_ops->get_link_ksettings(dev, link_ksettings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) EXPORT_SYMBOL(__ethtool_get_link_ksettings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) /* convert ethtool_link_usettings in user space to a kernel internal
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) * ethtool_link_ksettings. return 0 on success, errno on error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) static int load_link_ksettings_from_user(struct ethtool_link_ksettings *to,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) const void __user *from)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) struct ethtool_link_usettings link_usettings;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) if (copy_from_user(&link_usettings, from, sizeof(link_usettings)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) memcpy(&to->base, &link_usettings.base, sizeof(to->base));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) bitmap_from_arr32(to->link_modes.supported,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) link_usettings.link_modes.supported,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) __ETHTOOL_LINK_MODE_MASK_NBITS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) bitmap_from_arr32(to->link_modes.advertising,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) link_usettings.link_modes.advertising,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) __ETHTOOL_LINK_MODE_MASK_NBITS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) bitmap_from_arr32(to->link_modes.lp_advertising,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) link_usettings.link_modes.lp_advertising,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) __ETHTOOL_LINK_MODE_MASK_NBITS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) /* Check if the user is trying to change anything besides speed/duplex */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) bool ethtool_virtdev_validate_cmd(const struct ethtool_link_ksettings *cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) struct ethtool_link_settings base2 = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) base2.speed = cmd->base.speed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) base2.port = PORT_OTHER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) base2.duplex = cmd->base.duplex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) base2.cmd = cmd->base.cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) base2.link_mode_masks_nwords = cmd->base.link_mode_masks_nwords;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) return !memcmp(&base2, &cmd->base, sizeof(base2)) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) bitmap_empty(cmd->link_modes.supported,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) __ETHTOOL_LINK_MODE_MASK_NBITS) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) bitmap_empty(cmd->link_modes.lp_advertising,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) __ETHTOOL_LINK_MODE_MASK_NBITS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) /* convert a kernel internal ethtool_link_ksettings to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) * ethtool_link_usettings in user space. return 0 on success, errno on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) * error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) store_link_ksettings_for_user(void __user *to,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) const struct ethtool_link_ksettings *from)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) struct ethtool_link_usettings link_usettings;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) memcpy(&link_usettings, from, sizeof(link_usettings));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) bitmap_to_arr32(link_usettings.link_modes.supported,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) from->link_modes.supported,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) __ETHTOOL_LINK_MODE_MASK_NBITS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) bitmap_to_arr32(link_usettings.link_modes.advertising,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) from->link_modes.advertising,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) __ETHTOOL_LINK_MODE_MASK_NBITS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) bitmap_to_arr32(link_usettings.link_modes.lp_advertising,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) from->link_modes.lp_advertising,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) __ETHTOOL_LINK_MODE_MASK_NBITS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) if (copy_to_user(to, &link_usettings, sizeof(link_usettings)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) /* Query device for its ethtool_link_settings. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) static int ethtool_get_link_ksettings(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) struct ethtool_link_ksettings link_ksettings;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) ASSERT_RTNL();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) if (!dev->ethtool_ops->get_link_ksettings)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) /* handle bitmap nbits handshake */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) if (copy_from_user(&link_ksettings.base, useraddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) sizeof(link_ksettings.base)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) if (__ETHTOOL_LINK_MODE_MASK_NU32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) != link_ksettings.base.link_mode_masks_nwords) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) /* wrong link mode nbits requested */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) memset(&link_ksettings, 0, sizeof(link_ksettings));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) link_ksettings.base.cmd = ETHTOOL_GLINKSETTINGS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) /* send back number of words required as negative val */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) compiletime_assert(__ETHTOOL_LINK_MODE_MASK_NU32 <= S8_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) "need too many bits for link modes!");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) link_ksettings.base.link_mode_masks_nwords
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) = -((s8)__ETHTOOL_LINK_MODE_MASK_NU32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) /* copy the base fields back to user, not the link
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) * mode bitmaps
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) if (copy_to_user(useraddr, &link_ksettings.base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) sizeof(link_ksettings.base)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) /* handshake successful: user/kernel agree on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) * link_mode_masks_nwords
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) memset(&link_ksettings, 0, sizeof(link_ksettings));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) err = dev->ethtool_ops->get_link_ksettings(dev, &link_ksettings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) /* make sure we tell the right values to user */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) link_ksettings.base.cmd = ETHTOOL_GLINKSETTINGS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) link_ksettings.base.link_mode_masks_nwords
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) = __ETHTOOL_LINK_MODE_MASK_NU32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) link_ksettings.base.master_slave_cfg = MASTER_SLAVE_CFG_UNSUPPORTED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) link_ksettings.base.master_slave_state = MASTER_SLAVE_STATE_UNSUPPORTED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) return store_link_ksettings_for_user(useraddr, &link_ksettings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) /* Update device ethtool_link_settings. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) static int ethtool_set_link_ksettings(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) struct ethtool_link_ksettings link_ksettings;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) ASSERT_RTNL();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) if (!dev->ethtool_ops->set_link_ksettings)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) /* make sure nbits field has expected value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) if (copy_from_user(&link_ksettings.base, useraddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) sizeof(link_ksettings.base)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) if (__ETHTOOL_LINK_MODE_MASK_NU32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) != link_ksettings.base.link_mode_masks_nwords)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) /* copy the whole structure, now that we know it has expected
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) * format
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) err = load_link_ksettings_from_user(&link_ksettings, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) /* re-check nwords field, just in case */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) if (__ETHTOOL_LINK_MODE_MASK_NU32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) != link_ksettings.base.link_mode_masks_nwords)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) if (link_ksettings.base.master_slave_cfg ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) link_ksettings.base.master_slave_state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) err = dev->ethtool_ops->set_link_ksettings(dev, &link_ksettings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) if (err >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) ethtool_notify(dev, ETHTOOL_MSG_LINKINFO_NTF, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) ethtool_notify(dev, ETHTOOL_MSG_LINKMODES_NTF, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) int ethtool_virtdev_set_link_ksettings(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) const struct ethtool_link_ksettings *cmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) u32 *dev_speed, u8 *dev_duplex)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) u32 speed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) u8 duplex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) speed = cmd->base.speed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) duplex = cmd->base.duplex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) /* don't allow custom speed and duplex */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) if (!ethtool_validate_speed(speed) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) !ethtool_validate_duplex(duplex) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) !ethtool_virtdev_validate_cmd(cmd))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) *dev_speed = speed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) *dev_duplex = duplex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) EXPORT_SYMBOL(ethtool_virtdev_set_link_ksettings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) /* Query device for its ethtool_cmd settings.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) * Backward compatibility note: for compatibility with legacy ethtool, this is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) * now implemented via get_link_ksettings. When driver reports higher link mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) * bits, a kernel warning is logged once (with name of 1st driver/device) to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) * recommend user to upgrade ethtool, but the command is successful (only the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) * lower link mode bits reported back to user). Deprecated fields from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) * ethtool_cmd (transceiver/maxrxpkt/maxtxpkt) are always set to zero.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) static int ethtool_get_settings(struct net_device *dev, void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) struct ethtool_link_ksettings link_ksettings;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) struct ethtool_cmd cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) ASSERT_RTNL();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) if (!dev->ethtool_ops->get_link_ksettings)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) memset(&link_ksettings, 0, sizeof(link_ksettings));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) err = dev->ethtool_ops->get_link_ksettings(dev, &link_ksettings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) convert_link_ksettings_to_legacy_settings(&cmd, &link_ksettings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) /* send a sensible cmd tag back to user */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) cmd.cmd = ETHTOOL_GSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) /* Update device link settings with given ethtool_cmd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) * Backward compatibility note: for compatibility with legacy ethtool, this is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) * now always implemented via set_link_settings. When user's request updates
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) * deprecated ethtool_cmd fields (transceiver/maxrxpkt/maxtxpkt), a kernel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) * warning is logged once (with name of 1st driver/device) to recommend user to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) * upgrade ethtool, and the request is rejected.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) static int ethtool_set_settings(struct net_device *dev, void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) struct ethtool_link_ksettings link_ksettings;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) struct ethtool_cmd cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) ASSERT_RTNL();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) if (!dev->ethtool_ops->set_link_ksettings)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) if (!convert_legacy_settings_to_link_ksettings(&link_ksettings, &cmd))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) link_ksettings.base.link_mode_masks_nwords =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) __ETHTOOL_LINK_MODE_MASK_NU32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) ret = dev->ethtool_ops->set_link_ksettings(dev, &link_ksettings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) if (ret >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) ethtool_notify(dev, ETHTOOL_MSG_LINKINFO_NTF, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) ethtool_notify(dev, ETHTOOL_MSG_LINKMODES_NTF, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) struct ethtool_drvinfo info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) const struct ethtool_ops *ops = dev->ethtool_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) memset(&info, 0, sizeof(info));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) info.cmd = ETHTOOL_GDRVINFO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) strlcpy(info.version, UTS_RELEASE, sizeof(info.version));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) if (ops->get_drvinfo) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) ops->get_drvinfo(dev, &info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) } else if (dev->dev.parent && dev->dev.parent->driver) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) strlcpy(info.bus_info, dev_name(dev->dev.parent),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) sizeof(info.bus_info));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) strlcpy(info.driver, dev->dev.parent->driver->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) sizeof(info.driver));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) * this method of obtaining string set info is deprecated;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) * Use ETHTOOL_GSSET_INFO instead.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) if (ops->get_sset_count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) rc = ops->get_sset_count(dev, ETH_SS_TEST);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) if (rc >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) info.testinfo_len = rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) rc = ops->get_sset_count(dev, ETH_SS_STATS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) if (rc >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) info.n_stats = rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) rc = ops->get_sset_count(dev, ETH_SS_PRIV_FLAGS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) if (rc >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) info.n_priv_flags = rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) if (ops->get_regs_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) int ret = ops->get_regs_len(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) if (ret > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) info.regdump_len = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) if (ops->get_eeprom_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) info.eedump_len = ops->get_eeprom_len(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) if (!info.fw_version[0])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) devlink_compat_running_version(dev, info.fw_version,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) sizeof(info.fw_version));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) if (copy_to_user(useraddr, &info, sizeof(info)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) static noinline_for_stack int ethtool_get_sset_info(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) struct ethtool_sset_info info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) u64 sset_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) int i, idx = 0, n_bits = 0, ret, rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) u32 *info_buf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) if (copy_from_user(&info, useraddr, sizeof(info)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) /* store copy of mask, because we zero struct later on */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) sset_mask = info.sset_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) if (!sset_mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) /* calculate size of return buffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) n_bits = hweight64(sset_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) memset(&info, 0, sizeof(info));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) info.cmd = ETHTOOL_GSSET_INFO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) info_buf = kcalloc(n_bits, sizeof(u32), GFP_USER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) if (!info_buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) * fill return buffer based on input bitmask and successful
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) * get_sset_count return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) for (i = 0; i < 64; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) if (!(sset_mask & (1ULL << i)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) rc = __ethtool_get_sset_count(dev, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) if (rc >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) info.sset_mask |= (1ULL << i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) info_buf[idx++] = rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) if (copy_to_user(useraddr, &info, sizeof(info)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) useraddr += offsetof(struct ethtool_sset_info, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) if (copy_to_user(useraddr, info_buf, idx * sizeof(u32)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) kfree(info_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) static noinline_for_stack int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) ethtool_rxnfc_copy_from_compat(struct ethtool_rxnfc *rxnfc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) const struct compat_ethtool_rxnfc __user *useraddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) struct compat_ethtool_rxnfc crxnfc = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) /* We expect there to be holes between fs.m_ext and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) * fs.ring_cookie and at the end of fs, but nowhere else.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) * On non-x86, no conversion should be needed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) BUILD_BUG_ON(!IS_ENABLED(CONFIG_X86_64) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) sizeof(struct compat_ethtool_rxnfc) !=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) sizeof(struct ethtool_rxnfc));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) BUILD_BUG_ON(offsetof(struct compat_ethtool_rxnfc, fs.m_ext) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) sizeof(useraddr->fs.m_ext) !=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) offsetof(struct ethtool_rxnfc, fs.m_ext) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) sizeof(rxnfc->fs.m_ext));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) BUILD_BUG_ON(offsetof(struct compat_ethtool_rxnfc, fs.location) -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) offsetof(struct compat_ethtool_rxnfc, fs.ring_cookie) !=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) offsetof(struct ethtool_rxnfc, fs.location) -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) offsetof(struct ethtool_rxnfc, fs.ring_cookie));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) if (copy_from_user(&crxnfc, useraddr, min(size, sizeof(crxnfc))))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) *rxnfc = (struct ethtool_rxnfc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) .cmd = crxnfc.cmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) .flow_type = crxnfc.flow_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) .data = crxnfc.data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) .fs = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) .flow_type = crxnfc.fs.flow_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) .h_u = crxnfc.fs.h_u,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) .h_ext = crxnfc.fs.h_ext,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) .m_u = crxnfc.fs.m_u,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) .m_ext = crxnfc.fs.m_ext,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) .ring_cookie = crxnfc.fs.ring_cookie,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) .location = crxnfc.fs.location,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) .rule_cnt = crxnfc.rule_cnt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) static int ethtool_rxnfc_copy_from_user(struct ethtool_rxnfc *rxnfc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) const void __user *useraddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) if (compat_need_64bit_alignment_fixup())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) return ethtool_rxnfc_copy_from_compat(rxnfc, useraddr, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) if (copy_from_user(rxnfc, useraddr, size))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) static int ethtool_rxnfc_copy_to_compat(void __user *useraddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) const struct ethtool_rxnfc *rxnfc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) size_t size, const u32 *rule_buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) struct compat_ethtool_rxnfc crxnfc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) memset(&crxnfc, 0, sizeof(crxnfc));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) crxnfc = (struct compat_ethtool_rxnfc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) .cmd = rxnfc->cmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) .flow_type = rxnfc->flow_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) .data = rxnfc->data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) .fs = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) .flow_type = rxnfc->fs.flow_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) .h_u = rxnfc->fs.h_u,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) .h_ext = rxnfc->fs.h_ext,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) .m_u = rxnfc->fs.m_u,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) .m_ext = rxnfc->fs.m_ext,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) .ring_cookie = rxnfc->fs.ring_cookie,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) .location = rxnfc->fs.location,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) .rule_cnt = rxnfc->rule_cnt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) if (copy_to_user(useraddr, &crxnfc, min(size, sizeof(crxnfc))))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) static int ethtool_rxnfc_copy_to_user(void __user *useraddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) const struct ethtool_rxnfc *rxnfc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) size_t size, const u32 *rule_buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) if (compat_need_64bit_alignment_fixup()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) ret = ethtool_rxnfc_copy_to_compat(useraddr, rxnfc, size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) rule_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) useraddr += offsetof(struct compat_ethtool_rxnfc, rule_locs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) ret = copy_to_user(useraddr, rxnfc, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) useraddr += offsetof(struct ethtool_rxnfc, rule_locs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) if (rule_buf) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) if (copy_to_user(useraddr, rule_buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) rxnfc->rule_cnt * sizeof(u32)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) u32 cmd, void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) struct ethtool_rxnfc info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) size_t info_size = sizeof(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) if (!dev->ethtool_ops->set_rxnfc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) /* struct ethtool_rxnfc was originally defined for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) * ETHTOOL_{G,S}RXFH with only the cmd, flow_type and data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) * members. User-space might still be using that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) * definition. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) if (cmd == ETHTOOL_SRXFH)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) info_size = (offsetof(struct ethtool_rxnfc, data) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) sizeof(info.data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) if (ethtool_rxnfc_copy_from_user(&info, useraddr, info_size))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) rc = dev->ethtool_ops->set_rxnfc(dev, &info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) if (cmd == ETHTOOL_SRXCLSRLINS &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) ethtool_rxnfc_copy_to_user(useraddr, &info, info_size, NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) u32 cmd, void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) struct ethtool_rxnfc info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) size_t info_size = sizeof(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) const struct ethtool_ops *ops = dev->ethtool_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) void *rule_buf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) if (!ops->get_rxnfc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) /* struct ethtool_rxnfc was originally defined for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) * ETHTOOL_{G,S}RXFH with only the cmd, flow_type and data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) * members. User-space might still be using that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) * definition. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) if (cmd == ETHTOOL_GRXFH)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) info_size = (offsetof(struct ethtool_rxnfc, data) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) sizeof(info.data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) if (ethtool_rxnfc_copy_from_user(&info, useraddr, info_size))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) /* If FLOW_RSS was requested then user-space must be using the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) * new definition, as FLOW_RSS is newer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) if (cmd == ETHTOOL_GRXFH && info.flow_type & FLOW_RSS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) info_size = sizeof(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) if (ethtool_rxnfc_copy_from_user(&info, useraddr, info_size))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) /* Since malicious users may modify the original data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) * we need to check whether FLOW_RSS is still requested.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) if (!(info.flow_type & FLOW_RSS))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) if (info.cmd != cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) if (info.cmd == ETHTOOL_GRXCLSRLALL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) if (info.rule_cnt > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) if (info.rule_cnt <= KMALLOC_MAX_SIZE / sizeof(u32))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) rule_buf = kcalloc(info.rule_cnt, sizeof(u32),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) GFP_USER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) if (!rule_buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) ret = ops->get_rxnfc(dev, &info, rule_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) goto err_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) ret = ethtool_rxnfc_copy_to_user(useraddr, &info, info_size, rule_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) err_out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) kfree(rule_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) static int ethtool_copy_validate_indir(u32 *indir, void __user *useraddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) struct ethtool_rxnfc *rx_rings,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) u32 size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) if (copy_from_user(indir, useraddr, size * sizeof(indir[0])))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) /* Validate ring indices */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) for (i = 0; i < size; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) if (indir[i] >= rx_rings->data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) u8 netdev_rss_key[NETDEV_RSS_KEY_LEN] __read_mostly;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) void netdev_rss_key_fill(void *buffer, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) BUG_ON(len > sizeof(netdev_rss_key));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) net_get_random_once(netdev_rss_key, sizeof(netdev_rss_key));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) memcpy(buffer, netdev_rss_key, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) EXPORT_SYMBOL(netdev_rss_key_fill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) u32 user_size, dev_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) u32 *indir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) if (!dev->ethtool_ops->get_rxfh_indir_size ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) !dev->ethtool_ops->get_rxfh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) dev_size = dev->ethtool_ops->get_rxfh_indir_size(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) if (dev_size == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) if (copy_from_user(&user_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) useraddr + offsetof(struct ethtool_rxfh_indir, size),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) sizeof(user_size)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) if (copy_to_user(useraddr + offsetof(struct ethtool_rxfh_indir, size),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) &dev_size, sizeof(dev_size)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) /* If the user buffer size is 0, this is just a query for the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) * device table size. Otherwise, if it's smaller than the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) * device table size it's an error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) if (user_size < dev_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) return user_size == 0 ? 0 : -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) indir = kcalloc(dev_size, sizeof(indir[0]), GFP_USER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) if (!indir)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) ret = dev->ethtool_ops->get_rxfh(dev, indir, NULL, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) if (copy_to_user(useraddr +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) offsetof(struct ethtool_rxfh_indir, ring_index[0]),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) indir, dev_size * sizeof(indir[0])))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) kfree(indir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) struct ethtool_rxnfc rx_rings;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) u32 user_size, dev_size, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) u32 *indir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) const struct ethtool_ops *ops = dev->ethtool_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) u32 ringidx_offset = offsetof(struct ethtool_rxfh_indir, ring_index[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) if (!ops->get_rxfh_indir_size || !ops->set_rxfh ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) !ops->get_rxnfc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) dev_size = ops->get_rxfh_indir_size(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) if (dev_size == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) if (copy_from_user(&user_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) useraddr + offsetof(struct ethtool_rxfh_indir, size),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) sizeof(user_size)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) if (user_size != 0 && user_size != dev_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) indir = kcalloc(dev_size, sizeof(indir[0]), GFP_USER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) if (!indir)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) rx_rings.cmd = ETHTOOL_GRXRINGS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) ret = ops->get_rxnfc(dev, &rx_rings, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) if (user_size == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) for (i = 0; i < dev_size; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) ret = ethtool_copy_validate_indir(indir,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) useraddr + ringidx_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) &rx_rings,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) dev_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) ret = ops->set_rxfh(dev, indir, NULL, ETH_RSS_HASH_NO_CHANGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) /* indicate whether rxfh was set to default */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) if (user_size == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) dev->priv_flags &= ~IFF_RXFH_CONFIGURED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) dev->priv_flags |= IFF_RXFH_CONFIGURED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) kfree(indir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) const struct ethtool_ops *ops = dev->ethtool_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) u32 user_indir_size, user_key_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) u32 dev_indir_size = 0, dev_key_size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) struct ethtool_rxfh rxfh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) u32 total_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) u32 indir_bytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) u32 *indir = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) u8 dev_hfunc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) u8 *hkey = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) u8 *rss_config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) if (!ops->get_rxfh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) if (ops->get_rxfh_indir_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) dev_indir_size = ops->get_rxfh_indir_size(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) if (ops->get_rxfh_key_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) dev_key_size = ops->get_rxfh_key_size(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) if (copy_from_user(&rxfh, useraddr, sizeof(rxfh)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) user_indir_size = rxfh.indir_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) user_key_size = rxfh.key_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) /* Check that reserved fields are 0 for now */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) if (rxfh.rsvd8[0] || rxfh.rsvd8[1] || rxfh.rsvd8[2] || rxfh.rsvd32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) /* Most drivers don't handle rss_context, check it's 0 as well */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) if (rxfh.rss_context && !ops->get_rxfh_context)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) rxfh.indir_size = dev_indir_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) rxfh.key_size = dev_key_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) if (copy_to_user(useraddr, &rxfh, sizeof(rxfh)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) if ((user_indir_size && (user_indir_size != dev_indir_size)) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) (user_key_size && (user_key_size != dev_key_size)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) indir_bytes = user_indir_size * sizeof(indir[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) total_size = indir_bytes + user_key_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) rss_config = kzalloc(total_size, GFP_USER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) if (!rss_config)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) if (user_indir_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) indir = (u32 *)rss_config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) if (user_key_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) hkey = rss_config + indir_bytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) if (rxfh.rss_context)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) ret = dev->ethtool_ops->get_rxfh_context(dev, indir, hkey,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) &dev_hfunc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) rxfh.rss_context);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) ret = dev->ethtool_ops->get_rxfh(dev, indir, hkey, &dev_hfunc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) if (copy_to_user(useraddr + offsetof(struct ethtool_rxfh, hfunc),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) &dev_hfunc, sizeof(rxfh.hfunc))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) } else if (copy_to_user(useraddr +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) offsetof(struct ethtool_rxfh, rss_config[0]),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) rss_config, total_size)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) kfree(rss_config);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) const struct ethtool_ops *ops = dev->ethtool_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) struct ethtool_rxnfc rx_rings;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) struct ethtool_rxfh rxfh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) u32 dev_indir_size = 0, dev_key_size = 0, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) u32 *indir = NULL, indir_bytes = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) u8 *hkey = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) u8 *rss_config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) u32 rss_cfg_offset = offsetof(struct ethtool_rxfh, rss_config[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) bool delete = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) if (!ops->get_rxnfc || !ops->set_rxfh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) if (ops->get_rxfh_indir_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) dev_indir_size = ops->get_rxfh_indir_size(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) if (ops->get_rxfh_key_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) dev_key_size = ops->get_rxfh_key_size(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) if (copy_from_user(&rxfh, useraddr, sizeof(rxfh)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) /* Check that reserved fields are 0 for now */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) if (rxfh.rsvd8[0] || rxfh.rsvd8[1] || rxfh.rsvd8[2] || rxfh.rsvd32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) /* Most drivers don't handle rss_context, check it's 0 as well */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) if (rxfh.rss_context && !ops->set_rxfh_context)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) /* If either indir, hash key or function is valid, proceed further.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) * Must request at least one change: indir size, hash key or function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) if ((rxfh.indir_size &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) rxfh.indir_size != dev_indir_size) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) (rxfh.key_size && (rxfh.key_size != dev_key_size)) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) (rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) rxfh.key_size == 0 && rxfh.hfunc == ETH_RSS_HASH_NO_CHANGE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) if (rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) indir_bytes = dev_indir_size * sizeof(indir[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) rss_config = kzalloc(indir_bytes + rxfh.key_size, GFP_USER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) if (!rss_config)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) rx_rings.cmd = ETHTOOL_GRXRINGS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) ret = ops->get_rxnfc(dev, &rx_rings, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) /* rxfh.indir_size == 0 means reset the indir table to default (master
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) * context) or delete the context (other RSS contexts).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) * rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE means leave it unchanged.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) if (rxfh.indir_size &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) indir = (u32 *)rss_config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) ret = ethtool_copy_validate_indir(indir,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) useraddr + rss_cfg_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) &rx_rings,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) rxfh.indir_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) } else if (rxfh.indir_size == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) if (rxfh.rss_context == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) indir = (u32 *)rss_config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) for (i = 0; i < dev_indir_size; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) delete = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) if (rxfh.key_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) hkey = rss_config + indir_bytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) if (copy_from_user(hkey,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) useraddr + rss_cfg_offset + indir_bytes,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) rxfh.key_size)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) if (rxfh.rss_context)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) ret = ops->set_rxfh_context(dev, indir, hkey, rxfh.hfunc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) &rxfh.rss_context, delete);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) ret = ops->set_rxfh(dev, indir, hkey, rxfh.hfunc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) if (copy_to_user(useraddr + offsetof(struct ethtool_rxfh, rss_context),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) &rxfh.rss_context, sizeof(rxfh.rss_context)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) if (!rxfh.rss_context) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) /* indicate whether rxfh was set to default */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) if (rxfh.indir_size == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) dev->priv_flags &= ~IFF_RXFH_CONFIGURED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) else if (rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) dev->priv_flags |= IFF_RXFH_CONFIGURED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) kfree(rss_config);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) struct ethtool_regs regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) const struct ethtool_ops *ops = dev->ethtool_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) void *regbuf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) int reglen, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) if (!ops->get_regs || !ops->get_regs_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) if (copy_from_user(®s, useraddr, sizeof(regs)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) reglen = ops->get_regs_len(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) if (reglen <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) return reglen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) if (regs.len > reglen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) regs.len = reglen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) regbuf = vzalloc(reglen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) if (!regbuf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) if (regs.len < reglen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372) reglen = regs.len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) ops->get_regs(dev, ®s, regbuf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) if (copy_to_user(useraddr, ®s, sizeof(regs)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) useraddr += offsetof(struct ethtool_regs, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) if (copy_to_user(useraddr, regbuf, reglen))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) vfree(regbuf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) static int ethtool_reset(struct net_device *dev, char __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) struct ethtool_value reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) if (!dev->ethtool_ops->reset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) if (copy_from_user(&reset, useraddr, sizeof(reset)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) ret = dev->ethtool_ops->reset(dev, &reset.data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) if (copy_to_user(useraddr, &reset, sizeof(reset)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) static int ethtool_get_wol(struct net_device *dev, char __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411) struct ethtool_wolinfo wol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) if (!dev->ethtool_ops->get_wol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) memset(&wol, 0, sizeof(struct ethtool_wolinfo));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) wol.cmd = ETHTOOL_GWOL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418) dev->ethtool_ops->get_wol(dev, &wol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) if (copy_to_user(useraddr, &wol, sizeof(wol)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) static int ethtool_set_wol(struct net_device *dev, char __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) struct ethtool_wolinfo wol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430) if (!dev->ethtool_ops->set_wol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) if (copy_from_user(&wol, useraddr, sizeof(wol)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) ret = dev->ethtool_ops->set_wol(dev, &wol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440) dev->wol_enabled = !!wol.wolopts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441) ethtool_notify(dev, ETHTOOL_MSG_WOL_NTF, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) static int ethtool_get_eee(struct net_device *dev, char __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) struct ethtool_eee edata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451) if (!dev->ethtool_ops->get_eee)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) memset(&edata, 0, sizeof(struct ethtool_eee));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455) edata.cmd = ETHTOOL_GEEE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) rc = dev->ethtool_ops->get_eee(dev, &edata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) if (copy_to_user(useraddr, &edata, sizeof(edata)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467) static int ethtool_set_eee(struct net_device *dev, char __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) struct ethtool_eee edata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) if (!dev->ethtool_ops->set_eee)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475) if (copy_from_user(&edata, useraddr, sizeof(edata)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) ret = dev->ethtool_ops->set_eee(dev, &edata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480) ethtool_notify(dev, ETHTOOL_MSG_EEE_NTF, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) static int ethtool_nway_reset(struct net_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486) if (!dev->ethtool_ops->nway_reset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) return dev->ethtool_ops->nway_reset(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492) static int ethtool_get_link(struct net_device *dev, char __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494) struct ethtool_value edata = { .cmd = ETHTOOL_GLINK };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495) int link = __ethtool_get_link(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497) if (link < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498) return link;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500) edata.data = link;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501) if (copy_to_user(useraddr, &edata, sizeof(edata)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506) static int ethtool_get_any_eeprom(struct net_device *dev, void __user *useraddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507) int (*getter)(struct net_device *,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508) struct ethtool_eeprom *, u8 *),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509) u32 total_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511) struct ethtool_eeprom eeprom;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512) void __user *userbuf = useraddr + sizeof(eeprom);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513) u32 bytes_remaining;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514) u8 *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517) if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520) /* Check for wrap and zero */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521) if (eeprom.offset + eeprom.len <= eeprom.offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524) /* Check for exceeding total eeprom len */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525) if (eeprom.offset + eeprom.len > total_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528) data = kzalloc(PAGE_SIZE, GFP_USER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529) if (!data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532) bytes_remaining = eeprom.len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533) while (bytes_remaining > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534) eeprom.len = min(bytes_remaining, (u32)PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536) ret = getter(dev, &eeprom, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539) if (copy_to_user(userbuf, data, eeprom.len)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1541) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1542) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1543) userbuf += eeprom.len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544) eeprom.offset += eeprom.len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545) bytes_remaining -= eeprom.len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548) eeprom.len = userbuf - (useraddr + sizeof(eeprom));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549) eeprom.offset -= eeprom.len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550) if (copy_to_user(useraddr, &eeprom, sizeof(eeprom)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553) kfree(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557) static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559) const struct ethtool_ops *ops = dev->ethtool_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561) if (!ops->get_eeprom || !ops->get_eeprom_len ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562) !ops->get_eeprom_len(dev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565) return ethtool_get_any_eeprom(dev, useraddr, ops->get_eeprom,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566) ops->get_eeprom_len(dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569) static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571) struct ethtool_eeprom eeprom;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572) const struct ethtool_ops *ops = dev->ethtool_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573) void __user *userbuf = useraddr + sizeof(eeprom);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574) u32 bytes_remaining;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575) u8 *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578) if (!ops->set_eeprom || !ops->get_eeprom_len ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) !ops->get_eeprom_len(dev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1580) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1582) if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1583) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1584)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1585) /* Check for wrap and zero */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1586) if (eeprom.offset + eeprom.len <= eeprom.offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1587) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1589) /* Check for exceeding total eeprom len */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1590) if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1591) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1593) data = kzalloc(PAGE_SIZE, GFP_USER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1594) if (!data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1595) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1596)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1597) bytes_remaining = eeprom.len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1598) while (bytes_remaining > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1599) eeprom.len = min(bytes_remaining, (u32)PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1601) if (copy_from_user(data, userbuf, eeprom.len)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1602) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1603) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1604) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1605) ret = ops->set_eeprom(dev, &eeprom, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1606) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1607) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1608) userbuf += eeprom.len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1609) eeprom.offset += eeprom.len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1610) bytes_remaining -= eeprom.len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1611) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1612)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1613) kfree(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1614) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1615) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1617) static noinline_for_stack int ethtool_get_coalesce(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1618) void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1619) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1620) struct ethtool_coalesce coalesce = { .cmd = ETHTOOL_GCOALESCE };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1621) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1622)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1623) if (!dev->ethtool_ops->get_coalesce)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1624) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1625)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1626) ret = dev->ethtool_ops->get_coalesce(dev, &coalesce);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1627) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1628) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1630) if (copy_to_user(useraddr, &coalesce, sizeof(coalesce)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1631) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1632) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1633) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1635) static bool
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1636) ethtool_set_coalesce_supported(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1637) struct ethtool_coalesce *coalesce)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1638) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1639) u32 supported_params = dev->ethtool_ops->supported_coalesce_params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1640) u32 nonzero_params = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1641)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1642) if (coalesce->rx_coalesce_usecs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1643) nonzero_params |= ETHTOOL_COALESCE_RX_USECS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1644) if (coalesce->rx_max_coalesced_frames)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1645) nonzero_params |= ETHTOOL_COALESCE_RX_MAX_FRAMES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1646) if (coalesce->rx_coalesce_usecs_irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1647) nonzero_params |= ETHTOOL_COALESCE_RX_USECS_IRQ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1648) if (coalesce->rx_max_coalesced_frames_irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1649) nonzero_params |= ETHTOOL_COALESCE_RX_MAX_FRAMES_IRQ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1650) if (coalesce->tx_coalesce_usecs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1651) nonzero_params |= ETHTOOL_COALESCE_TX_USECS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1652) if (coalesce->tx_max_coalesced_frames)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1653) nonzero_params |= ETHTOOL_COALESCE_TX_MAX_FRAMES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1654) if (coalesce->tx_coalesce_usecs_irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1655) nonzero_params |= ETHTOOL_COALESCE_TX_USECS_IRQ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1656) if (coalesce->tx_max_coalesced_frames_irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1657) nonzero_params |= ETHTOOL_COALESCE_TX_MAX_FRAMES_IRQ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1658) if (coalesce->stats_block_coalesce_usecs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1659) nonzero_params |= ETHTOOL_COALESCE_STATS_BLOCK_USECS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1660) if (coalesce->use_adaptive_rx_coalesce)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1661) nonzero_params |= ETHTOOL_COALESCE_USE_ADAPTIVE_RX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1662) if (coalesce->use_adaptive_tx_coalesce)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1663) nonzero_params |= ETHTOOL_COALESCE_USE_ADAPTIVE_TX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1664) if (coalesce->pkt_rate_low)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1665) nonzero_params |= ETHTOOL_COALESCE_PKT_RATE_LOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1666) if (coalesce->rx_coalesce_usecs_low)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1667) nonzero_params |= ETHTOOL_COALESCE_RX_USECS_LOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1668) if (coalesce->rx_max_coalesced_frames_low)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1669) nonzero_params |= ETHTOOL_COALESCE_RX_MAX_FRAMES_LOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1670) if (coalesce->tx_coalesce_usecs_low)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1671) nonzero_params |= ETHTOOL_COALESCE_TX_USECS_LOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1672) if (coalesce->tx_max_coalesced_frames_low)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1673) nonzero_params |= ETHTOOL_COALESCE_TX_MAX_FRAMES_LOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1674) if (coalesce->pkt_rate_high)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1675) nonzero_params |= ETHTOOL_COALESCE_PKT_RATE_HIGH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1676) if (coalesce->rx_coalesce_usecs_high)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1677) nonzero_params |= ETHTOOL_COALESCE_RX_USECS_HIGH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1678) if (coalesce->rx_max_coalesced_frames_high)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1679) nonzero_params |= ETHTOOL_COALESCE_RX_MAX_FRAMES_HIGH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1680) if (coalesce->tx_coalesce_usecs_high)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1681) nonzero_params |= ETHTOOL_COALESCE_TX_USECS_HIGH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1682) if (coalesce->tx_max_coalesced_frames_high)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1683) nonzero_params |= ETHTOOL_COALESCE_TX_MAX_FRAMES_HIGH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1684) if (coalesce->rate_sample_interval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1685) nonzero_params |= ETHTOOL_COALESCE_RATE_SAMPLE_INTERVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1686)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1687) return (supported_params & nonzero_params) == nonzero_params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1688) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1689)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1690) static noinline_for_stack int ethtool_set_coalesce(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1691) void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1692) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1693) struct ethtool_coalesce coalesce;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1694) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1696) if (!dev->ethtool_ops->set_coalesce)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1697) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1698)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1699) if (copy_from_user(&coalesce, useraddr, sizeof(coalesce)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1700) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1702) if (!ethtool_set_coalesce_supported(dev, &coalesce))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1703) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1705) ret = dev->ethtool_ops->set_coalesce(dev, &coalesce);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1706) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1707) ethtool_notify(dev, ETHTOOL_MSG_COALESCE_NTF, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1708) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1709) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1711) static int ethtool_get_ringparam(struct net_device *dev, void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1712) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1713) struct ethtool_ringparam ringparam = { .cmd = ETHTOOL_GRINGPARAM };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1714)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1715) if (!dev->ethtool_ops->get_ringparam)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1716) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1717)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1718) dev->ethtool_ops->get_ringparam(dev, &ringparam);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1719)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1720) if (copy_to_user(useraddr, &ringparam, sizeof(ringparam)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1721) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1722) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1723) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1724)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1725) static int ethtool_set_ringparam(struct net_device *dev, void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1726) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1727) struct ethtool_ringparam ringparam, max = { .cmd = ETHTOOL_GRINGPARAM };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1728) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1729)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1730) if (!dev->ethtool_ops->set_ringparam || !dev->ethtool_ops->get_ringparam)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1731) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1732)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1733) if (copy_from_user(&ringparam, useraddr, sizeof(ringparam)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1734) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1735)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1736) dev->ethtool_ops->get_ringparam(dev, &max);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1737)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1738) /* ensure new ring parameters are within the maximums */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1739) if (ringparam.rx_pending > max.rx_max_pending ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1740) ringparam.rx_mini_pending > max.rx_mini_max_pending ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1741) ringparam.rx_jumbo_pending > max.rx_jumbo_max_pending ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1742) ringparam.tx_pending > max.tx_max_pending)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1743) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1744)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1745) ret = dev->ethtool_ops->set_ringparam(dev, &ringparam);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1746) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1747) ethtool_notify(dev, ETHTOOL_MSG_RINGS_NTF, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1748) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1749) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1750)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1751) static noinline_for_stack int ethtool_get_channels(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1752) void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1753) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1754) struct ethtool_channels channels = { .cmd = ETHTOOL_GCHANNELS };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1755)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1756) if (!dev->ethtool_ops->get_channels)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1757) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1758)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1759) dev->ethtool_ops->get_channels(dev, &channels);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1760)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1761) if (copy_to_user(useraddr, &channels, sizeof(channels)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1762) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1763) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1764) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1765)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1766) static noinline_for_stack int ethtool_set_channels(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1767) void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1768) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1769) struct ethtool_channels channels, curr = { .cmd = ETHTOOL_GCHANNELS };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1770) u16 from_channel, to_channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1771) u32 max_rx_in_use = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1772) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1773) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1774)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1775) if (!dev->ethtool_ops->set_channels || !dev->ethtool_ops->get_channels)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1776) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1777)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1778) if (copy_from_user(&channels, useraddr, sizeof(channels)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1779) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1780)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1781) dev->ethtool_ops->get_channels(dev, &curr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1782)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1783) if (channels.rx_count == curr.rx_count &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1784) channels.tx_count == curr.tx_count &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1785) channels.combined_count == curr.combined_count &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1786) channels.other_count == curr.other_count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1787) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1788)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1789) /* ensure new counts are within the maximums */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1790) if (channels.rx_count > curr.max_rx ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1791) channels.tx_count > curr.max_tx ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1792) channels.combined_count > curr.max_combined ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1793) channels.other_count > curr.max_other)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1794) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1795)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1796) /* ensure there is at least one RX and one TX channel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1797) if (!channels.combined_count &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1798) (!channels.rx_count || !channels.tx_count))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1799) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1800)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1801) /* ensure the new Rx count fits within the configured Rx flow
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1802) * indirection table settings */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1803) if (netif_is_rxfh_configured(dev) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1804) !ethtool_get_max_rxfh_channel(dev, &max_rx_in_use) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1805) (channels.combined_count + channels.rx_count) <= max_rx_in_use)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1806) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1807)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1808) /* Disabling channels, query zero-copy AF_XDP sockets */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1809) from_channel = channels.combined_count +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1810) min(channels.rx_count, channels.tx_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1811) to_channel = curr.combined_count + max(curr.rx_count, curr.tx_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1812) for (i = from_channel; i < to_channel; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1813) if (xsk_get_pool_from_qid(dev, i))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1814) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1815)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1816) ret = dev->ethtool_ops->set_channels(dev, &channels);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1817) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1818) ethtool_notify(dev, ETHTOOL_MSG_CHANNELS_NTF, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1819) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1820) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1821)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1822) static int ethtool_get_pauseparam(struct net_device *dev, void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1823) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1824) struct ethtool_pauseparam pauseparam = { .cmd = ETHTOOL_GPAUSEPARAM };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1825)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1826) if (!dev->ethtool_ops->get_pauseparam)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1827) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1828)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1829) dev->ethtool_ops->get_pauseparam(dev, &pauseparam);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1830)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1831) if (copy_to_user(useraddr, &pauseparam, sizeof(pauseparam)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1832) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1833) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1834) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1835)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1836) static int ethtool_set_pauseparam(struct net_device *dev, void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1837) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1838) struct ethtool_pauseparam pauseparam;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1839) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1840)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1841) if (!dev->ethtool_ops->set_pauseparam)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1842) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1843)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1844) if (copy_from_user(&pauseparam, useraddr, sizeof(pauseparam)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1845) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1846)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1847) ret = dev->ethtool_ops->set_pauseparam(dev, &pauseparam);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1848) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1849) ethtool_notify(dev, ETHTOOL_MSG_PAUSE_NTF, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1850) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1851) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1852)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1853) static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1854) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1855) struct ethtool_test test;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1856) const struct ethtool_ops *ops = dev->ethtool_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1857) u64 *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1858) int ret, test_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1859)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1860) if (!ops->self_test || !ops->get_sset_count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1861) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1862)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1863) test_len = ops->get_sset_count(dev, ETH_SS_TEST);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1864) if (test_len < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1865) return test_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1866) WARN_ON(test_len == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1867)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1868) if (copy_from_user(&test, useraddr, sizeof(test)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1869) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1870)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1871) test.len = test_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1872) data = kcalloc(test_len, sizeof(u64), GFP_USER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1873) if (!data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1874) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1875)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1876) netif_testing_on(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1877) ops->self_test(dev, &test, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1878) netif_testing_off(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1879)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1880) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1881) if (copy_to_user(useraddr, &test, sizeof(test)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1882) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1883) useraddr += sizeof(test);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1884) if (copy_to_user(useraddr, data, test.len * sizeof(u64)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1885) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1886) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1887)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1888) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1889) kfree(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1890) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1891) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1892)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1893) static int ethtool_get_strings(struct net_device *dev, void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1894) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1895) struct ethtool_gstrings gstrings;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1896) u8 *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1897) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1898)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1899) if (copy_from_user(&gstrings, useraddr, sizeof(gstrings)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1900) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1901)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1902) ret = __ethtool_get_sset_count(dev, gstrings.string_set);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1903) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1904) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1905) if (ret > S32_MAX / ETH_GSTRING_LEN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1906) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1907) WARN_ON_ONCE(!ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1908)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1909) gstrings.len = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1910)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1911) if (gstrings.len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1912) data = vzalloc(array_size(gstrings.len, ETH_GSTRING_LEN));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1913) if (!data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1914) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1915)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1916) __ethtool_get_strings(dev, gstrings.string_set, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1917) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1918) data = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1919) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1920)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1921) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1922) if (copy_to_user(useraddr, &gstrings, sizeof(gstrings)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1923) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1924) useraddr += sizeof(gstrings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1925) if (gstrings.len &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1926) copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1927) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1928) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1929)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1930) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1931) vfree(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1932) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1933) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1934)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1935) static int ethtool_phys_id(struct net_device *dev, void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1936) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1937) struct ethtool_value id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1938) static bool busy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1939) const struct ethtool_ops *ops = dev->ethtool_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1940) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1941)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1942) if (!ops->set_phys_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1943) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1944)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1945) if (busy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1946) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1947)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1948) if (copy_from_user(&id, useraddr, sizeof(id)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1949) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1950)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1951) rc = ops->set_phys_id(dev, ETHTOOL_ID_ACTIVE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1952) if (rc < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1953) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1954)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1955) /* Drop the RTNL lock while waiting, but prevent reentry or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1956) * removal of the device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1957) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1958) busy = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1959) dev_hold(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1960) rtnl_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1961)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1962) if (rc == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1963) /* Driver will handle this itself */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1964) schedule_timeout_interruptible(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1965) id.data ? (id.data * HZ) : MAX_SCHEDULE_TIMEOUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1966) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1967) /* Driver expects to be called at twice the frequency in rc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1968) int n = rc * 2, interval = HZ / n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1969) u64 count = n * id.data, i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1970)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1971) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1972) rtnl_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1973) rc = ops->set_phys_id(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1974) (i++ & 1) ? ETHTOOL_ID_OFF : ETHTOOL_ID_ON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1975) rtnl_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1976) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1977) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1978) schedule_timeout_interruptible(interval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1979) } while (!signal_pending(current) && (!id.data || i < count));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1980) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1981)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1982) rtnl_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1983) dev_put(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1984) busy = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1985)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1986) (void) ops->set_phys_id(dev, ETHTOOL_ID_INACTIVE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1987) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1988) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1989)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1990) static int ethtool_get_stats(struct net_device *dev, void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1991) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1992) struct ethtool_stats stats;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1993) const struct ethtool_ops *ops = dev->ethtool_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1994) u64 *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1995) int ret, n_stats;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1996)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1997) if (!ops->get_ethtool_stats || !ops->get_sset_count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1998) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1999)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2000) n_stats = ops->get_sset_count(dev, ETH_SS_STATS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2001) if (n_stats < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2002) return n_stats;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2003) if (n_stats > S32_MAX / sizeof(u64))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2004) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2005) WARN_ON_ONCE(!n_stats);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2006) if (copy_from_user(&stats, useraddr, sizeof(stats)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2007) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2008)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2009) stats.n_stats = n_stats;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2010)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2011) if (n_stats) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2012) data = vzalloc(array_size(n_stats, sizeof(u64)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2013) if (!data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2014) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2015) ops->get_ethtool_stats(dev, &stats, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2016) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2017) data = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2018) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2019)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2020) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2021) if (copy_to_user(useraddr, &stats, sizeof(stats)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2022) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2023) useraddr += sizeof(stats);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2024) if (n_stats && copy_to_user(useraddr, data, array_size(n_stats, sizeof(u64))))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2025) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2026) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2027)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2028) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2029) vfree(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2030) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2031) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2032)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2033) static int ethtool_get_phy_stats(struct net_device *dev, void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2034) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2035) const struct ethtool_phy_ops *phy_ops = ethtool_phy_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2036) const struct ethtool_ops *ops = dev->ethtool_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2037) struct phy_device *phydev = dev->phydev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2038) struct ethtool_stats stats;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2039) u64 *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2040) int ret, n_stats;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2041)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2042) if (!phydev && (!ops->get_ethtool_phy_stats || !ops->get_sset_count))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2043) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2044)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2045) if (dev->phydev && !ops->get_ethtool_phy_stats &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2046) phy_ops && phy_ops->get_sset_count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2047) n_stats = phy_ops->get_sset_count(dev->phydev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2048) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2049) n_stats = ops->get_sset_count(dev, ETH_SS_PHY_STATS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2050) if (n_stats < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2051) return n_stats;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2052) if (n_stats > S32_MAX / sizeof(u64))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2053) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2054) WARN_ON_ONCE(!n_stats);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2055)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2056) if (copy_from_user(&stats, useraddr, sizeof(stats)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2057) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2058)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2059) stats.n_stats = n_stats;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2060)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2061) if (n_stats) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2062) data = vzalloc(array_size(n_stats, sizeof(u64)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2063) if (!data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2064) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2065)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2066) if (dev->phydev && !ops->get_ethtool_phy_stats &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2067) phy_ops && phy_ops->get_stats) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2068) ret = phy_ops->get_stats(dev->phydev, &stats, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2069) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2070) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2071) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2072) ops->get_ethtool_phy_stats(dev, &stats, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2073) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2074) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2075) data = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2076) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2077)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2078) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2079) if (copy_to_user(useraddr, &stats, sizeof(stats)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2080) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2081) useraddr += sizeof(stats);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2082) if (n_stats && copy_to_user(useraddr, data, array_size(n_stats, sizeof(u64))))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2083) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2084) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2085)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2086) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2087) vfree(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2088) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2089) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2090)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2091) static int ethtool_get_perm_addr(struct net_device *dev, void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2092) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2093) struct ethtool_perm_addr epaddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2094)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2095) if (copy_from_user(&epaddr, useraddr, sizeof(epaddr)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2096) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2097)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2098) if (epaddr.size < dev->addr_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2099) return -ETOOSMALL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2100) epaddr.size = dev->addr_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2102) if (copy_to_user(useraddr, &epaddr, sizeof(epaddr)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2103) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2104) useraddr += sizeof(epaddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2105) if (copy_to_user(useraddr, dev->perm_addr, epaddr.size))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2106) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2107) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2108) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2110) static int ethtool_get_value(struct net_device *dev, char __user *useraddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2111) u32 cmd, u32 (*actor)(struct net_device *))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2112) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2113) struct ethtool_value edata = { .cmd = cmd };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2115) if (!actor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2116) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2118) edata.data = actor(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2120) if (copy_to_user(useraddr, &edata, sizeof(edata)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2121) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2122) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2125) static int ethtool_set_value_void(struct net_device *dev, char __user *useraddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2126) void (*actor)(struct net_device *, u32))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2127) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2128) struct ethtool_value edata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2130) if (!actor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2131) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2133) if (copy_from_user(&edata, useraddr, sizeof(edata)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2134) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2136) actor(dev, edata.data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2137) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2140) static int ethtool_set_value(struct net_device *dev, char __user *useraddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2141) int (*actor)(struct net_device *, u32))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2142) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2143) struct ethtool_value edata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2145) if (!actor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2146) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2148) if (copy_from_user(&edata, useraddr, sizeof(edata)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2149) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2151) return actor(dev, edata.data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2154) static noinline_for_stack int ethtool_flash_device(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2155) char __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2156) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2157) struct ethtool_flash efl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2159) if (copy_from_user(&efl, useraddr, sizeof(efl)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2160) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2161) efl.data[ETHTOOL_FLASH_MAX_FILENAME - 1] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2163) if (!dev->ethtool_ops->flash_device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2164) return devlink_compat_flash_update(dev, efl.data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2166) return dev->ethtool_ops->flash_device(dev, &efl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2167) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2169) static int ethtool_set_dump(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2170) void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2171) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2172) struct ethtool_dump dump;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2174) if (!dev->ethtool_ops->set_dump)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2175) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2177) if (copy_from_user(&dump, useraddr, sizeof(dump)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2178) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2180) return dev->ethtool_ops->set_dump(dev, &dump);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2181) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2183) static int ethtool_get_dump_flag(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2184) void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2185) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2186) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2187) struct ethtool_dump dump;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2188) const struct ethtool_ops *ops = dev->ethtool_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2190) if (!ops->get_dump_flag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2191) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2193) if (copy_from_user(&dump, useraddr, sizeof(dump)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2194) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2196) ret = ops->get_dump_flag(dev, &dump);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2197) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2198) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2200) if (copy_to_user(useraddr, &dump, sizeof(dump)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2201) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2202) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2203) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2205) static int ethtool_get_dump_data(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2206) void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2207) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2208) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2209) __u32 len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2210) struct ethtool_dump dump, tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2211) const struct ethtool_ops *ops = dev->ethtool_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2212) void *data = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2214) if (!ops->get_dump_data || !ops->get_dump_flag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2215) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2217) if (copy_from_user(&dump, useraddr, sizeof(dump)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2218) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2220) memset(&tmp, 0, sizeof(tmp));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2221) tmp.cmd = ETHTOOL_GET_DUMP_FLAG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2222) ret = ops->get_dump_flag(dev, &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2223) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2224) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2226) len = min(tmp.len, dump.len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2227) if (!len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2228) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2230) /* Don't ever let the driver think there's more space available
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2231) * than it requested with .get_dump_flag().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2232) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2233) dump.len = len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2235) /* Always allocate enough space to hold the whole thing so that the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2236) * driver does not need to check the length and bother with partial
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2237) * dumping.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2238) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2239) data = vzalloc(tmp.len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2240) if (!data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2241) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2242) ret = ops->get_dump_data(dev, &dump, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2243) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2244) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2246) /* There are two sane possibilities:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2247) * 1. The driver's .get_dump_data() does not touch dump.len.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2248) * 2. Or it may set dump.len to how much it really writes, which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2249) * should be tmp.len (or len if it can do a partial dump).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2250) * In any case respond to userspace with the actual length of data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2251) * it's receiving.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2252) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2253) WARN_ON(dump.len != len && dump.len != tmp.len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2254) dump.len = len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2256) if (copy_to_user(useraddr, &dump, sizeof(dump))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2257) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2258) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2260) useraddr += offsetof(struct ethtool_dump, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2261) if (copy_to_user(useraddr, data, len))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2262) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2263) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2264) vfree(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2265) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2266) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2268) static int ethtool_get_ts_info(struct net_device *dev, void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2269) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2270) struct ethtool_ts_info info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2271) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2273) err = __ethtool_get_ts_info(dev, &info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2274) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2275) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2277) if (copy_to_user(useraddr, &info, sizeof(info)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2278) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2280) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2281) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2283) static int __ethtool_get_module_info(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2284) struct ethtool_modinfo *modinfo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2285) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2286) const struct ethtool_ops *ops = dev->ethtool_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2287) struct phy_device *phydev = dev->phydev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2289) if (dev->sfp_bus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2290) return sfp_get_module_info(dev->sfp_bus, modinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2292) if (phydev && phydev->drv && phydev->drv->module_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2293) return phydev->drv->module_info(phydev, modinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2295) if (ops->get_module_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2296) return ops->get_module_info(dev, modinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2298) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2299) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2301) static int ethtool_get_module_info(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2302) void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2303) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2304) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2305) struct ethtool_modinfo modinfo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2307) if (copy_from_user(&modinfo, useraddr, sizeof(modinfo)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2308) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2310) ret = __ethtool_get_module_info(dev, &modinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2311) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2312) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2314) if (copy_to_user(useraddr, &modinfo, sizeof(modinfo)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2315) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2317) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2318) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2320) static int __ethtool_get_module_eeprom(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2321) struct ethtool_eeprom *ee, u8 *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2322) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2323) const struct ethtool_ops *ops = dev->ethtool_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2324) struct phy_device *phydev = dev->phydev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2326) if (dev->sfp_bus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2327) return sfp_get_module_eeprom(dev->sfp_bus, ee, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2329) if (phydev && phydev->drv && phydev->drv->module_eeprom)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2330) return phydev->drv->module_eeprom(phydev, ee, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2332) if (ops->get_module_eeprom)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2333) return ops->get_module_eeprom(dev, ee, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2335) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2336) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2338) static int ethtool_get_module_eeprom(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2339) void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2340) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2341) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2342) struct ethtool_modinfo modinfo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2344) ret = __ethtool_get_module_info(dev, &modinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2345) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2346) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2348) return ethtool_get_any_eeprom(dev, useraddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2349) __ethtool_get_module_eeprom,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2350) modinfo.eeprom_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2351) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2353) static int ethtool_tunable_valid(const struct ethtool_tunable *tuna)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2354) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2355) switch (tuna->id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2356) case ETHTOOL_RX_COPYBREAK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2357) case ETHTOOL_TX_COPYBREAK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2358) if (tuna->len != sizeof(u32) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2359) tuna->type_id != ETHTOOL_TUNABLE_U32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2360) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2361) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2362) case ETHTOOL_PFC_PREVENTION_TOUT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2363) if (tuna->len != sizeof(u16) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2364) tuna->type_id != ETHTOOL_TUNABLE_U16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2365) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2366) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2367) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2368) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2369) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2371) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2372) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2374) static int ethtool_get_tunable(struct net_device *dev, void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2375) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2376) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2377) struct ethtool_tunable tuna;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2378) const struct ethtool_ops *ops = dev->ethtool_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2379) void *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2381) if (!ops->get_tunable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2382) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2383) if (copy_from_user(&tuna, useraddr, sizeof(tuna)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2384) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2385) ret = ethtool_tunable_valid(&tuna);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2386) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2387) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2388) data = kzalloc(tuna.len, GFP_USER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2389) if (!data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2390) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2391) ret = ops->get_tunable(dev, &tuna, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2392) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2393) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2394) useraddr += sizeof(tuna);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2395) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2396) if (copy_to_user(useraddr, data, tuna.len))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2397) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2398) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2400) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2401) kfree(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2402) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2403) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2405) static int ethtool_set_tunable(struct net_device *dev, void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2406) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2407) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2408) struct ethtool_tunable tuna;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2409) const struct ethtool_ops *ops = dev->ethtool_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2410) void *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2412) if (!ops->set_tunable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2413) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2414) if (copy_from_user(&tuna, useraddr, sizeof(tuna)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2415) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2416) ret = ethtool_tunable_valid(&tuna);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2417) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2418) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2419) useraddr += sizeof(tuna);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2420) data = memdup_user(useraddr, tuna.len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2421) if (IS_ERR(data))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2422) return PTR_ERR(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2423) ret = ops->set_tunable(dev, &tuna, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2425) kfree(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2426) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2427) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2429) static noinline_for_stack int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2430) ethtool_get_per_queue_coalesce(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2431) void __user *useraddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2432) struct ethtool_per_queue_op *per_queue_opt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2433) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2434) u32 bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2435) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2436) DECLARE_BITMAP(queue_mask, MAX_NUM_QUEUE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2438) if (!dev->ethtool_ops->get_per_queue_coalesce)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2439) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2441) useraddr += sizeof(*per_queue_opt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2443) bitmap_from_arr32(queue_mask, per_queue_opt->queue_mask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2444) MAX_NUM_QUEUE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2446) for_each_set_bit(bit, queue_mask, MAX_NUM_QUEUE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2447) struct ethtool_coalesce coalesce = { .cmd = ETHTOOL_GCOALESCE };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2449) ret = dev->ethtool_ops->get_per_queue_coalesce(dev, bit, &coalesce);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2450) if (ret != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2451) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2452) if (copy_to_user(useraddr, &coalesce, sizeof(coalesce)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2453) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2454) useraddr += sizeof(coalesce);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2455) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2457) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2458) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2460) static noinline_for_stack int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2461) ethtool_set_per_queue_coalesce(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2462) void __user *useraddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2463) struct ethtool_per_queue_op *per_queue_opt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2464) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2465) u32 bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2466) int i, ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2467) int n_queue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2468) struct ethtool_coalesce *backup = NULL, *tmp = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2469) DECLARE_BITMAP(queue_mask, MAX_NUM_QUEUE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2471) if ((!dev->ethtool_ops->set_per_queue_coalesce) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2472) (!dev->ethtool_ops->get_per_queue_coalesce))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2473) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2475) useraddr += sizeof(*per_queue_opt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2477) bitmap_from_arr32(queue_mask, per_queue_opt->queue_mask, MAX_NUM_QUEUE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2478) n_queue = bitmap_weight(queue_mask, MAX_NUM_QUEUE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2479) tmp = backup = kmalloc_array(n_queue, sizeof(*backup), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2480) if (!backup)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2481) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2483) for_each_set_bit(bit, queue_mask, MAX_NUM_QUEUE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2484) struct ethtool_coalesce coalesce;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2486) ret = dev->ethtool_ops->get_per_queue_coalesce(dev, bit, tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2487) if (ret != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2488) goto roll_back;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2489)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2490) tmp++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2492) if (copy_from_user(&coalesce, useraddr, sizeof(coalesce))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2493) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2494) goto roll_back;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2495) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2497) if (!ethtool_set_coalesce_supported(dev, &coalesce)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2498) ret = -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2499) goto roll_back;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2500) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2502) ret = dev->ethtool_ops->set_per_queue_coalesce(dev, bit, &coalesce);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2503) if (ret != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2504) goto roll_back;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2505)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2506) useraddr += sizeof(coalesce);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2507) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2508)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2509) roll_back:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2510) if (ret != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2511) tmp = backup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2512) for_each_set_bit(i, queue_mask, bit) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2513) dev->ethtool_ops->set_per_queue_coalesce(dev, i, tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2514) tmp++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2515) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2516) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2517) kfree(backup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2518)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2519) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2520) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2522) static int noinline_for_stack ethtool_set_per_queue(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2523) void __user *useraddr, u32 sub_cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2524) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2525) struct ethtool_per_queue_op per_queue_opt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2526)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2527) if (copy_from_user(&per_queue_opt, useraddr, sizeof(per_queue_opt)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2528) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2530) if (per_queue_opt.sub_command != sub_cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2531) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2533) switch (per_queue_opt.sub_command) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2534) case ETHTOOL_GCOALESCE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2535) return ethtool_get_per_queue_coalesce(dev, useraddr, &per_queue_opt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2536) case ETHTOOL_SCOALESCE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2537) return ethtool_set_per_queue_coalesce(dev, useraddr, &per_queue_opt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2538) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2539) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2540) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2541) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2542)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2543) static int ethtool_phy_tunable_valid(const struct ethtool_tunable *tuna)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2544) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2545) switch (tuna->id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2546) case ETHTOOL_PHY_DOWNSHIFT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2547) case ETHTOOL_PHY_FAST_LINK_DOWN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2548) if (tuna->len != sizeof(u8) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2549) tuna->type_id != ETHTOOL_TUNABLE_U8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2550) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2551) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2552) case ETHTOOL_PHY_EDPD:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2553) if (tuna->len != sizeof(u16) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2554) tuna->type_id != ETHTOOL_TUNABLE_U16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2555) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2556) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2557) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2558) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2559) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2561) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2562) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2564) static int get_phy_tunable(struct net_device *dev, void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2565) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2566) struct phy_device *phydev = dev->phydev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2567) struct ethtool_tunable tuna;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2568) bool phy_drv_tunable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2569) void *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2570) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2571)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2572) phy_drv_tunable = phydev && phydev->drv && phydev->drv->get_tunable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2573) if (!phy_drv_tunable && !dev->ethtool_ops->get_phy_tunable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2574) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2575) if (copy_from_user(&tuna, useraddr, sizeof(tuna)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2576) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2577) ret = ethtool_phy_tunable_valid(&tuna);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2578) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2579) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2580) data = kzalloc(tuna.len, GFP_USER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2581) if (!data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2582) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2583) if (phy_drv_tunable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2584) mutex_lock(&phydev->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2585) ret = phydev->drv->get_tunable(phydev, &tuna, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2586) mutex_unlock(&phydev->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2587) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2588) ret = dev->ethtool_ops->get_phy_tunable(dev, &tuna, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2589) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2590) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2591) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2592) useraddr += sizeof(tuna);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2593) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2594) if (copy_to_user(useraddr, data, tuna.len))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2595) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2596) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2598) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2599) kfree(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2600) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2601) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2603) static int set_phy_tunable(struct net_device *dev, void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2604) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2605) struct phy_device *phydev = dev->phydev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2606) struct ethtool_tunable tuna;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2607) bool phy_drv_tunable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2608) void *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2609) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2610)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2611) phy_drv_tunable = phydev && phydev->drv && phydev->drv->get_tunable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2612) if (!phy_drv_tunable && !dev->ethtool_ops->set_phy_tunable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2613) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2614) if (copy_from_user(&tuna, useraddr, sizeof(tuna)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2615) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2616) ret = ethtool_phy_tunable_valid(&tuna);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2617) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2618) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2619) useraddr += sizeof(tuna);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2620) data = memdup_user(useraddr, tuna.len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2621) if (IS_ERR(data))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2622) return PTR_ERR(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2623) if (phy_drv_tunable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2624) mutex_lock(&phydev->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2625) ret = phydev->drv->set_tunable(phydev, &tuna, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2626) mutex_unlock(&phydev->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2627) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2628) ret = dev->ethtool_ops->set_phy_tunable(dev, &tuna, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2629) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2630)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2631) kfree(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2632) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2633) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2635) static int ethtool_get_fecparam(struct net_device *dev, void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2636) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2637) struct ethtool_fecparam fecparam = { .cmd = ETHTOOL_GFECPARAM };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2638) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2640) if (!dev->ethtool_ops->get_fecparam)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2641) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2642)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2643) rc = dev->ethtool_ops->get_fecparam(dev, &fecparam);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2644) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2645) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2647) if (copy_to_user(useraddr, &fecparam, sizeof(fecparam)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2648) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2649) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2650) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2652) static int ethtool_set_fecparam(struct net_device *dev, void __user *useraddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2653) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2654) struct ethtool_fecparam fecparam;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2655)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2656) if (!dev->ethtool_ops->set_fecparam)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2657) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2659) if (copy_from_user(&fecparam, useraddr, sizeof(fecparam)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2660) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2662) return dev->ethtool_ops->set_fecparam(dev, &fecparam);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2663) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2665) /* The main entry point in this file. Called from net/core/dev_ioctl.c */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2667) int dev_ethtool(struct net *net, struct ifreq *ifr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2668) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2669) struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2670) void __user *useraddr = ifr->ifr_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2671) u32 ethcmd, sub_cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2672) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2673) netdev_features_t old_features;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2675) if (!dev || !netif_device_present(dev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2676) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2677)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2678) if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2679) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2680)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2681) if (ethcmd == ETHTOOL_PERQUEUE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2682) if (copy_from_user(&sub_cmd, useraddr + sizeof(ethcmd), sizeof(sub_cmd)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2683) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2684) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2685) sub_cmd = ethcmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2686) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2687) /* Allow some commands to be done by anyone */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2688) switch (sub_cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2689) case ETHTOOL_GSET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2690) case ETHTOOL_GDRVINFO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2691) case ETHTOOL_GMSGLVL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2692) case ETHTOOL_GLINK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2693) case ETHTOOL_GCOALESCE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2694) case ETHTOOL_GRINGPARAM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2695) case ETHTOOL_GPAUSEPARAM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2696) case ETHTOOL_GRXCSUM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2697) case ETHTOOL_GTXCSUM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2698) case ETHTOOL_GSG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2699) case ETHTOOL_GSSET_INFO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2700) case ETHTOOL_GSTRINGS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2701) case ETHTOOL_GSTATS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2702) case ETHTOOL_GPHYSTATS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2703) case ETHTOOL_GTSO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2704) case ETHTOOL_GPERMADDR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2705) case ETHTOOL_GUFO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2706) case ETHTOOL_GGSO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2707) case ETHTOOL_GGRO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2708) case ETHTOOL_GFLAGS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2709) case ETHTOOL_GPFLAGS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2710) case ETHTOOL_GRXFH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2711) case ETHTOOL_GRXRINGS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2712) case ETHTOOL_GRXCLSRLCNT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2713) case ETHTOOL_GRXCLSRULE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2714) case ETHTOOL_GRXCLSRLALL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2715) case ETHTOOL_GRXFHINDIR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2716) case ETHTOOL_GRSSH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2717) case ETHTOOL_GFEATURES:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2718) case ETHTOOL_GCHANNELS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2719) case ETHTOOL_GET_TS_INFO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2720) case ETHTOOL_GEEE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2721) case ETHTOOL_GTUNABLE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2722) case ETHTOOL_PHY_GTUNABLE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2723) case ETHTOOL_GLINKSETTINGS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2724) case ETHTOOL_GFECPARAM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2725) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2726) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2727) if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2728) return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2729) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2730)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2731) if (dev->ethtool_ops->begin) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2732) rc = dev->ethtool_ops->begin(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2733) if (rc < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2734) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2735) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2736) old_features = dev->features;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2737)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2738) switch (ethcmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2739) case ETHTOOL_GSET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2740) rc = ethtool_get_settings(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2741) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2742) case ETHTOOL_SSET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2743) rc = ethtool_set_settings(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2744) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2745) case ETHTOOL_GDRVINFO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2746) rc = ethtool_get_drvinfo(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2747) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2748) case ETHTOOL_GREGS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2749) rc = ethtool_get_regs(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2750) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2751) case ETHTOOL_GWOL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2752) rc = ethtool_get_wol(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2753) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2754) case ETHTOOL_SWOL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2755) rc = ethtool_set_wol(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2756) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2757) case ETHTOOL_GMSGLVL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2758) rc = ethtool_get_value(dev, useraddr, ethcmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2759) dev->ethtool_ops->get_msglevel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2760) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2761) case ETHTOOL_SMSGLVL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2762) rc = ethtool_set_value_void(dev, useraddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2763) dev->ethtool_ops->set_msglevel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2764) if (!rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2765) ethtool_notify(dev, ETHTOOL_MSG_DEBUG_NTF, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2766) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2767) case ETHTOOL_GEEE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2768) rc = ethtool_get_eee(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2769) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2770) case ETHTOOL_SEEE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2771) rc = ethtool_set_eee(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2772) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2773) case ETHTOOL_NWAY_RST:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2774) rc = ethtool_nway_reset(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2775) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2776) case ETHTOOL_GLINK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2777) rc = ethtool_get_link(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2778) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2779) case ETHTOOL_GEEPROM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2780) rc = ethtool_get_eeprom(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2781) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2782) case ETHTOOL_SEEPROM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2783) rc = ethtool_set_eeprom(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2784) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2785) case ETHTOOL_GCOALESCE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2786) rc = ethtool_get_coalesce(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2787) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2788) case ETHTOOL_SCOALESCE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2789) rc = ethtool_set_coalesce(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2790) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2791) case ETHTOOL_GRINGPARAM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2792) rc = ethtool_get_ringparam(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2793) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2794) case ETHTOOL_SRINGPARAM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2795) rc = ethtool_set_ringparam(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2796) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2797) case ETHTOOL_GPAUSEPARAM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2798) rc = ethtool_get_pauseparam(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2799) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2800) case ETHTOOL_SPAUSEPARAM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2801) rc = ethtool_set_pauseparam(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2802) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2803) case ETHTOOL_TEST:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2804) rc = ethtool_self_test(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2805) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2806) case ETHTOOL_GSTRINGS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2807) rc = ethtool_get_strings(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2808) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2809) case ETHTOOL_PHYS_ID:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2810) rc = ethtool_phys_id(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2811) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2812) case ETHTOOL_GSTATS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2813) rc = ethtool_get_stats(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2814) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2815) case ETHTOOL_GPERMADDR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2816) rc = ethtool_get_perm_addr(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2817) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2818) case ETHTOOL_GFLAGS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2819) rc = ethtool_get_value(dev, useraddr, ethcmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2820) __ethtool_get_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2821) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2822) case ETHTOOL_SFLAGS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2823) rc = ethtool_set_value(dev, useraddr, __ethtool_set_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2824) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2825) case ETHTOOL_GPFLAGS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2826) rc = ethtool_get_value(dev, useraddr, ethcmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2827) dev->ethtool_ops->get_priv_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2828) if (!rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2829) ethtool_notify(dev, ETHTOOL_MSG_PRIVFLAGS_NTF, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2830) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2831) case ETHTOOL_SPFLAGS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2832) rc = ethtool_set_value(dev, useraddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2833) dev->ethtool_ops->set_priv_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2834) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2835) case ETHTOOL_GRXFH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2836) case ETHTOOL_GRXRINGS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2837) case ETHTOOL_GRXCLSRLCNT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2838) case ETHTOOL_GRXCLSRULE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2839) case ETHTOOL_GRXCLSRLALL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2840) rc = ethtool_get_rxnfc(dev, ethcmd, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2841) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2842) case ETHTOOL_SRXFH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2843) case ETHTOOL_SRXCLSRLDEL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2844) case ETHTOOL_SRXCLSRLINS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2845) rc = ethtool_set_rxnfc(dev, ethcmd, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2846) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2847) case ETHTOOL_FLASHDEV:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2848) rc = ethtool_flash_device(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2849) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2850) case ETHTOOL_RESET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2851) rc = ethtool_reset(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2852) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2853) case ETHTOOL_GSSET_INFO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2854) rc = ethtool_get_sset_info(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2855) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2856) case ETHTOOL_GRXFHINDIR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2857) rc = ethtool_get_rxfh_indir(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2858) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2859) case ETHTOOL_SRXFHINDIR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2860) rc = ethtool_set_rxfh_indir(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2861) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2862) case ETHTOOL_GRSSH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2863) rc = ethtool_get_rxfh(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2864) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2865) case ETHTOOL_SRSSH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2866) rc = ethtool_set_rxfh(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2867) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2868) case ETHTOOL_GFEATURES:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2869) rc = ethtool_get_features(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2870) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2871) case ETHTOOL_SFEATURES:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2872) rc = ethtool_set_features(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2873) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2874) case ETHTOOL_GTXCSUM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2875) case ETHTOOL_GRXCSUM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2876) case ETHTOOL_GSG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2877) case ETHTOOL_GTSO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2878) case ETHTOOL_GGSO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2879) case ETHTOOL_GGRO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2880) rc = ethtool_get_one_feature(dev, useraddr, ethcmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2881) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2882) case ETHTOOL_STXCSUM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2883) case ETHTOOL_SRXCSUM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2884) case ETHTOOL_SSG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2885) case ETHTOOL_STSO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2886) case ETHTOOL_SGSO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2887) case ETHTOOL_SGRO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2888) rc = ethtool_set_one_feature(dev, useraddr, ethcmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2889) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2890) case ETHTOOL_GCHANNELS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2891) rc = ethtool_get_channels(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2892) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2893) case ETHTOOL_SCHANNELS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2894) rc = ethtool_set_channels(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2895) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2896) case ETHTOOL_SET_DUMP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2897) rc = ethtool_set_dump(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2898) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2899) case ETHTOOL_GET_DUMP_FLAG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2900) rc = ethtool_get_dump_flag(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2901) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2902) case ETHTOOL_GET_DUMP_DATA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2903) rc = ethtool_get_dump_data(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2904) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2905) case ETHTOOL_GET_TS_INFO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2906) rc = ethtool_get_ts_info(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2907) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2908) case ETHTOOL_GMODULEINFO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2909) rc = ethtool_get_module_info(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2910) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2911) case ETHTOOL_GMODULEEEPROM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2912) rc = ethtool_get_module_eeprom(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2913) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2914) case ETHTOOL_GTUNABLE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2915) rc = ethtool_get_tunable(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2916) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2917) case ETHTOOL_STUNABLE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2918) rc = ethtool_set_tunable(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2919) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2920) case ETHTOOL_GPHYSTATS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2921) rc = ethtool_get_phy_stats(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2922) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2923) case ETHTOOL_PERQUEUE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2924) rc = ethtool_set_per_queue(dev, useraddr, sub_cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2925) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2926) case ETHTOOL_GLINKSETTINGS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2927) rc = ethtool_get_link_ksettings(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2928) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2929) case ETHTOOL_SLINKSETTINGS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2930) rc = ethtool_set_link_ksettings(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2931) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2932) case ETHTOOL_PHY_GTUNABLE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2933) rc = get_phy_tunable(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2934) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2935) case ETHTOOL_PHY_STUNABLE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2936) rc = set_phy_tunable(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2937) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2938) case ETHTOOL_GFECPARAM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2939) rc = ethtool_get_fecparam(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2940) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2941) case ETHTOOL_SFECPARAM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2942) rc = ethtool_set_fecparam(dev, useraddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2943) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2944) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2945) rc = -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2946) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2947)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2948) if (dev->ethtool_ops->complete)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2949) dev->ethtool_ops->complete(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2950)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2951) if (old_features != dev->features)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2952) netdev_features_change(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2953)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2954) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2955) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2956)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2957) struct ethtool_rx_flow_key {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2958) struct flow_dissector_key_basic basic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2959) union {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2960) struct flow_dissector_key_ipv4_addrs ipv4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2961) struct flow_dissector_key_ipv6_addrs ipv6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2962) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2963) struct flow_dissector_key_ports tp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2964) struct flow_dissector_key_ip ip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2965) struct flow_dissector_key_vlan vlan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2966) struct flow_dissector_key_eth_addrs eth_addrs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2967) } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2968)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2969) struct ethtool_rx_flow_match {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2970) struct flow_dissector dissector;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2971) struct ethtool_rx_flow_key key;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2972) struct ethtool_rx_flow_key mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2973) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2974)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2975) struct ethtool_rx_flow_rule *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2976) ethtool_rx_flow_rule_create(const struct ethtool_rx_flow_spec_input *input)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2977) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2978) const struct ethtool_rx_flow_spec *fs = input->fs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2979) static struct in6_addr zero_addr = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2980) struct ethtool_rx_flow_match *match;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2981) struct ethtool_rx_flow_rule *flow;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2982) struct flow_action_entry *act;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2983)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2984) flow = kzalloc(sizeof(struct ethtool_rx_flow_rule) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2985) sizeof(struct ethtool_rx_flow_match), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2986) if (!flow)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2987) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2988)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2989) /* ethtool_rx supports only one single action per rule. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2990) flow->rule = flow_rule_alloc(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2991) if (!flow->rule) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2992) kfree(flow);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2993) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2994) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2995)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2996) match = (struct ethtool_rx_flow_match *)flow->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2997) flow->rule->match.dissector = &match->dissector;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2998) flow->rule->match.mask = &match->mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2999) flow->rule->match.key = &match->key;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3001) match->mask.basic.n_proto = htons(0xffff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3002)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3003) switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3004) case ETHER_FLOW: {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3005) const struct ethhdr *ether_spec, *ether_m_spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3006)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3007) ether_spec = &fs->h_u.ether_spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3008) ether_m_spec = &fs->m_u.ether_spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3009)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3010) if (!is_zero_ether_addr(ether_m_spec->h_source)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3011) ether_addr_copy(match->key.eth_addrs.src,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3012) ether_spec->h_source);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3013) ether_addr_copy(match->mask.eth_addrs.src,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3014) ether_m_spec->h_source);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3015) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3016) if (!is_zero_ether_addr(ether_m_spec->h_dest)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3017) ether_addr_copy(match->key.eth_addrs.dst,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3018) ether_spec->h_dest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3019) ether_addr_copy(match->mask.eth_addrs.dst,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3020) ether_m_spec->h_dest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3021) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3022) if (ether_m_spec->h_proto) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3023) match->key.basic.n_proto = ether_spec->h_proto;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3024) match->mask.basic.n_proto = ether_m_spec->h_proto;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3025) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3026) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3027) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3028) case TCP_V4_FLOW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3029) case UDP_V4_FLOW: {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3030) const struct ethtool_tcpip4_spec *v4_spec, *v4_m_spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3031)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3032) match->key.basic.n_proto = htons(ETH_P_IP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3033)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3034) v4_spec = &fs->h_u.tcp_ip4_spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3035) v4_m_spec = &fs->m_u.tcp_ip4_spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3036)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3037) if (v4_m_spec->ip4src) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3038) match->key.ipv4.src = v4_spec->ip4src;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3039) match->mask.ipv4.src = v4_m_spec->ip4src;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3040) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3041) if (v4_m_spec->ip4dst) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3042) match->key.ipv4.dst = v4_spec->ip4dst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3043) match->mask.ipv4.dst = v4_m_spec->ip4dst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3044) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3045) if (v4_m_spec->ip4src ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3046) v4_m_spec->ip4dst) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3047) match->dissector.used_keys |=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3048) BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3049) match->dissector.offset[FLOW_DISSECTOR_KEY_IPV4_ADDRS] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3050) offsetof(struct ethtool_rx_flow_key, ipv4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3051) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3052) if (v4_m_spec->psrc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3053) match->key.tp.src = v4_spec->psrc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3054) match->mask.tp.src = v4_m_spec->psrc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3055) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3056) if (v4_m_spec->pdst) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3057) match->key.tp.dst = v4_spec->pdst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3058) match->mask.tp.dst = v4_m_spec->pdst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3059) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3060) if (v4_m_spec->psrc ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3061) v4_m_spec->pdst) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3062) match->dissector.used_keys |=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3063) BIT(FLOW_DISSECTOR_KEY_PORTS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3064) match->dissector.offset[FLOW_DISSECTOR_KEY_PORTS] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3065) offsetof(struct ethtool_rx_flow_key, tp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3066) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3067) if (v4_m_spec->tos) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3068) match->key.ip.tos = v4_spec->tos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3069) match->mask.ip.tos = v4_m_spec->tos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3070) match->dissector.used_keys |=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3071) BIT(FLOW_DISSECTOR_KEY_IP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3072) match->dissector.offset[FLOW_DISSECTOR_KEY_IP] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3073) offsetof(struct ethtool_rx_flow_key, ip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3074) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3075) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3076) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3077) case TCP_V6_FLOW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3078) case UDP_V6_FLOW: {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3079) const struct ethtool_tcpip6_spec *v6_spec, *v6_m_spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3080)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3081) match->key.basic.n_proto = htons(ETH_P_IPV6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3082)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3083) v6_spec = &fs->h_u.tcp_ip6_spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3084) v6_m_spec = &fs->m_u.tcp_ip6_spec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3085) if (memcmp(v6_m_spec->ip6src, &zero_addr, sizeof(zero_addr))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3086) memcpy(&match->key.ipv6.src, v6_spec->ip6src,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3087) sizeof(match->key.ipv6.src));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3088) memcpy(&match->mask.ipv6.src, v6_m_spec->ip6src,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3089) sizeof(match->mask.ipv6.src));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3090) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3091) if (memcmp(v6_m_spec->ip6dst, &zero_addr, sizeof(zero_addr))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3092) memcpy(&match->key.ipv6.dst, v6_spec->ip6dst,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3093) sizeof(match->key.ipv6.dst));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3094) memcpy(&match->mask.ipv6.dst, v6_m_spec->ip6dst,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3095) sizeof(match->mask.ipv6.dst));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3096) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3097) if (memcmp(v6_m_spec->ip6src, &zero_addr, sizeof(zero_addr)) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3098) memcmp(v6_m_spec->ip6dst, &zero_addr, sizeof(zero_addr))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3099) match->dissector.used_keys |=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3100) BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3101) match->dissector.offset[FLOW_DISSECTOR_KEY_IPV6_ADDRS] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3102) offsetof(struct ethtool_rx_flow_key, ipv6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3104) if (v6_m_spec->psrc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3105) match->key.tp.src = v6_spec->psrc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3106) match->mask.tp.src = v6_m_spec->psrc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3108) if (v6_m_spec->pdst) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3109) match->key.tp.dst = v6_spec->pdst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3110) match->mask.tp.dst = v6_m_spec->pdst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3112) if (v6_m_spec->psrc ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3113) v6_m_spec->pdst) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3114) match->dissector.used_keys |=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3115) BIT(FLOW_DISSECTOR_KEY_PORTS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3116) match->dissector.offset[FLOW_DISSECTOR_KEY_PORTS] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3117) offsetof(struct ethtool_rx_flow_key, tp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3119) if (v6_m_spec->tclass) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3120) match->key.ip.tos = v6_spec->tclass;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3121) match->mask.ip.tos = v6_m_spec->tclass;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3122) match->dissector.used_keys |=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3123) BIT(FLOW_DISSECTOR_KEY_IP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3124) match->dissector.offset[FLOW_DISSECTOR_KEY_IP] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3125) offsetof(struct ethtool_rx_flow_key, ip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3127) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3128) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3129) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3130) ethtool_rx_flow_rule_destroy(flow);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3131) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3134) switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3135) case TCP_V4_FLOW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3136) case TCP_V6_FLOW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3137) match->key.basic.ip_proto = IPPROTO_TCP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3138) match->mask.basic.ip_proto = 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3139) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3140) case UDP_V4_FLOW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3141) case UDP_V6_FLOW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3142) match->key.basic.ip_proto = IPPROTO_UDP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3143) match->mask.basic.ip_proto = 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3144) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3147) match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_BASIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3148) match->dissector.offset[FLOW_DISSECTOR_KEY_BASIC] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3149) offsetof(struct ethtool_rx_flow_key, basic);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3151) if (fs->flow_type & FLOW_EXT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3152) const struct ethtool_flow_ext *ext_h_spec = &fs->h_ext;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3153) const struct ethtool_flow_ext *ext_m_spec = &fs->m_ext;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3155) if (ext_m_spec->vlan_etype) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3156) match->key.vlan.vlan_tpid = ext_h_spec->vlan_etype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3157) match->mask.vlan.vlan_tpid = ext_m_spec->vlan_etype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3160) if (ext_m_spec->vlan_tci) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3161) match->key.vlan.vlan_id =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3162) ntohs(ext_h_spec->vlan_tci) & 0x0fff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3163) match->mask.vlan.vlan_id =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3164) ntohs(ext_m_spec->vlan_tci) & 0x0fff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3166) match->key.vlan.vlan_dei =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3167) !!(ext_h_spec->vlan_tci & htons(0x1000));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3168) match->mask.vlan.vlan_dei =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3169) !!(ext_m_spec->vlan_tci & htons(0x1000));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3171) match->key.vlan.vlan_priority =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3172) (ntohs(ext_h_spec->vlan_tci) & 0xe000) >> 13;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3173) match->mask.vlan.vlan_priority =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3174) (ntohs(ext_m_spec->vlan_tci) & 0xe000) >> 13;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3175) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3177) if (ext_m_spec->vlan_etype ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3178) ext_m_spec->vlan_tci) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3179) match->dissector.used_keys |=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3180) BIT(FLOW_DISSECTOR_KEY_VLAN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3181) match->dissector.offset[FLOW_DISSECTOR_KEY_VLAN] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3182) offsetof(struct ethtool_rx_flow_key, vlan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3184) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3185) if (fs->flow_type & FLOW_MAC_EXT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3186) const struct ethtool_flow_ext *ext_h_spec = &fs->h_ext;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3187) const struct ethtool_flow_ext *ext_m_spec = &fs->m_ext;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3189) memcpy(match->key.eth_addrs.dst, ext_h_spec->h_dest,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3190) ETH_ALEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3191) memcpy(match->mask.eth_addrs.dst, ext_m_spec->h_dest,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3192) ETH_ALEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3194) match->dissector.used_keys |=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3195) BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3196) match->dissector.offset[FLOW_DISSECTOR_KEY_ETH_ADDRS] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3197) offsetof(struct ethtool_rx_flow_key, eth_addrs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3200) act = &flow->rule->action.entries[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3201) switch (fs->ring_cookie) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3202) case RX_CLS_FLOW_DISC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3203) act->id = FLOW_ACTION_DROP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3204) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3205) case RX_CLS_FLOW_WAKE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3206) act->id = FLOW_ACTION_WAKE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3207) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3208) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3209) act->id = FLOW_ACTION_QUEUE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3210) if (fs->flow_type & FLOW_RSS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3211) act->queue.ctx = input->rss_ctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3213) act->queue.vf = ethtool_get_flow_spec_ring_vf(fs->ring_cookie);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3214) act->queue.index = ethtool_get_flow_spec_ring(fs->ring_cookie);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3215) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3218) return flow;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3219) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3220) EXPORT_SYMBOL(ethtool_rx_flow_rule_create);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3222) void ethtool_rx_flow_rule_destroy(struct ethtool_rx_flow_rule *flow)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3223) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3224) kfree(flow->rule);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3225) kfree(flow);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3226) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3227) EXPORT_SYMBOL(ethtool_rx_flow_rule_destroy);