32
32
#include <generated/utsrelease.h>
33
33
#include "common.h"
34
34
35
+ /* State held across locks and calls for commands which have devlink fallback */
36
+ struct ethtool_devlink_compat {
37
+ union {
38
+ struct ethtool_flash efl ;
39
+ struct ethtool_drvinfo info ;
40
+ };
41
+ };
42
+
35
43
/*
36
44
* Some useful ethtool_ops methods that're device independent.
37
45
* If we find that all drivers want to do the same thing here,
@@ -697,22 +705,20 @@ static int ethtool_set_settings(struct net_device *dev, void __user *useraddr)
697
705
return ret ;
698
706
}
699
707
700
- static noinline_for_stack int ethtool_get_drvinfo ( struct net_device * dev ,
701
- void __user * useraddr )
708
+ static int
709
+ ethtool_get_drvinfo ( struct net_device * dev , struct ethtool_devlink_compat * rsp )
702
710
{
703
- struct ethtool_drvinfo info ;
704
711
const struct ethtool_ops * ops = dev -> ethtool_ops ;
705
712
706
- memset (& info , 0 , sizeof (info ));
707
- info .cmd = ETHTOOL_GDRVINFO ;
708
- strlcpy (info .version , UTS_RELEASE , sizeof (info .version ));
713
+ rsp -> info .cmd = ETHTOOL_GDRVINFO ;
714
+ strlcpy (rsp -> info .version , UTS_RELEASE , sizeof (rsp -> info .version ));
709
715
if (ops -> get_drvinfo ) {
710
- ops -> get_drvinfo (dev , & info );
716
+ ops -> get_drvinfo (dev , & rsp -> info );
711
717
} else if (dev -> dev .parent && dev -> dev .parent -> driver ) {
712
- strlcpy (info .bus_info , dev_name (dev -> dev .parent ),
713
- sizeof (info .bus_info ));
714
- strlcpy (info .driver , dev -> dev .parent -> driver -> name ,
715
- sizeof (info .driver ));
718
+ strlcpy (rsp -> info .bus_info , dev_name (dev -> dev .parent ),
719
+ sizeof (rsp -> info .bus_info ));
720
+ strlcpy (rsp -> info .driver , dev -> dev .parent -> driver -> name ,
721
+ sizeof (rsp -> info .driver ));
716
722
} else {
717
723
return - EOPNOTSUPP ;
718
724
}
@@ -726,30 +732,27 @@ static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
726
732
727
733
rc = ops -> get_sset_count (dev , ETH_SS_TEST );
728
734
if (rc >= 0 )
729
- info .testinfo_len = rc ;
735
+ rsp -> info .testinfo_len = rc ;
730
736
rc = ops -> get_sset_count (dev , ETH_SS_STATS );
731
737
if (rc >= 0 )
732
- info .n_stats = rc ;
738
+ rsp -> info .n_stats = rc ;
733
739
rc = ops -> get_sset_count (dev , ETH_SS_PRIV_FLAGS );
734
740
if (rc >= 0 )
735
- info .n_priv_flags = rc ;
741
+ rsp -> info .n_priv_flags = rc ;
736
742
}
737
743
if (ops -> get_regs_len ) {
738
744
int ret = ops -> get_regs_len (dev );
739
745
740
746
if (ret > 0 )
741
- info .regdump_len = ret ;
747
+ rsp -> info .regdump_len = ret ;
742
748
}
743
749
744
750
if (ops -> get_eeprom_len )
745
- info .eedump_len = ops -> get_eeprom_len (dev );
746
-
747
- if (!info .fw_version [0 ])
748
- devlink_compat_running_version (dev , info .fw_version ,
749
- sizeof (info .fw_version ));
751
+ rsp -> info .eedump_len = ops -> get_eeprom_len (dev );
750
752
751
- if (copy_to_user (useraddr , & info , sizeof (info )))
752
- return - EFAULT ;
753
+ if (!rsp -> info .fw_version [0 ])
754
+ devlink_compat_running_version (dev , rsp -> info .fw_version ,
755
+ sizeof (rsp -> info .fw_version ));
753
756
return 0 ;
754
757
}
755
758
@@ -2178,19 +2181,13 @@ static int ethtool_set_value(struct net_device *dev, char __user *useraddr,
2178
2181
return actor (dev , edata .data );
2179
2182
}
2180
2183
2181
- static noinline_for_stack int ethtool_flash_device ( struct net_device * dev ,
2182
- char __user * useraddr )
2184
+ static int
2185
+ ethtool_flash_device ( struct net_device * dev , struct ethtool_devlink_compat * req )
2183
2186
{
2184
- struct ethtool_flash efl ;
2185
-
2186
- if (copy_from_user (& efl , useraddr , sizeof (efl )))
2187
- return - EFAULT ;
2188
- efl .data [ETHTOOL_FLASH_MAX_FILENAME - 1 ] = 0 ;
2189
-
2190
2187
if (!dev -> ethtool_ops -> flash_device )
2191
- return devlink_compat_flash_update (dev , efl .data );
2188
+ return devlink_compat_flash_update (dev , req -> efl .data );
2192
2189
2193
- return dev -> ethtool_ops -> flash_device (dev , & efl );
2190
+ return dev -> ethtool_ops -> flash_device (dev , & req -> efl );
2194
2191
}
2195
2192
2196
2193
static int ethtool_set_dump (struct net_device * dev ,
@@ -2701,19 +2698,18 @@ static int ethtool_set_fecparam(struct net_device *dev, void __user *useraddr)
2701
2698
/* The main entry point in this file. Called from net/core/dev_ioctl.c */
2702
2699
2703
2700
static int
2704
- __dev_ethtool (struct net * net , struct ifreq * ifr , void __user * useraddr )
2701
+ __dev_ethtool (struct net * net , struct ifreq * ifr , void __user * useraddr ,
2702
+ u32 ethcmd , struct ethtool_devlink_compat * devlink_state )
2705
2703
{
2706
- struct net_device * dev = __dev_get_by_name ( net , ifr -> ifr_name ) ;
2707
- u32 ethcmd , sub_cmd ;
2704
+ struct net_device * dev ;
2705
+ u32 sub_cmd ;
2708
2706
int rc ;
2709
2707
netdev_features_t old_features ;
2710
2708
2709
+ dev = __dev_get_by_name (net , ifr -> ifr_name );
2711
2710
if (!dev )
2712
2711
return - ENODEV ;
2713
2712
2714
- if (copy_from_user (& ethcmd , useraddr , sizeof (ethcmd )))
2715
- return - EFAULT ;
2716
-
2717
2713
if (ethcmd == ETHTOOL_PERQUEUE ) {
2718
2714
if (copy_from_user (& sub_cmd , useraddr + sizeof (ethcmd ), sizeof (sub_cmd )))
2719
2715
return - EFAULT ;
@@ -2787,7 +2783,7 @@ __dev_ethtool(struct net *net, struct ifreq *ifr, void __user *useraddr)
2787
2783
rc = ethtool_set_settings (dev , useraddr );
2788
2784
break ;
2789
2785
case ETHTOOL_GDRVINFO :
2790
- rc = ethtool_get_drvinfo (dev , useraddr );
2786
+ rc = ethtool_get_drvinfo (dev , devlink_state );
2791
2787
break ;
2792
2788
case ETHTOOL_GREGS :
2793
2789
rc = ethtool_get_regs (dev , useraddr );
@@ -2889,7 +2885,7 @@ __dev_ethtool(struct net *net, struct ifreq *ifr, void __user *useraddr)
2889
2885
rc = ethtool_set_rxnfc (dev , ethcmd , useraddr );
2890
2886
break ;
2891
2887
case ETHTOOL_FLASHDEV :
2892
- rc = ethtool_flash_device (dev , useraddr );
2888
+ rc = ethtool_flash_device (dev , devlink_state );
2893
2889
break ;
2894
2890
case ETHTOOL_RESET :
2895
2891
rc = ethtool_reset (dev , useraddr );
@@ -3003,12 +2999,44 @@ __dev_ethtool(struct net *net, struct ifreq *ifr, void __user *useraddr)
3003
2999
3004
3000
int dev_ethtool (struct net * net , struct ifreq * ifr , void __user * useraddr )
3005
3001
{
3002
+ struct ethtool_devlink_compat * state ;
3003
+ u32 ethcmd ;
3006
3004
int rc ;
3007
3005
3006
+ if (copy_from_user (& ethcmd , useraddr , sizeof (ethcmd )))
3007
+ return - EFAULT ;
3008
+
3009
+ state = kzalloc (sizeof (* state ), GFP_KERNEL );
3010
+ if (!state )
3011
+ return - ENOMEM ;
3012
+
3013
+ switch (ethcmd ) {
3014
+ case ETHTOOL_FLASHDEV :
3015
+ if (copy_from_user (& state -> efl , useraddr , sizeof (state -> efl ))) {
3016
+ rc = - EFAULT ;
3017
+ goto exit_free ;
3018
+ }
3019
+ state -> efl .data [ETHTOOL_FLASH_MAX_FILENAME - 1 ] = 0 ;
3020
+ break ;
3021
+ }
3022
+
3008
3023
rtnl_lock ();
3009
- rc = __dev_ethtool (net , ifr , useraddr );
3024
+ rc = __dev_ethtool (net , ifr , useraddr , ethcmd , state );
3010
3025
rtnl_unlock ();
3026
+ if (rc )
3027
+ goto exit_free ;
3028
+
3029
+ switch (ethcmd ) {
3030
+ case ETHTOOL_GDRVINFO :
3031
+ if (copy_to_user (useraddr , & state -> info , sizeof (state -> info ))) {
3032
+ rc = - EFAULT ;
3033
+ goto exit_free ;
3034
+ }
3035
+ break ;
3036
+ }
3011
3037
3038
+ exit_free :
3039
+ kfree (state );
3012
3040
return rc ;
3013
3041
}
3014
3042
0 commit comments