aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Garzik <jgarzik@redhat.com>2010-03-03 17:51:50 -0500
committerDavid S. Miller <davem@davemloft.net>2010-03-05 17:00:17 -0500
commit723b2f57ad83ee7087acf9a95e8e289414b1f521 (patch)
treee8120bff2899245d2c84905b1368a128bf881268
parent4b79a1aedcb9dd6e3f27b970dcb553aefcd97254 (diff)
ethtool: Add direct access to ops->get_sset_count
This patch is an alternative approach for accessing string counts, vs. the drvinfo indirect approach. This way the drvinfo space doesn't run out, and we don't break ABI later. Signed-off-by: Jeff Garzik <jgarzik@redhat.com> Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/ethtool.h17
-rw-r--r--net/core/ethtool.c72
2 files changed, 86 insertions, 3 deletions
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index cca1c3de140d..f6f961fefbe5 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -253,6 +253,17 @@ struct ethtool_gstrings {
253 __u8 data[0]; 253 __u8 data[0];
254}; 254};
255 255
256struct ethtool_sset_info {
257 __u32 cmd; /* ETHTOOL_GSSET_INFO */
258 __u32 reserved;
259 __u64 sset_mask; /* input: each bit selects an sset to query */
260 /* output: each bit a returned sset */
261 __u32 data[0]; /* ETH_SS_xxx count, in order, based on bits
262 in sset_mask. One bit implies one
263 __u32, two bits implies two
264 __u32's, etc. */
265};
266
256enum ethtool_test_flags { 267enum ethtool_test_flags {
257 ETH_TEST_FL_OFFLINE = (1 << 0), /* online / offline */ 268 ETH_TEST_FL_OFFLINE = (1 << 0), /* online / offline */
258 ETH_TEST_FL_FAILED = (1 << 1), /* test passed / failed */ 269 ETH_TEST_FL_FAILED = (1 << 1), /* test passed / failed */
@@ -606,9 +617,9 @@ struct ethtool_ops {
606#define ETHTOOL_SRXCLSRLINS 0x00000032 /* Insert RX classification rule */ 617#define ETHTOOL_SRXCLSRLINS 0x00000032 /* Insert RX classification rule */
607#define ETHTOOL_FLASHDEV 0x00000033 /* Flash firmware to device */ 618#define ETHTOOL_FLASHDEV 0x00000033 /* Flash firmware to device */
608#define ETHTOOL_RESET 0x00000034 /* Reset hardware */ 619#define ETHTOOL_RESET 0x00000034 /* Reset hardware */
609 620#define ETHTOOL_SRXNTUPLE 0x00000035 /* Add an n-tuple filter to device */
610#define ETHTOOL_SRXNTUPLE 0x00000035 /* Add an n-tuple filter to device */ 621#define ETHTOOL_GRXNTUPLE 0x00000036 /* Get n-tuple filters from device */
611#define ETHTOOL_GRXNTUPLE 0x00000036 /* Get n-tuple filters from device */ 622#define ETHTOOL_GSSET_INFO 0x00000037 /* Get string set info */
612 623
613/* compatibility with older code */ 624/* compatibility with older code */
614#define SPARC_ETH_GSET ETHTOOL_GSET 625#define SPARC_ETH_GSET ETHTOOL_GSET
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 0f2f82185ec4..70075c47ada8 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -214,6 +214,10 @@ static noinline int ethtool_get_drvinfo(struct net_device *dev, void __user *use
214 info.cmd = ETHTOOL_GDRVINFO; 214 info.cmd = ETHTOOL_GDRVINFO;
215 ops->get_drvinfo(dev, &info); 215 ops->get_drvinfo(dev, &info);
216 216
217 /*
218 * this method of obtaining string set info is deprecated;
219 * consider using ETHTOOL_GSSET_INFO instead
220 */
217 if (ops->get_sset_count) { 221 if (ops->get_sset_count) {
218 int rc; 222 int rc;
219 223
@@ -240,6 +244,71 @@ static noinline int ethtool_get_drvinfo(struct net_device *dev, void __user *use
240/* 244/*
241 * noinline attribute so that gcc doesnt use too much stack in dev_ethtool() 245 * noinline attribute so that gcc doesnt use too much stack in dev_ethtool()
242 */ 246 */
247static noinline int ethtool_get_sset_info(struct net_device *dev,
248 void __user *useraddr)
249{
250 struct ethtool_sset_info info;
251 const struct ethtool_ops *ops = dev->ethtool_ops;
252 u64 sset_mask;
253 int i, idx = 0, n_bits = 0, ret, rc;
254 u32 *info_buf = NULL;
255
256 if (!ops->get_sset_count)
257 return -EOPNOTSUPP;
258
259 if (copy_from_user(&info, useraddr, sizeof(info)))
260 return -EFAULT;
261
262 /* store copy of mask, because we zero struct later on */
263 sset_mask = info.sset_mask;
264 if (!sset_mask)
265 return 0;
266
267 /* calculate size of return buffer */
268 for (i = 0; i < 64; i++)
269 if (sset_mask & (1ULL << i))
270 n_bits++;
271
272 memset(&info, 0, sizeof(info));
273 info.cmd = ETHTOOL_GSSET_INFO;
274
275 info_buf = kzalloc(n_bits * sizeof(u32), GFP_USER);
276 if (!info_buf)
277 return -ENOMEM;
278
279 /*
280 * fill return buffer based on input bitmask and successful
281 * get_sset_count return
282 */
283 for (i = 0; i < 64; i++) {
284 if (!(sset_mask & (1ULL << i)))
285 continue;
286
287 rc = ops->get_sset_count(dev, i);
288 if (rc >= 0) {
289 info.sset_mask |= (1ULL << i);
290 info_buf[idx++] = rc;
291 }
292 }
293
294 ret = -EFAULT;
295 if (copy_to_user(useraddr, &info, sizeof(info)))
296 goto out;
297
298 useraddr += offsetof(struct ethtool_sset_info, data);
299 if (copy_to_user(useraddr, info_buf, idx * sizeof(u32)))
300 goto out;
301
302 ret = 0;
303
304out:
305 kfree(info_buf);
306 return ret;
307}
308
309/*
310 * noinline attribute so that gcc doesnt use too much stack in dev_ethtool()
311 */
243static noinline int ethtool_set_rxnfc(struct net_device *dev, void __user *useraddr) 312static noinline int ethtool_set_rxnfc(struct net_device *dev, void __user *useraddr)
244{ 313{
245 struct ethtool_rxnfc cmd; 314 struct ethtool_rxnfc cmd;
@@ -1471,6 +1540,9 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
1471 case ETHTOOL_GRXNTUPLE: 1540 case ETHTOOL_GRXNTUPLE:
1472 rc = ethtool_get_rx_ntuple(dev, useraddr); 1541 rc = ethtool_get_rx_ntuple(dev, useraddr);
1473 break; 1542 break;
1543 case ETHTOOL_GSSET_INFO:
1544 rc = ethtool_get_sset_info(dev, useraddr);
1545 break;
1474 default: 1546 default:
1475 rc = -EOPNOTSUPP; 1547 rc = -EOPNOTSUPP;
1476 } 1548 }