📄 ethtool.c
字号:
/******************************************************************************* Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. The full GNU General Public License is included in this distribution in the file called LICENSE. Contact Information: Linux NICS <linux.nics@intel.com> Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497*******************************************************************************//* * net/core/ethtool.c - Ethtool ioctl handler * Copyright (c) 2003 Matthew Wilcox <matthew@wil.cx> * * This file is where we call all the ethtool_ops commands to get * the information ethtool needs. We fall back to calling do_ioctl() * for drivers which haven't been converted to ethtool_ops yet. * * It's GPL, stupid. * * Modification by sfeldma@pobox.com to work as backward compat * solution for pre-ethtool_ops kernels. * - copied struct ethtool_ops from ethtool.h * - defined SET_ETHTOOL_OPS * - put in some #ifndef NETIF_F_xxx wrappers * - changes refs to dev->ethtool_ops to ethtool_ops * - changed dev_ethtool to ethtool_ioctl * - remove EXPORT_SYMBOL()s * - added _kc_ prefix in built-in ethtool_op_xxx ops. */#include <linux/module.h>#include <linux/types.h>#include <linux/errno.h>#include <linux/ethtool.h>#include <linux/netdevice.h>#include <asm/uaccess.h>#undef ethtool_ops#define ethtool_ops _kc_ethtool_opsstruct _kc_ethtool_ops { int (*get_settings)(struct net_device *, struct ethtool_cmd *); int (*set_settings)(struct net_device *, struct ethtool_cmd *); void (*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *); int (*get_regs_len)(struct net_device *); void (*get_regs)(struct net_device *, struct ethtool_regs *, void *); void (*get_wol)(struct net_device *, struct ethtool_wolinfo *); int (*set_wol)(struct net_device *, struct ethtool_wolinfo *); u32 (*get_msglevel)(struct net_device *); void (*set_msglevel)(struct net_device *, u32); int (*nway_reset)(struct net_device *); u32 (*get_link)(struct net_device *); int (*get_eeprom_len)(struct net_device *); int (*get_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *); int (*set_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *); int (*get_coalesce)(struct net_device *, struct ethtool_coalesce *); int (*set_coalesce)(struct net_device *, struct ethtool_coalesce *); void (*get_ringparam)(struct net_device *, struct ethtool_ringparam *); int (*set_ringparam)(struct net_device *, struct ethtool_ringparam *); void (*get_pauseparam)(struct net_device *, struct ethtool_pauseparam*); int (*set_pauseparam)(struct net_device *, struct ethtool_pauseparam*); u32 (*get_rx_csum)(struct net_device *); int (*set_rx_csum)(struct net_device *, u32); u32 (*get_tx_csum)(struct net_device *); int (*set_tx_csum)(struct net_device *, u32); u32 (*get_sg)(struct net_device *); int (*set_sg)(struct net_device *, u32); u32 (*get_tso)(struct net_device *); int (*set_tso)(struct net_device *, u32); int (*self_test_count)(struct net_device *); void (*self_test)(struct net_device *, struct ethtool_test *, u64 *); void (*get_strings)(struct net_device *, u32 stringset, u8 *); int (*phys_id)(struct net_device *, u32); int (*get_stats_count)(struct net_device *); void (*get_ethtool_stats)(struct net_device *, struct ethtool_stats *, u64 *);} *ethtool_ops = NULL;#undef SET_ETHTOOL_OPS#define SET_ETHTOOL_OPS(netdev, ops) (ethtool_ops = (ops)) /* * Some useful ethtool_ops methods that're device independent. * If we find that all drivers want to do the same thing here, * we can turn these into dev_() function calls. */#undef ethtool_op_get_link#define ethtool_op_get_link _kc_ethtool_op_get_linku32 _kc_ethtool_op_get_link(struct net_device *dev){ return netif_carrier_ok(dev) ? 1 : 0;}#undef ethtool_op_get_tx_csum#define ethtool_op_get_tx_csum _kc_ethtool_op_get_tx_csumu32 _kc_ethtool_op_get_tx_csum(struct net_device *dev){#ifdef NETIF_F_IP_CSUM return (dev->features & NETIF_F_IP_CSUM) != 0;#else return 0;#endif}#undef ethtool_op_set_tx_csum#define ethtool_op_set_tx_csum _kc_ethtool_op_set_tx_csumint _kc_ethtool_op_set_tx_csum(struct net_device *dev, u32 data){#ifdef NETIF_F_IP_CSUM if (data) dev->features |= NETIF_F_IP_CSUM; else dev->features &= ~NETIF_F_IP_CSUM;#endif return 0;}#undef ethtool_op_get_sg#define ethtool_op_get_sg _kc_ethtool_op_get_sgu32 _kc_ethtool_op_get_sg(struct net_device *dev){#ifdef NETIF_F_SG return (dev->features & NETIF_F_SG) != 0;#else return 0;#endif}#undef ethtool_op_set_sg#define ethtool_op_set_sg _kc_ethtool_op_set_sgint _kc_ethtool_op_set_sg(struct net_device *dev, u32 data){#ifdef NETIF_F_SG if (data) dev->features |= NETIF_F_SG; else dev->features &= ~NETIF_F_SG;#endif return 0;}#undef ethtool_op_get_tso#define ethtool_op_get_tso _kc_ethtool_op_get_tsou32 _kc_ethtool_op_get_tso(struct net_device *dev){#ifdef NETIF_F_TSO return (dev->features & NETIF_F_TSO) != 0;#else return 0;#endif}#undef ethtool_op_set_tso#define ethtool_op_set_tso _kc_ethtool_op_set_tsoint _kc_ethtool_op_set_tso(struct net_device *dev, u32 data){#ifdef NETIF_F_TSO if (data) dev->features |= NETIF_F_TSO; else dev->features &= ~NETIF_F_TSO;#endif return 0;}/* Handlers for each ethtool command */static int ethtool_get_settings(struct net_device *dev, void *useraddr){ struct ethtool_cmd cmd = { ETHTOOL_GSET }; int err; if (!ethtool_ops->get_settings) return -EOPNOTSUPP; err = ethtool_ops->get_settings(dev, &cmd); if (err < 0) return err; if (copy_to_user(useraddr, &cmd, sizeof(cmd))) return -EFAULT; return 0;}static int ethtool_set_settings(struct net_device *dev, void *useraddr){ struct ethtool_cmd cmd; if (!ethtool_ops->set_settings) return -EOPNOTSUPP; if (copy_from_user(&cmd, useraddr, sizeof(cmd))) return -EFAULT; return ethtool_ops->set_settings(dev, &cmd);}static int ethtool_get_drvinfo(struct net_device *dev, void *useraddr){ struct ethtool_drvinfo info; struct ethtool_ops *ops = ethtool_ops; if (!ops->get_drvinfo) return -EOPNOTSUPP; memset(&info, 0, sizeof(info)); info.cmd = ETHTOOL_GDRVINFO; ops->get_drvinfo(dev, &info); if (ops->self_test_count) info.testinfo_len = ops->self_test_count(dev); if (ops->get_stats_count) info.n_stats = ops->get_stats_count(dev); if (ops->get_regs_len) info.regdump_len = ops->get_regs_len(dev); if (ops->get_eeprom_len) info.eedump_len = ops->get_eeprom_len(dev); if (copy_to_user(useraddr, &info, sizeof(info))) return -EFAULT; return 0;}static int ethtool_get_regs(struct net_device *dev, char *useraddr){ struct ethtool_regs regs; struct ethtool_ops *ops = ethtool_ops; void *regbuf; int reglen, ret; if (!ops->get_regs || !ops->get_regs_len) return -EOPNOTSUPP; if (copy_from_user(®s, useraddr, sizeof(regs))) return -EFAULT; reglen = ops->get_regs_len(dev); if (regs.len > reglen) regs.len = reglen; regbuf = kmalloc(reglen, GFP_USER); if (!regbuf) return -ENOMEM; ops->get_regs(dev, ®s, regbuf); ret = -EFAULT; if (copy_to_user(useraddr, ®s, sizeof(regs))) goto out; useraddr += offsetof(struct ethtool_regs, data); if (copy_to_user(useraddr, regbuf, reglen)) goto out; ret = 0; out: kfree(regbuf); return ret;}static int ethtool_get_wol(struct net_device *dev, char *useraddr){ struct ethtool_wolinfo wol = { ETHTOOL_GWOL }; if (!ethtool_ops->get_wol) return -EOPNOTSUPP; ethtool_ops->get_wol(dev, &wol); if (copy_to_user(useraddr, &wol, sizeof(wol))) return -EFAULT; return 0;}static int ethtool_set_wol(struct net_device *dev, char *useraddr){ struct ethtool_wolinfo wol; if (!ethtool_ops->set_wol) return -EOPNOTSUPP; if (copy_from_user(&wol, useraddr, sizeof(wol))) return -EFAULT; return ethtool_ops->set_wol(dev, &wol);}static int ethtool_get_msglevel(struct net_device *dev, char *useraddr){ struct ethtool_value edata = { ETHTOOL_GMSGLVL }; if (!ethtool_ops->get_msglevel) return -EOPNOTSUPP; edata.data = ethtool_ops->get_msglevel(dev); if (copy_to_user(useraddr, &edata, sizeof(edata))) return -EFAULT; return 0;}static int ethtool_set_msglevel(struct net_device *dev, char *useraddr){ struct ethtool_value edata; if (!ethtool_ops->set_msglevel) return -EOPNOTSUPP; if (copy_from_user(&edata, useraddr, sizeof(edata))) return -EFAULT; ethtool_ops->set_msglevel(dev, edata.data); return 0;}static int ethtool_nway_reset(struct net_device *dev){ if (!ethtool_ops->nway_reset) return -EOPNOTSUPP; return ethtool_ops->nway_reset(dev);}static int ethtool_get_link(struct net_device *dev, void *useraddr){ struct ethtool_value edata = { ETHTOOL_GLINK }; if (!ethtool_ops->get_link) return -EOPNOTSUPP; edata.data = ethtool_ops->get_link(dev); if (copy_to_user(useraddr, &edata, sizeof(edata))) return -EFAULT; return 0;}static int ethtool_get_eeprom(struct net_device *dev, void *useraddr){ struct ethtool_eeprom eeprom; struct ethtool_ops *ops = ethtool_ops; u8 *data; int ret; if (!ops->get_eeprom || !ops->get_eeprom_len) return -EOPNOTSUPP; if (copy_from_user(&eeprom, useraddr, sizeof(eeprom))) return -EFAULT; /* Check for wrap and zero */ if (eeprom.offset + eeprom.len <= eeprom.offset) return -EINVAL; /* Check for exceeding total eeprom len */ if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev)) return -EINVAL; data = kmalloc(eeprom.len, GFP_USER); if (!data) return -ENOMEM; ret = -EFAULT; if (copy_from_user(data, useraddr + sizeof(eeprom), eeprom.len)) goto out; ret = ops->get_eeprom(dev, &eeprom, data); if (ret) goto out; ret = -EFAULT; if (copy_to_user(useraddr, &eeprom, sizeof(eeprom))) goto out; if (copy_to_user(useraddr + sizeof(eeprom), data, eeprom.len)) goto out; ret = 0; out: kfree(data); return ret;}static int ethtool_set_eeprom(struct net_device *dev, void *useraddr){ struct ethtool_eeprom eeprom; struct ethtool_ops *ops = ethtool_ops; u8 *data; int ret; if (!ops->set_eeprom || !ops->get_eeprom_len) return -EOPNOTSUPP; if (copy_from_user(&eeprom, useraddr, sizeof(eeprom))) return -EFAULT; /* Check for wrap and zero */ if (eeprom.offset + eeprom.len <= eeprom.offset) return -EINVAL; /* Check for exceeding total eeprom len */ if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev)) return -EINVAL; data = kmalloc(eeprom.len, GFP_USER);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -