aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/ethtool.h7
-rw-r--r--net/core/ethtool.c95
2 files changed, 75 insertions, 27 deletions
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 0e5de2fb960c..f617998b87f1 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -376,11 +376,9 @@ struct ethtool_ops {
376 int (*set_sg)(struct net_device *, u32); 376 int (*set_sg)(struct net_device *, u32);
377 u32 (*get_tso)(struct net_device *); 377 u32 (*get_tso)(struct net_device *);
378 int (*set_tso)(struct net_device *, u32); 378 int (*set_tso)(struct net_device *, u32);
379 int (*self_test_count)(struct net_device *);
380 void (*self_test)(struct net_device *, struct ethtool_test *, u64 *); 379 void (*self_test)(struct net_device *, struct ethtool_test *, u64 *);
381 void (*get_strings)(struct net_device *, u32 stringset, u8 *); 380 void (*get_strings)(struct net_device *, u32 stringset, u8 *);
382 int (*phys_id)(struct net_device *, u32); 381 int (*phys_id)(struct net_device *, u32);
383 int (*get_stats_count)(struct net_device *);
384 void (*get_ethtool_stats)(struct net_device *, struct ethtool_stats *, u64 *); 382 void (*get_ethtool_stats)(struct net_device *, struct ethtool_stats *, u64 *);
385 int (*begin)(struct net_device *); 383 int (*begin)(struct net_device *);
386 void (*complete)(struct net_device *); 384 void (*complete)(struct net_device *);
@@ -388,6 +386,11 @@ struct ethtool_ops {
388 int (*set_ufo)(struct net_device *, u32); 386 int (*set_ufo)(struct net_device *, u32);
389 u32 (*get_flags)(struct net_device *); 387 u32 (*get_flags)(struct net_device *);
390 int (*set_flags)(struct net_device *, u32); 388 int (*set_flags)(struct net_device *, u32);
389 int (*get_sset_count)(struct net_device *, int);
390
391 /* the following hooks are obsolete */
392 int (*self_test_count)(struct net_device *);/* use get_sset_count */
393 int (*get_stats_count)(struct net_device *);/* use get_sset_count */
391}; 394};
392#endif /* __KERNEL__ */ 395#endif /* __KERNEL__ */
393 396
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 6f8b78bcfd84..1edae460d616 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -179,10 +179,23 @@ static int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr)
179 info.cmd = ETHTOOL_GDRVINFO; 179 info.cmd = ETHTOOL_GDRVINFO;
180 ops->get_drvinfo(dev, &info); 180 ops->get_drvinfo(dev, &info);
181 181
182 if (ops->self_test_count) 182 if (ops->get_sset_count) {
183 info.testinfo_len = ops->self_test_count(dev); 183 int rc;
184 if (ops->get_stats_count) 184
185 info.n_stats = ops->get_stats_count(dev); 185 rc = ops->get_sset_count(dev, ETH_SS_TEST);
186 if (rc >= 0)
187 info.testinfo_len = rc;
188 rc = ops->get_sset_count(dev, ETH_SS_STATS);
189 if (rc >= 0)
190 info.n_stats = rc;
191 } else {
192 /* code path for obsolete hooks */
193
194 if (ops->self_test_count)
195 info.testinfo_len = ops->self_test_count(dev);
196 if (ops->get_stats_count)
197 info.n_stats = ops->get_stats_count(dev);
198 }
186 if (ops->get_regs_len) 199 if (ops->get_regs_len)
187 info.regdump_len = ops->get_regs_len(dev); 200 info.regdump_len = ops->get_regs_len(dev);
188 if (ops->get_eeprom_len) 201 if (ops->get_eeprom_len)
@@ -669,16 +682,27 @@ static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
669 struct ethtool_test test; 682 struct ethtool_test test;
670 const struct ethtool_ops *ops = dev->ethtool_ops; 683 const struct ethtool_ops *ops = dev->ethtool_ops;
671 u64 *data; 684 u64 *data;
672 int ret; 685 int ret, test_len;
673 686
674 if (!ops->self_test || !ops->self_test_count) 687 if (!ops->self_test)
688 return -EOPNOTSUPP;
689 if (!ops->get_sset_count && !ops->self_test_count)
675 return -EOPNOTSUPP; 690 return -EOPNOTSUPP;
676 691
692 if (ops->get_sset_count)
693 test_len = ops->get_sset_count(dev, ETH_SS_TEST);
694 else
695 /* code path for obsolete hook */
696 test_len = ops->self_test_count(dev);
697 if (test_len < 0)
698 return test_len;
699 WARN_ON(test_len == 0);
700
677 if (copy_from_user(&test, useraddr, sizeof(test))) 701 if (copy_from_user(&test, useraddr, sizeof(test)))
678 return -EFAULT; 702 return -EFAULT;
679 703
680 test.len = ops->self_test_count(dev); 704 test.len = test_len;
681 data = kmalloc(test.len * sizeof(u64), GFP_USER); 705 data = kmalloc(test_len * sizeof(u64), GFP_USER);
682 if (!data) 706 if (!data)
683 return -ENOMEM; 707 return -ENOMEM;
684 708
@@ -710,19 +734,29 @@ static int ethtool_get_strings(struct net_device *dev, void __user *useraddr)
710 if (copy_from_user(&gstrings, useraddr, sizeof(gstrings))) 734 if (copy_from_user(&gstrings, useraddr, sizeof(gstrings)))
711 return -EFAULT; 735 return -EFAULT;
712 736
713 switch (gstrings.string_set) { 737 if (ops->get_sset_count) {
714 case ETH_SS_TEST: 738 ret = ops->get_sset_count(dev, gstrings.string_set);
715 if (!ops->self_test_count) 739 if (ret < 0)
716 return -EOPNOTSUPP; 740 return ret;
717 gstrings.len = ops->self_test_count(dev); 741
718 break; 742 gstrings.len = ret;
719 case ETH_SS_STATS: 743 } else {
720 if (!ops->get_stats_count) 744 /* code path for obsolete hooks */
721 return -EOPNOTSUPP; 745
722 gstrings.len = ops->get_stats_count(dev); 746 switch (gstrings.string_set) {
723 break; 747 case ETH_SS_TEST:
724 default: 748 if (!ops->self_test_count)
725 return -EINVAL; 749 return -EOPNOTSUPP;
750 gstrings.len = ops->self_test_count(dev);
751 break;
752 case ETH_SS_STATS:
753 if (!ops->get_stats_count)
754 return -EOPNOTSUPP;
755 gstrings.len = ops->get_stats_count(dev);
756 break;
757 default:
758 return -EINVAL;
759 }
726 } 760 }
727 761
728 data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER); 762 data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER);
@@ -762,16 +796,27 @@ static int ethtool_get_stats(struct net_device *dev, void __user *useraddr)
762 struct ethtool_stats stats; 796 struct ethtool_stats stats;
763 const struct ethtool_ops *ops = dev->ethtool_ops; 797 const struct ethtool_ops *ops = dev->ethtool_ops;
764 u64 *data; 798 u64 *data;
765 int ret; 799 int ret, n_stats;
766 800
767 if (!ops->get_ethtool_stats || !ops->get_stats_count) 801 if (!ops->get_ethtool_stats)
768 return -EOPNOTSUPP; 802 return -EOPNOTSUPP;
803 if (!ops->get_sset_count && !ops->get_stats_count)
804 return -EOPNOTSUPP;
805
806 if (ops->get_sset_count)
807 n_stats = ops->get_sset_count(dev, ETH_SS_STATS);
808 else
809 /* code path for obsolete hook */
810 n_stats = ops->get_stats_count(dev);
811 if (n_stats < 0)
812 return n_stats;
813 WARN_ON(n_stats == 0);
769 814
770 if (copy_from_user(&stats, useraddr, sizeof(stats))) 815 if (copy_from_user(&stats, useraddr, sizeof(stats)))
771 return -EFAULT; 816 return -EFAULT;
772 817
773 stats.n_stats = ops->get_stats_count(dev); 818 stats.n_stats = n_stats;
774 data = kmalloc(stats.n_stats * sizeof(u64), GFP_USER); 819 data = kmalloc(n_stats * sizeof(u64), GFP_USER);
775 if (!data) 820 if (!data)
776 return -ENOMEM; 821 return -ENOMEM;
777 822