@@ -1060,6 +1060,93 @@ static int ethtool_check_flow_types(struct net_device *dev, u32 input_xfrm)
1060
1060
return 0 ;
1061
1061
}
1062
1062
1063
+ static noinline_for_stack int
1064
+ ethtool_set_rxfh_fields (struct net_device * dev , u32 cmd , void __user * useraddr )
1065
+ {
1066
+ const struct ethtool_ops * ops = dev -> ethtool_ops ;
1067
+ struct ethtool_rxnfc info ;
1068
+ size_t info_size = sizeof (info );
1069
+ int rc ;
1070
+
1071
+ if (!ops -> set_rxnfc )
1072
+ return - EOPNOTSUPP ;
1073
+
1074
+ rc = ethtool_rxnfc_copy_struct (cmd , & info , & info_size , useraddr );
1075
+ if (rc )
1076
+ return rc ;
1077
+
1078
+ if (cmd == ETHTOOL_SRXCLSRLINS && info .fs .flow_type & FLOW_RSS ) {
1079
+ /* Nonzero ring with RSS only makes sense
1080
+ * if NIC adds them together
1081
+ */
1082
+ if (!ops -> cap_rss_rxnfc_adds &&
1083
+ ethtool_get_flow_spec_ring (info .fs .ring_cookie ))
1084
+ return - EINVAL ;
1085
+
1086
+ if (!xa_load (& dev -> ethtool -> rss_ctx , info .rss_context ))
1087
+ return - EINVAL ;
1088
+ }
1089
+
1090
+ if (cmd == ETHTOOL_SRXFH && ops -> get_rxfh ) {
1091
+ struct ethtool_rxfh_param rxfh = {};
1092
+
1093
+ rc = ops -> get_rxfh (dev , & rxfh );
1094
+ if (rc )
1095
+ return rc ;
1096
+
1097
+ rc = ethtool_check_xfrm_rxfh (rxfh .input_xfrm , info .data );
1098
+ if (rc )
1099
+ return rc ;
1100
+ }
1101
+
1102
+ rc = ops -> set_rxnfc (dev , & info );
1103
+ if (rc )
1104
+ return rc ;
1105
+
1106
+ if (cmd == ETHTOOL_SRXCLSRLINS &&
1107
+ ethtool_rxnfc_copy_to_user (useraddr , & info , info_size , NULL ))
1108
+ return - EFAULT ;
1109
+
1110
+ return 0 ;
1111
+ }
1112
+
1113
+ static noinline_for_stack int
1114
+ ethtool_get_rxfh_fields (struct net_device * dev , u32 cmd , void __user * useraddr )
1115
+ {
1116
+ struct ethtool_rxnfc info ;
1117
+ size_t info_size = sizeof (info );
1118
+ const struct ethtool_ops * ops = dev -> ethtool_ops ;
1119
+ int ret ;
1120
+ void * rule_buf = NULL ;
1121
+
1122
+ if (!ops -> get_rxnfc )
1123
+ return - EOPNOTSUPP ;
1124
+
1125
+ ret = ethtool_rxnfc_copy_struct (cmd , & info , & info_size , useraddr );
1126
+ if (ret )
1127
+ return ret ;
1128
+
1129
+ if (info .cmd == ETHTOOL_GRXCLSRLALL ) {
1130
+ if (info .rule_cnt > 0 ) {
1131
+ if (info .rule_cnt <= KMALLOC_MAX_SIZE / sizeof (u32 ))
1132
+ rule_buf = kcalloc (info .rule_cnt , sizeof (u32 ),
1133
+ GFP_USER );
1134
+ if (!rule_buf )
1135
+ return - ENOMEM ;
1136
+ }
1137
+ }
1138
+
1139
+ ret = ops -> get_rxnfc (dev , & info , rule_buf );
1140
+ if (ret < 0 )
1141
+ goto err_out ;
1142
+
1143
+ ret = ethtool_rxnfc_copy_to_user (useraddr , & info , info_size , rule_buf );
1144
+ err_out :
1145
+ kfree (rule_buf );
1146
+
1147
+ return ret ;
1148
+ }
1149
+
1063
1150
static noinline_for_stack int ethtool_set_rxnfc (struct net_device * dev ,
1064
1151
u32 cmd , void __user * useraddr )
1065
1152
{
@@ -3339,13 +3426,17 @@ __dev_ethtool(struct net *net, struct ifreq *ifr, void __user *useraddr,
3339
3426
dev -> ethtool_ops -> set_priv_flags );
3340
3427
break ;
3341
3428
case ETHTOOL_GRXFH :
3429
+ rc = ethtool_get_rxfh_fields (dev , ethcmd , useraddr );
3430
+ break ;
3431
+ case ETHTOOL_SRXFH :
3432
+ rc = ethtool_set_rxfh_fields (dev , ethcmd , useraddr );
3433
+ break ;
3342
3434
case ETHTOOL_GRXRINGS :
3343
3435
case ETHTOOL_GRXCLSRLCNT :
3344
3436
case ETHTOOL_GRXCLSRULE :
3345
3437
case ETHTOOL_GRXCLSRLALL :
3346
3438
rc = ethtool_get_rxnfc (dev , ethcmd , useraddr );
3347
3439
break ;
3348
- case ETHTOOL_SRXFH :
3349
3440
case ETHTOOL_SRXCLSRLDEL :
3350
3441
case ETHTOOL_SRXCLSRLINS :
3351
3442
rc = ethtool_set_rxnfc (dev , ethcmd , useraddr );
0 commit comments