aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/core/ethtool.c95
1 files changed, 70 insertions, 25 deletions
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