diff options
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/ethtool.c | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 69a3edc182f9..c1a71bb738da 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c | |||
@@ -178,6 +178,64 @@ static void ethtool_get_features_compat(struct net_device *dev, | |||
178 | if (dev->ethtool_ops->get_rx_csum) | 178 | if (dev->ethtool_ops->get_rx_csum) |
179 | if (dev->ethtool_ops->get_rx_csum(dev)) | 179 | if (dev->ethtool_ops->get_rx_csum(dev)) |
180 | features[0].active |= NETIF_F_RXCSUM; | 180 | features[0].active |= NETIF_F_RXCSUM; |
181 | |||
182 | /* mark legacy-changeable features */ | ||
183 | if (dev->ethtool_ops->set_sg) | ||
184 | features[0].available |= NETIF_F_SG; | ||
185 | if (dev->ethtool_ops->set_tx_csum) | ||
186 | features[0].available |= NETIF_F_ALL_CSUM; | ||
187 | if (dev->ethtool_ops->set_tso) | ||
188 | features[0].available |= NETIF_F_ALL_TSO; | ||
189 | if (dev->ethtool_ops->set_rx_csum) | ||
190 | features[0].available |= NETIF_F_RXCSUM; | ||
191 | if (dev->ethtool_ops->set_flags) | ||
192 | features[0].available |= flags_dup_features; | ||
193 | } | ||
194 | |||
195 | static int ethtool_set_feature_compat(struct net_device *dev, | ||
196 | int (*legacy_set)(struct net_device *, u32), | ||
197 | struct ethtool_set_features_block *features, u32 mask) | ||
198 | { | ||
199 | u32 do_set; | ||
200 | |||
201 | if (!legacy_set) | ||
202 | return 0; | ||
203 | |||
204 | if (!(features[0].valid & mask)) | ||
205 | return 0; | ||
206 | |||
207 | features[0].valid &= ~mask; | ||
208 | |||
209 | do_set = !!(features[0].requested & mask); | ||
210 | |||
211 | if (legacy_set(dev, do_set) < 0) | ||
212 | netdev_info(dev, | ||
213 | "Legacy feature change (%s) failed for 0x%08x\n", | ||
214 | do_set ? "set" : "clear", mask); | ||
215 | |||
216 | return 1; | ||
217 | } | ||
218 | |||
219 | static int ethtool_set_features_compat(struct net_device *dev, | ||
220 | struct ethtool_set_features_block *features) | ||
221 | { | ||
222 | int compat; | ||
223 | |||
224 | if (!dev->ethtool_ops) | ||
225 | return 0; | ||
226 | |||
227 | compat = ethtool_set_feature_compat(dev, dev->ethtool_ops->set_sg, | ||
228 | features, NETIF_F_SG); | ||
229 | compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_tx_csum, | ||
230 | features, NETIF_F_ALL_CSUM); | ||
231 | compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_tso, | ||
232 | features, NETIF_F_ALL_TSO); | ||
233 | compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_rx_csum, | ||
234 | features, NETIF_F_RXCSUM); | ||
235 | compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_flags, | ||
236 | features, flags_dup_features); | ||
237 | |||
238 | return compat; | ||
181 | } | 239 | } |
182 | 240 | ||
183 | static int ethtool_get_features(struct net_device *dev, void __user *useraddr) | 241 | static int ethtool_get_features(struct net_device *dev, void __user *useraddr) |
@@ -234,6 +292,9 @@ static int ethtool_set_features(struct net_device *dev, void __user *useraddr) | |||
234 | if (features[0].valid & ~NETIF_F_ETHTOOL_BITS) | 292 | if (features[0].valid & ~NETIF_F_ETHTOOL_BITS) |
235 | return -EINVAL; | 293 | return -EINVAL; |
236 | 294 | ||
295 | if (ethtool_set_features_compat(dev, features)) | ||
296 | ret |= ETHTOOL_F_COMPAT; | ||
297 | |||
237 | if (features[0].valid & ~dev->hw_features) { | 298 | if (features[0].valid & ~dev->hw_features) { |
238 | features[0].valid &= dev->hw_features; | 299 | features[0].valid &= dev->hw_features; |
239 | ret |= ETHTOOL_F_UNSUPPORTED; | 300 | ret |= ETHTOOL_F_UNSUPPORTED; |