netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH ethtool 00/21] ethtool refactoring and misc changes
@ 2011-11-01 22:35 Ben Hutchings
  2011-11-01 23:13 ` [PATCH ethtool 01/21] Report pause frame autonegotiation result Ben Hutchings
                   ` (21 more replies)
  0 siblings, 22 replies; 24+ messages in thread
From: Ben Hutchings @ 2011-11-01 22:35 UTC (permalink / raw)
  To: netdev; +Cc: linux-net-drivers

As I looked into supporting features cleanly within the existing -k/-K
options, it became clear that ethtool was overdue for refactoring.  And
in order to be confident about doing that, I needed to add some tests.

So I intend to push the following changes:

1. Reporting of pause frame autonegotiation.  I don't believe this
   requires a new command in the kernel interface; it just needs drivers
   to fill out the AN flags.

2. Minor fixes to manual page and online help.

3. Cleanup of ethtool-bitops.h and ethtool-util.h.

4. Encapsulate shared command state into a structure passed into each
   sub-command function (and several others).

5. Test argument parsing.  Currently this just checks that each command
   line is accepted or rejected as expected.

6. For each sub-command (option), move all argument parsing into the
   function that implements it.  Move the associated static variables
   likewise.  Declare static constants as const, so that there are no
   static variables left (outside of the test wrapper).

7. Run the main ethtool code in the same process as the test code.
   This will allow for test cases that cover the ioctl requests and
   responses.

Ben.

Ben Hutchings (21):
  Report pause frame autonegotiation result
  ethtool.8: Fix initial blank line/page
  Combine ethtool-{bitops,util}.h into internal.h
  Fix type of bit-number parameter to set_bit() and clear_bit()
  ethtool.8: Change device name metavariable from 'ethX' to 'devname'
  ethtool.8: Allow line-break in description of parameters after -N
  Fix format of help text for -f option
  Use standard indentation for definition of struct option args
  Encapsulate command context in a structure
  Add test cases for command-line parsing
  Add more test cases for command-line parsing
  Move argument parsing to sub-command functions
  Support arbitrary numbers of option names for each mode
  Fix reference to cmdline_ring in do_schannels()
  Convert cmdline_msglvl into array of named flags; convert back at
    run-time
  Replace global devname variable with a field in struct cmd_context
  Change most static global variables into automatic variables
  rxclass: Replace global rmgr with automatic variable/parameter
  Declare static variables const as appropriate
  Run tests in-process
  Rearrange definitions and remove unnecessary forward declarations

 Makefile.am                  |    7 +-
 amd8111e.c                   |    2 +-
 at76c50x-usb.c               |    2 +-
 configure.ac                 |    1 +
 de2104x.c                    |    2 +-
 e100.c                       |    2 +-
 e1000.c                      |    2 +-
 ethtool-bitops.h             |   25 -
 ethtool.8.in                 |   70 +-
 ethtool.c                    | 2352 +++++++++++++++++++-----------------------
 fec_8xx.c                    |    2 +-
 ibm_emac.c                   |    2 +-
 igb.c                        |    2 +-
 ethtool-util.h => internal.h |   57 +-
 ixgb.c                       |    2 +-
 ixgbe.c                      |    2 +-
 marvell.c                    |    2 +-
 natsemi.c                    |    2 +-
 pcnet32.c                    |    2 +-
 realtek.c                    |    2 +-
 rxclass.c                    |  129 +--
 sfc.c                        |    2 +-
 smsc911x.c                   |    2 +-
 stmmac.c                     |    2 +-
 test-cmdline.c               |  240 +++++
 test-common.c                |  101 ++
 tg3.c                        |    2 +-
 vioc.c                       |    2 +-
 28 files changed, 1565 insertions(+), 1455 deletions(-)
 delete mode 100644 ethtool-bitops.h
 rename ethtool-util.h => internal.h (71%)
 create mode 100644 test-cmdline.c
 create mode 100644 test-common.c

-- 
1.7.4.4


-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH ethtool 01/21] Report pause frame autonegotiation result
  2011-11-01 22:35 [PATCH ethtool 00/21] ethtool refactoring and misc changes Ben Hutchings
@ 2011-11-01 23:13 ` Ben Hutchings
  2011-11-01 23:13 ` [PATCH ethtool 02/21] ethtool.8: Fix initial blank line/page Ben Hutchings
                   ` (20 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Ben Hutchings @ 2011-11-01 23:13 UTC (permalink / raw)
  To: netdev; +Cc: linux-net-drivers, Matt Carlson

If pause frame autonegotiation is enabled and the driver reports the
link partner's advertising flags, report the result of autonegotiation.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 ethtool.c |   46 ++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 40 insertions(+), 6 deletions(-)

diff --git a/ethtool.c b/ethtool.c
index a4e8b58..ad2d583 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -1745,7 +1745,7 @@ static int dump_test(struct ethtool_drvinfo *info, struct ethtool_test *test,
 	return rc;
 }
 
-static int dump_pause(void)
+static int dump_pause(u32 advertising, u32 lp_advertising)
 {
 	fprintf(stdout,
 		"Autonegotiate:	%s\n"
@@ -1755,6 +1755,30 @@ static int dump_pause(void)
 		epause.rx_pause ? "on" : "off",
 		epause.tx_pause ? "on" : "off");
 
+	if (lp_advertising) {
+		int an_rx = 0, an_tx = 0;
+
+		/* Work out negotiated pause frame usage per
+		 * IEEE 802.3-2005 table 28B-3.
+		 */
+		if (advertising & lp_advertising & ADVERTISED_Pause) {
+			an_tx = 1;
+			an_rx = 1;
+		} else if (advertising & lp_advertising &
+			   ADVERTISED_Asym_Pause) {
+			if (advertising & ADVERTISED_Pause)
+				an_rx = 1;
+			else if (lp_advertising & ADVERTISED_Pause)
+				an_tx = 1;
+		}
+
+		fprintf(stdout,
+			"RX negotiated:	%s\n"
+			"TX negotiated:	%s\n",
+			an_rx ? "on" : "off",
+			an_tx ? "on" : "off");
+	}
+
 	fprintf(stdout, "\n");
 	return 0;
 }
@@ -2051,6 +2075,7 @@ static int do_gdrv(int fd, struct ifreq *ifr)
 
 static int do_gpause(int fd, struct ifreq *ifr)
 {
+	struct ethtool_cmd ecmd;
 	int err;
 
 	fprintf(stdout, "Pause parameters for %s:\n", devname);
@@ -2058,15 +2083,24 @@ static int do_gpause(int fd, struct ifreq *ifr)
 	epause.cmd = ETHTOOL_GPAUSEPARAM;
 	ifr->ifr_data = (caddr_t)&epause;
 	err = send_ioctl(fd, ifr);
-	if (err == 0) {
-		err = dump_pause();
-		if (err)
-			return err;
-	} else {
+	if (err) {
 		perror("Cannot get device pause settings");
 		return 76;
 	}
 
+	if (epause.autoneg) {
+		ecmd.cmd = ETHTOOL_GSET;
+		ifr->ifr_data = (caddr_t)&ecmd;
+		err = send_ioctl(fd, ifr);
+		if (err) {
+			perror("Cannot get device settings");
+			return 1;
+		}
+		dump_pause(ecmd.advertising, ecmd.lp_advertising);
+	} else {
+		dump_pause(0, 0);
+	}
+
 	return 0;
 }
 
-- 
1.7.4.4



-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH ethtool 02/21] ethtool.8: Fix initial blank line/page
  2011-11-01 22:35 [PATCH ethtool 00/21] ethtool refactoring and misc changes Ben Hutchings
  2011-11-01 23:13 ` [PATCH ethtool 01/21] Report pause frame autonegotiation result Ben Hutchings
@ 2011-11-01 23:13 ` Ben Hutchings
  2011-11-01 23:14 ` [PATCH ethtool 03/21] Combine ethtool-{bitops,util}.h into internal.h Ben Hutchings
                   ` (19 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Ben Hutchings @ 2011-11-01 23:13 UTC (permalink / raw)
  To: netdev; +Cc: linux-net-drivers

Commit 8d63f72ccdcb1b19358d753a8f48f08dcd2136f0 included a regression
of the problem fixed in commit 97b5471fc446d60f8772631b9c4e6d824404336d.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 ethtool.8.in |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/ethtool.8.in b/ethtool.8.in
index f9d3633..286d089 100644
--- a/ethtool.8.in
+++ b/ethtool.8.in
@@ -75,7 +75,7 @@
 .\"	\(*NC - Network Classifier type values
 .\"
 .ds NC \fBether\fP|\fBip4\fP|\fBtcp4\fP|\fBudp4\fP|\fBsctp4\fP|\fBah4\fP|\fBesp4\fP
-
+..
 .\"
 .\" Start URL.
 .de UR
-- 
1.7.4.4



-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH ethtool 03/21] Combine ethtool-{bitops,util}.h into internal.h
  2011-11-01 22:35 [PATCH ethtool 00/21] ethtool refactoring and misc changes Ben Hutchings
  2011-11-01 23:13 ` [PATCH ethtool 01/21] Report pause frame autonegotiation result Ben Hutchings
  2011-11-01 23:13 ` [PATCH ethtool 02/21] ethtool.8: Fix initial blank line/page Ben Hutchings
@ 2011-11-01 23:14 ` Ben Hutchings
  2011-11-01 23:14 ` [PATCH ethtool 04/21] Fix type of bit-number parameter to set_bit() and clear_bit() Ben Hutchings
                   ` (18 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Ben Hutchings @ 2011-11-01 23:14 UTC (permalink / raw)
  To: netdev; +Cc: linux-net-drivers

ethtool-util.h contains all kinds of declarations, not just utility
functions or macros.

ethtool-bitops.h contains just a few extra definitions, and its only
user also includes ethtool-util.h.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 Makefile.am                  |    2 +-
 amd8111e.c                   |    2 +-
 at76c50x-usb.c               |    2 +-
 de2104x.c                    |    2 +-
 e100.c                       |    2 +-
 e1000.c                      |    2 +-
 ethtool-bitops.h             |   25 -------------------------
 ethtool.c                    |    2 +-
 fec_8xx.c                    |    2 +-
 ibm_emac.c                   |    2 +-
 igb.c                        |    2 +-
 ethtool-util.h => internal.h |   27 ++++++++++++++++++++++++---
 ixgb.c                       |    2 +-
 ixgbe.c                      |    2 +-
 marvell.c                    |    2 +-
 natsemi.c                    |    2 +-
 pcnet32.c                    |    2 +-
 realtek.c                    |    2 +-
 rxclass.c                    |    3 +--
 sfc.c                        |    2 +-
 smsc911x.c                   |    2 +-
 stmmac.c                     |    2 +-
 tg3.c                        |    2 +-
 vioc.c                       |    2 +-
 24 files changed, 46 insertions(+), 51 deletions(-)
 delete mode 100644 ethtool-bitops.h
 rename ethtool-util.h => internal.h (86%)

diff --git a/Makefile.am b/Makefile.am
index c87fb39..1e05640 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4,7 +4,7 @@ man_MANS = ethtool.8
 EXTRA_DIST = LICENSE ethtool.8 ethtool.spec.in aclocal.m4 ChangeLog autogen.sh
 
 sbin_PROGRAMS = ethtool
-ethtool_SOURCES = ethtool.c ethtool-bitops.h ethtool-copy.h ethtool-util.h \
+ethtool_SOURCES = ethtool.c ethtool-copy.h internal.h \
 		  amd8111e.c de2104x.c e100.c e1000.c igb.c	\
 		  fec_8xx.c ibm_emac.c ixgb.c ixgbe.c natsemi.c	\
 		  pcnet32.c realtek.c tg3.c marvell.c vioc.c	\
diff --git a/amd8111e.c b/amd8111e.c
index b4cd65d..23478f0 100644
--- a/amd8111e.c
+++ b/amd8111e.c
@@ -1,7 +1,7 @@
 
 /* Copyright (C) 2003  Advanced Micro Devices Inc. */
 #include <stdio.h>
-#include "ethtool-util.h"
+#include "internal.h"
 
 typedef enum {
 	/* VAL2 */
diff --git a/at76c50x-usb.c b/at76c50x-usb.c
index 4c2a1a8..39e24a4 100644
--- a/at76c50x-usb.c
+++ b/at76c50x-usb.c
@@ -1,5 +1,5 @@
 #include <stdio.h>
-#include "ethtool-util.h"
+#include "internal.h"
 
 static char *hw_versions[] = {
         "503_ISL3861",
diff --git a/de2104x.c b/de2104x.c
index f64e1b2..856e0c0 100644
--- a/de2104x.c
+++ b/de2104x.c
@@ -1,6 +1,6 @@
 /* Copyright 2001 Sun Microsystems (thockin@sun.com) */
 #include <stdio.h>
-#include "ethtool-util.h"
+#include "internal.h"
 
 static const char * const csr0_tap[4] = {
 	"No transmit automatic polling",
diff --git a/e100.c b/e100.c
index 4d1cef3..65627ab 100644
--- a/e100.c
+++ b/e100.c
@@ -1,6 +1,6 @@
 /* Copyright (c) 2002 Intel Corporation */
 #include <stdio.h>
-#include "ethtool-util.h"
+#include "internal.h"
 
 #define D102_REV_ID		12
 
diff --git a/e1000.c b/e1000.c
index 2eb3ac6..d1d3c73 100644
--- a/e1000.c
+++ b/e1000.c
@@ -1,6 +1,6 @@
 /* Copyright (c) 2002 Intel Corporation */
 #include <stdio.h>
-#include "ethtool-util.h"
+#include "internal.h"
 
 /* Register Bit Masks */
 /* Device Control */
diff --git a/ethtool-bitops.h b/ethtool-bitops.h
deleted file mode 100644
index b1eb426..0000000
--- a/ethtool-bitops.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef ETHTOOL_BITOPS_H__
-#define ETHTOOL_BITOPS_H__
-
-#define BITS_PER_BYTE		8
-#define BITS_PER_LONG		(BITS_PER_BYTE * sizeof(long))
-#define DIV_ROUND_UP(n, d)	(((n) + (d) - 1) / (d))
-#define BITS_TO_LONGS(nr)	DIV_ROUND_UP(nr, BITS_PER_LONG)
-
-static inline void set_bit(int nr, unsigned long *addr)
-{
-	addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG);
-}
-
-static inline void clear_bit(int nr, unsigned long *addr)
-{
-	addr[nr / BITS_PER_LONG] &= ~(1UL << (nr % BITS_PER_LONG));
-}
-
-static inline int test_bit(unsigned int nr, const unsigned long *addr)
-{
-	return !!((1UL << (nr % BITS_PER_LONG)) &
-		  (((unsigned long *)addr)[nr / BITS_PER_LONG]));
-}
-
-#endif
diff --git a/ethtool.c b/ethtool.c
index ad2d583..f772f61 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -23,7 +23,7 @@
  *   * show settings for all devices
  */
 
-#include "ethtool-util.h"
+#include "internal.h"
 #include <string.h>
 #include <stdlib.h>
 #include <sys/stat.h>
diff --git a/fec_8xx.c b/fec_8xx.c
index 06a25d9..69db8c8 100644
--- a/fec_8xx.c
+++ b/fec_8xx.c
@@ -7,7 +7,7 @@
 #include <stdint.h>
 #include <stddef.h>
 
-#include "ethtool-util.h"
+#include "internal.h"
 
 struct fec {
 	uint32_t	addr_low;	/* lower 32 bits of station address	*/
diff --git a/ibm_emac.c b/ibm_emac.c
index 7974836..e128e48 100644
--- a/ibm_emac.c
+++ b/ibm_emac.c
@@ -6,7 +6,7 @@
 #include <stdint.h>
 #include <stddef.h>
 
-#include "ethtool-util.h"
+#include "internal.h"
 
 /* Ethtool get_regs complex data.
  * we want to get not just EMAC registers, but also MAL, ZMII, RGMII, TAH
diff --git a/igb.c b/igb.c
index 4b836d9..ec35d36 100644
--- a/igb.c
+++ b/igb.c
@@ -1,6 +1,6 @@
 /* Copyright (c) 2007 Intel Corporation */
 #include <stdio.h>
-#include "ethtool-util.h"
+#include "internal.h"
 
 /* Register Bit Masks */
 /* Device Control */
diff --git a/ethtool-util.h b/internal.h
similarity index 86%
rename from ethtool-util.h
rename to internal.h
index 79be7f2..693b091 100644
--- a/ethtool-util.h
+++ b/internal.h
@@ -1,7 +1,7 @@
 /* Portions Copyright 2001 Sun Microsystems (thockin@sun.com) */
 /* Portions Copyright 2002 Intel (scott.feldman@intel.com) */
-#ifndef ETHTOOL_UTIL_H__
-#define ETHTOOL_UTIL_H__
+#ifndef ETHTOOL_INTERNAL_H__
+#define ETHTOOL_INTERNAL_H__
 
 #ifdef HAVE_CONFIG_H
 #include "ethtool-config.h"
@@ -57,6 +57,27 @@ static inline u64 cpu_to_be64(u64 value)
 #define ntohll cpu_to_be64
 #define htonll cpu_to_be64
 
+#define BITS_PER_BYTE		8
+#define BITS_PER_LONG		(BITS_PER_BYTE * sizeof(long))
+#define DIV_ROUND_UP(n, d)	(((n) + (d) - 1) / (d))
+#define BITS_TO_LONGS(nr)	DIV_ROUND_UP(nr, BITS_PER_LONG)
+
+static inline void set_bit(int nr, unsigned long *addr)
+{
+	addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG);
+}
+
+static inline void clear_bit(int nr, unsigned long *addr)
+{
+	addr[nr / BITS_PER_LONG] &= ~(1UL << (nr % BITS_PER_LONG));
+}
+
+static inline int test_bit(unsigned int nr, const unsigned long *addr)
+{
+	return !!((1UL << (nr % BITS_PER_LONG)) &
+		  (((unsigned long *)addr)[nr / BITS_PER_LONG]));
+}
+
 #ifndef ARRAY_SIZE
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 #endif
@@ -140,4 +161,4 @@ int rxclass_rule_ins(int fd, struct ifreq *ifr,
 		     struct ethtool_rx_flow_spec *fsp);
 int rxclass_rule_del(int fd, struct ifreq *ifr, __u32 loc);
 
-#endif /* ETHTOOL_UTIL_H__ */
+#endif /* ETHTOOL_INTERNAL_H__ */
diff --git a/ixgb.c b/ixgb.c
index 00c90d3..8687c21 100644
--- a/ixgb.c
+++ b/ixgb.c
@@ -1,6 +1,6 @@
 /* Copyright (c) 2006 Intel Corporation */
 #include <stdio.h>
-#include "ethtool-util.h"
+#include "internal.h"
 
 /* CTRL0 Bit Masks */
 #define IXGB_CTRL0_LRST           0x00000008
diff --git a/ixgbe.c b/ixgbe.c
index e64d34a..dae11d4 100644
--- a/ixgbe.c
+++ b/ixgbe.c
@@ -1,6 +1,6 @@
 /* Copyright (c) 2007 Intel Corporation */
 #include <stdio.h>
-#include "ethtool-util.h"
+#include "internal.h"
 
 /* Register Bit Masks */
 #define IXGBE_FCTRL_SBP            0x00000002
diff --git a/marvell.c b/marvell.c
index af38c21..e583c82 100644
--- a/marvell.c
+++ b/marvell.c
@@ -7,7 +7,7 @@
 
 #include <stdio.h>
 
-#include "ethtool-util.h"
+#include "internal.h"
 
 static void dump_addr(int n, const u8 *a)
 {
diff --git a/natsemi.c b/natsemi.c
index 24a7cb3..eaf83e2 100644
--- a/natsemi.c
+++ b/natsemi.c
@@ -1,6 +1,6 @@
 /* Copyright 2001 Sun Microsystems (thockin@sun.com) */
 #include <stdio.h>
-#include "ethtool-util.h"
+#include "internal.h"
 
 #define PCI_VENDOR_NATSEMI		0x100b
 #define PCI_DEVICE_DP83815		0x0020
diff --git a/pcnet32.c b/pcnet32.c
index 1dac02d..b87cee7 100644
--- a/pcnet32.c
+++ b/pcnet32.c
@@ -2,7 +2,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#include "ethtool-util.h"
+#include "internal.h"
 
 #define BIT0  0x0001
 #define BIT1  0x0002
diff --git a/realtek.c b/realtek.c
index 11ed835..c3d7ae5 100644
--- a/realtek.c
+++ b/realtek.c
@@ -1,7 +1,7 @@
 /* Copyright 2001 Sun Microsystems (thockin@sun.com) */
 #include <stdio.h>
 #include <stdlib.h>
-#include "ethtool-util.h"
+#include "internal.h"
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 
diff --git a/rxclass.c b/rxclass.c
index b227901..809b073 100644
--- a/rxclass.c
+++ b/rxclass.c
@@ -10,8 +10,7 @@
 
 #include <linux/sockios.h>
 #include <arpa/inet.h>
-#include "ethtool-util.h"
-#include "ethtool-bitops.h"
+#include "internal.h"
 
 static void invert_flow_mask(struct ethtool_rx_flow_spec *fsp)
 {
diff --git a/sfc.c b/sfc.c
index c8ca74a..46a617b 100644
--- a/sfc.c
+++ b/sfc.c
@@ -9,7 +9,7 @@
 
 #include <stdio.h>
 #include <string.h>
-#include "ethtool-util.h"
+#include "internal.h"
 
 #ifndef ARRAY_SIZE
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
diff --git a/smsc911x.c b/smsc911x.c
index 1aa39a1..c55b97b 100644
--- a/smsc911x.c
+++ b/smsc911x.c
@@ -1,6 +1,6 @@
 #include <stdio.h>
 #include <string.h>
-#include "ethtool-util.h"
+#include "internal.h"
 
 int smsc911x_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs)
 {
diff --git a/stmmac.c b/stmmac.c
index ad4311c..fb69bfe 100644
--- a/stmmac.c
+++ b/stmmac.c
@@ -12,7 +12,7 @@
 
 #include <stdio.h>
 #include <string.h>
-#include "ethtool-util.h"
+#include "internal.h"
 
 int st_mac100_dump_regs(struct ethtool_drvinfo *info,
 			struct ethtool_regs *regs)
diff --git a/tg3.c b/tg3.c
index 4868504..3232339 100644
--- a/tg3.c
+++ b/tg3.c
@@ -1,6 +1,6 @@
 #include <stdio.h>
 #include <string.h>
-#include "ethtool-util.h"
+#include "internal.h"
 
 #define TG3_MAGIC 0x669955aa
 
diff --git a/vioc.c b/vioc.c
index c771737..eff533d 100644
--- a/vioc.c
+++ b/vioc.c
@@ -2,7 +2,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#include "ethtool-util.h"
+#include "internal.h"
 
 struct regs_line {
 		u32	addr;
-- 
1.7.4.4



-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH ethtool 04/21] Fix type of bit-number parameter to set_bit() and clear_bit()
  2011-11-01 22:35 [PATCH ethtool 00/21] ethtool refactoring and misc changes Ben Hutchings
                   ` (2 preceding siblings ...)
  2011-11-01 23:14 ` [PATCH ethtool 03/21] Combine ethtool-{bitops,util}.h into internal.h Ben Hutchings
@ 2011-11-01 23:14 ` Ben Hutchings
  2011-11-01 23:15 ` [PATCH ethtool 05/21] ethtool.8: Change device name metavariable from 'ethX' to 'devname' Ben Hutchings
                   ` (17 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Ben Hutchings @ 2011-11-01 23:14 UTC (permalink / raw)
  To: netdev; +Cc: linux-net-drivers, Alexander Duyck

The index must not be negative, so the parameter does not need to be
signed.  Division and modulus on signed operands generally cannot be
optimised to right-shift and bitwise-and.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 internal.h |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/internal.h b/internal.h
index 693b091..2b6a54a 100644
--- a/internal.h
+++ b/internal.h
@@ -62,12 +62,12 @@ static inline u64 cpu_to_be64(u64 value)
 #define DIV_ROUND_UP(n, d)	(((n) + (d) - 1) / (d))
 #define BITS_TO_LONGS(nr)	DIV_ROUND_UP(nr, BITS_PER_LONG)
 
-static inline void set_bit(int nr, unsigned long *addr)
+static inline void set_bit(unsigned int nr, unsigned long *addr)
 {
 	addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG);
 }
 
-static inline void clear_bit(int nr, unsigned long *addr)
+static inline void clear_bit(unsigned int nr, unsigned long *addr)
 {
 	addr[nr / BITS_PER_LONG] &= ~(1UL << (nr % BITS_PER_LONG));
 }
-- 
1.7.4.4



-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH ethtool 05/21] ethtool.8: Change device name metavariable from 'ethX' to 'devname'
  2011-11-01 22:35 [PATCH ethtool 00/21] ethtool refactoring and misc changes Ben Hutchings
                   ` (3 preceding siblings ...)
  2011-11-01 23:14 ` [PATCH ethtool 04/21] Fix type of bit-number parameter to set_bit() and clear_bit() Ben Hutchings
@ 2011-11-01 23:15 ` Ben Hutchings
  2011-11-01 23:15 ` [PATCH ethtool 06/21] ethtool.8: Allow line-break in description of parameters after -N Ben Hutchings
                   ` (16 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Ben Hutchings @ 2011-11-01 23:15 UTC (permalink / raw)
  To: netdev; +Cc: linux-net-drivers

The name 'ethX' is a poor choice because:
- Many ethtool options are applicable to non-Ethernet devices
- Ethernet device names don't have to begin with 'eth', and the
  new convention is to use the prefix 'lan' for LAN-on-motherboard
  or 'pci' for PCI plug-in cards

The online help text already uses 'DEVNAME' instead, so change the
manual page to be consistent.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 ethtool.8.in |   62 +++++++++++++++++++++++++++++-----------------------------
 1 files changed, 31 insertions(+), 31 deletions(-)

diff --git a/ethtool.8.in b/ethtool.8.in
index 286d089..65392d6 100644
--- a/ethtool.8.in
+++ b/ethtool.8.in
@@ -123,26 +123,26 @@ ethtool \- query or control network driver and hardware settings
 .nh
 .HP
 .B ethtool
-.I ethX
+.I devname
 .HP
 .B ethtool \-h|\-\-help
 .HP
 .B ethtool \-\-version
 .HP
 .B ethtool \-a|\-\-show\-pause
-.I ethX
+.I devname
 .HP
 .B ethtool \-A|\-\-pause
-.I ethX
+.I devname
 .B2 autoneg on off
 .B2 rx on off
 .B2 tx on off
 .HP
 .B ethtool \-c|\-\-show\-coalesce
-.I ethX
+.I devname
 .HP
 .B ethtool \-C|\-\-coalesce
-.I ethX
+.I devname
 .B2 adaptive\-rx on off
 .B2 adaptive\-tx on off
 .BN rx\-usecs
@@ -167,43 +167,43 @@ ethtool \- query or control network driver and hardware settings
 .BN sample\-interval
 .HP
 .B ethtool \-g|\-\-show\-ring
-.I ethX
+.I devname
 .HP
 .B ethtool \-G|\-\-set\-ring
-.I ethX
+.I devname
 .BN rx
 .BN rx\-mini
 .BN rx\-jumbo
 .BN tx
 .HP
 .B ethtool \-i|\-\-driver
-.I ethX
+.I devname
 .HP
 .B ethtool \-d|\-\-register\-dump
-.I ethX
+.I devname
 .B2 raw on off
 .B2 hex on off
 .RB [ file 
 .IR name ]
 .HP
 .B ethtool \-e|\-\-eeprom\-dump
-.I ethX
+.I devname
 .B2 raw on off
 .BN offset
 .BN length
 .HP
 .B ethtool \-E|\-\-change\-eeprom
-.I ethX
+.I devname
 .BN magic
 .BN offset
 .BN length
 .BN value
 .HP
 .B ethtool \-k|\-\-show\-offload
-.I ethX
+.I devname
 .HP
 .B ethtool \-K|\-\-offload
-.I ethX
+.I devname
 .B2 rx on off
 .B2 tx on off
 .B2 sg on off
@@ -217,24 +217,24 @@ ethtool \- query or control network driver and hardware settings
 .B2 rxhash on off
 .HP
 .B ethtool \-p|\-\-identify
-.I ethX
+.I devname
 .RI [ N ]
 .HP
 .B ethtool \-P|\-\-show\-permaddr
-.I ethX
+.I devname
 .HP
 .B ethtool \-r|\-\-negotiate
-.I ethX
+.I devname
 .HP
 .B ethtool \-S|\-\-statistics
-.I ethX
+.I devname
 .HP
 .B ethtool \-t|\-\-test
-.I ethX
+.I devname
 .RI [\*(SD]
 .HP
 .B ethtool \-s
-.I ethX
+.I devname
 .BI speed \ N
 .B2 duplex half full
 .B4 port tp aui bnc mii fibre
@@ -251,27 +251,27 @@ ethtool \- query or control network driver and hardware settings
 .RB ...]
 .HP
 .B ethtool \-n
-.I ethX
+.I devname
 .RB [ rx\-flow\-hash \ \*(FL]
 .HP
 .B ethtool \-N
-.I ethX
+.I devname
 .RB [ rx\-flow\-hash \ \*(FL \  \*(HO]
 .HP
 .B ethtool \-w|\-\-get\-dump
-.I ethX
+.I devname
 .RB [ data
 .IR filename ]
 .HP
 .B ethtool\ \-W|\-\-set\-dump
-.I ethX
+.I devname
 .BI \ N
 .HP
 .B ethtool \-x|\-\-show\-rxfh\-indir
-.I ethX
+.I devname
 .HP
 .B ethtool \-X|\-\-set\-rxfh\-indir
-.I ethX
+.I devname
 .RB [\  equal
 .IR N \ |
 .BI weight\  W0
@@ -279,15 +279,15 @@ ethtool \- query or control network driver and hardware settings
 .RB ...\ ]
 .HP
 .B ethtool \-f|\-\-flash
-.I ethX
+.I devname
 .RI FILE
 .RI [ N ]
 .HP
 .B ethtool \-u|\-\-show\-ntuple
-.I ethX
+.I devname
 .BN rule
 .HP
-.BI ethtool\ \-U|\-\-config\-ntuple \ ethX
+.BI ethtool\ \-U|\-\-config\-ntuple \ devname
 .BN delete
 .RB [\  flow\-type \ \*(NC
 .RB [ src \ \*(MA\ [ m \ \*(MA]]
@@ -309,10 +309,10 @@ ethtool \- query or control network driver and hardware settings
 .RB ]
 .HP
 .B ethtool \-l|\-\-show\-channels
-.I ethX
+.I devname
 .HP
 .B ethtool \-L|\-\-set\-channels
-.I ethX
+.I devname
 .BN rx
 .BN tx
 .BN other
@@ -327,7 +327,7 @@ ethtool \- query or control network driver and hardware settings
 is used to query and control network device driver and hardware
 settings, particularly for wired Ethernet devices.
 
-.I ethX
+.I devname
 is the name of the network device on which ethtool should operate.
 
 .SH OPTIONS
-- 
1.7.4.4



-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH ethtool 06/21] ethtool.8: Allow line-break in description of parameters after -N
  2011-11-01 22:35 [PATCH ethtool 00/21] ethtool refactoring and misc changes Ben Hutchings
                   ` (4 preceding siblings ...)
  2011-11-01 23:15 ` [PATCH ethtool 05/21] ethtool.8: Change device name metavariable from 'ethX' to 'devname' Ben Hutchings
@ 2011-11-01 23:15 ` Ben Hutchings
  2011-11-01 23:15 ` [PATCH ethtool 07/21] Fix format of help text for -f option Ben Hutchings
                   ` (15 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Ben Hutchings @ 2011-11-01 23:15 UTC (permalink / raw)
  To: netdev; +Cc: linux-net-drivers

These lines are currently unbreakable and result in ugly wrapping
in an 80-column window.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 ethtool.8.in |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/ethtool.8.in b/ethtool.8.in
index 65392d6..3304fe5 100644
--- a/ethtool.8.in
+++ b/ethtool.8.in
@@ -256,7 +256,7 @@ ethtool \- query or control network driver and hardware settings
 .HP
 .B ethtool \-N
 .I devname
-.RB [ rx\-flow\-hash \ \*(FL \  \*(HO]
+.RB [ rx\-flow\-hash \ \*(FL \: \*(HO]
 .HP
 .B ethtool \-w|\-\-get\-dump
 .I devname
@@ -605,7 +605,7 @@ sctp6	SCTP over IPv6
 .B \-N \-\-config\-nfc
 Configures the receive network flow classification.
 .TP
-.BR rx\-flow\-hash \ \*(FL \ \*(HO
+.BR rx\-flow\-hash \ \*(FL \: \*(HO
 Configures the hash options for the specified network traffic type.
 .TS
 nokeep;
-- 
1.7.4.4



-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH ethtool 07/21] Fix format of help text for -f option
  2011-11-01 22:35 [PATCH ethtool 00/21] ethtool refactoring and misc changes Ben Hutchings
                   ` (5 preceding siblings ...)
  2011-11-01 23:15 ` [PATCH ethtool 06/21] ethtool.8: Allow line-break in description of parameters after -N Ben Hutchings
@ 2011-11-01 23:15 ` Ben Hutchings
  2011-11-01 23:15 ` [PATCH ethtool 08/21] Use standard indentation for definition of struct option args Ben Hutchings
                   ` (14 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Ben Hutchings @ 2011-11-01 23:15 UTC (permalink / raw)
  To: netdev; +Cc: linux-net-drivers

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 ethtool.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/ethtool.c b/ethtool.c
index f772f61..aab1e41 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -229,9 +229,9 @@ static struct option {
 		"options",
 		"		[ rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
 		"tcp6|udp6|ah6|esp6|sctp6 ]\n" },
-    { "-f", "--flash", MODE_FLASHDEV, "FILENAME " "Flash firmware image "
+    { "-f", "--flash", MODE_FLASHDEV, "Flash firmware image "
     		"from the specified file to a region on the device",
-		"               [ REGION-NUMBER-TO-FLASH ]\n" },
+		"               FILENAME [ REGION-NUMBER-TO-FLASH ]\n" },
     { "-N", "--config-nfc", MODE_SNFC, "Configure Rx network flow "
 		"classification options",
 		"		[ rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
-- 
1.7.4.4



-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH ethtool 08/21] Use standard indentation for definition of struct option args
  2011-11-01 22:35 [PATCH ethtool 00/21] ethtool refactoring and misc changes Ben Hutchings
                   ` (6 preceding siblings ...)
  2011-11-01 23:15 ` [PATCH ethtool 07/21] Fix format of help text for -f option Ben Hutchings
@ 2011-11-01 23:15 ` Ben Hutchings
  2011-11-01 23:16 ` [PATCH ethtool 09/21] Encapsulate command context in a structure Ben Hutchings
                   ` (13 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Ben Hutchings @ 2011-11-01 23:15 UTC (permalink / raw)
  To: netdev; +Cc: linux-net-drivers

Also put the whole of the help string on a line of its own where
necessary.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 ethtool.c |  280 +++++++++++++++++++++++++++++++------------------------------
 1 files changed, 142 insertions(+), 138 deletions(-)

diff --git a/ethtool.c b/ethtool.c
index aab1e41..f967f84 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -140,145 +140,149 @@ static enum {
 } mode = MODE_GSET;
 
 static struct option {
-    char *srt, *lng;
-    int Mode;
-    char *help;
-    char *opthelp;
+	char *srt, *lng;
+	int Mode;
+	char *help;
+	char *opthelp;
 } args[] = {
-    { "-s", "--change", MODE_SSET, "Change generic options",
-		"		[ speed %d ]\n"
-		"		[ duplex half|full ]\n"
-		"		[ port tp|aui|bnc|mii|fibre ]\n"
-		"		[ autoneg on|off ]\n"
-		"		[ advertise %x ]\n"
-		"		[ phyad %d ]\n"
-		"		[ xcvr internal|external ]\n"
-		"		[ wol p|u|m|b|a|g|s|d... ]\n"
-		"		[ sopass %x:%x:%x:%x:%x:%x ]\n"
-		"		[ msglvl %d | msglvl type on|off ... ]\n" },
-    { "-a", "--show-pause", MODE_GPAUSE, "Show pause options" },
-    { "-A", "--pause", MODE_SPAUSE, "Set pause options",
-      "		[ autoneg on|off ]\n"
-      "		[ rx on|off ]\n"
-      "		[ tx on|off ]\n" },
-    { "-c", "--show-coalesce", MODE_GCOALESCE, "Show coalesce options" },
-    { "-C", "--coalesce", MODE_SCOALESCE, "Set coalesce options",
-		"		[adaptive-rx on|off]\n"
-		"		[adaptive-tx on|off]\n"
-		"		[rx-usecs N]\n"
-		"		[rx-frames N]\n"
-		"		[rx-usecs-irq N]\n"
-		"		[rx-frames-irq N]\n"
-		"		[tx-usecs N]\n"
-		"		[tx-frames N]\n"
-		"		[tx-usecs-irq N]\n"
-		"		[tx-frames-irq N]\n"
-		"		[stats-block-usecs N]\n"
-		"		[pkt-rate-low N]\n"
-		"		[rx-usecs-low N]\n"
-		"		[rx-frames-low N]\n"
-		"		[tx-usecs-low N]\n"
-		"		[tx-frames-low N]\n"
-		"		[pkt-rate-high N]\n"
-		"		[rx-usecs-high N]\n"
-		"		[rx-frames-high N]\n"
-		"		[tx-usecs-high N]\n"
-		"		[tx-frames-high N]\n"
-	        "		[sample-interval N]\n" },
-    { "-g", "--show-ring", MODE_GRING, "Query RX/TX ring parameters" },
-    { "-G", "--set-ring", MODE_SRING, "Set RX/TX ring parameters",
-		"		[ rx N ]\n"
-		"		[ rx-mini N ]\n"
-		"		[ rx-jumbo N ]\n"
-	        "		[ tx N ]\n" },
-    { "-k", "--show-offload", MODE_GOFFLOAD, "Get protocol offload information" },
-    { "-K", "--offload", MODE_SOFFLOAD, "Set protocol offload",
-		"		[ rx on|off ]\n"
-		"		[ tx on|off ]\n"
-		"		[ sg on|off ]\n"
-	        "		[ tso on|off ]\n"
-	        "		[ ufo on|off ]\n"
-		"		[ gso on|off ]\n"
-		"		[ gro on|off ]\n"
-		"		[ lro on|off ]\n"
-		"		[ rxvlan on|off ]\n"
-		"		[ txvlan on|off ]\n"
-		"		[ ntuple on|off ]\n"
-		"		[ rxhash on|off ]\n"
-    },
-    { "-i", "--driver", MODE_GDRV, "Show driver information" },
-    { "-d", "--register-dump", MODE_GREGS, "Do a register dump",
-		"		[ raw on|off ]\n"
-		"		[ file FILENAME ]\n" },
-    { "-e", "--eeprom-dump", MODE_GEEPROM, "Do a EEPROM dump",
-		"		[ raw on|off ]\n"
-		"		[ offset N ]\n"
-		"		[ length N ]\n" },
-    { "-E", "--change-eeprom", MODE_SEEPROM, "Change bytes in device EEPROM",
-		"		[ magic N ]\n"
-		"		[ offset N ]\n"
-		"		[ length N ]\n"
-		"		[ value N ]\n" },
-    { "-r", "--negotiate", MODE_NWAY_RST, "Restart N-WAY negotiation" },
-    { "-p", "--identify", MODE_PHYS_ID, "Show visible port identification (e.g. blinking)",
-                "               [ TIME-IN-SECONDS ]\n" },
-    { "-t", "--test", MODE_TEST, "Execute adapter self test",
-		"               [ online | offline | external_lb ]\n" },
-    { "-S", "--statistics", MODE_GSTATS, "Show adapter statistics" },
-    { "-n", "--show-nfc", MODE_GNFC, "Show Rx network flow classification "
-		"options",
-		"		[ rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
-		"tcp6|udp6|ah6|esp6|sctp6 ]\n" },
-    { "-f", "--flash", MODE_FLASHDEV, "Flash firmware image "
-    		"from the specified file to a region on the device",
-		"               FILENAME [ REGION-NUMBER-TO-FLASH ]\n" },
-    { "-N", "--config-nfc", MODE_SNFC, "Configure Rx network flow "
-		"classification options",
-		"		[ rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
-		"tcp6|udp6|ah6|esp6|sctp6 m|v|t|s|d|f|n|r... ]\n" },
-    { "-x", "--show-rxfh-indir", MODE_GRXFHINDIR, "Show Rx flow hash "
-		"indirection" },
-    { "-X", "--set-rxfh-indir", MODE_SRXFHINDIR, "Set Rx flow hash indirection",
-		"		equal N | weight W0 W1 ...\n" },
-    { "-U", "--config-ntuple", MODE_SCLSRULE, "Configure Rx ntuple filters "
-		"and actions",
-		"		[ delete %d ] |\n"
-		"		[ flow-type ether|ip4|tcp4|udp4|sctp4|ah4|esp4\n"
-		"			[ src %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
-		"			[ dst %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
-		"			[ proto %d [m %x] ]\n"
-		"			[ src-ip %d.%d.%d.%d [m %d.%d.%d.%d] ]\n"
-		"			[ dst-ip %d.%d.%d.%d [m %d.%d.%d.%d] ]\n"
-		"			[ tos %d [m %x] ]\n"
-		"			[ l4proto %d [m %x] ]\n"
-		"			[ src-port %d [m %x] ]\n"
-		"			[ dst-port %d [m %x] ]\n"
-		"			[ spi %d [m %x] ]\n"
-		"			[ vlan-etype %x [m %x] ]\n"
-		"			[ vlan %x [m %x] ]\n"
-		"			[ user-def %x [m %x] ]\n"
-		"			[ action %d ]\n"
-		"			[ loc %d]]\n" },
-    { "-u", "--show-ntuple", MODE_GCLSRULE,
-		"Get Rx ntuple filters and actions",
-		"		[ rule %d ]\n"},
-    { "-P", "--show-permaddr", MODE_PERMADDR,
-		"Show permanent hardware address" },
-    { "-w", "--get-dump", MODE_GET_DUMP,
-		"Get dump flag, data",
-		"		[ data FILENAME ]\n" },
-    { "-W", "--set-dump", MODE_SET_DUMP,
-		"Set dump flag of the device",
-		"		N\n"},
-    { "-l", "--show-channels", MODE_GCHANNELS, "Query Channels" },
-    { "-L", "--set-channels", MODE_SCHANNELS, "Set Channels",
-		"               [ rx N ]\n"
-		"               [ tx N ]\n"
-		"               [ other N ]\n"
-		"               [ combined N ]\n" },
-    { "-h", "--help", MODE_HELP, "Show this help" },
-    { NULL, "--version", MODE_VERSION, "Show version number" },
-    {}
+	{ "-s", "--change", MODE_SSET, "Change generic options",
+	  "		[ speed %d ]\n"
+	  "		[ duplex half|full ]\n"
+	  "		[ port tp|aui|bnc|mii|fibre ]\n"
+	  "		[ autoneg on|off ]\n"
+	  "		[ advertise %x ]\n"
+	  "		[ phyad %d ]\n"
+	  "		[ xcvr internal|external ]\n"
+	  "		[ wol p|u|m|b|a|g|s|d... ]\n"
+	  "		[ sopass %x:%x:%x:%x:%x:%x ]\n"
+	  "		[ msglvl %d | msglvl type on|off ... ]\n" },
+	{ "-a", "--show-pause", MODE_GPAUSE, "Show pause options" },
+	{ "-A", "--pause", MODE_SPAUSE, "Set pause options",
+	  "		[ autoneg on|off ]\n"
+	  "		[ rx on|off ]\n"
+	  "		[ tx on|off ]\n" },
+	{ "-c", "--show-coalesce", MODE_GCOALESCE, "Show coalesce options" },
+	{ "-C", "--coalesce", MODE_SCOALESCE, "Set coalesce options",
+	  "		[adaptive-rx on|off]\n"
+	  "		[adaptive-tx on|off]\n"
+	  "		[rx-usecs N]\n"
+	  "		[rx-frames N]\n"
+	  "		[rx-usecs-irq N]\n"
+	  "		[rx-frames-irq N]\n"
+	  "		[tx-usecs N]\n"
+	  "		[tx-frames N]\n"
+	  "		[tx-usecs-irq N]\n"
+	  "		[tx-frames-irq N]\n"
+	  "		[stats-block-usecs N]\n"
+	  "		[pkt-rate-low N]\n"
+	  "		[rx-usecs-low N]\n"
+	  "		[rx-frames-low N]\n"
+	  "		[tx-usecs-low N]\n"
+	  "		[tx-frames-low N]\n"
+	  "		[pkt-rate-high N]\n"
+	  "		[rx-usecs-high N]\n"
+	  "		[rx-frames-high N]\n"
+	  "		[tx-usecs-high N]\n"
+	  "		[tx-frames-high N]\n"
+	  "		[sample-interval N]\n" },
+	{ "-g", "--show-ring", MODE_GRING, "Query RX/TX ring parameters" },
+	{ "-G", "--set-ring", MODE_SRING, "Set RX/TX ring parameters",
+	  "		[ rx N ]\n"
+	  "		[ rx-mini N ]\n"
+	  "		[ rx-jumbo N ]\n"
+	  "		[ tx N ]\n" },
+	{ "-k", "--show-offload", MODE_GOFFLOAD,
+	  "Get protocol offload information" },
+	{ "-K", "--offload", MODE_SOFFLOAD, "Set protocol offload",
+	  "		[ rx on|off ]\n"
+	  "		[ tx on|off ]\n"
+	  "		[ sg on|off ]\n"
+	  "		[ tso on|off ]\n"
+	  "		[ ufo on|off ]\n"
+	  "		[ gso on|off ]\n"
+	  "		[ gro on|off ]\n"
+	  "		[ lro on|off ]\n"
+	  "		[ rxvlan on|off ]\n"
+	  "		[ txvlan on|off ]\n"
+	  "		[ ntuple on|off ]\n"
+	  "		[ rxhash on|off ]\n"
+	},
+	{ "-i", "--driver", MODE_GDRV, "Show driver information" },
+	{ "-d", "--register-dump", MODE_GREGS, "Do a register dump",
+	  "		[ raw on|off ]\n"
+	  "		[ file FILENAME ]\n" },
+	{ "-e", "--eeprom-dump", MODE_GEEPROM, "Do a EEPROM dump",
+	  "		[ raw on|off ]\n"
+	  "		[ offset N ]\n"
+	  "		[ length N ]\n" },
+	{ "-E", "--change-eeprom", MODE_SEEPROM,
+	  "Change bytes in device EEPROM",
+	  "		[ magic N ]\n"
+	  "		[ offset N ]\n"
+	  "		[ length N ]\n"
+	  "		[ value N ]\n" },
+	{ "-r", "--negotiate", MODE_NWAY_RST, "Restart N-WAY negotiation" },
+	{ "-p", "--identify", MODE_PHYS_ID,
+	  "Show visible port identification (e.g. blinking)",
+	  "               [ TIME-IN-SECONDS ]\n" },
+	{ "-t", "--test", MODE_TEST, "Execute adapter self test",
+	  "               [ online | offline | external_lb ]\n" },
+	{ "-S", "--statistics", MODE_GSTATS, "Show adapter statistics" },
+	{ "-n", "--show-nfc", MODE_GNFC,
+	  "Show Rx network flow classification options",
+	  "		[ rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
+	  "tcp6|udp6|ah6|esp6|sctp6 ]\n" },
+	{ "-f", "--flash", MODE_FLASHDEV,
+	  "Flash firmware image from the specified file to a region on the device",
+	  "               FILENAME [ REGION-NUMBER-TO-FLASH ]\n" },
+	{ "-N", "--config-nfc", MODE_SNFC,
+	  "Configure Rx network flow classification options",
+	  "		[ rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
+	  "tcp6|udp6|ah6|esp6|sctp6 m|v|t|s|d|f|n|r... ]\n" },
+	{ "-x", "--show-rxfh-indir", MODE_GRXFHINDIR,
+	  "Show Rx flow hash indirection" },
+	{ "-X", "--set-rxfh-indir", MODE_SRXFHINDIR,
+	  "Set Rx flow hash indirection",
+	  "		equal N | weight W0 W1 ...\n" },
+	{ "-U", "--config-ntuple", MODE_SCLSRULE,
+	  "Configure Rx ntuple filters and actions",
+	  "		[ delete %d ] |\n"
+	  "		[ flow-type ether|ip4|tcp4|udp4|sctp4|ah4|esp4\n"
+	  "			[ src %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
+	  "			[ dst %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
+	  "			[ proto %d [m %x] ]\n"
+	  "			[ src-ip %d.%d.%d.%d [m %d.%d.%d.%d] ]\n"
+	  "			[ dst-ip %d.%d.%d.%d [m %d.%d.%d.%d] ]\n"
+	  "			[ tos %d [m %x] ]\n"
+	  "			[ l4proto %d [m %x] ]\n"
+	  "			[ src-port %d [m %x] ]\n"
+	  "			[ dst-port %d [m %x] ]\n"
+	  "			[ spi %d [m %x] ]\n"
+	  "			[ vlan-etype %x [m %x] ]\n"
+	  "			[ vlan %x [m %x] ]\n"
+	  "			[ user-def %x [m %x] ]\n"
+	  "			[ action %d ]\n"
+	  "			[ loc %d]]\n" },
+	{ "-u", "--show-ntuple", MODE_GCLSRULE,
+	  "Get Rx ntuple filters and actions",
+	  "		[ rule %d ]\n"},
+	{ "-P", "--show-permaddr", MODE_PERMADDR,
+	  "Show permanent hardware address" },
+	{ "-w", "--get-dump", MODE_GET_DUMP,
+	  "Get dump flag, data",
+	  "		[ data FILENAME ]\n" },
+	{ "-W", "--set-dump", MODE_SET_DUMP,
+	  "Set dump flag of the device",
+	  "		N\n"},
+	{ "-l", "--show-channels", MODE_GCHANNELS, "Query Channels" },
+	{ "-L", "--set-channels", MODE_SCHANNELS, "Set Channels",
+	  "               [ rx N ]\n"
+	  "               [ tx N ]\n"
+	  "               [ other N ]\n"
+	  "               [ combined N ]\n" },
+	{ "-h", "--help", MODE_HELP, "Show this help" },
+	{ NULL, "--version", MODE_VERSION, "Show version number" },
+	{}
 };
 

-- 
1.7.4.4



-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH ethtool 09/21] Encapsulate command context in a structure
  2011-11-01 22:35 [PATCH ethtool 00/21] ethtool refactoring and misc changes Ben Hutchings
                   ` (7 preceding siblings ...)
  2011-11-01 23:15 ` [PATCH ethtool 08/21] Use standard indentation for definition of struct option args Ben Hutchings
@ 2011-11-01 23:16 ` Ben Hutchings
  2011-11-01 23:17 ` [PATCH ethtool 10/21] Add test cases for command-line parsing Ben Hutchings
                   ` (12 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Ben Hutchings @ 2011-11-01 23:16 UTC (permalink / raw)
  To: netdev; +Cc: linux-net-drivers

Replace the fd and ifr arguments to each sub-command handler with
struct cmd_context.  Change send_ioctl() to take a pointer to
this context and a pointer to the ethtool_cmd or other structure.
Use send_ioctl() consistently.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 ethtool.c  |  419 +++++++++++++++++++++++++-----------------------------------
 internal.h |   16 ++-
 rxclass.c  |   42 +++----
 3 files changed, 204 insertions(+), 273 deletions(-)

diff --git a/ethtool.c b/ethtool.c
index f967f84..b6f535c 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -67,42 +67,40 @@ enum {
 static int parse_wolopts(char *optstr, u32 *data);
 static char *unparse_wolopts(int wolopts);
 static void get_mac_addr(char *src, unsigned char *dest);
-static int do_gdrv(int fd, struct ifreq *ifr);
-static int do_gset(int fd, struct ifreq *ifr);
-static int do_sset(int fd, struct ifreq *ifr);
-static int do_gregs(int fd, struct ifreq *ifr);
-static int do_nway_rst(int fd, struct ifreq *ifr);
-static int do_geeprom(int fd, struct ifreq *ifr);
-static int do_seeprom(int fd, struct ifreq *ifr);
-static int do_test(int fd, struct ifreq *ifr);
-static int do_phys_id(int fd, struct ifreq *ifr);
-static int do_gpause(int fd, struct ifreq *ifr);
-static int do_spause(int fd, struct ifreq *ifr);
-static int do_gring(int fd, struct ifreq *ifr);
-static int do_sring(int fd, struct ifreq *ifr);
-static int do_schannels(int fd, struct ifreq *ifr);
-static int do_gchannels(int fd, struct ifreq *ifr);
-static int do_gcoalesce(int fd, struct ifreq *ifr);
-static int do_scoalesce(int fd, struct ifreq *ifr);
-static int do_goffload(int fd, struct ifreq *ifr);
-static int do_soffload(int fd, struct ifreq *ifr);
-static int do_gstats(int fd, struct ifreq *ifr);
+static int do_gdrv(struct cmd_context *ctx);
+static int do_gset(struct cmd_context *ctx);
+static int do_sset(struct cmd_context *ctx);
+static int do_gregs(struct cmd_context *ctx);
+static int do_nway_rst(struct cmd_context *ctx);
+static int do_geeprom(struct cmd_context *ctx);
+static int do_seeprom(struct cmd_context *ctx);
+static int do_test(struct cmd_context *ctx);
+static int do_phys_id(struct cmd_context *ctx);
+static int do_gpause(struct cmd_context *ctx);
+static int do_spause(struct cmd_context *ctx);
+static int do_gring(struct cmd_context *ctx);
+static int do_sring(struct cmd_context *ctx);
+static int do_schannels(struct cmd_context *ctx);
+static int do_gchannels(struct cmd_context *ctx);
+static int do_gcoalesce(struct cmd_context *ctx);
+static int do_scoalesce(struct cmd_context *ctx);
+static int do_goffload(struct cmd_context *ctx);
+static int do_soffload(struct cmd_context *ctx);
+static int do_gstats(struct cmd_context *ctx);
 static int rxflow_str_to_type(const char *str);
 static int parse_rxfhashopts(char *optstr, u32 *data);
 static char *unparse_rxfhashopts(u64 opts);
 static int dump_rxfhash(int fhash, u64 val);
-static int do_srxclass(int fd, struct ifreq *ifr);
-static int do_grxclass(int fd, struct ifreq *ifr);
-static int do_grxfhindir(int fd, struct ifreq *ifr);
-static int do_srxfhindir(int fd, struct ifreq *ifr);
-static int do_srxclsrule(int fd, struct ifreq *ifr);
-static int do_grxclsrule(int fd, struct ifreq *ifr);
-static int do_flash(int fd, struct ifreq *ifr);
-static int do_permaddr(int fd, struct ifreq *ifr);
-static int do_getfwdump(int fd, struct ifreq *ifr);
-static int do_setfwdump(int fd, struct ifreq *ifr);
-
-static int send_ioctl(int fd, struct ifreq *ifr);
+static int do_srxclass(struct cmd_context *ctx);
+static int do_grxclass(struct cmd_context *ctx);
+static int do_grxfhindir(struct cmd_context *ctx);
+static int do_srxfhindir(struct cmd_context *ctx);
+static int do_srxclsrule(struct cmd_context *ctx);
+static int do_grxclsrule(struct cmd_context *ctx);
+static int do_flash(struct cmd_context *ctx);
+static int do_permaddr(struct cmd_context *ctx);
+static int do_getfwdump(struct cmd_context *ctx);
+static int do_setfwdump(struct cmd_context *ctx);
 
 static enum {
 	MODE_VERSION = -2,
@@ -1982,94 +1980,92 @@ static int dump_rxfhash(int fhash, u64 val)
 
 static int doit(void)
 {
-	struct ifreq ifr;
-	int fd;
+	struct cmd_context ctx;
 
 	/* Setup our control structures. */
-	memset(&ifr, 0, sizeof(ifr));
-	strcpy(ifr.ifr_name, devname);
+	memset(&ctx.ifr, 0, sizeof(ctx.ifr));
+	strcpy(ctx.ifr.ifr_name, devname);
 
 	/* Open control socket. */
-	fd = socket(AF_INET, SOCK_DGRAM, 0);
-	if (fd < 0) {
+	ctx.fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (ctx.fd < 0) {
 		perror("Cannot get control socket");
 		return 70;
 	}
 
 	/* all of these are expected to populate ifr->ifr_data as needed */
 	if (mode == MODE_GDRV) {
-		return do_gdrv(fd, &ifr);
+		return do_gdrv(&ctx);
 	} else if (mode == MODE_GSET) {
-		return do_gset(fd, &ifr);
+		return do_gset(&ctx);
 	} else if (mode == MODE_SSET) {
-		return do_sset(fd, &ifr);
+		return do_sset(&ctx);
 	} else if (mode == MODE_GREGS) {
-		return do_gregs(fd, &ifr);
+		return do_gregs(&ctx);
 	} else if (mode == MODE_NWAY_RST) {
-		return do_nway_rst(fd, &ifr);
+		return do_nway_rst(&ctx);
 	} else if (mode == MODE_GEEPROM) {
-		return do_geeprom(fd, &ifr);
+		return do_geeprom(&ctx);
 	} else if (mode == MODE_SEEPROM) {
-		return do_seeprom(fd, &ifr);
+		return do_seeprom(&ctx);
 	} else if (mode == MODE_TEST) {
-		return do_test(fd, &ifr);
+		return do_test(&ctx);
 	} else if (mode == MODE_PHYS_ID) {
-		return do_phys_id(fd, &ifr);
+		return do_phys_id(&ctx);
 	} else if (mode == MODE_GPAUSE) {
-		return do_gpause(fd, &ifr);
+		return do_gpause(&ctx);
 	} else if (mode == MODE_SPAUSE) {
-		return do_spause(fd, &ifr);
+		return do_spause(&ctx);
 	} else if (mode == MODE_GCOALESCE) {
-		return do_gcoalesce(fd, &ifr);
+		return do_gcoalesce(&ctx);
 	} else if (mode == MODE_SCOALESCE) {
-		return do_scoalesce(fd, &ifr);
+		return do_scoalesce(&ctx);
 	} else if (mode == MODE_GRING) {
-		return do_gring(fd, &ifr);
+		return do_gring(&ctx);
 	} else if (mode == MODE_SRING) {
-		return do_sring(fd, &ifr);
+		return do_sring(&ctx);
 	} else if (mode == MODE_GCHANNELS) {
-		return do_gchannels(fd, &ifr);
+		return do_gchannels(&ctx);
 	} else if (mode == MODE_SCHANNELS) {
-		return do_schannels(fd, &ifr);
+		return do_schannels(&ctx);
 	} else if (mode == MODE_GOFFLOAD) {
-		return do_goffload(fd, &ifr);
+		return do_goffload(&ctx);
 	} else if (mode == MODE_SOFFLOAD) {
-		return do_soffload(fd, &ifr);
+		return do_soffload(&ctx);
 	} else if (mode == MODE_GSTATS) {
-		return do_gstats(fd, &ifr);
+		return do_gstats(&ctx);
 	} else if (mode == MODE_GNFC) {
-		return do_grxclass(fd, &ifr);
+		return do_grxclass(&ctx);
 	} else if (mode == MODE_SNFC) {
-		return do_srxclass(fd, &ifr);
+		return do_srxclass(&ctx);
 	} else if (mode == MODE_GRXFHINDIR) {
-		return do_grxfhindir(fd, &ifr);
+		return do_grxfhindir(&ctx);
 	} else if (mode == MODE_SRXFHINDIR) {
-		return do_srxfhindir(fd, &ifr);
+		return do_srxfhindir(&ctx);
 	} else if (mode == MODE_SCLSRULE) {
-		return do_srxclsrule(fd, &ifr);
+		return do_srxclsrule(&ctx);
 	} else if (mode == MODE_GCLSRULE) {
-		return do_grxclsrule(fd, &ifr);
+		return do_grxclsrule(&ctx);
 	} else if (mode == MODE_FLASHDEV) {
-		return do_flash(fd, &ifr);
+		return do_flash(&ctx);
 	} else if (mode == MODE_PERMADDR) {
-		return do_permaddr(fd, &ifr);
+		return do_permaddr(&ctx);
 	} else if (mode == MODE_GET_DUMP) {
-		return do_getfwdump(fd, &ifr);
+		return do_getfwdump(&ctx);
 	} else if (mode == MODE_SET_DUMP) {
-		return do_setfwdump(fd, &ifr);
+		return do_setfwdump(&ctx);
 	}
 
 	return 69;
 }
 
-static int do_gdrv(int fd, struct ifreq *ifr)
+static int do_gdrv(struct cmd_context *ctx)
 {
 	int err;
 	struct ethtool_drvinfo drvinfo;
 
 	drvinfo.cmd = ETHTOOL_GDRVINFO;
-	ifr->ifr_data = (caddr_t)&drvinfo;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &drvinfo);
 	if (err < 0) {
 		perror("Cannot get driver information");
 		return 71;
@@ -2077,7 +2073,7 @@ static int do_gdrv(int fd, struct ifreq *ifr)
 	return dump_drvinfo(&drvinfo);
 }
 
-static int do_gpause(int fd, struct ifreq *ifr)
+static int do_gpause(struct cmd_context *ctx)
 {
 	struct ethtool_cmd ecmd;
 	int err;
@@ -2085,8 +2081,7 @@ static int do_gpause(int fd, struct ifreq *ifr)
 	fprintf(stdout, "Pause parameters for %s:\n", devname);
 
 	epause.cmd = ETHTOOL_GPAUSEPARAM;
-	ifr->ifr_data = (caddr_t)&epause;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &epause);
 	if (err) {
 		perror("Cannot get device pause settings");
 		return 76;
@@ -2094,8 +2089,7 @@ static int do_gpause(int fd, struct ifreq *ifr)
 
 	if (epause.autoneg) {
 		ecmd.cmd = ETHTOOL_GSET;
-		ifr->ifr_data = (caddr_t)&ecmd;
-		err = send_ioctl(fd, ifr);
+		err = send_ioctl(ctx, &ecmd);
 		if (err) {
 			perror("Cannot get device settings");
 			return 1;
@@ -2137,13 +2131,12 @@ static void do_generic_set(struct cmdline_info *info,
 		do_generic_set1(&info[i], changed_out);
 }
 
-static int do_spause(int fd, struct ifreq *ifr)
+static int do_spause(struct cmd_context *ctx)
 {
 	int err, changed = 0;
 
 	epause.cmd = ETHTOOL_GPAUSEPARAM;
-	ifr->ifr_data = (caddr_t)&epause;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &epause);
 	if (err) {
 		perror("Cannot get device pause settings");
 		return 77;
@@ -2157,8 +2150,7 @@ static int do_spause(int fd, struct ifreq *ifr)
 	}
 
 	epause.cmd = ETHTOOL_SPAUSEPARAM;
-	ifr->ifr_data = (caddr_t)&epause;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &epause);
 	if (err) {
 		perror("Cannot set device pause parameters");
 		return 79;
@@ -2167,13 +2159,12 @@ static int do_spause(int fd, struct ifreq *ifr)
 	return 0;
 }
 
-static int do_sring(int fd, struct ifreq *ifr)
+static int do_sring(struct cmd_context *ctx)
 {
 	int err, changed = 0;
 
 	ering.cmd = ETHTOOL_GRINGPARAM;
-	ifr->ifr_data = (caddr_t)&ering;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &ering);
 	if (err) {
 		perror("Cannot get device ring settings");
 		return 76;
@@ -2187,8 +2178,7 @@ static int do_sring(int fd, struct ifreq *ifr)
 	}
 
 	ering.cmd = ETHTOOL_SRINGPARAM;
-	ifr->ifr_data = (caddr_t)&ering;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &ering);
 	if (err) {
 		perror("Cannot set device ring parameters");
 		return 81;
@@ -2197,15 +2187,14 @@ static int do_sring(int fd, struct ifreq *ifr)
 	return 0;
 }
 
-static int do_gring(int fd, struct ifreq *ifr)
+static int do_gring(struct cmd_context *ctx)
 {
 	int err;
 
 	fprintf(stdout, "Ring parameters for %s:\n", devname);
 
 	ering.cmd = ETHTOOL_GRINGPARAM;
-	ifr->ifr_data = (caddr_t)&ering;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &ering);
 	if (err == 0) {
 		err = dump_ring();
 		if (err)
@@ -2218,13 +2207,12 @@ static int do_gring(int fd, struct ifreq *ifr)
 	return 0;
 }
 
-static int do_schannels(int fd, struct ifreq *ifr)
+static int do_schannels(struct cmd_context *ctx)
 {
 	int err, changed = 0;
 
 	echannels.cmd = ETHTOOL_GCHANNELS;
-	ifr->ifr_data = (caddr_t)&echannels;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &echannels);
 	if (err) {
 		perror("Cannot get device channel parameters");
 		return 1;
@@ -2243,8 +2231,7 @@ static int do_schannels(int fd, struct ifreq *ifr)
 	}
 
 	echannels.cmd = ETHTOOL_SCHANNELS;
-	ifr->ifr_data = (caddr_t)&echannels;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &echannels);
 	if (err) {
 		perror("Cannot set device channel parameters");
 		return 1;
@@ -2253,15 +2240,14 @@ static int do_schannels(int fd, struct ifreq *ifr)
 	return 0;
 }
 
-static int do_gchannels(int fd, struct ifreq *ifr)
+static int do_gchannels(struct cmd_context *ctx)
 {
 	int err;
 
 	fprintf(stdout, "Channel parameters for %s:\n", devname);
 
 	echannels.cmd = ETHTOOL_GCHANNELS;
-	ifr->ifr_data = (caddr_t)&echannels;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &echannels);
 	if (err == 0) {
 		err = dump_channels();
 		if (err)
@@ -2274,15 +2260,14 @@ static int do_gchannels(int fd, struct ifreq *ifr)
 
 }
 
-static int do_gcoalesce(int fd, struct ifreq *ifr)
+static int do_gcoalesce(struct cmd_context *ctx)
 {
 	int err;
 
 	fprintf(stdout, "Coalesce parameters for %s:\n", devname);
 
 	ecoal.cmd = ETHTOOL_GCOALESCE;
-	ifr->ifr_data = (caddr_t)&ecoal;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &ecoal);
 	if (err == 0) {
 		err = dump_coalesce();
 		if (err)
@@ -2295,13 +2280,12 @@ static int do_gcoalesce(int fd, struct ifreq *ifr)
 	return 0;
 }
 
-static int do_scoalesce(int fd, struct ifreq *ifr)
+static int do_scoalesce(struct cmd_context *ctx)
 {
 	int err, changed = 0;
 
 	ecoal.cmd = ETHTOOL_GCOALESCE;
-	ifr->ifr_data = (caddr_t)&ecoal;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &ecoal);
 	if (err) {
 		perror("Cannot get device coalesce settings");
 		return 76;
@@ -2316,8 +2300,7 @@ static int do_scoalesce(int fd, struct ifreq *ifr)
 	}
 
 	ecoal.cmd = ETHTOOL_SCOALESCE;
-	ifr->ifr_data = (caddr_t)&ecoal;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &ecoal);
 	if (err) {
 		perror("Cannot set device coalesce parameters");
 		return 81;
@@ -2326,7 +2309,7 @@ static int do_scoalesce(int fd, struct ifreq *ifr)
 	return 0;
 }
 
-static int do_goffload(int fd, struct ifreq *ifr)
+static int do_goffload(struct cmd_context *ctx)
 {
 	struct ethtool_value eval;
 	int err, allfail = 1, rx = 0, tx = 0, sg = 0;
@@ -2336,8 +2319,7 @@ static int do_goffload(int fd, struct ifreq *ifr)
 	fprintf(stdout, "Offload parameters for %s:\n", devname);
 
 	eval.cmd = ETHTOOL_GRXCSUM;
-	ifr->ifr_data = (caddr_t)&eval;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &eval);
 	if (err)
 		perror("Cannot get device rx csum settings");
 	else {
@@ -2346,8 +2328,7 @@ static int do_goffload(int fd, struct ifreq *ifr)
 	}
 
 	eval.cmd = ETHTOOL_GTXCSUM;
-	ifr->ifr_data = (caddr_t)&eval;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &eval);
 	if (err)
 		perror("Cannot get device tx csum settings");
 	else {
@@ -2356,8 +2337,7 @@ static int do_goffload(int fd, struct ifreq *ifr)
 	}
 
 	eval.cmd = ETHTOOL_GSG;
-	ifr->ifr_data = (caddr_t)&eval;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &eval);
 	if (err)
 		perror("Cannot get device scatter-gather settings");
 	else {
@@ -2366,8 +2346,7 @@ static int do_goffload(int fd, struct ifreq *ifr)
 	}
 
 	eval.cmd = ETHTOOL_GTSO;
-	ifr->ifr_data = (caddr_t)&eval;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &eval);
 	if (err)
 		perror("Cannot get device tcp segmentation offload settings");
 	else {
@@ -2376,8 +2355,7 @@ static int do_goffload(int fd, struct ifreq *ifr)
 	}
 
 	eval.cmd = ETHTOOL_GUFO;
-	ifr->ifr_data = (caddr_t)&eval;
-	err = ioctl(fd, SIOCETHTOOL, ifr);
+	err = send_ioctl(ctx, &eval);
 	if (err)
 		perror("Cannot get device udp large send offload settings");
 	else {
@@ -2386,8 +2364,7 @@ static int do_goffload(int fd, struct ifreq *ifr)
 	}
 
 	eval.cmd = ETHTOOL_GGSO;
-	ifr->ifr_data = (caddr_t)&eval;
-	err = ioctl(fd, SIOCETHTOOL, ifr);
+	err = send_ioctl(ctx, &eval);
 	if (err)
 		perror("Cannot get device generic segmentation offload settings");
 	else {
@@ -2396,8 +2373,7 @@ static int do_goffload(int fd, struct ifreq *ifr)
 	}
 
 	eval.cmd = ETHTOOL_GFLAGS;
-	ifr->ifr_data = (caddr_t)&eval;
-	err = ioctl(fd, SIOCETHTOOL, ifr);
+	err = send_ioctl(ctx, &eval);
 	if (err) {
 		perror("Cannot get device flags");
 	} else {
@@ -2410,8 +2386,7 @@ static int do_goffload(int fd, struct ifreq *ifr)
 	}
 
 	eval.cmd = ETHTOOL_GGRO;
-	ifr->ifr_data = (caddr_t)&eval;
-	err = ioctl(fd, SIOCETHTOOL, ifr);
+	err = send_ioctl(ctx, &eval);
 	if (err)
 		perror("Cannot get device GRO settings");
 	else {
@@ -2428,7 +2403,7 @@ static int do_goffload(int fd, struct ifreq *ifr)
 			    ntuple, rxhash);
 }
 
-static int do_soffload(int fd, struct ifreq *ifr)
+static int do_soffload(struct cmd_context *ctx)
 {
 	struct ethtool_value eval;
 	int err, changed = 0;
@@ -2437,8 +2412,7 @@ static int do_soffload(int fd, struct ifreq *ifr)
 		changed = 1;
 		eval.cmd = ETHTOOL_SRXCSUM;
 		eval.data = (off_csum_rx_wanted == 1);
-		ifr->ifr_data = (caddr_t)&eval;
-		err = send_ioctl(fd, ifr);
+		err = send_ioctl(ctx, &eval);
 		if (err) {
 			perror("Cannot set device rx csum settings");
 			return 84;
@@ -2449,8 +2423,7 @@ static int do_soffload(int fd, struct ifreq *ifr)
 		changed = 1;
 		eval.cmd = ETHTOOL_STXCSUM;
 		eval.data = (off_csum_tx_wanted == 1);
-		ifr->ifr_data = (caddr_t)&eval;
-		err = send_ioctl(fd, ifr);
+		err = send_ioctl(ctx, &eval);
 		if (err) {
 			perror("Cannot set device tx csum settings");
 			return 85;
@@ -2461,8 +2434,7 @@ static int do_soffload(int fd, struct ifreq *ifr)
 		changed = 1;
 		eval.cmd = ETHTOOL_SSG;
 		eval.data = (off_sg_wanted == 1);
-		ifr->ifr_data = (caddr_t)&eval;
-		err = send_ioctl(fd, ifr);
+		err = send_ioctl(ctx, &eval);
 		if (err) {
 			perror("Cannot set device scatter-gather settings");
 			return 86;
@@ -2473,8 +2445,7 @@ static int do_soffload(int fd, struct ifreq *ifr)
 		changed = 1;
 		eval.cmd = ETHTOOL_STSO;
 		eval.data = (off_tso_wanted == 1);
-		ifr->ifr_data = (caddr_t)&eval;
-		err = send_ioctl(fd, ifr);
+		err = send_ioctl(ctx, &eval);
 		if (err) {
 			perror("Cannot set device tcp segmentation offload settings");
 			return 88;
@@ -2484,8 +2455,7 @@ static int do_soffload(int fd, struct ifreq *ifr)
 		changed = 1;
 		eval.cmd = ETHTOOL_SUFO;
 		eval.data = (off_ufo_wanted == 1);
-		ifr->ifr_data = (caddr_t)&eval;
-		err = ioctl(fd, SIOCETHTOOL, ifr);
+		err = send_ioctl(ctx, &eval);
 		if (err) {
 			perror("Cannot set device udp large send offload settings");
 			return 89;
@@ -2495,8 +2465,7 @@ static int do_soffload(int fd, struct ifreq *ifr)
 		changed = 1;
 		eval.cmd = ETHTOOL_SGSO;
 		eval.data = (off_gso_wanted == 1);
-		ifr->ifr_data = (caddr_t)&eval;
-		err = ioctl(fd, SIOCETHTOOL, ifr);
+		err = send_ioctl(ctx, &eval);
 		if (err) {
 			perror("Cannot set device generic segmentation offload settings");
 			return 90;
@@ -2506,8 +2475,7 @@ static int do_soffload(int fd, struct ifreq *ifr)
 		changed = 1;
 		eval.cmd = ETHTOOL_GFLAGS;
 		eval.data = 0;
-		ifr->ifr_data = (caddr_t)&eval;
-		err = ioctl(fd, SIOCETHTOOL, ifr);
+		err = send_ioctl(ctx, &eval);
 		if (err) {
 			perror("Cannot get device flag settings");
 			return 91;
@@ -2517,7 +2485,7 @@ static int do_soffload(int fd, struct ifreq *ifr)
 		eval.data = ((eval.data & ~off_flags_mask) |
 			     off_flags_wanted);
 
-		err = ioctl(fd, SIOCETHTOOL, ifr);
+		err = send_ioctl(ctx, &eval);
 		if (err) {
 			perror("Cannot set device flag settings");
 			return 92;
@@ -2527,8 +2495,7 @@ static int do_soffload(int fd, struct ifreq *ifr)
 		changed = 1;
 		eval.cmd = ETHTOOL_SGRO;
 		eval.data = (off_gro_wanted == 1);
-		ifr->ifr_data = (caddr_t)&eval;
-		err = ioctl(fd, SIOCETHTOOL, ifr);
+		err = send_ioctl(ctx, &eval);
 		if (err) {
 			perror("Cannot set device GRO settings");
 			return 93;
@@ -2542,7 +2509,7 @@ static int do_soffload(int fd, struct ifreq *ifr)
 	return 0;
 }
 
-static int do_gset(int fd, struct ifreq *ifr)
+static int do_gset(struct cmd_context *ctx)
 {
 	int err;
 	struct ethtool_cmd ecmd;
@@ -2553,8 +2520,7 @@ static int do_gset(int fd, struct ifreq *ifr)
 	fprintf(stdout, "Settings for %s:\n", devname);
 
 	ecmd.cmd = ETHTOOL_GSET;
-	ifr->ifr_data = (caddr_t)&ecmd;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &ecmd);
 	if (err == 0) {
 		err = dump_ecmd(&ecmd);
 		if (err)
@@ -2565,8 +2531,7 @@ static int do_gset(int fd, struct ifreq *ifr)
 	}
 
 	wolinfo.cmd = ETHTOOL_GWOL;
-	ifr->ifr_data = (caddr_t)&wolinfo;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &wolinfo);
 	if (err == 0) {
 		err = dump_wol(&wolinfo);
 		if (err)
@@ -2577,8 +2542,7 @@ static int do_gset(int fd, struct ifreq *ifr)
 	}
 
 	edata.cmd = ETHTOOL_GMSGLVL;
-	ifr->ifr_data = (caddr_t)&edata;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &edata);
 	if (err == 0) {
 		fprintf(stdout, "	Current message level: 0x%08x (%d)\n"
 			"			       ",
@@ -2592,8 +2556,7 @@ static int do_gset(int fd, struct ifreq *ifr)
 	}
 
 	edata.cmd = ETHTOOL_GLINK;
-	ifr->ifr_data = (caddr_t)&edata;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &edata);
 	if (err == 0) {
 		fprintf(stdout, "	Link detected: %s\n",
 			edata.data ? "yes":"no");
@@ -2609,7 +2572,7 @@ static int do_gset(int fd, struct ifreq *ifr)
 	return 0;
 }
 
-static int do_sset(int fd, struct ifreq *ifr)
+static int do_sset(struct cmd_context *ctx)
 {
 	int err;
 
@@ -2617,8 +2580,7 @@ static int do_sset(int fd, struct ifreq *ifr)
 		struct ethtool_cmd ecmd;
 
 		ecmd.cmd = ETHTOOL_GSET;
-		ifr->ifr_data = (caddr_t)&ecmd;
-		err = send_ioctl(fd, ifr);
+		err = send_ioctl(ctx, &ecmd);
 		if (err < 0) {
 			perror("Cannot get current device settings");
 		} else {
@@ -2671,8 +2633,7 @@ static int do_sset(int fd, struct ifreq *ifr)
 
 			/* Try to perform the update. */
 			ecmd.cmd = ETHTOOL_SSET;
-			ifr->ifr_data = (caddr_t)&ecmd;
-			err = send_ioctl(fd, ifr);
+			err = send_ioctl(ctx, &ecmd);
 			if (err < 0)
 				perror("Cannot set new settings");
 		}
@@ -2696,8 +2657,7 @@ static int do_sset(int fd, struct ifreq *ifr)
 		struct ethtool_wolinfo wol;
 
 		wol.cmd = ETHTOOL_GWOL;
-		ifr->ifr_data = (caddr_t)&wol;
-		err = send_ioctl(fd, ifr);
+		err = send_ioctl(ctx, &wol);
 		if (err < 0) {
 			perror("Cannot get current wake-on-lan settings");
 		} else {
@@ -2714,8 +2674,7 @@ static int do_sset(int fd, struct ifreq *ifr)
 
 			/* Try to perform the update. */
 			wol.cmd = ETHTOOL_SWOL;
-			ifr->ifr_data = (caddr_t)&wol;
-			err = send_ioctl(fd, ifr);
+			err = send_ioctl(ctx, &wol);
 			if (err < 0)
 				perror("Cannot set new wake-on-lan settings");
 		}
@@ -2731,16 +2690,14 @@ static int do_sset(int fd, struct ifreq *ifr)
 		struct ethtool_value edata;
 
 		edata.cmd = ETHTOOL_GMSGLVL;
-		ifr->ifr_data = (caddr_t)&edata;
-		err = send_ioctl(fd, ifr);
+		err = send_ioctl(ctx, &edata);
 		if (err < 0) {
 			perror("Cannot get msglvl");
 		} else {
 			edata.cmd = ETHTOOL_SMSGLVL;
 			edata.data = ((edata.data & ~msglvl_mask) |
 				      msglvl_wanted);
-			ifr->ifr_data = (caddr_t)&edata;
-			err = send_ioctl(fd, ifr);
+			err = send_ioctl(ctx, &edata);
 			if (err < 0)
 				perror("Cannot set new msglvl");
 		}
@@ -2749,15 +2706,14 @@ static int do_sset(int fd, struct ifreq *ifr)
 	return 0;
 }
 
-static int do_gregs(int fd, struct ifreq *ifr)
+static int do_gregs(struct cmd_context *ctx)
 {
 	int err;
 	struct ethtool_drvinfo drvinfo;
 	struct ethtool_regs *regs;
 
 	drvinfo.cmd = ETHTOOL_GDRVINFO;
-	ifr->ifr_data = (caddr_t)&drvinfo;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &drvinfo);
 	if (err < 0) {
 		perror("Cannot get driver information");
 		return 72;
@@ -2770,8 +2726,7 @@ static int do_gregs(int fd, struct ifreq *ifr)
 	}
 	regs->cmd = ETHTOOL_GREGS;
 	regs->len = drvinfo.regdump_len;
-	ifr->ifr_data = (caddr_t)regs;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, regs);
 	if (err < 0) {
 		perror("Cannot get register dump");
 		free(regs);
@@ -2787,29 +2742,27 @@ static int do_gregs(int fd, struct ifreq *ifr)
 	return 0;
 }
 
-static int do_nway_rst(int fd, struct ifreq *ifr)
+static int do_nway_rst(struct cmd_context *ctx)
 {
 	struct ethtool_value edata;
 	int err;
 
 	edata.cmd = ETHTOOL_NWAY_RST;
-	ifr->ifr_data = (caddr_t)&edata;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &edata);
 	if (err < 0)
 		perror("Cannot restart autonegotiation");
 
 	return err;
 }
 
-static int do_geeprom(int fd, struct ifreq *ifr)
+static int do_geeprom(struct cmd_context *ctx)
 {
 	int err;
 	struct ethtool_drvinfo drvinfo;
 	struct ethtool_eeprom *eeprom;
 
 	drvinfo.cmd = ETHTOOL_GDRVINFO;
-	ifr->ifr_data = (caddr_t)&drvinfo;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &drvinfo);
 	if (err < 0) {
 		perror("Cannot get driver information");
 		return 74;
@@ -2829,8 +2782,7 @@ static int do_geeprom(int fd, struct ifreq *ifr)
 	eeprom->cmd = ETHTOOL_GEEPROM;
 	eeprom->len = geeprom_length;
 	eeprom->offset = geeprom_offset;
-	ifr->ifr_data = (caddr_t)eeprom;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, eeprom);
 	if (err < 0) {
 		perror("Cannot get EEPROM data");
 		free(eeprom);
@@ -2842,15 +2794,14 @@ static int do_geeprom(int fd, struct ifreq *ifr)
 	return err;
 }
 
-static int do_seeprom(int fd, struct ifreq *ifr)
+static int do_seeprom(struct cmd_context *ctx)
 {
 	int err;
 	struct ethtool_drvinfo drvinfo;
 	struct ethtool_eeprom *eeprom;
 
 	drvinfo.cmd = ETHTOOL_GDRVINFO;
-	ifr->ifr_data = (caddr_t)&drvinfo;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &drvinfo);
 	if (err < 0) {
 		perror("Cannot get driver information");
 		return 74;
@@ -2881,8 +2832,7 @@ static int do_seeprom(int fd, struct ifreq *ifr)
 	if (!seeprom_value_seen)
 		eeprom->len = fread(eeprom->data, 1, eeprom->len, stdin);
 
-	ifr->ifr_data = (caddr_t)eeprom;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, eeprom);
 	if (err < 0) {
 		perror("Cannot set EEPROM data");
 		err = 87;
@@ -2892,7 +2842,7 @@ static int do_seeprom(int fd, struct ifreq *ifr)
 	return err;
 }
 
-static int do_test(int fd, struct ifreq *ifr)
+static int do_test(struct cmd_context *ctx)
 {
 	int err;
 	struct ethtool_drvinfo drvinfo;
@@ -2900,8 +2850,7 @@ static int do_test(int fd, struct ifreq *ifr)
 	struct ethtool_gstrings *strings;
 
 	drvinfo.cmd = ETHTOOL_GDRVINFO;
-	ifr->ifr_data = (caddr_t)&drvinfo;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &drvinfo);
 	if (err < 0) {
 		perror("Cannot get driver information");
 		return 72;
@@ -2921,8 +2870,7 @@ static int do_test(int fd, struct ifreq *ifr)
 		test->flags = ETH_TEST_FL_OFFLINE;
 	else
 		test->flags = 0;
-	ifr->ifr_data = (caddr_t)test;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, test);
 	if (err < 0) {
 		perror("Cannot test");
 		free (test);
@@ -2940,8 +2888,7 @@ static int do_test(int fd, struct ifreq *ifr)
 	strings->cmd = ETHTOOL_GSTRINGS;
 	strings->string_set = ETH_SS_TEST;
 	strings->len = drvinfo.testinfo_len;
-	ifr->ifr_data = (caddr_t)strings;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, strings);
 	if (err < 0) {
 		perror("Cannot get strings");
 		free (test);
@@ -2955,22 +2902,21 @@ static int do_test(int fd, struct ifreq *ifr)
 	return err;
 }
 
-static int do_phys_id(int fd, struct ifreq *ifr)
+static int do_phys_id(struct cmd_context *ctx)
 {
 	int err;
 	struct ethtool_value edata;
 
 	edata.cmd = ETHTOOL_PHYS_ID;
 	edata.data = phys_id_time;
-	ifr->ifr_data = (caddr_t)&edata;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &edata);
 	if (err < 0)
 		perror("Cannot identify NIC");
 
 	return err;
 }
 
-static int do_gstats(int fd, struct ifreq *ifr)
+static int do_gstats(struct cmd_context *ctx)
 {
 	struct ethtool_drvinfo drvinfo;
 	struct ethtool_gstrings *strings;
@@ -2979,8 +2925,7 @@ static int do_gstats(int fd, struct ifreq *ifr)
 	int err;
 
 	drvinfo.cmd = ETHTOOL_GDRVINFO;
-	ifr->ifr_data = (caddr_t)&drvinfo;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &drvinfo);
 	if (err < 0) {
 		perror("Cannot get driver information");
 		return 71;
@@ -3005,8 +2950,7 @@ static int do_gstats(int fd, struct ifreq *ifr)
 	strings->cmd = ETHTOOL_GSTRINGS;
 	strings->string_set = ETH_SS_STATS;
 	strings->len = n_stats;
-	ifr->ifr_data = (caddr_t) strings;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, strings);
 	if (err < 0) {
 		perror("Cannot get stats strings information");
 		free(strings);
@@ -3016,8 +2960,7 @@ static int do_gstats(int fd, struct ifreq *ifr)
 
 	stats->cmd = ETHTOOL_GSTATS;
 	stats->n_stats = n_stats;
-	ifr->ifr_data = (caddr_t) stats;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, stats);
 	if (err < 0) {
 		perror("Cannot get stats information");
 		free(strings);
@@ -3040,7 +2983,7 @@ static int do_gstats(int fd, struct ifreq *ifr)
 }
 

-static int do_srxclass(int fd, struct ifreq *ifr)
+static int do_srxclass(struct cmd_context *ctx)
 {
 	int err;
 
@@ -3051,8 +2994,7 @@ static int do_srxclass(int fd, struct ifreq *ifr)
 		nfccmd.flow_type = rx_fhash_set;
 		nfccmd.data = rx_fhash_val;
 
-		ifr->ifr_data = (caddr_t)&nfccmd;
-		err = ioctl(fd, SIOCETHTOOL, ifr);
+		err = send_ioctl(ctx, &nfccmd);
 		if (err < 0)
 			perror("Cannot change RX network flow hashing options");
 
@@ -3061,7 +3003,7 @@ static int do_srxclass(int fd, struct ifreq *ifr)
 	return 0;
 }
 
-static int do_grxclass(int fd, struct ifreq *ifr)
+static int do_grxclass(struct cmd_context *ctx)
 {
 	int err;
 
@@ -3070,8 +3012,7 @@ static int do_grxclass(int fd, struct ifreq *ifr)
 
 		nfccmd.cmd = ETHTOOL_GRXFH;
 		nfccmd.flow_type = rx_fhash_get;
-		ifr->ifr_data = (caddr_t)&nfccmd;
-		err = ioctl(fd, SIOCETHTOOL, ifr);
+		err = send_ioctl(ctx, &nfccmd);
 		if (err < 0)
 			perror("Cannot get RX network flow hashing options");
 		else
@@ -3081,7 +3022,7 @@ static int do_grxclass(int fd, struct ifreq *ifr)
 	return 0;
 }
 
-static int do_grxfhindir(int fd, struct ifreq *ifr)
+static int do_grxfhindir(struct cmd_context *ctx)
 {
 	struct ethtool_rxnfc ring_count;
 	struct ethtool_rxfh_indir indir_head;
@@ -3090,8 +3031,7 @@ static int do_grxfhindir(int fd, struct ifreq *ifr)
 	int err;
 
 	ring_count.cmd = ETHTOOL_GRXRINGS;
-	ifr->ifr_data = (caddr_t) &ring_count;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &ring_count);
 	if (err < 0) {
 		perror("Cannot get RX ring count");
 		return 102;
@@ -3099,8 +3039,7 @@ static int do_grxfhindir(int fd, struct ifreq *ifr)
 
 	indir_head.cmd = ETHTOOL_GRXFHINDIR;
 	indir_head.size = 0;
-	ifr->ifr_data = (caddr_t) &indir_head;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &indir_head);
 	if (err < 0) {
 		perror("Cannot get RX flow hash indirection table size");
 		return 103;
@@ -3110,8 +3049,7 @@ static int do_grxfhindir(int fd, struct ifreq *ifr)
 		       indir_head.size * sizeof(*indir->ring_index));
 	indir->cmd = ETHTOOL_GRXFHINDIR;
 	indir->size = indir_head.size;
-	ifr->ifr_data = (caddr_t) indir;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, indir);
 	if (err < 0) {
 		perror("Cannot get RX flow hash indirection table");
 		return 103;
@@ -3129,7 +3067,7 @@ static int do_grxfhindir(int fd, struct ifreq *ifr)
 	return 0;
 }
 
-static int do_srxfhindir(int fd, struct ifreq *ifr)
+static int do_srxfhindir(struct cmd_context *ctx)
 {
 	struct ethtool_rxfh_indir indir_head;
 	struct ethtool_rxfh_indir *indir;
@@ -3141,8 +3079,7 @@ static int do_srxfhindir(int fd, struct ifreq *ifr)
 
 	indir_head.cmd = ETHTOOL_GRXFHINDIR;
 	indir_head.size = 0;
-	ifr->ifr_data = (caddr_t) &indir_head;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &indir_head);
 	if (err < 0) {
 		perror("Cannot get RX flow hash indirection table size");
 		return 104;
@@ -3188,8 +3125,7 @@ static int do_srxfhindir(int fd, struct ifreq *ifr)
 		}
 	}
 
-	ifr->ifr_data = (caddr_t) indir;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, indir);
 	if (err < 0) {
 		perror("Cannot set RX flow hash indirection table");
 		return 105;
@@ -3198,7 +3134,7 @@ static int do_srxfhindir(int fd, struct ifreq *ifr)
 	return 0;
 }
 
-static int do_flash(int fd, struct ifreq *ifr)
+static int do_flash(struct cmd_context *ctx)
 {
 	struct ethtool_flash efl;
 	int err;
@@ -3222,15 +3158,14 @@ static int do_flash(int fd, struct ifreq *ifr)
 	else
 		efl.region = flash_region;
 
-	ifr->ifr_data = (caddr_t)&efl;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &efl);
 	if (err < 0)
 		perror("Flashing failed");
 
 	return err;
 }
 
-static int do_permaddr(int fd, struct ifreq *ifr)
+static int do_permaddr(struct cmd_context *ctx)
 {
 	int i, err;
 	struct ethtool_perm_addr *epaddr;
@@ -3238,9 +3173,8 @@ static int do_permaddr(int fd, struct ifreq *ifr)
 	epaddr = malloc(sizeof(struct ethtool_perm_addr) + MAX_ADDR_LEN);
 	epaddr->cmd = ETHTOOL_GPERMADDR;
 	epaddr->size = MAX_ADDR_LEN;
-	ifr->ifr_data = (caddr_t)epaddr;
 
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, epaddr);
 	if (err < 0)
 		perror("Cannot read permanent address");
 	else {
@@ -3332,7 +3266,7 @@ static int flow_spec_to_ntuple(struct ethtool_rx_flow_spec *fsp,
 	return 0;
 }
 
-static int do_srxntuple(int fd, struct ifreq *ifr)
+static int do_srxntuple(struct cmd_context *ctx)
 {
 	struct ethtool_rx_ntuple ntuplecmd;
 	struct ethtool_value eval;
@@ -3349,15 +3283,13 @@ static int do_srxntuple(int fd, struct ifreq *ifr)
 	 * flag not being set on the device
 	 */
 	eval.cmd = ETHTOOL_GFLAGS;
-	ifr->ifr_data = (caddr_t)&eval;
-	err = ioctl(fd, SIOCETHTOOL, ifr);
+	err = send_ioctl(ctx, &eval);
 	if (err || !(eval.data & ETH_FLAG_NTUPLE))
 		return -1;
 
 	/* send rule via N-tuple */
 	ntuplecmd.cmd = ETHTOOL_SRXNTUPLE;
-	ifr->ifr_data = (caddr_t)&ntuplecmd;
-	err = ioctl(fd, SIOCETHTOOL, ifr);
+	err = send_ioctl(ctx, &ntuplecmd);
 
 	/*
 	 * Display error only if reponse is something other than op not
@@ -3373,25 +3305,25 @@ static int do_srxntuple(int fd, struct ifreq *ifr)
 	return 0;
 }
 
-static int do_srxclsrule(int fd, struct ifreq *ifr)
+static int do_srxclsrule(struct cmd_context *ctx)
 {
 	int err;
 
 	if (rx_class_rule_added) {
 		/* attempt to add rule via N-tuple specifier */
-		err = do_srxntuple(fd, ifr);
+		err = do_srxntuple(ctx);
 		if (!err)
 			return 0;
 
 		/* attempt to add rule via network flow classifier */
-		err = rxclass_rule_ins(fd, ifr, &rx_rule_fs);
+		err = rxclass_rule_ins(ctx, &rx_rule_fs);
 		if (err < 0) {
 			fprintf(stderr, "Cannot insert"
 				" classification rule\n");
 			return 1;
 		}
 	} else if (rx_class_rule_del >= 0) {
-		err = rxclass_rule_del(fd, ifr, rx_class_rule_del);
+		err = rxclass_rule_del(ctx, rx_class_rule_del);
 
 		if (err < 0) {
 			fprintf(stderr, "Cannot delete"
@@ -3405,28 +3337,27 @@ static int do_srxclsrule(int fd, struct ifreq *ifr)
 	return 0;
 }
 
-static int do_grxclsrule(int fd, struct ifreq *ifr)
+static int do_grxclsrule(struct cmd_context *ctx)
 {
 	struct ethtool_rxnfc nfccmd;
 	int err;
 
 	if (rx_class_rule_get >= 0) {
-		err = rxclass_rule_get(fd, ifr, rx_class_rule_get);
+		err = rxclass_rule_get(ctx, rx_class_rule_get);
 		if (err < 0)
 			fprintf(stderr, "Cannot get RX classification rule\n");
 		return err ? 1 : 0;
 	}
 
 	nfccmd.cmd = ETHTOOL_GRXRINGS;
-	ifr->ifr_data = (caddr_t)&nfccmd;
-	err = ioctl(fd, SIOCETHTOOL, ifr);
+	err = send_ioctl(ctx, &nfccmd);
 	if (err < 0)
 		perror("Cannot get RX rings");
 	else
 		fprintf(stdout, "%d RX rings available\n",
 			(int)nfccmd.data);
 
-	err = rxclass_rule_getall(fd, ifr);
+	err = rxclass_rule_getall(ctx);
 	if (err < 0)
 		fprintf(stderr, "RX classification rule retrieval failed\n");
 
@@ -3459,7 +3390,7 @@ static int do_writefwdump(struct ethtool_dump *dump)
 	return err;
 }
 
-static int do_getfwdump(int fd, struct ifreq *ifr)
+static int do_getfwdump(struct cmd_context *ctx)
 {
 	int err;
 	struct ethtool_dump edata;
@@ -3467,8 +3398,7 @@ static int do_getfwdump(int fd, struct ifreq *ifr)
 
 	edata.cmd = ETHTOOL_GET_DUMP_FLAG;
 
-	ifr->ifr_data = (caddr_t) &edata;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &edata);
 	if (err < 0) {
 		perror("Can not get dump level\n");
 		return 1;
@@ -3485,8 +3415,7 @@ static int do_getfwdump(int fd, struct ifreq *ifr)
 	}
 	data->cmd = ETHTOOL_GET_DUMP_DATA;
 	data->len = edata.len;
-	ifr->ifr_data = (caddr_t) data;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, data);
 	if (err < 0) {
 		perror("Can not get dump data\n");
 		err = 1;
@@ -3498,15 +3427,14 @@ free:
 	return err;
 }
 
-static int do_setfwdump(int fd, struct ifreq *ifr)
+static int do_setfwdump(struct cmd_context *ctx)
 {
 	int err;
 	struct ethtool_dump dump;
 
 	dump.cmd = ETHTOOL_SET_DUMP;
 	dump.flag = dump_flag;
-	ifr->ifr_data = (caddr_t)&dump;
-	err = send_ioctl(fd, ifr);
+	err = send_ioctl(ctx, &dump);
 	if (err < 0) {
 		perror("Can not set dump level\n");
 		return 1;
@@ -3514,9 +3442,10 @@ static int do_setfwdump(int fd, struct ifreq *ifr)
 	return 0;
 }
 
-static int send_ioctl(int fd, struct ifreq *ifr)
+int send_ioctl(struct cmd_context *ctx, void *cmd)
 {
-	return ioctl(fd, SIOCETHTOOL, ifr);
+	ctx->ifr.ifr_data = cmd;
+	return ioctl(ctx->fd, SIOCETHTOOL, &ctx->ifr);
 }
 
 int main(int argc, char **argp, char **envp)
diff --git a/internal.h b/internal.h
index 2b6a54a..c2f504a 100644
--- a/internal.h
+++ b/internal.h
@@ -88,6 +88,14 @@ static inline int test_bit(unsigned int nr, const unsigned long *addr)
 
 #define	RX_CLS_LOC_UNSPEC	0xffffffffUL
 
+/* Context for sub-commands */
+struct cmd_context {
+	int fd;			/* socket suitable for ethtool ioctl */
+	struct ifreq ifr;	/* ifreq suitable for ethtool ioctl */
+};
+
+int send_ioctl(struct cmd_context *ctx, void *cmd);
+
 /* National Semiconductor DP83815, DP83816 */
 int natsemi_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
 int natsemi_dump_eeprom(struct ethtool_drvinfo *info,
@@ -155,10 +163,10 @@ int st_gmac_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
 /* Rx flow classification */
 int rxclass_parse_ruleopts(char **optstr, int opt_cnt,
 			   struct ethtool_rx_flow_spec *fsp);
-int rxclass_rule_getall(int fd, struct ifreq *ifr);
-int rxclass_rule_get(int fd, struct ifreq *ifr, __u32 loc);
-int rxclass_rule_ins(int fd, struct ifreq *ifr,
+int rxclass_rule_getall(struct cmd_context *ctx);
+int rxclass_rule_get(struct cmd_context *ctx, __u32 loc);
+int rxclass_rule_ins(struct cmd_context *ctx,
 		     struct ethtool_rx_flow_spec *fsp);
-int rxclass_rule_del(int fd, struct ifreq *ifr, __u32 loc);
+int rxclass_rule_del(struct cmd_context *ctx, __u32 loc);
 
 #endif /* ETHTOOL_INTERNAL_H__ */
diff --git a/rxclass.c b/rxclass.c
index 809b073..dec9dd5 100644
--- a/rxclass.c
+++ b/rxclass.c
@@ -203,7 +203,7 @@ static void rxclass_print_rule(struct ethtool_rx_flow_spec *fsp)
 	}
 }
 
-static int rxclass_get_count(int fd, struct ifreq *ifr, __u32 *count)
+static int rxclass_get_count(struct cmd_context *ctx, __u32 *count)
 {
 	struct ethtool_rxnfc nfccmd;
 	int err;
@@ -211,8 +211,7 @@ static int rxclass_get_count(int fd, struct ifreq *ifr, __u32 *count)
 	/* request count and store */
 	nfccmd.cmd = ETHTOOL_GRXCLSRLCNT;
 	nfccmd.rule_cnt = 0;
-	ifr->ifr_data = (caddr_t)&nfccmd;
-	err = ioctl(fd, SIOCETHTOOL, ifr);
+	err = send_ioctl(ctx, &nfccmd);
 	*count = nfccmd.rule_cnt;
 	if (err < 0)
 		perror("rxclass: Cannot get RX class rule count");
@@ -220,7 +219,7 @@ static int rxclass_get_count(int fd, struct ifreq *ifr, __u32 *count)
 	return err;
 }
 
-int rxclass_rule_get(int fd, struct ifreq *ifr, __u32 loc)
+int rxclass_rule_get(struct cmd_context *ctx, __u32 loc)
 {
 	struct ethtool_rxnfc nfccmd;
 	int err;
@@ -229,8 +228,7 @@ int rxclass_rule_get(int fd, struct ifreq *ifr, __u32 loc)
 	nfccmd.cmd = ETHTOOL_GRXCLSRULE;
 	memset(&nfccmd.fs, 0, sizeof(struct ethtool_rx_flow_spec));
 	nfccmd.fs.location = loc;
-	ifr->ifr_data = (caddr_t)&nfccmd;
-	err = ioctl(fd, SIOCETHTOOL, ifr);
+	err = send_ioctl(ctx, &nfccmd);
 	if (err < 0) {
 		perror("rxclass: Cannot get RX class rule");
 		return err;
@@ -241,7 +239,7 @@ int rxclass_rule_get(int fd, struct ifreq *ifr, __u32 loc)
 	return err;
 }
 
-int rxclass_rule_getall(int fd, struct ifreq *ifr)
+int rxclass_rule_getall(struct cmd_context *ctx)
 {
 	struct ethtool_rxnfc *nfccmd;
 	__u32 *rule_locs;
@@ -249,7 +247,7 @@ int rxclass_rule_getall(int fd, struct ifreq *ifr)
 	__u32 count;
 
 	/* determine rule count */
-	err = rxclass_get_count(fd, ifr, &count);
+	err = rxclass_get_count(ctx, &count);
 	if (err < 0)
 		return err;
 
@@ -266,8 +264,7 @@ int rxclass_rule_getall(int fd, struct ifreq *ifr)
 	/* request location list */
 	nfccmd->cmd = ETHTOOL_GRXCLSRLALL;
 	nfccmd->rule_cnt = count;
-	ifr->ifr_data = (caddr_t)nfccmd;
-	err = ioctl(fd, SIOCETHTOOL, ifr);
+	err = send_ioctl(ctx, nfccmd);
 	if (err < 0) {
 		perror("rxclass: Cannot get RX class rules");
 		free(nfccmd);
@@ -277,7 +274,7 @@ int rxclass_rule_getall(int fd, struct ifreq *ifr)
 	/* write locations to bitmap */
 	rule_locs = nfccmd->rule_locs;
 	for (i = 0; i < count; i++) {
-		err = rxclass_rule_get(fd, ifr, rule_locs[i]);
+		err = rxclass_rule_get(ctx, rule_locs[i]);
 		if (err < 0)
 			break;
 	}
@@ -372,7 +369,7 @@ static int rmgr_find_empty_slot(struct ethtool_rx_flow_spec *fsp)
 	return -1;
 }
 
-static int rmgr_init(int fd, struct ifreq *ifr)
+static int rmgr_init(struct cmd_context *ctx)
 {
 	struct ethtool_rxnfc *nfccmd;
 	int err, i;
@@ -385,7 +382,7 @@ static int rmgr_init(int fd, struct ifreq *ifr)
 	memset(&rmgr, 0, sizeof(struct rmgr_ctrl));
 
 	/* request count and store in rmgr.n_rules */
-	err = rxclass_get_count(fd, ifr, &rmgr.n_rules);
+	err = rxclass_get_count(ctx, &rmgr.n_rules);
 	if (err < 0)
 		return err;
 
@@ -400,8 +397,7 @@ static int rmgr_init(int fd, struct ifreq *ifr)
 	/* request location list */
 	nfccmd->cmd = ETHTOOL_GRXCLSRLALL;
 	nfccmd->rule_cnt = rmgr.n_rules;
-	ifr->ifr_data = (caddr_t)nfccmd;
-	err = ioctl(fd, SIOCETHTOOL, ifr);
+	err = send_ioctl(ctx, nfccmd);
 	if (err < 0) {
 		perror("rmgr: Cannot get RX class rules");
 		free(nfccmd);
@@ -449,13 +445,13 @@ static void rmgr_cleanup(void)
 	rmgr.size = 0;
 }
 
-static int rmgr_set_location(int fd, struct ifreq *ifr,
+static int rmgr_set_location(struct cmd_context *ctx,
 			     struct ethtool_rx_flow_spec *fsp)
 {
 	int err;
 
 	/* init table of available rules */
-	err = rmgr_init(fd, ifr);
+	err = rmgr_init(ctx);
 	if (err < 0)
 		return err;
 
@@ -468,7 +464,7 @@ static int rmgr_set_location(int fd, struct ifreq *ifr,
 	return err;
 }
 
-int rxclass_rule_ins(int fd, struct ifreq *ifr,
+int rxclass_rule_ins(struct cmd_context *ctx,
 		     struct ethtool_rx_flow_spec *fsp)
 {
 	struct ethtool_rxnfc nfccmd;
@@ -480,7 +476,7 @@ int rxclass_rule_ins(int fd, struct ifreq *ifr,
 	 * and allocate a free rule for our use
 	 */
 	if (loc == RX_CLS_LOC_UNSPEC) {
-		err = rmgr_set_location(fd, ifr, fsp);
+		err = rmgr_set_location(ctx, fsp);
 		if (err < 0)
 			return err;
 	}
@@ -488,8 +484,7 @@ int rxclass_rule_ins(int fd, struct ifreq *ifr,
 	/* notify netdev of new rule */
 	nfccmd.cmd = ETHTOOL_SRXCLSRLINS;
 	nfccmd.fs = *fsp;
-	ifr->ifr_data = (caddr_t)&nfccmd;
-	err = ioctl(fd, SIOCETHTOOL, ifr);
+	err = send_ioctl(ctx, &nfccmd);
 	if (err < 0)
 		perror("rmgr: Cannot insert RX class rule");
 	else if (loc == RX_CLS_LOC_UNSPEC)
@@ -498,7 +493,7 @@ int rxclass_rule_ins(int fd, struct ifreq *ifr,
 	return 0;
 }
 
-int rxclass_rule_del(int fd, struct ifreq *ifr, __u32 loc)
+int rxclass_rule_del(struct cmd_context *ctx, __u32 loc)
 {
 	struct ethtool_rxnfc nfccmd;
 	int err;
@@ -506,8 +501,7 @@ int rxclass_rule_del(int fd, struct ifreq *ifr, __u32 loc)
 	/* notify netdev of rule removal */
 	nfccmd.cmd = ETHTOOL_SRXCLSRLDEL;
 	nfccmd.fs.location = loc;
-	ifr->ifr_data = (caddr_t)&nfccmd;
-	err = ioctl(fd, SIOCETHTOOL, ifr);
+	err = send_ioctl(ctx, &nfccmd);
 	if (err < 0)
 		perror("rmgr: Cannot delete RX class rule");
 
-- 
1.7.4.4



-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH ethtool 10/21] Add test cases for command-line parsing
  2011-11-01 22:35 [PATCH ethtool 00/21] ethtool refactoring and misc changes Ben Hutchings
                   ` (8 preceding siblings ...)
  2011-11-01 23:16 ` [PATCH ethtool 09/21] Encapsulate command context in a structure Ben Hutchings
@ 2011-11-01 23:17 ` Ben Hutchings
  2011-11-01 23:17 ` [PATCH ethtool 11/21] Add more " Ben Hutchings
                   ` (11 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Ben Hutchings @ 2011-11-01 23:17 UTC (permalink / raw)
  To: netdev; +Cc: linux-net-drivers

Preparation for refactoring command-line parsing.
All these test cases pass.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 Makefile.am    |    7 ++
 configure.ac   |    1 +
 ethtool.c      |    5 ++
 internal.h     |    4 +
 test-cmdline.c |  206 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 test-common.c  |   92 +++++++++++++++++++++++++
 6 files changed, 315 insertions(+), 0 deletions(-)
 create mode 100644 test-cmdline.c
 create mode 100644 test-common.c

diff --git a/Makefile.am b/Makefile.am
index 1e05640..4b0eb17 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -11,6 +11,13 @@ ethtool_SOURCES = ethtool.c ethtool-copy.h internal.h \
 		  smsc911x.c at76c50x-usb.c sfc.c stmmac.c	\
 		  rxclass.c
 
+TESTS = test-cmdline
+check_PROGRAMS = test-cmdline test-one-cmdline
+test_cmdline_SOURCES = test-cmdline.c test-common.c
+test_cmdline_CFLAGS = -DTEST_ETHTOOL
+test_one_cmdline_SOURCES = $(ethtool_SOURCES)
+test_one_cmdline_CFLAGS = -DTEST_ETHTOOL
+
 dist-hook:
 	cp $(top_srcdir)/ethtool.spec $(distdir)
 
diff --git a/configure.ac b/configure.ac
index 8bc8a56..ac5142b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -10,6 +10,7 @@ AM_MAINTAINER_MODE
 dnl Checks for programs.
 AC_PROG_CC
 AC_PROG_GCC_TRADITIONAL
+AM_PROG_CC_C_O
 
 dnl Checks for libraries.
 
diff --git a/ethtool.c b/ethtool.c
index b6f535c..7a26043 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -3444,8 +3444,13 @@ static int do_setfwdump(struct cmd_context *ctx)
 
 int send_ioctl(struct cmd_context *ctx, void *cmd)
 {
+#ifndef TEST_ETHTOOL
 	ctx->ifr.ifr_data = cmd;
 	return ioctl(ctx->fd, SIOCETHTOOL, &ctx->ifr);
+#else
+	/* If we get this far then parsing succeeded */
+	exit(0);
+#endif
 }
 
 int main(int argc, char **argp, char **envp)
diff --git a/internal.h b/internal.h
index c2f504a..ba7d719 100644
--- a/internal.h
+++ b/internal.h
@@ -94,6 +94,10 @@ struct cmd_context {
 	struct ifreq ifr;	/* ifreq suitable for ethtool ioctl */
 };
 
+#ifdef TEST_ETHTOOL
+int test_cmdline(const char *args);
+#endif
+
 int send_ioctl(struct cmd_context *ctx, void *cmd);
 
 /* National Semiconductor DP83815, DP83816 */
diff --git a/test-cmdline.c b/test-cmdline.c
new file mode 100644
index 0000000..88591df
--- /dev/null
+++ b/test-cmdline.c
@@ -0,0 +1,206 @@
+/****************************************************************************
+ * Test cases for ethtool command-line parsing
+ * Copyright 2011 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "internal.h"
+
+static struct test_case {
+	int rc;
+	const char *args;
+} test_cases[] = {
+	{ 1, "" },
+	{ 0, "devname" },
+	{ 0, "15_char_devname" },
+	{ 1, "16_char_devname!" },
+	/* Argument parsing for -s is specialised */
+	{ 0, "-s devname" },
+	{ 0, "--change devname speed 100 duplex half" },
+	{ 1, "-s devname speed foo" },
+	{ 1, "--change devname speed" },
+	{ 0, "-s devname duplex half" },
+	{ 1, "--change devname duplex foo" },
+	{ 1, "-s devname duplex" },
+	{ 0, "--change devname port tp" },
+	{ 1, "-s devname port foo" },
+	{ 1, "--change devname port" },
+	{ 0, "-s devname autoneg on" },
+	{ 1, "--change devname autoneg foo" },
+	{ 1, "-s devname autoneg" },
+	{ 0, "--change devname advertise 0x1" },
+	{ 1, "-s devname advertise foo" },
+	{ 1, "--change devname advertise" },
+	{ 0, "-s devname phyad 1" },
+	{ 1, "--change devname phyad foo" },
+	{ 1, "-s devname phyad" },
+	{ 0, "--change devname xcvr external" },
+	{ 1, "-s devname xcvr foo" },
+	{ 1, "--change devname xcvr" },
+	{ 0, "-s devname wol p" },
+	{ 1, "--change devname wol" },
+	{ 0, "-s devname sopass 01:23:45:67:89:ab" },
+	{ 1, "--change devname sopass 01:23:45:67:89:" },
+	{ 1, "-s devname sopass 01:23:45:67:89" },
+	{ 1, "--change devname sopass" },
+	{ 0, "-s devname msglvl 1" },
+	{ 1, "--change devname msglvl" },
+	{ 0, "-s devname msglvl hw on rx_status off" },
+	{ 1, "--change devname msglvl hw foo" },
+	{ 1, "-s devname msglvl hw" },
+	{ 0, "--change devname speed 100 duplex half port tp autoneg on advertise 0x1 phyad 1 xcvr external wol p sopass 01:23:45:67:89:ab msglvl 1" },
+	{ 1, "-s devname foo" },
+	{ 0, "-a devname" },
+	{ 0, "--show-pause devname" },
+	/* Many other sub-commands use parse_generic_cmdline() and
+	 * don't need to be check in that much detail. */
+	{ 0, "-A devname autoneg on" },
+	{ 1, "--pause devname autoneg foo" },
+	{ 1, "-A devname autoneg" },
+	{ 0, "--pause devname rx off" },
+	{ 0, "-A devname tx on rx on autoneg off" },
+	{ 1, "--pause devname foo on" },
+	{ 0, "-c devname" },
+	{ 0, "--show-coalesce devname" },
+	{ 0, "-C devname adaptive-rx on adaptive-tx off rx-usecs 1 rx-frames 2 rx-usecs-irq 3 rx-frames-irq 4 tx-usecs 5 tx-frames 6 tx-usecs-irq 7 tx-frames-irq 8 stats-block-usecs 9 pkt-rate-low 10" },
+	{ 0, "--coalesce devname rx-usecs-low 11 rx-frames-low 12 tx-usecs-low 13 tx-frames-low 14 pkt-rate-high 15 rx-usecs-high 16 rx-frames-high 17 tx-usecs-high 18 tx-frames-high 19 sample-interval 20" },
+	{ 1, "-C devname adaptive-rx foo" },
+	{ 1, "--coalesce devname adaptive-rx" },
+	{ 1, "-C devname foo on" },
+	{ 0, "-g devname" },
+	{ 0, "--show-ring devname" },
+	{ 0, "-G devname rx 1 rx-mini 2 rx-jumbo 3 tx 4" },
+	{ 0, "--set-ring devname rx 1 rx-mini 2 rx-jumbo 3 tx 4" },
+	{ 1, "-G devname rx foo" },
+	{ 1, "--set-ring devname rx" },
+	{ 1, "-G devname foo 1" },
+	{ 0, "-k devname" },
+	{ 0, "--show-offload devname" },
+	{ 0, "-K devname rx on tx off sg on tso off ufo on gso off gro on" },
+	{ 0, "--offload devname lro off rxvlan on txvlan off ntuple on rxhash off" },
+	{ 1, "-K devname rx foo" },
+	{ 1, "--offload devname rx" },
+	{ 1, "-K devname foo on" },
+	{ 0, "-i devname" },
+	{ 0, "--driver devname" },
+	{ 0, "-d devname" },
+	{ 0, "--register-dump devname raw on file foo" },
+	{ 1, "-d devname raw foo" },
+	{ 1, "--register-dump devname file" },
+	{ 1, "-d devname foo" },
+	{ 0, "-e devname" },
+	{ 0, "--eeprom-dump devname raw on offset 1 length 2" },
+	{ 1, "-e devname raw foo" },
+	{ 1, "--eeprom-dump devname offset foo" },
+	{ 1, "-e devname length" },
+	{ 1, "--eeprom-dump devname foo" },
+	{ 0, "-E devname" },
+	{ 0, "--change-eeprom devname magic 0x87654321 offset 0 value 1" },
+	{ 0, "-E devname magic 0x87654321 offset 0 length 2" },
+	{ 0, "-r devname" },
+	{ 0, "--negotiate devname" },
+	{ 0, "-p devname" },
+	{ 0, "--identify devname 1" },
+	{ 1, "-p devname 1 foo" },
+	{ 1, "--identify devname foo" },
+	/* Argument parsing for -t is specialised */
+	{ 0, "-t devname" },
+	{ 0, "--test devname online" },
+	{ 1, "-t devname foo" },
+	{ 1, "--test devname online foo" },
+	{ 0, "-S devname" },
+	{ 0, "--statistics devname" },
+	/* Argument parsing for -n is specialised */
+	{ 0, "-n devname rx-flow-hash tcp4" },
+	{ 0, "--show-nfc devname rx-flow-hash udp6" },
+	{ 1, "-n devname rx-flow-hash foo" },
+	{ 1, "--show-nfc devname rx-flow-hash" },
+	{ 1, "-n devname foo" },
+	/* Argument parsing for -f is specialised */
+	{ 1, "-f devname" },
+	{ 0, "--flash devname filename" },
+	{ 0, "-f devname filename 1" },
+	/* Argument parsing for -N is specialised */
+	{ 0, "-N devname rx-flow-hash tcp4 mvtsdfn" },
+	{ 0, "--config-nfc devname rx-flow-hash tcp4 r" },
+	{ 1, "-N devname rx-flow-hash tcp4" },
+	{ 1, "--config-nfc devname rx-flow-hash foo" },
+	{ 1, "-N devname rx-flow-hash" },
+	{ 1, "--config-nfc devname foo" },
+	{ 0, "-x devname" },
+	{ 0, "--show-rxfh-indir devname" },
+	/* Argument parsing for -X is specialised */
+	{ 0, "-X devname equal 2" },
+	{ 0, "--set-rxfh-indir devname equal 256" },
+	{ 1, "-X devname equal 0" },
+	{ 1, "--set-rxfh-indir devname equal foo" },
+	{ 1, "-X devname equal" },
+	{ 0, "--set-rxfh-indir devname weight 1 2 3 4" },
+	{ 1, "-X devname foo" },
+	/* Argument parsing for -U is specialised */
+	{ 0, "-U devname delete 1" },
+	{ 1, "--config-ntuple devname delete foo" },
+	{ 1, "-U devname delete" },
+	{ 0, "--config-ntuple devname flow-type ether src 01:23:45:67:89:ab m cd:ef:01:23:45:67 dst 89:ab:cd:ef:01:23 m 45:67:89:ab:cd:ef proto 0x0123 m 0x4567 vlan 0x89ab m 0xcdef action 0" },
+	{ 0, "-U devname flow-type ether src 01:23:45:67:89:ab src-mask cd:ef:01:23:45:67 dst 89:ab:cd:ef:01:23 dst-mask 45:67:89:ab:cd:ef proto 0x0123 proto-mask 0x4567 vlan 0x89ab vlan-mask 0xcdef action 1" },
+	{ 1, "--config-ntuple devname flow-type ether src 01:23:45:67:89: action 3" },
+	{ 1, "-U devname flow-type ether src 01:23:45:67:89 action 4" },
+	{ 0, "--config-ntuple devname flow-type ip4 src-ip 0.123.45.67 m 89.0.123.45 dst-ip 67.89.0.123 m 45.67.89.0 tos 1 m 1 l4proto 0x23 m 0x45 l4data 0xfedcba98 m 76543210 vlan 0x89ab m 0xcdef action 6" },
+	{ 0, "-U devname flow-type ip4 src-ip 0.123.45.67 src-ip-mask 89.0.123.45 dst-ip 67.89.0.123 dst-ip-mask 45.67.89.0 tos 1 tos-mask 1 l4proto 0x23 l4proto-mask 0x45 l4data 0xfedcba98 l4data-mask 76543210 vlan 0x89ab vlan-mask 0xcdef action 7" },
+	{ 0, "--config-ntuple devname flow-type tcp4 src-ip 0.123.45.67 m 89.0.123.45 dst-ip 67.89.0.123 m 45.67.89.0 tos 1 m 1 src-port 23456 m 7890 dst-port 12345 m 6789 vlan 0x89ab m 0xcdef action 8" },
+	{ 0, "-U devname flow-type tcp4 src-ip 0.123.45.67 src-ip-mask 89.0.123.45 dst-ip 67.89.0.123 dst-ip-mask 45.67.89.0 tos 1 tos-mask 1 src-port 23456 src-port-mask 7890 dst-port 12345 dst-port-mask 6789 vlan 0x89ab vlan-mask 0xcdef action 9" },
+	{ 0, "--config-ntuple devname flow-type ah4 src-ip 0.123.45.67 m 89.0.123.45 dst-ip 67.89.0.123 m 45.67.89.0 tos 1 m 1 spi 2 m 3 vlan 0x89ab m 0xcdef action 10" },
+	{ 0, "-U devname flow-type ah4 src-ip 0.123.45.67 src-ip-mask 89.0.123.45 dst-ip 67.89.0.123 dst-ip-mask 45.67.89.0 tos 1 tos-mask 1 spi 2 spi-mask 3 vlan 0x89ab vlan-mask 0xcdef action 11" },
+	{ 1, "--config-ntuple devname flow-type tcp4 action foo" },
+	{ 1, "-U devname flow-type foo" },
+	{ 1, "--config-ntuple devname flow-type" },
+	{ 1, "-U devname foo" },
+	{ 0, "-P devname" },
+	{ 0, "--show-permaddr devname" },
+	{ 0, "-w devname" },
+	{ 0, "--get-dump devname data filename" },
+	{ 0, "-w devname data filename" },
+	{ 1, "--get-dump devname data" },
+	{ 1, "-w devname foo" },
+	{ 0, "-W devname 1" },
+	{ 0, "--set-dump devname 2" },
+	{ 1, "-W devname foo" },
+	{ 0, "-l devname" },
+	{ 0, "--show-channels devname" },
+	{ 0, "-L devname rx 1 tx 2 other 3 combined 4" },
+	{ 0, "--set-channels devname rx 1 tx 2 other 3 combined 4" },
+	{ 1, "-L devname rx foo" },
+	{ 1, "--set-channels devname rx" },
+	{ 0, "-L devname" },
+	{ 0, "-h" },
+	{ 0, "--help" },
+	{ 0, "--version" },
+	{ 1, "--foo" },
+	{ 1, "-foo" },
+	{ 1, "-0" },
+};
+
+int main(void)
+{
+	struct test_case *tc;
+	int test_rc;
+	int rc = 0;
+
+	for (tc = test_cases; tc < test_cases + ARRAY_SIZE(test_cases); tc++) {
+		if (getenv("ETHTOOL_TEST_VERBOSE"))
+			printf("I: Test command line: ethtool %s\n", tc->args);
+		test_rc = test_cmdline(tc->args);
+		if (test_rc != tc->rc) {
+			fprintf(stderr, "E: ethtool %s returns %d\n",
+				tc->args, test_rc);
+			rc = 1;
+		}
+	}
+
+	return rc;
+}
diff --git a/test-common.c b/test-common.c
new file mode 100644
index 0000000..4ea84c8
--- /dev/null
+++ b/test-common.c
@@ -0,0 +1,92 @@
+/****************************************************************************
+ * Common test functions for ethtool
+ * Copyright 2011 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/fcntl.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include "internal.h"
+
+int test_cmdline(const char *args)
+{
+	int argc, i;
+	char **argv;
+	const char *arg;
+	size_t len;
+	pid_t pid;
+	int dev_null;
+	int status;
+	int rc;
+
+	/* Convert line to argv */
+	argc = 1;
+	arg = args;
+	for (;;) {
+		len = strcspn(arg, " ");
+		if (len == 0)
+			break;
+		argc++;
+		if (arg[len] == 0)
+			break;
+		arg += len + 1;
+	}
+	argv = calloc(argc + 1, sizeof(argv[0]));
+	argv[0] = strdup("ethtool");
+	arg = args;
+	for (i = 1; i < argc; i++) {
+		len = strcspn(arg, " ");
+		argv[i] = malloc(len + 1);
+		memcpy(argv[i], arg, len);
+		argv[i][len] = 0;
+		arg += len + 1;
+	}
+
+	dev_null = open("/dev/null", O_RDWR);
+	if (dev_null < 0) {
+		perror("open /dev/null");
+		rc = -1;
+		goto out;
+	}
+
+	fflush(NULL);
+	pid = fork();
+
+	/* Child */
+	if (pid == 0) {
+		dup2(dev_null, STDIN_FILENO);
+		if (!getenv("ETHTOOL_TEST_VERBOSE")) {
+			dup2(dev_null, STDOUT_FILENO);
+			dup2(dev_null, STDERR_FILENO);
+		}
+		execv("./test-one-cmdline", argv);
+		_exit(126);
+	}
+
+	/* Parent */
+	if (pid < 0) {
+		perror("fork");
+		close(dev_null);
+		rc = -1;
+		goto out;
+	}
+	close(dev_null);
+	if (waitpid(pid, &status, 0) < 0) {
+		perror("waitpid");
+		rc = -1;
+		goto out;
+	}
+	rc = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
+
+out:
+	for (i = 0; i < argc; i++)
+		free(argv[i]);
+	free(argv);
+	return rc;
+}
-- 
1.7.4.4



-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH ethtool 11/21] Add more test cases for command-line parsing
  2011-11-01 22:35 [PATCH ethtool 00/21] ethtool refactoring and misc changes Ben Hutchings
                   ` (9 preceding siblings ...)
  2011-11-01 23:17 ` [PATCH ethtool 10/21] Add test cases for command-line parsing Ben Hutchings
@ 2011-11-01 23:17 ` Ben Hutchings
  2011-11-01 23:18 ` [PATCH ethtool 12/21] Move argument parsing to sub-command functions Ben Hutchings
                   ` (10 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Ben Hutchings @ 2011-11-01 23:17 UTC (permalink / raw)
  To: netdev; +Cc: linux-net-drivers

These test cases currently fail.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 test-cmdline.c |   28 ++++++++++++++++++++++++++++
 1 files changed, 28 insertions(+), 0 deletions(-)

diff --git a/test-cmdline.c b/test-cmdline.c
index 88591df..7dd3b7c 100644
--- a/test-cmdline.c
+++ b/test-cmdline.c
@@ -55,8 +55,10 @@ static struct test_case {
 	{ 1, "-s devname msglvl hw" },
 	{ 0, "--change devname speed 100 duplex half port tp autoneg on advertise 0x1 phyad 1 xcvr external wol p sopass 01:23:45:67:89:ab msglvl 1" },
 	{ 1, "-s devname foo" },
+	{ 1, "-s" },
 	{ 0, "-a devname" },
 	{ 0, "--show-pause devname" },
+	{ 1, "-a" },
 	/* Many other sub-commands use parse_generic_cmdline() and
 	 * don't need to be check in that much detail. */
 	{ 0, "-A devname autoneg on" },
@@ -65,6 +67,7 @@ static struct test_case {
 	{ 0, "--pause devname rx off" },
 	{ 0, "-A devname tx on rx on autoneg off" },
 	{ 1, "--pause devname foo on" },
+	{ 1, "-A" },
 	{ 0, "-c devname" },
 	{ 0, "--show-coalesce devname" },
 	{ 0, "-C devname adaptive-rx on adaptive-tx off rx-usecs 1 rx-frames 2 rx-usecs-irq 3 rx-frames-irq 4 tx-usecs 5 tx-frames 6 tx-usecs-irq 7 tx-frames-irq 8 stats-block-usecs 9 pkt-rate-low 10" },
@@ -72,42 +75,53 @@ static struct test_case {
 	{ 1, "-C devname adaptive-rx foo" },
 	{ 1, "--coalesce devname adaptive-rx" },
 	{ 1, "-C devname foo on" },
+	{ 1, "-C" },
 	{ 0, "-g devname" },
 	{ 0, "--show-ring devname" },
+	{ 1, "-g" },
 	{ 0, "-G devname rx 1 rx-mini 2 rx-jumbo 3 tx 4" },
 	{ 0, "--set-ring devname rx 1 rx-mini 2 rx-jumbo 3 tx 4" },
 	{ 1, "-G devname rx foo" },
 	{ 1, "--set-ring devname rx" },
 	{ 1, "-G devname foo 1" },
+	{ 1, "-G" },
 	{ 0, "-k devname" },
 	{ 0, "--show-offload devname" },
+	{ 1, "-k" },
 	{ 0, "-K devname rx on tx off sg on tso off ufo on gso off gro on" },
 	{ 0, "--offload devname lro off rxvlan on txvlan off ntuple on rxhash off" },
 	{ 1, "-K devname rx foo" },
 	{ 1, "--offload devname rx" },
 	{ 1, "-K devname foo on" },
+	{ 1, "-K" },
 	{ 0, "-i devname" },
 	{ 0, "--driver devname" },
+	{ 1, "-i" },
 	{ 0, "-d devname" },
 	{ 0, "--register-dump devname raw on file foo" },
 	{ 1, "-d devname raw foo" },
 	{ 1, "--register-dump devname file" },
 	{ 1, "-d devname foo" },
+	{ 1, "-d" },
 	{ 0, "-e devname" },
 	{ 0, "--eeprom-dump devname raw on offset 1 length 2" },
 	{ 1, "-e devname raw foo" },
 	{ 1, "--eeprom-dump devname offset foo" },
 	{ 1, "-e devname length" },
 	{ 1, "--eeprom-dump devname foo" },
+	{ 1, "-e" },
 	{ 0, "-E devname" },
 	{ 0, "--change-eeprom devname magic 0x87654321 offset 0 value 1" },
 	{ 0, "-E devname magic 0x87654321 offset 0 length 2" },
+	{ 1, "-E" },
 	{ 0, "-r devname" },
 	{ 0, "--negotiate devname" },
+	{ 1, "-r" },
 	{ 0, "-p devname" },
 	{ 0, "--identify devname 1" },
 	{ 1, "-p devname 1 foo" },
 	{ 1, "--identify devname foo" },
+	{ 1, "-p" },
 	/* Argument parsing for -t is specialised */
 	{ 0, "-t devname" },
 	{ 0, "--test devname online" },
@@ -115,16 +129,20 @@ static struct test_case {
 	{ 1, "--test devname online foo" },
 	{ 0, "-S devname" },
 	{ 0, "--statistics devname" },
+	{ 1, "-S" },
 	/* Argument parsing for -n is specialised */
 	{ 0, "-n devname rx-flow-hash tcp4" },
 	{ 0, "--show-nfc devname rx-flow-hash udp6" },
 	{ 1, "-n devname rx-flow-hash foo" },
 	{ 1, "--show-nfc devname rx-flow-hash" },
 	{ 1, "-n devname foo" },
+	{ 1, "-n" },
 	/* Argument parsing for -f is specialised */
 	{ 1, "-f devname" },
 	{ 0, "--flash devname filename" },
 	{ 0, "-f devname filename 1" },
+	{ 1, "-f devname filename 1 foo" },
+	{ 1, "-f" },
 	/* Argument parsing for -N is specialised */
 	{ 0, "-N devname rx-flow-hash tcp4 mvtsdfn" },
 	{ 0, "--config-nfc devname rx-flow-hash tcp4 r" },
@@ -132,8 +150,10 @@ static struct test_case {
 	{ 1, "--config-nfc devname rx-flow-hash foo" },
 	{ 1, "-N devname rx-flow-hash" },
 	{ 1, "--config-nfc devname foo" },
+	{ 1, "-N" },
 	{ 0, "-x devname" },
 	{ 0, "--show-rxfh-indir devname" },
+	{ 1, "-x" },
 	/* Argument parsing for -X is specialised */
 	{ 0, "-X devname equal 2" },
 	{ 0, "--set-rxfh-indir devname equal 256" },
@@ -142,6 +162,7 @@ static struct test_case {
 	{ 1, "-X devname equal" },
 	{ 0, "--set-rxfh-indir devname weight 1 2 3 4" },
 	{ 1, "-X devname foo" },
+	{ 1, "-X" },
 	/* Argument parsing for -U is specialised */
 	{ 0, "-U devname delete 1" },
 	{ 1, "--config-ntuple devname delete foo" },
@@ -160,23 +181,30 @@ static struct test_case {
 	{ 1, "-U devname flow-type foo" },
 	{ 1, "--config-ntuple devname flow-type" },
 	{ 1, "-U devname foo" },
+	{ 1, "-U" },
 	{ 0, "-P devname" },
 	{ 0, "--show-permaddr devname" },
+	{ 1, "-P" },
 	{ 0, "-w devname" },
 	{ 0, "--get-dump devname data filename" },
 	{ 0, "-w devname data filename" },
 	{ 1, "--get-dump devname data" },
 	{ 1, "-w devname foo" },
+	{ 1, "-w" },
 	{ 0, "-W devname 1" },
 	{ 0, "--set-dump devname 2" },
+	{ 1, "-W devname 1 foo" },
 	{ 1, "-W devname foo" },
+	{ 1, "-W" },
 	{ 0, "-l devname" },
 	{ 0, "--show-channels devname" },
+	{ 1, "-l" },
 	{ 0, "-L devname rx 1 tx 2 other 3 combined 4" },
 	{ 0, "--set-channels devname rx 1 tx 2 other 3 combined 4" },
 	{ 1, "-L devname rx foo" },
 	{ 1, "--set-channels devname rx" },
 	{ 0, "-L devname" },
+	{ 1, "-L" },
 	{ 0, "-h" },
 	{ 0, "--help" },
 	{ 0, "--version" },
-- 
1.7.4.4



-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH ethtool 12/21] Move argument parsing to sub-command functions
  2011-11-01 22:35 [PATCH ethtool 00/21] ethtool refactoring and misc changes Ben Hutchings
                   ` (10 preceding siblings ...)
  2011-11-01 23:17 ` [PATCH ethtool 11/21] Add more " Ben Hutchings
@ 2011-11-01 23:18 ` Ben Hutchings
  2011-11-01 23:18 ` [PATCH ethtool 13/21] Support arbitrary numbers of option names for each mode Ben Hutchings
                   ` (9 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Ben Hutchings @ 2011-11-01 23:18 UTC (permalink / raw)
  To: netdev; +Cc: linux-net-drivers

Instead of doing most of the argument parsing in parse_cmdline(),
find the sub-command and (if required) the device name in main()
and do the rest in the sub-command handler function.  Pass argc
and argp around in struct cmd_context.

This also tightens up argument parsing slightly: extraneous or missing
arguments will now result in an error in a few cases where they were
previously ignored.  All test cases now pass.

Replace sub-command dispatch in doit() with a function pointer
in struct option.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 ethtool.8.in |    4 +-
 ethtool.c    |  988 +++++++++++++++++++++++-----------------------------------
 internal.h   |    4 +-
 rxclass.c    |    4 +-
 4 files changed, 390 insertions(+), 610 deletions(-)

diff --git a/ethtool.8.in b/ethtool.8.in
index 3304fe5..7c39629 100644
--- a/ethtool.8.in
+++ b/ethtool.8.in
@@ -252,11 +252,11 @@ ethtool \- query or control network driver and hardware settings
 .HP
 .B ethtool \-n
 .I devname
-.RB [ rx\-flow\-hash \ \*(FL]
+.BR rx\-flow\-hash \ \*(FL
 .HP
 .B ethtool \-N
 .I devname
-.RB [ rx\-flow\-hash \ \*(FL \: \*(HO]
+.BR rx\-flow\-hash \ \*(FL \: \*(HO
 .HP
 .B ethtool \-w|\-\-get\-dump
 .I devname
diff --git a/ethtool.c b/ethtool.c
index 7a26043..4eff916 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -64,6 +64,8 @@ enum {
 };
 #endif
 
+static int show_usage(struct cmd_context *ctx);
+static int do_version(struct cmd_context *ctx);
 static int parse_wolopts(char *optstr, u32 *data);
 static char *unparse_wolopts(int wolopts);
 static void get_mac_addr(char *src, unsigned char *dest);
@@ -102,48 +104,14 @@ static int do_permaddr(struct cmd_context *ctx);
 static int do_getfwdump(struct cmd_context *ctx);
 static int do_setfwdump(struct cmd_context *ctx);
 
-static enum {
-	MODE_VERSION = -2,
-	MODE_HELP = -1,
-	MODE_GSET=0,
-	MODE_SSET,
-	MODE_GDRV,
-	MODE_GREGS,
-	MODE_NWAY_RST,
-	MODE_GEEPROM,
-	MODE_SEEPROM,
-	MODE_TEST,
-	MODE_PHYS_ID,
-	MODE_GPAUSE,
-	MODE_SPAUSE,
-	MODE_GCOALESCE,
-	MODE_SCOALESCE,
-	MODE_GRING,
-	MODE_SRING,
-	MODE_GOFFLOAD,
-	MODE_SOFFLOAD,
-	MODE_GSTATS,
-	MODE_GNFC,
-	MODE_SNFC,
-	MODE_GRXFHINDIR,
-	MODE_SRXFHINDIR,
-	MODE_SCLSRULE,
-	MODE_GCLSRULE,
-	MODE_FLASHDEV,
-	MODE_PERMADDR,
-	MODE_SET_DUMP,
-	MODE_GET_DUMP,
-	MODE_GCHANNELS,
-	MODE_SCHANNELS
-} mode = MODE_GSET;
-
 static struct option {
 	char *srt, *lng;
-	int Mode;
+	int want_device;
+	int (*func)(struct cmd_context *);
 	char *help;
 	char *opthelp;
 } args[] = {
-	{ "-s", "--change", MODE_SSET, "Change generic options",
+	{ "-s", "--change", 1, do_sset, "Change generic options",
 	  "		[ speed %d ]\n"
 	  "		[ duplex half|full ]\n"
 	  "		[ port tp|aui|bnc|mii|fibre ]\n"
@@ -154,13 +122,13 @@ static struct option {
 	  "		[ wol p|u|m|b|a|g|s|d... ]\n"
 	  "		[ sopass %x:%x:%x:%x:%x:%x ]\n"
 	  "		[ msglvl %d | msglvl type on|off ... ]\n" },
-	{ "-a", "--show-pause", MODE_GPAUSE, "Show pause options" },
-	{ "-A", "--pause", MODE_SPAUSE, "Set pause options",
+	{ "-a", "--show-pause", 1, do_gpause, "Show pause options" },
+	{ "-A", "--pause", 1, do_spause, "Set pause options",
 	  "		[ autoneg on|off ]\n"
 	  "		[ rx on|off ]\n"
 	  "		[ tx on|off ]\n" },
-	{ "-c", "--show-coalesce", MODE_GCOALESCE, "Show coalesce options" },
-	{ "-C", "--coalesce", MODE_SCOALESCE, "Set coalesce options",
+	{ "-c", "--show-coalesce", 1, do_gcoalesce, "Show coalesce options" },
+	{ "-C", "--coalesce", 1, do_scoalesce, "Set coalesce options",
 	  "		[adaptive-rx on|off]\n"
 	  "		[adaptive-tx on|off]\n"
 	  "		[rx-usecs N]\n"
@@ -183,15 +151,15 @@ static struct option {
 	  "		[tx-usecs-high N]\n"
 	  "		[tx-frames-high N]\n"
 	  "		[sample-interval N]\n" },
-	{ "-g", "--show-ring", MODE_GRING, "Query RX/TX ring parameters" },
-	{ "-G", "--set-ring", MODE_SRING, "Set RX/TX ring parameters",
+	{ "-g", "--show-ring", 1, do_gring, "Query RX/TX ring parameters" },
+	{ "-G", "--set-ring", 1, do_sring, "Set RX/TX ring parameters",
 	  "		[ rx N ]\n"
 	  "		[ rx-mini N ]\n"
 	  "		[ rx-jumbo N ]\n"
 	  "		[ tx N ]\n" },
-	{ "-k", "--show-offload", MODE_GOFFLOAD,
+	{ "-k", "--show-offload", 1, do_goffload,
 	  "Get protocol offload information" },
-	{ "-K", "--offload", MODE_SOFFLOAD, "Set protocol offload",
+	{ "-K", "--offload", 1, do_soffload, "Set protocol offload",
 	  "		[ rx on|off ]\n"
 	  "		[ tx on|off ]\n"
 	  "		[ sg on|off ]\n"
@@ -205,44 +173,44 @@ static struct option {
 	  "		[ ntuple on|off ]\n"
 	  "		[ rxhash on|off ]\n"
 	},
-	{ "-i", "--driver", MODE_GDRV, "Show driver information" },
-	{ "-d", "--register-dump", MODE_GREGS, "Do a register dump",
+	{ "-i", "--driver", 1, do_gdrv, "Show driver information" },
+	{ "-d", "--register-dump", 1, do_gregs, "Do a register dump",
 	  "		[ raw on|off ]\n"
 	  "		[ file FILENAME ]\n" },
-	{ "-e", "--eeprom-dump", MODE_GEEPROM, "Do a EEPROM dump",
+	{ "-e", "--eeprom-dump", 1, do_geeprom, "Do a EEPROM dump",
 	  "		[ raw on|off ]\n"
 	  "		[ offset N ]\n"
 	  "		[ length N ]\n" },
-	{ "-E", "--change-eeprom", MODE_SEEPROM,
+	{ "-E", "--change-eeprom", 1, do_seeprom,
 	  "Change bytes in device EEPROM",
 	  "		[ magic N ]\n"
 	  "		[ offset N ]\n"
 	  "		[ length N ]\n"
 	  "		[ value N ]\n" },
-	{ "-r", "--negotiate", MODE_NWAY_RST, "Restart N-WAY negotiation" },
-	{ "-p", "--identify", MODE_PHYS_ID,
+	{ "-r", "--negotiate", 1, do_nway_rst, "Restart N-WAY negotiation" },
+	{ "-p", "--identify", 1, do_phys_id,
 	  "Show visible port identification (e.g. blinking)",
 	  "               [ TIME-IN-SECONDS ]\n" },
-	{ "-t", "--test", MODE_TEST, "Execute adapter self test",
+	{ "-t", "--test", 1, do_test, "Execute adapter self test",
 	  "               [ online | offline | external_lb ]\n" },
-	{ "-S", "--statistics", MODE_GSTATS, "Show adapter statistics" },
-	{ "-n", "--show-nfc", MODE_GNFC,
+	{ "-S", "--statistics", 1, do_gstats, "Show adapter statistics" },
+	{ "-n", "--show-nfc", 1, do_grxclass,
 	  "Show Rx network flow classification options",
 	  "		[ rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
 	  "tcp6|udp6|ah6|esp6|sctp6 ]\n" },
-	{ "-f", "--flash", MODE_FLASHDEV,
+	{ "-f", "--flash", 1, do_flash,
 	  "Flash firmware image from the specified file to a region on the device",
 	  "               FILENAME [ REGION-NUMBER-TO-FLASH ]\n" },
-	{ "-N", "--config-nfc", MODE_SNFC,
+	{ "-N", "--config-nfc", 1, do_srxclass,
 	  "Configure Rx network flow classification options",
 	  "		[ rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
 	  "tcp6|udp6|ah6|esp6|sctp6 m|v|t|s|d|f|n|r... ]\n" },
-	{ "-x", "--show-rxfh-indir", MODE_GRXFHINDIR,
+	{ "-x", "--show-rxfh-indir", 1, do_grxfhindir,
 	  "Show Rx flow hash indirection" },
-	{ "-X", "--set-rxfh-indir", MODE_SRXFHINDIR,
+	{ "-X", "--set-rxfh-indir", 1, do_srxfhindir,
 	  "Set Rx flow hash indirection",
 	  "		equal N | weight W0 W1 ...\n" },
-	{ "-U", "--config-ntuple", MODE_SCLSRULE,
+	{ "-U", "--config-ntuple", 1, do_srxclsrule,
 	  "Configure Rx ntuple filters and actions",
 	  "		[ delete %d ] |\n"
 	  "		[ flow-type ether|ip4|tcp4|udp4|sctp4|ah4|esp4\n"
@@ -261,25 +229,25 @@ static struct option {
 	  "			[ user-def %x [m %x] ]\n"
 	  "			[ action %d ]\n"
 	  "			[ loc %d]]\n" },
-	{ "-u", "--show-ntuple", MODE_GCLSRULE,
+	{ "-u", "--show-ntuple", 1, do_grxclsrule,
 	  "Get Rx ntuple filters and actions",
 	  "		[ rule %d ]\n"},
-	{ "-P", "--show-permaddr", MODE_PERMADDR,
+	{ "-P", "--show-permaddr", 1, do_permaddr,
 	  "Show permanent hardware address" },
-	{ "-w", "--get-dump", MODE_GET_DUMP,
+	{ "-w", "--get-dump", 1, do_getfwdump,
 	  "Get dump flag, data",
 	  "		[ data FILENAME ]\n" },
-	{ "-W", "--set-dump", MODE_SET_DUMP,
+	{ "-W", "--set-dump", 1, do_setfwdump,
 	  "Set dump flag of the device",
 	  "		N\n"},
-	{ "-l", "--show-channels", MODE_GCHANNELS, "Query Channels" },
-	{ "-L", "--set-channels", MODE_SCHANNELS, "Set Channels",
+	{ "-l", "--show-channels", 1, do_gchannels, "Query Channels" },
+	{ "-L", "--set-channels", 1, do_schannels, "Set Channels",
 	  "               [ rx N ]\n"
 	  "               [ tx N ]\n"
 	  "               [ other N ]\n"
 	  "               [ combined N ]\n" },
-	{ "-h", "--help", MODE_HELP, "Show this help" },
-	{ NULL, "--version", MODE_VERSION, "Show version number" },
+	{ "-h", "--help", 0, show_usage, "Show this help" },
+	{ NULL, "--version", 0, do_version, "Show version number" },
 	{}
 };
 
@@ -294,7 +262,7 @@ static void exit_bad_args(void)
 	exit(1);
 }
 
-static void show_usage(void)
+static int show_usage(struct cmd_context *ctx)
 {
 	int i;
 
@@ -310,11 +278,13 @@ static void show_usage(void)
 			fprintf(stdout, "%s|", args[i].srt);
 		fprintf(stdout, "%s %s\t%s\n",
 			args[i].lng,
-			args[i].Mode < 0 ? "\t" : "DEVNAME",
+			args[i].want_device ? "DEVNAME" : "\t",
 			args[i].help);
 		if (args[i].opthelp)
 			fputs(args[i].opthelp, stdout);
 	}
+
+	return 0;
 }
 
 static char *devname = NULL;
@@ -406,11 +376,9 @@ static int seeprom_value_seen = 0;
 static int rx_fhash_get = 0;
 static int rx_fhash_set = 0;
 static u32 rx_fhash_val = 0;
-static int rx_fhash_changed = 0;
 static int rxfhindir_equal = 0;
 static char **rxfhindir_weight = NULL;
 static char *flash_file = NULL;
-static int flash = -1;
 static int flash_region = -1;
 
 static int msglvl_changed;
@@ -421,7 +389,6 @@ static char *dump_file = NULL;
 
 static int rx_class_rule_get = -1;
 static int rx_class_rule_del = -1;
-static int rx_class_rule_added = 0;
 static struct ethtool_rx_flow_spec rx_rule_fs;
 
 static enum {
@@ -619,15 +586,17 @@ static u32 get_u32(char *str, int base)
 	return get_uint_range(str, base, 0xffffffff);
 }
 
-static void parse_generic_cmdline(int argc, char **argp,
-				  int first_arg, int *changed,
+static void parse_generic_cmdline(struct cmd_context *ctx,
+				  int *changed,
 				  struct cmdline_info *info,
 				  unsigned int n_info)
 {
+	int argc = ctx->argc;
+	char **argp = ctx->argp;
 	int i, idx;
 	int found;
 
-	for (i = first_arg; i < argc; i++) {
+	for (i = 0; i < argc; i++) {
 		found = 0;
 		for (idx = 0; idx < n_info; idx++) {
 			if (!strcmp(info[idx].name, argp[i])) {
@@ -773,443 +742,11 @@ static int rxflow_str_to_type(const char *str)
 	return flow_type;
 }
 
-static void parse_cmdline(int argc, char **argp)
+static int do_version(struct cmd_context *ctx)
 {
-	int i, k;
-
-	for (i = 1; i < argc; i++) {
-		switch (i) {
-		case 1:
-			for (k = 0; args[k].lng; k++)
-				if ((args[k].srt &&
-				     !strcmp(argp[i], args[k].srt)) ||
-				    !strcmp(argp[i], args[k].lng)) {
-					mode = args[k].Mode;
-					break;
-				}
-			if (mode == MODE_HELP) {
-				show_usage();
-				exit(0);
-			} else if (mode == MODE_VERSION) {
-				fprintf(stdout,
-					PACKAGE " version " VERSION "\n");
-				exit(0);
-			} else if (!args[k].lng && argp[i][0] == '-') {
-				exit_bad_args();
-			} else {
-				devname = argp[i];
-			}
-			break;
-		case 2:
-			if ((mode == MODE_SSET) ||
-			    (mode == MODE_GDRV) ||
-			    (mode == MODE_GREGS)||
-			    (mode == MODE_NWAY_RST) ||
-			    (mode == MODE_TEST) ||
-			    (mode == MODE_GEEPROM) ||
-			    (mode == MODE_SEEPROM) ||
-			    (mode == MODE_GPAUSE) ||
-			    (mode == MODE_SPAUSE) ||
-			    (mode == MODE_GCOALESCE) ||
-			    (mode == MODE_SCOALESCE) ||
-			    (mode == MODE_GRING) ||
-			    (mode == MODE_GCHANNELS) ||
-			    (mode == MODE_SCHANNELS) ||
-			    (mode == MODE_SRING) ||
-			    (mode == MODE_GOFFLOAD) ||
-			    (mode == MODE_SOFFLOAD) ||
-			    (mode == MODE_GSTATS) ||
-			    (mode == MODE_GNFC) ||
-			    (mode == MODE_SNFC) ||
-			    (mode == MODE_GRXFHINDIR) ||
-			    (mode == MODE_SRXFHINDIR) ||
-			    (mode == MODE_SCLSRULE) ||
-			    (mode == MODE_GCLSRULE) ||
-			    (mode == MODE_PHYS_ID) ||
-			    (mode == MODE_FLASHDEV) ||
-			    (mode == MODE_PERMADDR) ||
-			    (mode == MODE_SET_DUMP) ||
-			    (mode == MODE_GET_DUMP)) {
-				devname = argp[i];
-				break;
-			}
-			/* fallthrough */
-		case 3:
-			if (mode == MODE_TEST) {
-				if (!strcmp(argp[i], "online")) {
-					test_type = ONLINE;
-				} else if (!strcmp(argp[i], "offline")) {
-					test_type = OFFLINE;
-				} else if (!strcmp(argp[i], "external_lb")) {
-					test_type = EXTERNAL_LB;
-				} else {
-					exit_bad_args();
-				}
-				break;
-			} else if (mode == MODE_PHYS_ID) {
-				phys_id_time = get_int(argp[i],0);
-				break;
-			} else if (mode == MODE_FLASHDEV) {
-				flash_file = argp[i];
-				flash = 1;
-				break;
-			} else if (mode == MODE_SET_DUMP) {
-				dump_flag = get_u32(argp[i], 0);
-				break;
-			}
-			/* fallthrough */
-		default:
-			if (mode == MODE_GREGS) {
-				parse_generic_cmdline(argc, argp, i,
-					&gregs_changed,
-					cmdline_gregs,
-					ARRAY_SIZE(cmdline_gregs));
-				i = argc;
-				break;
-			}
-			if (mode == MODE_GEEPROM) {
-				parse_generic_cmdline(argc, argp, i,
-					&geeprom_changed,
-					cmdline_geeprom,
-					ARRAY_SIZE(cmdline_geeprom));
-				i = argc;
-				break;
-			}
-			if (mode == MODE_SEEPROM) {
-				parse_generic_cmdline(argc, argp, i,
-					&seeprom_changed,
-					cmdline_seeprom,
-					ARRAY_SIZE(cmdline_seeprom));
-				i = argc;
-				break;
-			}
-			if (mode == MODE_SPAUSE) {
-				parse_generic_cmdline(argc, argp, i,
-					&gpause_changed,
-			      		cmdline_pause,
-			      		ARRAY_SIZE(cmdline_pause));
-				i = argc;
-				break;
-			}
-			if (mode == MODE_SRING) {
-				parse_generic_cmdline(argc, argp, i,
-					&gring_changed,
-			      		cmdline_ring,
-			      		ARRAY_SIZE(cmdline_ring));
-				i = argc;
-				break;
-			}
-			if (mode == MODE_SCHANNELS) {
-				parse_generic_cmdline(argc, argp, i,
-					&gchannels_changed,
-					cmdline_channels,
-					ARRAY_SIZE(cmdline_ring));
-				i = argc;
-				break;
-			}
-			if (mode == MODE_SCOALESCE) {
-				parse_generic_cmdline(argc, argp, i,
-					&gcoalesce_changed,
-			      		cmdline_coalesce,
-			      		ARRAY_SIZE(cmdline_coalesce));
-				i = argc;
-				break;
-			}
-			if (mode == MODE_SOFFLOAD) {
-				parse_generic_cmdline(argc, argp, i,
-					&goffload_changed,
-			      		cmdline_offload,
-			      		ARRAY_SIZE(cmdline_offload));
-				i = argc;
-				break;
-			}
-			if (mode == MODE_SCLSRULE) {
-				if (!strcmp(argp[i], "flow-type")) {
-					i += 1;
-					if (i >= argc) {
-						exit_bad_args();
-						break;
-					}
-					if (rxclass_parse_ruleopts(&argp[i],
-							argc - i,
-							&rx_rule_fs) < 0) {
-						exit_bad_args();
-					} else {
-						i = argc;
-						rx_class_rule_added = 1;
-					}
-				} else if (!strcmp(argp[i], "delete")) {
-					i += 1;
-					if (i >= argc) {
-						exit_bad_args();
-						break;
-					}
-					rx_class_rule_del =
-						get_uint_range(argp[i], 0,
-							       INT_MAX);
-				} else {
-					exit_bad_args();
-				}
-				break;
-			}
-			if (mode == MODE_GCLSRULE) {
-				if (!strcmp(argp[i], "rule")) {
-					i += 1;
-					if (i >= argc) {
-						exit_bad_args();
-						break;
-					}
-					rx_class_rule_get =
-						get_uint_range(argp[i], 0,
-							       INT_MAX);
-				} else {
-					exit_bad_args();
-				}
-				break;
-			}
-			if (mode == MODE_GNFC) {
-				if (!strcmp(argp[i], "rx-flow-hash")) {
-					i += 1;
-					if (i >= argc) {
-						exit_bad_args();
-						break;
-					}
-					rx_fhash_get =
-						rxflow_str_to_type(argp[i]);
-					if (!rx_fhash_get)
-						exit_bad_args();
-				} else
-					exit_bad_args();
-				break;
-			}
-			if (mode == MODE_FLASHDEV) {
-				flash_region = strtol(argp[i], NULL, 0);
-				if ((flash_region < 0))
-					exit_bad_args();
-				break;
-			}
-			if (mode == MODE_SNFC) {
-				if (!strcmp(argp[i], "rx-flow-hash")) {
-					i += 1;
-					if (i >= argc) {
-						exit_bad_args();
-						break;
-					}
-					rx_fhash_set =
-						rxflow_str_to_type(argp[i]);
-					if (!rx_fhash_set) {
-						exit_bad_args();
-						break;
-					}
-					i += 1;
-					if (i >= argc) {
-						exit_bad_args();
-						break;
-					}
-					if (parse_rxfhashopts(argp[i],
-						&rx_fhash_val) < 0)
-						exit_bad_args();
-					else
-						rx_fhash_changed = 1;
-				} else
-					exit_bad_args();
-				break;
-			}
-			if (mode == MODE_SRXFHINDIR) {
-				if (!strcmp(argp[i], "equal")) {
-					if (argc != i + 2) {
-						exit_bad_args();
-						break;
-					}
-					i += 1;
-					rxfhindir_equal =
-						get_int_range(argp[i], 0, 1,
-							      INT_MAX);
-					i += 1;
-				} else if (!strcmp(argp[i], "weight")) {
-					i += 1;
-					if (i >= argc) {
-						exit_bad_args();
-						break;
-					}
-					rxfhindir_weight = argp + i;
-					i = argc;
-				} else {
-					exit_bad_args();
-				}
-				break;
-			}
-			if (mode == MODE_GET_DUMP) {
-				if (argc != i + 2) {
-					exit_bad_args();
-					break;
-				}
-				if (!strcmp(argp[i++], "data"))
-					dump_flag = ETHTOOL_GET_DUMP_DATA;
-				else {
-					exit_bad_args();
-					break;
-				}
-				dump_file = argp[i];
-				i = argc;
-				break;
-			}
-			if (mode != MODE_SSET)
-				exit_bad_args();
-			if (!strcmp(argp[i], "speed")) {
-				gset_changed = 1;
-				i += 1;
-				if (i >= argc)
-					exit_bad_args();
-				speed_wanted = get_int(argp[i],10);
-				break;
-			} else if (!strcmp(argp[i], "duplex")) {
-				gset_changed = 1;
-				i += 1;
-				if (i >= argc)
-					exit_bad_args();
-				if (!strcmp(argp[i], "half"))
-					duplex_wanted = DUPLEX_HALF;
-				else if (!strcmp(argp[i], "full"))
-					duplex_wanted = DUPLEX_FULL;
-				else
-					exit_bad_args();
-				break;
-			} else if (!strcmp(argp[i], "port")) {
-				gset_changed = 1;
-				i += 1;
-				if (i >= argc)
-					exit_bad_args();
-				if (!strcmp(argp[i], "tp"))
-					port_wanted = PORT_TP;
-				else if (!strcmp(argp[i], "aui"))
-					port_wanted = PORT_AUI;
-				else if (!strcmp(argp[i], "bnc"))
-					port_wanted = PORT_BNC;
-				else if (!strcmp(argp[i], "mii"))
-					port_wanted = PORT_MII;
-				else if (!strcmp(argp[i], "fibre"))
-					port_wanted = PORT_FIBRE;
-				else
-					exit_bad_args();
-				break;
-			} else if (!strcmp(argp[i], "autoneg")) {
-				i += 1;
-				if (i >= argc)
-					exit_bad_args();
-				if (!strcmp(argp[i], "on")) {
-					gset_changed = 1;
-					autoneg_wanted = AUTONEG_ENABLE;
-				} else if (!strcmp(argp[i], "off")) {
-					gset_changed = 1;
-					autoneg_wanted = AUTONEG_DISABLE;
-				} else {
-					exit_bad_args();
-				}
-				break;
-			} else if (!strcmp(argp[i], "advertise")) {
-				gset_changed = 1;
-				i += 1;
-				if (i >= argc)
-					exit_bad_args();
-				advertising_wanted = get_int(argp[i], 16);
-				break;
-			} else if (!strcmp(argp[i], "phyad")) {
-				gset_changed = 1;
-				i += 1;
-				if (i >= argc)
-					exit_bad_args();
-				phyad_wanted = get_int(argp[i], 0);
-				break;
-			} else if (!strcmp(argp[i], "xcvr")) {
-				gset_changed = 1;
-				i += 1;
-				if (i >= argc)
-					exit_bad_args();
-				if (!strcmp(argp[i], "internal"))
-					xcvr_wanted = XCVR_INTERNAL;
-				else if (!strcmp(argp[i], "external"))
-					xcvr_wanted = XCVR_EXTERNAL;
-				else
-					exit_bad_args();
-				break;
-			} else if (!strcmp(argp[i], "wol")) {
-				gwol_changed = 1;
-				i++;
-				if (i >= argc)
-					exit_bad_args();
-				if (parse_wolopts(argp[i], &wol_wanted) < 0)
-					exit_bad_args();
-				wol_change = 1;
-				break;
-			} else if (!strcmp(argp[i], "sopass")) {
-				gwol_changed = 1;
-				i++;
-				if (i >= argc)
-					exit_bad_args();
-				get_mac_addr(argp[i], sopass_wanted);
-				sopass_change = 1;
-				break;
-			} else if (!strcmp(argp[i], "msglvl")) {
-				i++;
-				if (i >= argc)
-					exit_bad_args();
-				if (isdigit((unsigned char)argp[i][0])) {
-					msglvl_changed = 1;
-					msglvl_mask = ~0;
-					msglvl_wanted =
-						get_uint_range(argp[i], 0,
-							       0xffffffff);
-				} else {
-					parse_generic_cmdline(
-						argc, argp, i,
-						&msglvl_changed,
-						cmdline_msglvl,
-						ARRAY_SIZE(cmdline_msglvl));
-					i = argc;
-				}
-				break;
-			}
-			exit_bad_args();
-		}
-	}
-
-	if (advertising_wanted < 0) {
-		if (speed_wanted == SPEED_10 && duplex_wanted == DUPLEX_HALF)
-			advertising_wanted = ADVERTISED_10baseT_Half;
-		else if (speed_wanted == SPEED_10 &&
-			 duplex_wanted == DUPLEX_FULL)
-			advertising_wanted = ADVERTISED_10baseT_Full;
-		else if (speed_wanted == SPEED_100 &&
-			 duplex_wanted == DUPLEX_HALF)
-			advertising_wanted = ADVERTISED_100baseT_Half;
-		else if (speed_wanted == SPEED_100 &&
-			 duplex_wanted == DUPLEX_FULL)
-			advertising_wanted = ADVERTISED_100baseT_Full;
-		else if (speed_wanted == SPEED_1000 &&
-			 duplex_wanted == DUPLEX_HALF)
-			advertising_wanted = ADVERTISED_1000baseT_Half;
-		else if (speed_wanted == SPEED_1000 &&
-			 duplex_wanted == DUPLEX_FULL)
-			advertising_wanted = ADVERTISED_1000baseT_Full;
-		else if (speed_wanted == SPEED_2500 &&
-			 duplex_wanted == DUPLEX_FULL)
-			advertising_wanted = ADVERTISED_2500baseX_Full;
-		else if (speed_wanted == SPEED_10000 &&
-			 duplex_wanted == DUPLEX_FULL)
-			advertising_wanted = ADVERTISED_10000baseT_Full;
-		else
-			/* auto negotiate without forcing,
-			 * all supported speed will be assigned in do_sset()
-			 */
-			advertising_wanted = 0;
-
-	}
-
-	if (devname == NULL)
-		exit_bad_args();
-	if (strlen(devname) >= IFNAMSIZ)
-		exit_bad_args();
+	fprintf(stdout,
+		PACKAGE " version " VERSION "\n");
+	return 0;
 }
 
 static void dump_link_caps(const char *prefix, const char *an_prefix, u32 mask);
@@ -1978,92 +1515,14 @@ static int dump_rxfhash(int fhash, u64 val)
 	return 0;
 }
 
-static int doit(void)
-{
-	struct cmd_context ctx;
-
-	/* Setup our control structures. */
-	memset(&ctx.ifr, 0, sizeof(ctx.ifr));
-	strcpy(ctx.ifr.ifr_name, devname);
-
-	/* Open control socket. */
-	ctx.fd = socket(AF_INET, SOCK_DGRAM, 0);
-	if (ctx.fd < 0) {
-		perror("Cannot get control socket");
-		return 70;
-	}
-
-	/* all of these are expected to populate ifr->ifr_data as needed */
-	if (mode == MODE_GDRV) {
-		return do_gdrv(&ctx);
-	} else if (mode == MODE_GSET) {
-		return do_gset(&ctx);
-	} else if (mode == MODE_SSET) {
-		return do_sset(&ctx);
-	} else if (mode == MODE_GREGS) {
-		return do_gregs(&ctx);
-	} else if (mode == MODE_NWAY_RST) {
-		return do_nway_rst(&ctx);
-	} else if (mode == MODE_GEEPROM) {
-		return do_geeprom(&ctx);
-	} else if (mode == MODE_SEEPROM) {
-		return do_seeprom(&ctx);
-	} else if (mode == MODE_TEST) {
-		return do_test(&ctx);
-	} else if (mode == MODE_PHYS_ID) {
-		return do_phys_id(&ctx);
-	} else if (mode == MODE_GPAUSE) {
-		return do_gpause(&ctx);
-	} else if (mode == MODE_SPAUSE) {
-		return do_spause(&ctx);
-	} else if (mode == MODE_GCOALESCE) {
-		return do_gcoalesce(&ctx);
-	} else if (mode == MODE_SCOALESCE) {
-		return do_scoalesce(&ctx);
-	} else if (mode == MODE_GRING) {
-		return do_gring(&ctx);
-	} else if (mode == MODE_SRING) {
-		return do_sring(&ctx);
-	} else if (mode == MODE_GCHANNELS) {
-		return do_gchannels(&ctx);
-	} else if (mode == MODE_SCHANNELS) {
-		return do_schannels(&ctx);
-	} else if (mode == MODE_GOFFLOAD) {
-		return do_goffload(&ctx);
-	} else if (mode == MODE_SOFFLOAD) {
-		return do_soffload(&ctx);
-	} else if (mode == MODE_GSTATS) {
-		return do_gstats(&ctx);
-	} else if (mode == MODE_GNFC) {
-		return do_grxclass(&ctx);
-	} else if (mode == MODE_SNFC) {
-		return do_srxclass(&ctx);
-	} else if (mode == MODE_GRXFHINDIR) {
-		return do_grxfhindir(&ctx);
-	} else if (mode == MODE_SRXFHINDIR) {
-		return do_srxfhindir(&ctx);
-	} else if (mode == MODE_SCLSRULE) {
-		return do_srxclsrule(&ctx);
-	} else if (mode == MODE_GCLSRULE) {
-		return do_grxclsrule(&ctx);
-	} else if (mode == MODE_FLASHDEV) {
-		return do_flash(&ctx);
-	} else if (mode == MODE_PERMADDR) {
-		return do_permaddr(&ctx);
-	} else if (mode == MODE_GET_DUMP) {
-		return do_getfwdump(&ctx);
-	} else if (mode == MODE_SET_DUMP) {
-		return do_setfwdump(&ctx);
-	}
-
-	return 69;
-}
-
 static int do_gdrv(struct cmd_context *ctx)
 {
 	int err;
 	struct ethtool_drvinfo drvinfo;
 
+	if (ctx->argc != 0)
+		exit_bad_args();
+
 	drvinfo.cmd = ETHTOOL_GDRVINFO;
 	err = send_ioctl(ctx, &drvinfo);
 	if (err < 0) {
@@ -2078,6 +1537,9 @@ static int do_gpause(struct cmd_context *ctx)
 	struct ethtool_cmd ecmd;
 	int err;
 
+	if (ctx->argc != 0)
+		exit_bad_args();
+
 	fprintf(stdout, "Pause parameters for %s:\n", devname);
 
 	epause.cmd = ETHTOOL_GPAUSEPARAM;
@@ -2135,6 +1597,9 @@ static int do_spause(struct cmd_context *ctx)
 {
 	int err, changed = 0;
 
+	parse_generic_cmdline(ctx, &gpause_changed,
+			      cmdline_pause, ARRAY_SIZE(cmdline_pause));
+
 	epause.cmd = ETHTOOL_GPAUSEPARAM;
 	err = send_ioctl(ctx, &epause);
 	if (err) {
@@ -2163,6 +1628,9 @@ static int do_sring(struct cmd_context *ctx)
 {
 	int err, changed = 0;
 
+	parse_generic_cmdline(ctx, &gring_changed,
+			      cmdline_ring, ARRAY_SIZE(cmdline_ring));
+
 	ering.cmd = ETHTOOL_GRINGPARAM;
 	err = send_ioctl(ctx, &ering);
 	if (err) {
@@ -2191,6 +1659,9 @@ static int do_gring(struct cmd_context *ctx)
 {
 	int err;
 
+	if (ctx->argc != 0)
+		exit_bad_args();
+
 	fprintf(stdout, "Ring parameters for %s:\n", devname);
 
 	ering.cmd = ETHTOOL_GRINGPARAM;
@@ -2211,6 +1682,9 @@ static int do_schannels(struct cmd_context *ctx)
 {
 	int err, changed = 0;
 
+	parse_generic_cmdline(ctx, &gchannels_changed,
+			      cmdline_channels, ARRAY_SIZE(cmdline_ring));
+
 	echannels.cmd = ETHTOOL_GCHANNELS;
 	err = send_ioctl(ctx, &echannels);
 	if (err) {
@@ -2244,6 +1718,9 @@ static int do_gchannels(struct cmd_context *ctx)
 {
 	int err;
 
+	if (ctx->argc != 0)
+		exit_bad_args();
+
 	fprintf(stdout, "Channel parameters for %s:\n", devname);
 
 	echannels.cmd = ETHTOOL_GCHANNELS;
@@ -2264,6 +1741,9 @@ static int do_gcoalesce(struct cmd_context *ctx)
 {
 	int err;
 
+	if (ctx->argc != 0)
+		exit_bad_args();
+
 	fprintf(stdout, "Coalesce parameters for %s:\n", devname);
 
 	ecoal.cmd = ETHTOOL_GCOALESCE;
@@ -2284,6 +1764,9 @@ static int do_scoalesce(struct cmd_context *ctx)
 {
 	int err, changed = 0;
 
+	parse_generic_cmdline(ctx, &gcoalesce_changed,
+			      cmdline_coalesce, ARRAY_SIZE(cmdline_coalesce));
+
 	ecoal.cmd = ETHTOOL_GCOALESCE;
 	err = send_ioctl(ctx, &ecoal);
 	if (err) {
@@ -2316,6 +1799,9 @@ static int do_goffload(struct cmd_context *ctx)
 	int tso = 0, ufo = 0, gso = 0, gro = 0, lro = 0, rxvlan = 0, txvlan = 0,
 	    ntuple = 0, rxhash = 0;
 
+	if (ctx->argc != 0)
+		exit_bad_args();
+
 	fprintf(stdout, "Offload parameters for %s:\n", devname);
 
 	eval.cmd = ETHTOOL_GRXCSUM;
@@ -2408,6 +1894,9 @@ static int do_soffload(struct cmd_context *ctx)
 	struct ethtool_value eval;
 	int err, changed = 0;
 
+	parse_generic_cmdline(ctx, &goffload_changed,
+			      cmdline_offload, ARRAY_SIZE(cmdline_offload));
+
 	if (off_csum_rx_wanted >= 0) {
 		changed = 1;
 		eval.cmd = ETHTOOL_SRXCSUM;
@@ -2517,6 +2006,9 @@ static int do_gset(struct cmd_context *ctx)
 	struct ethtool_value edata;
 	int allfail = 1;
 
+	if (ctx->argc != 0)
+		exit_bad_args();
+
 	fprintf(stdout, "Settings for %s:\n", devname);
 
 	ecmd.cmd = ETHTOOL_GSET;
@@ -2574,8 +2066,152 @@ static int do_gset(struct cmd_context *ctx)
 
 static int do_sset(struct cmd_context *ctx)
 {
+	int argc = ctx->argc;
+	char **argp = ctx->argp;
+	int i;
 	int err;
 
+	for (i = 0; i < argc; i++) {
+		if (!strcmp(argp[i], "speed")) {
+			gset_changed = 1;
+			i += 1;
+			if (i >= argc)
+				exit_bad_args();
+			speed_wanted = get_int(argp[i],10);
+		} else if (!strcmp(argp[i], "duplex")) {
+			gset_changed = 1;
+			i += 1;
+			if (i >= argc)
+				exit_bad_args();
+			if (!strcmp(argp[i], "half"))
+				duplex_wanted = DUPLEX_HALF;
+			else if (!strcmp(argp[i], "full"))
+				duplex_wanted = DUPLEX_FULL;
+			else
+				exit_bad_args();
+		} else if (!strcmp(argp[i], "port")) {
+			gset_changed = 1;
+			i += 1;
+			if (i >= argc)
+				exit_bad_args();
+			if (!strcmp(argp[i], "tp"))
+				port_wanted = PORT_TP;
+			else if (!strcmp(argp[i], "aui"))
+				port_wanted = PORT_AUI;
+			else if (!strcmp(argp[i], "bnc"))
+				port_wanted = PORT_BNC;
+			else if (!strcmp(argp[i], "mii"))
+				port_wanted = PORT_MII;
+			else if (!strcmp(argp[i], "fibre"))
+				port_wanted = PORT_FIBRE;
+			else
+				exit_bad_args();
+		} else if (!strcmp(argp[i], "autoneg")) {
+			i += 1;
+			if (i >= argc)
+				exit_bad_args();
+			if (!strcmp(argp[i], "on")) {
+				gset_changed = 1;
+				autoneg_wanted = AUTONEG_ENABLE;
+			} else if (!strcmp(argp[i], "off")) {
+				gset_changed = 1;
+				autoneg_wanted = AUTONEG_DISABLE;
+			} else {
+				exit_bad_args();
+			}
+		} else if (!strcmp(argp[i], "advertise")) {
+			gset_changed = 1;
+			i += 1;
+			if (i >= argc)
+				exit_bad_args();
+			advertising_wanted = get_int(argp[i], 16);
+		} else if (!strcmp(argp[i], "phyad")) {
+			gset_changed = 1;
+			i += 1;
+			if (i >= argc)
+				exit_bad_args();
+			phyad_wanted = get_int(argp[i], 0);
+		} else if (!strcmp(argp[i], "xcvr")) {
+			gset_changed = 1;
+			i += 1;
+			if (i >= argc)
+				exit_bad_args();
+			if (!strcmp(argp[i], "internal"))
+				xcvr_wanted = XCVR_INTERNAL;
+			else if (!strcmp(argp[i], "external"))
+				xcvr_wanted = XCVR_EXTERNAL;
+			else
+				exit_bad_args();
+		} else if (!strcmp(argp[i], "wol")) {
+			gwol_changed = 1;
+			i++;
+			if (i >= argc)
+				exit_bad_args();
+			if (parse_wolopts(argp[i], &wol_wanted) < 0)
+				exit_bad_args();
+			wol_change = 1;
+		} else if (!strcmp(argp[i], "sopass")) {
+			gwol_changed = 1;
+			i++;
+			if (i >= argc)
+				exit_bad_args();
+			get_mac_addr(argp[i], sopass_wanted);
+			sopass_change = 1;
+		} else if (!strcmp(argp[i], "msglvl")) {
+			i++;
+			if (i >= argc)
+				exit_bad_args();
+			if (isdigit((unsigned char)argp[i][0])) {
+				msglvl_changed = 1;
+				msglvl_mask = ~0;
+				msglvl_wanted =
+					get_uint_range(argp[i], 0,
+						       0xffffffff);
+			} else {
+				ctx->argc -= i;
+				ctx->argp += i;
+				parse_generic_cmdline(
+					ctx, &msglvl_changed,
+					cmdline_msglvl,
+					ARRAY_SIZE(cmdline_msglvl));
+				break;
+			}
+		} else {
+			exit_bad_args();
+		}
+	}
+
+	if (advertising_wanted < 0) {
+		if (speed_wanted == SPEED_10 && duplex_wanted == DUPLEX_HALF)
+			advertising_wanted = ADVERTISED_10baseT_Half;
+		else if (speed_wanted == SPEED_10 &&
+			 duplex_wanted == DUPLEX_FULL)
+			advertising_wanted = ADVERTISED_10baseT_Full;
+		else if (speed_wanted == SPEED_100 &&
+			 duplex_wanted == DUPLEX_HALF)
+			advertising_wanted = ADVERTISED_100baseT_Half;
+		else if (speed_wanted == SPEED_100 &&
+			 duplex_wanted == DUPLEX_FULL)
+			advertising_wanted = ADVERTISED_100baseT_Full;
+		else if (speed_wanted == SPEED_1000 &&
+			 duplex_wanted == DUPLEX_HALF)
+			advertising_wanted = ADVERTISED_1000baseT_Half;
+		else if (speed_wanted == SPEED_1000 &&
+			 duplex_wanted == DUPLEX_FULL)
+			advertising_wanted = ADVERTISED_1000baseT_Full;
+		else if (speed_wanted == SPEED_2500 &&
+			 duplex_wanted == DUPLEX_FULL)
+			advertising_wanted = ADVERTISED_2500baseX_Full;
+		else if (speed_wanted == SPEED_10000 &&
+			 duplex_wanted == DUPLEX_FULL)
+			advertising_wanted = ADVERTISED_10000baseT_Full;
+		else
+			/* auto negotiate without forcing,
+			 * all supported speed will be assigned below
+			 */
+			advertising_wanted = 0;
+	}
+
 	if (gset_changed) {
 		struct ethtool_cmd ecmd;
 
@@ -2712,6 +2348,9 @@ static int do_gregs(struct cmd_context *ctx)
 	struct ethtool_drvinfo drvinfo;
 	struct ethtool_regs *regs;
 
+	parse_generic_cmdline(ctx, &gregs_changed,
+			      cmdline_gregs, ARRAY_SIZE(cmdline_gregs));
+
 	drvinfo.cmd = ETHTOOL_GDRVINFO;
 	err = send_ioctl(ctx, &drvinfo);
 	if (err < 0) {
@@ -2747,6 +2386,9 @@ static int do_nway_rst(struct cmd_context *ctx)
 	struct ethtool_value edata;
 	int err;
 
+	if (ctx->argc != 0)
+		exit_bad_args();
+
 	edata.cmd = ETHTOOL_NWAY_RST;
 	err = send_ioctl(ctx, &edata);
 	if (err < 0)
@@ -2761,6 +2403,9 @@ static int do_geeprom(struct cmd_context *ctx)
 	struct ethtool_drvinfo drvinfo;
 	struct ethtool_eeprom *eeprom;
 
+	parse_generic_cmdline(ctx, &geeprom_changed,
+			      cmdline_geeprom, ARRAY_SIZE(cmdline_geeprom));
+
 	drvinfo.cmd = ETHTOOL_GDRVINFO;
 	err = send_ioctl(ctx, &drvinfo);
 	if (err < 0) {
@@ -2800,6 +2445,9 @@ static int do_seeprom(struct cmd_context *ctx)
 	struct ethtool_drvinfo drvinfo;
 	struct ethtool_eeprom *eeprom;
 
+	parse_generic_cmdline(ctx, &seeprom_changed,
+			      cmdline_seeprom, ARRAY_SIZE(cmdline_seeprom));
+
 	drvinfo.cmd = ETHTOOL_GDRVINFO;
 	err = send_ioctl(ctx, &drvinfo);
 	if (err < 0) {
@@ -2849,6 +2497,20 @@ static int do_test(struct cmd_context *ctx)
 	struct ethtool_test *test;
 	struct ethtool_gstrings *strings;
 
+	if (ctx->argc > 1)
+		exit_bad_args();
+	if (ctx->argc == 1) {
+		if (!strcmp(ctx->argp[0], "online")) {
+			test_type = ONLINE;
+	 	} else if (!strcmp(*ctx->argp, "offline")) {
+			test_type = OFFLINE;
+		} else if (!strcmp(*ctx->argp, "external_lb")) {
+			test_type = EXTERNAL_LB;
+		} else {
+			exit_bad_args();
+		}
+	}
+
 	drvinfo.cmd = ETHTOOL_GDRVINFO;
 	err = send_ioctl(ctx, &drvinfo);
 	if (err < 0) {
@@ -2907,6 +2569,11 @@ static int do_phys_id(struct cmd_context *ctx)
 	int err;
 	struct ethtool_value edata;
 
+	if (ctx->argc > 1)
+		exit_bad_args();
+	if (ctx->argc == 1)
+		phys_id_time = get_int(*ctx->argp, 0);
+
 	edata.cmd = ETHTOOL_PHYS_ID;
 	edata.data = phys_id_time;
 	err = send_ioctl(ctx, &edata);
@@ -2924,6 +2591,9 @@ static int do_gstats(struct cmd_context *ctx)
 	unsigned int n_stats, sz_str, sz_stats, i;
 	int err;
 
+	if (ctx->argc != 0)
+		exit_bad_args();
+
 	drvinfo.cmd = ETHTOOL_GDRVINFO;
 	err = send_ioctl(ctx, &drvinfo);
 	if (err < 0) {
@@ -2985,10 +2655,15 @@ static int do_gstats(struct cmd_context *ctx)
 
 static int do_srxclass(struct cmd_context *ctx)
 {
+	struct ethtool_rxnfc nfccmd;
 	int err;
 
-	if (rx_fhash_changed) {
-		struct ethtool_rxnfc nfccmd;
+	if (ctx->argc == 3 && !strcmp(ctx->argp[0], "rx-flow-hash")) {
+		rx_fhash_set = rxflow_str_to_type(ctx->argp[1]);
+		if (!rx_fhash_set)
+			exit_bad_args();
+		if (parse_rxfhashopts(ctx->argp[2], &rx_fhash_val) < 0)
+			exit_bad_args();
 
 		nfccmd.cmd = ETHTOOL_SRXFH;
 		nfccmd.flow_type = rx_fhash_set;
@@ -2997,7 +2672,8 @@ static int do_srxclass(struct cmd_context *ctx)
 		err = send_ioctl(ctx, &nfccmd);
 		if (err < 0)
 			perror("Cannot change RX network flow hashing options");
-
+	} else {
+		exit_bad_args();
 	}
 
 	return 0;
@@ -3005,10 +2681,13 @@ static int do_srxclass(struct cmd_context *ctx)
 
 static int do_grxclass(struct cmd_context *ctx)
 {
+	struct ethtool_rxnfc nfccmd;
 	int err;
 
-	if (rx_fhash_get) {
-		struct ethtool_rxnfc nfccmd;
+	if (ctx->argc == 2 && !strcmp(ctx->argp[0], "rx-flow-hash")) {
+		rx_fhash_get = rxflow_str_to_type(ctx->argp[1]);
+		if (!rx_fhash_get)
+			exit_bad_args();
 
 		nfccmd.cmd = ETHTOOL_GRXFH;
 		nfccmd.flow_type = rx_fhash_get;
@@ -3017,6 +2696,8 @@ static int do_grxclass(struct cmd_context *ctx)
 			perror("Cannot get RX network flow hashing options");
 		else
 			dump_rxfhash(rx_fhash_get, nfccmd.data);
+	} else {
+		exit_bad_args();
 	}
 
 	return 0;
@@ -3074,8 +2755,17 @@ static int do_srxfhindir(struct cmd_context *ctx)
 	u32 i;
 	int err;
 
-	if (!rxfhindir_equal && !rxfhindir_weight)
+	if (ctx->argc < 2)
+		exit_bad_args();
+	if (!strcmp(ctx->argp[0], "equal")) {
+		if (ctx->argc != 2)
+			exit_bad_args();
+		rxfhindir_equal = get_int_range(ctx->argp[1], 0, 1, INT_MAX);
+	} else if (!strcmp(ctx->argp[0], "weight")) {
+		rxfhindir_weight = ctx->argp + 1;
+	} else {
 		exit_bad_args();
+	}
 
 	indir_head.cmd = ETHTOOL_GRXFHINDIR;
 	indir_head.size = 0;
@@ -3139,10 +2829,13 @@ static int do_flash(struct cmd_context *ctx)
 	struct ethtool_flash efl;
 	int err;
 
-	if (flash < 0) {
-		fprintf(stdout, "Missing filename argument\n");
+	if (ctx->argc < 1 || ctx->argc > 2)
 		exit_bad_args();
-		return 98;
+	flash_file = ctx->argp[0];
+	if (ctx->argc == 2) {
+		flash_region = strtol(ctx->argp[1], NULL, 0);
+		if (flash_region < 0)
+			exit_bad_args();
 	}
 
 	if (strlen(flash_file) > ETHTOOL_FLASH_MAX_FILENAME - 1) {
@@ -3309,7 +3002,15 @@ static int do_srxclsrule(struct cmd_context *ctx)
 {
 	int err;
 
-	if (rx_class_rule_added) {
+	if (ctx->argc < 2)
+		exit_bad_args();
+
+	if (!strcmp(ctx->argp[0], "flow-type")) {
+		ctx->argc--;
+		ctx->argp++;
+		if (rxclass_parse_ruleopts(ctx, &rx_rule_fs) < 0)
+			exit_bad_args();
+
 		/* attempt to add rule via N-tuple specifier */
 		err = do_srxntuple(ctx);
 		if (!err)
@@ -3322,7 +3023,9 @@ static int do_srxclsrule(struct cmd_context *ctx)
 				" classification rule\n");
 			return 1;
 		}
-	} else if (rx_class_rule_del >= 0) {
+	} else if (!strcmp(ctx->argp[0], "delete")) {
+		rx_class_rule_del = get_uint_range(ctx->argp[1], 0, INT_MAX);
+
 		err = rxclass_rule_del(ctx, rx_class_rule_del);
 
 		if (err < 0) {
@@ -3342,13 +3045,18 @@ static int do_grxclsrule(struct cmd_context *ctx)
 	struct ethtool_rxnfc nfccmd;
 	int err;
 
-	if (rx_class_rule_get >= 0) {
+	if (ctx->argc == 2 && !strcmp(ctx->argp[0], "rule")) {
+		rx_class_rule_get = get_uint_range(ctx->argp[1], 0, INT_MAX);
+
 		err = rxclass_rule_get(ctx, rx_class_rule_get);
 		if (err < 0)
 			fprintf(stderr, "Cannot get RX classification rule\n");
 		return err ? 1 : 0;
 	}
 
+	if (ctx->argc != 0)
+		exit_bad_args();
+
 	nfccmd.cmd = ETHTOOL_GRXRINGS;
 	err = send_ioctl(ctx, &nfccmd);
 	if (err < 0)
@@ -3396,6 +3104,13 @@ static int do_getfwdump(struct cmd_context *ctx)
 	struct ethtool_dump edata;
 	struct ethtool_dump *data;
 
+	if (ctx->argc == 2 && !strcmp(ctx->argp[0], "data")) {
+		dump_flag = ETHTOOL_GET_DUMP_DATA;
+		dump_file = ctx->argp[1];
+	} else if (ctx->argc != 0) {
+		exit_bad_args();
+	}
+
 	edata.cmd = ETHTOOL_GET_DUMP_FLAG;
 
 	err = send_ioctl(ctx, &edata);
@@ -3432,6 +3147,10 @@ static int do_setfwdump(struct cmd_context *ctx)
 	int err;
 	struct ethtool_dump dump;
 
+	if (ctx->argc != 1)
+		exit_bad_args();
+	dump_flag = get_u32(ctx->argp[0], 0);
+
 	dump.cmd = ETHTOOL_SET_DUMP;
 	dump.flag = dump_flag;
 	err = send_ioctl(ctx, &dump);
@@ -3455,6 +3174,63 @@ int send_ioctl(struct cmd_context *ctx, void *cmd)
 
 int main(int argc, char **argp, char **envp)
 {
-	parse_cmdline(argc, argp);
-	return doit();
+	int (*func)(struct cmd_context *) = NULL;
+	int want_device = 0;
+	struct cmd_context ctx;
+	int k;
+
+	/* Skip command name */
+	argp++;
+	argc--;
+
+	/* First argument must be either a valid option or a device
+	 * name to get settings for (which we don't expect to begin
+	 * with '-').
+	 */
+	if (argc == 0)
+		exit_bad_args();
+	for (k = 0; args[k].lng; k++) {
+		if ((args[k].srt && !strcmp(*argp, args[k].srt)) ||
+		    !strcmp(*argp, args[k].lng)) {
+			argp++;
+			argc--;
+			func = args[k].func;
+			want_device = args[k].want_device;
+			break;
+		}
+	}
+	if (!func) {
+		if ((*argp)[0] == '-')
+			exit_bad_args();
+		func = do_gset;
+		want_device = 1;
+	}
+
+	if (want_device) {
+		devname = *argp++;
+		argc--;
+
+		if (devname == NULL)
+			exit_bad_args();
+		if (strlen(devname) >= IFNAMSIZ)
+			exit_bad_args();
+
+		/* Setup our control structures. */
+		memset(&ctx.ifr, 0, sizeof(ctx.ifr));
+		strcpy(ctx.ifr.ifr_name, devname);
+
+		/* Open control socket. */
+		ctx.fd = socket(AF_INET, SOCK_DGRAM, 0);
+		if (ctx.fd < 0) {
+			perror("Cannot get control socket");
+			return 70;
+		}
+	} else {
+		ctx.fd = -1;
+	}
+
+	ctx.argc = argc;
+	ctx.argp = argp;
+
+	return func(&ctx);
 }
diff --git a/internal.h b/internal.h
index ba7d719..eb13db8 100644
--- a/internal.h
+++ b/internal.h
@@ -92,6 +92,8 @@ static inline int test_bit(unsigned int nr, const unsigned long *addr)
 struct cmd_context {
 	int fd;			/* socket suitable for ethtool ioctl */
 	struct ifreq ifr;	/* ifreq suitable for ethtool ioctl */
+	int argc;		/* number of arguments to the sub-command */
+	char **argp;		/* arguments to the sub-command */
 };
 
 #ifdef TEST_ETHTOOL
@@ -165,7 +167,7 @@ int st_mac100_dump_regs(struct ethtool_drvinfo *info,
 int st_gmac_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
 
 /* Rx flow classification */
-int rxclass_parse_ruleopts(char **optstr, int opt_cnt,
+int rxclass_parse_ruleopts(struct cmd_context *ctx,
 			   struct ethtool_rx_flow_spec *fsp);
 int rxclass_rule_getall(struct cmd_context *ctx);
 int rxclass_rule_get(struct cmd_context *ctx, __u32 loc);
diff --git a/rxclass.c b/rxclass.c
index dec9dd5..0c7b916 100644
--- a/rxclass.c
+++ b/rxclass.c
@@ -950,7 +950,7 @@ static int rxclass_get_mask(char *str, unsigned char *p,
 	return 0;
 }
 
-int rxclass_parse_ruleopts(char **argp, int argc,
+int rxclass_parse_ruleopts(struct cmd_context *ctx,
 			   struct ethtool_rx_flow_spec *fsp)
 {
 	const struct rule_opts *options;
@@ -958,6 +958,8 @@ int rxclass_parse_ruleopts(char **argp, int argc,
 	int i = 0, n_opts, err;
 	u32 flags = 0;
 	int flow_type;
+	int argc = ctx->argc;
+	char **argp = ctx->argp;
 
 	if (argc < 1)
 		goto syntax_err;
-- 
1.7.4.4



-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH ethtool 13/21] Support arbitrary numbers of option names for each mode
  2011-11-01 22:35 [PATCH ethtool 00/21] ethtool refactoring and misc changes Ben Hutchings
                   ` (11 preceding siblings ...)
  2011-11-01 23:18 ` [PATCH ethtool 12/21] Move argument parsing to sub-command functions Ben Hutchings
@ 2011-11-01 23:18 ` Ben Hutchings
  2011-11-01 23:18 ` [PATCH ethtool 14/21] Fix reference to cmdline_ring in do_schannels() Ben Hutchings
                   ` (8 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Ben Hutchings @ 2011-11-01 23:18 UTC (permalink / raw)
  To: netdev; +Cc: linux-net-drivers

Instead of supporting a single short and long option for each
mode, take a string of options separated by "|" (matching the
way they are displayed in online help).

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 ethtool.c |  110 ++++++++++++++++++++++++++++++++-----------------------------
 1 files changed, 58 insertions(+), 52 deletions(-)

diff --git a/ethtool.c b/ethtool.c
index 4eff916..9d416e1 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -105,13 +105,13 @@ static int do_getfwdump(struct cmd_context *ctx);
 static int do_setfwdump(struct cmd_context *ctx);
 
 static struct option {
-	char *srt, *lng;
+	const char *opts;
 	int want_device;
 	int (*func)(struct cmd_context *);
 	char *help;
 	char *opthelp;
 } args[] = {
-	{ "-s", "--change", 1, do_sset, "Change generic options",
+	{ "-s|--change", 1, do_sset, "Change generic options",
 	  "		[ speed %d ]\n"
 	  "		[ duplex half|full ]\n"
 	  "		[ port tp|aui|bnc|mii|fibre ]\n"
@@ -122,13 +122,13 @@ static struct option {
 	  "		[ wol p|u|m|b|a|g|s|d... ]\n"
 	  "		[ sopass %x:%x:%x:%x:%x:%x ]\n"
 	  "		[ msglvl %d | msglvl type on|off ... ]\n" },
-	{ "-a", "--show-pause", 1, do_gpause, "Show pause options" },
-	{ "-A", "--pause", 1, do_spause, "Set pause options",
+	{ "-a|--show-pause", 1, do_gpause, "Show pause options" },
+	{ "-A|--pause", 1, do_spause, "Set pause options",
 	  "		[ autoneg on|off ]\n"
 	  "		[ rx on|off ]\n"
 	  "		[ tx on|off ]\n" },
-	{ "-c", "--show-coalesce", 1, do_gcoalesce, "Show coalesce options" },
-	{ "-C", "--coalesce", 1, do_scoalesce, "Set coalesce options",
+	{ "-c|--show-coalesce", 1, do_gcoalesce, "Show coalesce options" },
+	{ "-C|--coalesce", 1, do_scoalesce, "Set coalesce options",
 	  "		[adaptive-rx on|off]\n"
 	  "		[adaptive-tx on|off]\n"
 	  "		[rx-usecs N]\n"
@@ -151,15 +151,15 @@ static struct option {
 	  "		[tx-usecs-high N]\n"
 	  "		[tx-frames-high N]\n"
 	  "		[sample-interval N]\n" },
-	{ "-g", "--show-ring", 1, do_gring, "Query RX/TX ring parameters" },
-	{ "-G", "--set-ring", 1, do_sring, "Set RX/TX ring parameters",
+	{ "-g|--show-ring", 1, do_gring, "Query RX/TX ring parameters" },
+	{ "-G|--set-ring", 1, do_sring, "Set RX/TX ring parameters",
 	  "		[ rx N ]\n"
 	  "		[ rx-mini N ]\n"
 	  "		[ rx-jumbo N ]\n"
 	  "		[ tx N ]\n" },
-	{ "-k", "--show-offload", 1, do_goffload,
+	{ "-k|--show-offload", 1, do_goffload,
 	  "Get protocol offload information" },
-	{ "-K", "--offload", 1, do_soffload, "Set protocol offload",
+	{ "-K|--offload", 1, do_soffload, "Set protocol offload",
 	  "		[ rx on|off ]\n"
 	  "		[ tx on|off ]\n"
 	  "		[ sg on|off ]\n"
@@ -173,44 +173,44 @@ static struct option {
 	  "		[ ntuple on|off ]\n"
 	  "		[ rxhash on|off ]\n"
 	},
-	{ "-i", "--driver", 1, do_gdrv, "Show driver information" },
-	{ "-d", "--register-dump", 1, do_gregs, "Do a register dump",
+	{ "-i|--driver", 1, do_gdrv, "Show driver information" },
+	{ "-d|--register-dump", 1, do_gregs, "Do a register dump",
 	  "		[ raw on|off ]\n"
 	  "		[ file FILENAME ]\n" },
-	{ "-e", "--eeprom-dump", 1, do_geeprom, "Do a EEPROM dump",
+	{ "-e|--eeprom-dump", 1, do_geeprom, "Do a EEPROM dump",
 	  "		[ raw on|off ]\n"
 	  "		[ offset N ]\n"
 	  "		[ length N ]\n" },
-	{ "-E", "--change-eeprom", 1, do_seeprom,
+	{ "-E|--change-eeprom", 1, do_seeprom,
 	  "Change bytes in device EEPROM",
 	  "		[ magic N ]\n"
 	  "		[ offset N ]\n"
 	  "		[ length N ]\n"
 	  "		[ value N ]\n" },
-	{ "-r", "--negotiate", 1, do_nway_rst, "Restart N-WAY negotiation" },
-	{ "-p", "--identify", 1, do_phys_id,
+	{ "-r|--negotiate", 1, do_nway_rst, "Restart N-WAY negotiation" },
+	{ "-p|--identify", 1, do_phys_id,
 	  "Show visible port identification (e.g. blinking)",
 	  "               [ TIME-IN-SECONDS ]\n" },
-	{ "-t", "--test", 1, do_test, "Execute adapter self test",
+	{ "-t|--test", 1, do_test, "Execute adapter self test",
 	  "               [ online | offline | external_lb ]\n" },
-	{ "-S", "--statistics", 1, do_gstats, "Show adapter statistics" },
-	{ "-n", "--show-nfc", 1, do_grxclass,
+	{ "-S|--statistics", 1, do_gstats, "Show adapter statistics" },
+	{ "-n|--show-nfc", 1, do_grxclass,
 	  "Show Rx network flow classification options",
 	  "		[ rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
 	  "tcp6|udp6|ah6|esp6|sctp6 ]\n" },
-	{ "-f", "--flash", 1, do_flash,
+	{ "-f|--flash", 1, do_flash,
 	  "Flash firmware image from the specified file to a region on the device",
 	  "               FILENAME [ REGION-NUMBER-TO-FLASH ]\n" },
-	{ "-N", "--config-nfc", 1, do_srxclass,
+	{ "-N|--config-nfc", 1, do_srxclass,
 	  "Configure Rx network flow classification options",
 	  "		[ rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
 	  "tcp6|udp6|ah6|esp6|sctp6 m|v|t|s|d|f|n|r... ]\n" },
-	{ "-x", "--show-rxfh-indir", 1, do_grxfhindir,
+	{ "-x|--show-rxfh-indir", 1, do_grxfhindir,
 	  "Show Rx flow hash indirection" },
-	{ "-X", "--set-rxfh-indir", 1, do_srxfhindir,
+	{ "-X|--set-rxfh-indir", 1, do_srxfhindir,
 	  "Set Rx flow hash indirection",
 	  "		equal N | weight W0 W1 ...\n" },
-	{ "-U", "--config-ntuple", 1, do_srxclsrule,
+	{ "-U|--config-ntuple", 1, do_srxclsrule,
 	  "Configure Rx ntuple filters and actions",
 	  "		[ delete %d ] |\n"
 	  "		[ flow-type ether|ip4|tcp4|udp4|sctp4|ah4|esp4\n"
@@ -229,25 +229,25 @@ static struct option {
 	  "			[ user-def %x [m %x] ]\n"
 	  "			[ action %d ]\n"
 	  "			[ loc %d]]\n" },
-	{ "-u", "--show-ntuple", 1, do_grxclsrule,
+	{ "-u|--show-ntuple", 1, do_grxclsrule,
 	  "Get Rx ntuple filters and actions",
 	  "		[ rule %d ]\n"},
-	{ "-P", "--show-permaddr", 1, do_permaddr,
+	{ "-P|--show-permaddr", 1, do_permaddr,
 	  "Show permanent hardware address" },
-	{ "-w", "--get-dump", 1, do_getfwdump,
+	{ "-w|--get-dump", 1, do_getfwdump,
 	  "Get dump flag, data",
 	  "		[ data FILENAME ]\n" },
-	{ "-W", "--set-dump", 1, do_setfwdump,
+	{ "-W|--set-dump", 1, do_setfwdump,
 	  "Set dump flag of the device",
 	  "		N\n"},
-	{ "-l", "--show-channels", 1, do_gchannels, "Query Channels" },
-	{ "-L", "--set-channels", 1, do_schannels, "Set Channels",
+	{ "-l|--show-channels", 1, do_gchannels, "Query Channels" },
+	{ "-L|--set-channels", 1, do_schannels, "Set Channels",
 	  "               [ rx N ]\n"
 	  "               [ tx N ]\n"
 	  "               [ other N ]\n"
 	  "               [ combined N ]\n" },
-	{ "-h", "--help", 0, show_usage, "Show this help" },
-	{ NULL, "--version", 0, do_version, "Show version number" },
+	{ "-h|--help", 0, show_usage, "Show this help" },
+	{ "--version", 0, do_version, "Show version number" },
 	{}
 };
 
@@ -272,12 +272,10 @@ static int show_usage(struct cmd_context *ctx)
 		"Usage:\n"
 		"        ethtool DEVNAME\t"
 		"Display standard information about device\n");
-	for (i = 0; args[i].lng; i++) {
+	for (i = 0; args[i].opts; i++) {
 		fputs("        ethtool ", stdout);
-		if (args[i].srt)
-			fprintf(stdout, "%s|", args[i].srt);
 		fprintf(stdout, "%s %s\t%s\n",
-			args[i].lng,
+			args[i].opts,
 			args[i].want_device ? "DEVNAME" : "\t",
 			args[i].help);
 		if (args[i].opthelp)
@@ -3174,8 +3172,8 @@ int send_ioctl(struct cmd_context *ctx, void *cmd)
 
 int main(int argc, char **argp, char **envp)
 {
-	int (*func)(struct cmd_context *) = NULL;
-	int want_device = 0;
+	int (*func)(struct cmd_context *);
+	int want_device;
 	struct cmd_context ctx;
 	int k;
 
@@ -3189,23 +3187,31 @@ int main(int argc, char **argp, char **envp)
 	 */
 	if (argc == 0)
 		exit_bad_args();
-	for (k = 0; args[k].lng; k++) {
-		if ((args[k].srt && !strcmp(*argp, args[k].srt)) ||
-		    !strcmp(*argp, args[k].lng)) {
-			argp++;
-			argc--;
-			func = args[k].func;
-			want_device = args[k].want_device;
-			break;
+	for (k = 0; args[k].opts; k++) {
+		const char *opt;
+		size_t len;
+		opt = args[k].opts;
+		for (;;) {
+			len = strcspn(opt, "|");
+			if (strncmp(*argp, opt, len) == 0 &&
+			    (*argp)[len] == 0) {
+				argp++;
+				argc--;
+				func = args[k].func;
+				want_device = args[k].want_device;
+				goto opt_found;
+			}
+			if (opt[len] == 0)
+				break;
+			opt += len + 1;
 		}
 	}
-	if (!func) {
-		if ((*argp)[0] == '-')
-			exit_bad_args();
-		func = do_gset;
-		want_device = 1;
-	}
+	if ((*argp)[0] == '-')
+		exit_bad_args();
+	func = do_gset;
+	want_device = 1;
 
+opt_found:
 	if (want_device) {
 		devname = *argp++;
 		argc--;
-- 
1.7.4.4



-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH ethtool 14/21] Fix reference to cmdline_ring in do_schannels()
  2011-11-01 22:35 [PATCH ethtool 00/21] ethtool refactoring and misc changes Ben Hutchings
                   ` (12 preceding siblings ...)
  2011-11-01 23:18 ` [PATCH ethtool 13/21] Support arbitrary numbers of option names for each mode Ben Hutchings
@ 2011-11-01 23:18 ` Ben Hutchings
  2011-11-01 23:19 ` [PATCH ethtool 15/21] Convert cmdline_msglvl into array of named flags; convert back at run-time Ben Hutchings
                   ` (7 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Ben Hutchings @ 2011-11-01 23:18 UTC (permalink / raw)
  To: netdev; +Cc: linux-net-drivers

cmdline_ring and cmdline_channels have the same array size, so this
just happened to work.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 ethtool.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/ethtool.c b/ethtool.c
index 9d416e1..7bdf173 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -1681,7 +1681,7 @@ static int do_schannels(struct cmd_context *ctx)
 	int err, changed = 0;
 
 	parse_generic_cmdline(ctx, &gchannels_changed,
-			      cmdline_channels, ARRAY_SIZE(cmdline_ring));
+			      cmdline_channels, ARRAY_SIZE(cmdline_channels));
 
 	echannels.cmd = ETHTOOL_GCHANNELS;
 	err = send_ioctl(ctx, &echannels);
-- 
1.7.4.4



-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH ethtool 15/21] Convert cmdline_msglvl into array of named flags; convert back at run-time
  2011-11-01 22:35 [PATCH ethtool 00/21] ethtool refactoring and misc changes Ben Hutchings
                   ` (13 preceding siblings ...)
  2011-11-01 23:18 ` [PATCH ethtool 14/21] Fix reference to cmdline_ring in do_schannels() Ben Hutchings
@ 2011-11-01 23:19 ` Ben Hutchings
  2011-11-01 23:20 ` [PATCH ethtool 16/21] Replace global devname variable with a field in struct cmd_context Ben Hutchings
                   ` (6 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Ben Hutchings @ 2011-11-01 23:19 UTC (permalink / raw)
  To: netdev; +Cc: linux-net-drivers

cmdline_msglvl is used both in do_gset() and do_sset(), but it refers
to variables only used in do_sset().  I want to get rid of the global
variables without duplicating the flag definitions.  So separate out
the flag definitions into a new structure and generate cmdline_msglvl
from that at run-time.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 ethtool.c |   79 ++++++++++++++++++++++++++++++++++---------------------------
 1 files changed, 44 insertions(+), 35 deletions(-)

diff --git a/ethtool.c b/ethtool.c
index 7bdf173..438fc26 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -426,6 +426,11 @@ struct cmdline_info {
 	void *seen_val;
 };
 
+struct flag_info {
+	const char *name;
+	u32 value;
+};
+
 static struct cmdline_info cmdline_gregs[] = {
 	{ "raw", CMDL_BOOL, &gregs_dump_raw, NULL },
 	{ "hex", CMDL_BOOL, &gregs_dump_hex, NULL },
@@ -511,37 +516,22 @@ static struct cmdline_info cmdline_coalesce[] = {
 	{ "tx-frames-high", CMDL_S32, &coal_tx_frames_high_wanted, &ecoal.tx_max_coalesced_frames_high },
 };
 
-static struct cmdline_info cmdline_msglvl[] = {
-	{ "drv", CMDL_FLAG, &msglvl_wanted, NULL,
-	  NETIF_MSG_DRV, &msglvl_mask },
-	{ "probe", CMDL_FLAG, &msglvl_wanted, NULL,
-	  NETIF_MSG_PROBE, &msglvl_mask },
-	{ "link", CMDL_FLAG, &msglvl_wanted, NULL,
-	  NETIF_MSG_LINK, &msglvl_mask },
-	{ "timer", CMDL_FLAG, &msglvl_wanted, NULL,
-	  NETIF_MSG_TIMER, &msglvl_mask },
-	{ "ifdown", CMDL_FLAG, &msglvl_wanted, NULL,
-	  NETIF_MSG_IFDOWN, &msglvl_mask },
-	{ "ifup", CMDL_FLAG, &msglvl_wanted, NULL,
-	  NETIF_MSG_IFUP, &msglvl_mask },
-	{ "rx_err", CMDL_FLAG, &msglvl_wanted, NULL,
-	  NETIF_MSG_RX_ERR, &msglvl_mask },
-	{ "tx_err", CMDL_FLAG, &msglvl_wanted, NULL,
-	  NETIF_MSG_TX_ERR, &msglvl_mask },
-	{ "tx_queued", CMDL_FLAG, &msglvl_wanted, NULL,
-	  NETIF_MSG_TX_QUEUED, &msglvl_mask },
-	{ "intr", CMDL_FLAG, &msglvl_wanted, NULL,
-	  NETIF_MSG_INTR, &msglvl_mask },
-	{ "tx_done", CMDL_FLAG, &msglvl_wanted, NULL,
-	  NETIF_MSG_TX_DONE, &msglvl_mask },
-	{ "rx_status", CMDL_FLAG, &msglvl_wanted, NULL,
-	  NETIF_MSG_RX_STATUS, &msglvl_mask },
-	{ "pktdata", CMDL_FLAG, &msglvl_wanted, NULL,
-	  NETIF_MSG_PKTDATA, &msglvl_mask },
-	{ "hw", CMDL_FLAG, &msglvl_wanted, NULL,
-	  NETIF_MSG_HW, &msglvl_mask },
-	{ "wol", CMDL_FLAG, &msglvl_wanted, NULL,
-	  NETIF_MSG_WOL, &msglvl_mask },
+static const struct flag_info flags_msglvl[] = {
+	{ "drv",	NETIF_MSG_DRV },
+	{ "probe",	NETIF_MSG_PROBE },
+	{ "link",	NETIF_MSG_LINK },
+	{ "timer",	NETIF_MSG_TIMER },
+	{ "ifdown",	NETIF_MSG_IFDOWN },
+	{ "ifup",	NETIF_MSG_IFUP },
+	{ "rx_err",	NETIF_MSG_RX_ERR },
+	{ "tx_err",	NETIF_MSG_TX_ERR },
+	{ "tx_queued",	NETIF_MSG_TX_QUEUED },
+	{ "intr",	NETIF_MSG_INTR },
+	{ "tx_done",	NETIF_MSG_TX_DONE },
+	{ "rx_status",	NETIF_MSG_RX_STATUS },
+	{ "pktdata",	NETIF_MSG_PKTDATA },
+	{ "hw",		NETIF_MSG_HW },
+	{ "wol",	NETIF_MSG_WOL },
 };
 
 static long long
@@ -694,16 +684,28 @@ static void parse_generic_cmdline(struct cmd_context *ctx,
 	}
 }
 
+static void flag_to_cmdline_info(const char *name, u32 value,
+				 u32 *wanted, u32 *mask,
+				 struct cmdline_info *cli)
+{
+	memset(cli, 0, sizeof(*cli));
+	cli->name = name;
+	cli->type = CMDL_FLAG;
+	cli->flag_val = value;
+	cli->wanted_val = wanted;
+	cli->seen_val = mask;
+}
+
 static void
-print_flags(const struct cmdline_info *info, unsigned int n_info, u32 value)
+print_flags(const struct flag_info *info, unsigned int n_info, u32 value)
 {
 	const char *sep = "";
 
 	while (n_info) {
-		if (info->type == CMDL_FLAG && value & info->flag_val) {
+		if (value & info->value) {
 			printf("%s%s", sep, info->name);
 			sep = " ";
-			value &= ~info->flag_val;
+			value &= ~info->value;
 		}
 		++info;
 		--n_info;
@@ -2037,7 +2039,7 @@ static int do_gset(struct cmd_context *ctx)
 		fprintf(stdout, "	Current message level: 0x%08x (%d)\n"
 			"			       ",
 			edata.data, edata.data);
-		print_flags(cmdline_msglvl, ARRAY_SIZE(cmdline_msglvl),
+		print_flags(flags_msglvl, ARRAY_SIZE(flags_msglvl),
 			    edata.data);
 		fprintf(stdout, "\n");
 		allfail = 0;
@@ -2064,11 +2066,18 @@ static int do_gset(struct cmd_context *ctx)
 
 static int do_sset(struct cmd_context *ctx)
 {
+	struct cmdline_info cmdline_msglvl[ARRAY_SIZE(flags_msglvl)];
 	int argc = ctx->argc;
 	char **argp = ctx->argp;
 	int i;
 	int err;
 
+	for (i = 0; i < ARRAY_SIZE(flags_msglvl); i++)
+		flag_to_cmdline_info(flags_msglvl[i].name,
+				     flags_msglvl[i].value,
+				     &msglvl_wanted, &msglvl_mask,
+				     &cmdline_msglvl[i]);
+
 	for (i = 0; i < argc; i++) {
 		if (!strcmp(argp[i], "speed")) {
 			gset_changed = 1;
-- 
1.7.4.4



-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH ethtool 16/21] Replace global devname variable with a field in struct cmd_context
  2011-11-01 22:35 [PATCH ethtool 00/21] ethtool refactoring and misc changes Ben Hutchings
                   ` (14 preceding siblings ...)
  2011-11-01 23:19 ` [PATCH ethtool 15/21] Convert cmdline_msglvl into array of named flags; convert back at run-time Ben Hutchings
@ 2011-11-01 23:20 ` Ben Hutchings
  2011-11-01 23:21 ` [PATCH ethtool 17/21] Change most static global variables into automatic variables Ben Hutchings
                   ` (5 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Ben Hutchings @ 2011-11-01 23:20 UTC (permalink / raw)
  To: netdev; +Cc: linux-net-drivers

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 ethtool.c  |   24 +++++++++++-------------
 internal.h |    1 +
 2 files changed, 12 insertions(+), 13 deletions(-)

diff --git a/ethtool.c b/ethtool.c
index 438fc26..d0929c7 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -285,8 +285,6 @@ static int show_usage(struct cmd_context *ctx)
 	return 0;
 }
 
-static char *devname = NULL;
-
 static int goffload_changed = 0;
 static int off_csum_rx_wanted = -1;
 static int off_csum_tx_wanted = -1;
@@ -1540,7 +1538,7 @@ static int do_gpause(struct cmd_context *ctx)
 	if (ctx->argc != 0)
 		exit_bad_args();
 
-	fprintf(stdout, "Pause parameters for %s:\n", devname);
+	fprintf(stdout, "Pause parameters for %s:\n", ctx->devname);
 
 	epause.cmd = ETHTOOL_GPAUSEPARAM;
 	err = send_ioctl(ctx, &epause);
@@ -1662,7 +1660,7 @@ static int do_gring(struct cmd_context *ctx)
 	if (ctx->argc != 0)
 		exit_bad_args();
 
-	fprintf(stdout, "Ring parameters for %s:\n", devname);
+	fprintf(stdout, "Ring parameters for %s:\n", ctx->devname);
 
 	ering.cmd = ETHTOOL_GRINGPARAM;
 	err = send_ioctl(ctx, &ering);
@@ -1721,7 +1719,7 @@ static int do_gchannels(struct cmd_context *ctx)
 	if (ctx->argc != 0)
 		exit_bad_args();
 
-	fprintf(stdout, "Channel parameters for %s:\n", devname);
+	fprintf(stdout, "Channel parameters for %s:\n", ctx->devname);
 
 	echannels.cmd = ETHTOOL_GCHANNELS;
 	err = send_ioctl(ctx, &echannels);
@@ -1744,7 +1742,7 @@ static int do_gcoalesce(struct cmd_context *ctx)
 	if (ctx->argc != 0)
 		exit_bad_args();
 
-	fprintf(stdout, "Coalesce parameters for %s:\n", devname);
+	fprintf(stdout, "Coalesce parameters for %s:\n", ctx->devname);
 
 	ecoal.cmd = ETHTOOL_GCOALESCE;
 	err = send_ioctl(ctx, &ecoal);
@@ -1802,7 +1800,7 @@ static int do_goffload(struct cmd_context *ctx)
 	if (ctx->argc != 0)
 		exit_bad_args();
 
-	fprintf(stdout, "Offload parameters for %s:\n", devname);
+	fprintf(stdout, "Offload parameters for %s:\n", ctx->devname);
 
 	eval.cmd = ETHTOOL_GRXCSUM;
 	err = send_ioctl(ctx, &eval);
@@ -2009,7 +2007,7 @@ static int do_gset(struct cmd_context *ctx)
 	if (ctx->argc != 0)
 		exit_bad_args();
 
-	fprintf(stdout, "Settings for %s:\n", devname);
+	fprintf(stdout, "Settings for %s:\n", ctx->devname);
 
 	ecmd.cmd = ETHTOOL_GSET;
 	err = send_ioctl(ctx, &ecmd);
@@ -2744,7 +2742,7 @@ static int do_grxfhindir(struct cmd_context *ctx)
 	}
 
 	printf("RX flow hash indirection table for %s with %llu RX ring(s):\n",
-	       devname, ring_count.data);
+	       ctx->devname, ring_count.data);
 	for (i = 0; i < indir->size; i++) {
 		if (i % 8 == 0)
 			printf("%5u: ", i);
@@ -3222,17 +3220,17 @@ int main(int argc, char **argp, char **envp)
 
 opt_found:
 	if (want_device) {
-		devname = *argp++;
+		ctx.devname = *argp++;
 		argc--;
 
-		if (devname == NULL)
+		if (ctx.devname == NULL)
 			exit_bad_args();
-		if (strlen(devname) >= IFNAMSIZ)
+		if (strlen(ctx.devname) >= IFNAMSIZ)
 			exit_bad_args();
 
 		/* Setup our control structures. */
 		memset(&ctx.ifr, 0, sizeof(ctx.ifr));
-		strcpy(ctx.ifr.ifr_name, devname);
+		strcpy(ctx.ifr.ifr_name, ctx.devname);
 
 		/* Open control socket. */
 		ctx.fd = socket(AF_INET, SOCK_DGRAM, 0);
diff --git a/internal.h b/internal.h
index eb13db8..cb126b3 100644
--- a/internal.h
+++ b/internal.h
@@ -90,6 +90,7 @@ static inline int test_bit(unsigned int nr, const unsigned long *addr)
 
 /* Context for sub-commands */
 struct cmd_context {
+	const char *devname;	/* net device name */
 	int fd;			/* socket suitable for ethtool ioctl */
 	struct ifreq ifr;	/* ifreq suitable for ethtool ioctl */
 	int argc;		/* number of arguments to the sub-command */
-- 
1.7.4.4



-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH ethtool 17/21] Change most static global variables into automatic variables
  2011-11-01 22:35 [PATCH ethtool 00/21] ethtool refactoring and misc changes Ben Hutchings
                   ` (15 preceding siblings ...)
  2011-11-01 23:20 ` [PATCH ethtool 16/21] Replace global devname variable with a field in struct cmd_context Ben Hutchings
@ 2011-11-01 23:21 ` Ben Hutchings
  2011-11-01 23:22 ` [PATCH ethtool 18/21] rxclass: Replace global rmgr with automatic variable/parameter Ben Hutchings
                   ` (4 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Ben Hutchings @ 2011-11-01 23:21 UTC (permalink / raw)
  To: netdev; +Cc: linux-net-drivers

This is necessary preparation for in-process testing.  It should also
reduce the risk of some classes of bug by putting declaration and use
closer together.

Add parameters to various functions as necessary.

Leave the global constants alone.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 ethtool.c |  553 ++++++++++++++++++++++++++++++++-----------------------------
 1 files changed, 293 insertions(+), 260 deletions(-)

diff --git a/ethtool.c b/ethtool.c
index d0929c7..13fb0ef 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -285,114 +285,6 @@ static int show_usage(struct cmd_context *ctx)
 	return 0;
 }
 
-static int goffload_changed = 0;
-static int off_csum_rx_wanted = -1;
-static int off_csum_tx_wanted = -1;
-static int off_sg_wanted = -1;
-static int off_tso_wanted = -1;
-static int off_ufo_wanted = -1;
-static int off_gso_wanted = -1;
-static u32 off_flags_wanted = 0;
-static u32 off_flags_mask = 0;
-static int off_gro_wanted = -1;
-
-static struct ethtool_pauseparam epause;
-static int gpause_changed = 0;
-static int pause_autoneg_wanted = -1;
-static int pause_rx_wanted = -1;
-static int pause_tx_wanted = -1;
-
-static struct ethtool_ringparam ering;
-static int gring_changed = 0;
-static s32 ring_rx_wanted = -1;
-static s32 ring_rx_mini_wanted = -1;
-static s32 ring_rx_jumbo_wanted = -1;
-static s32 ring_tx_wanted = -1;
-
-static struct ethtool_channels echannels;
-static int gchannels_changed;
-static s32 channels_rx_wanted = -1;
-static s32 channels_tx_wanted = -1;
-static s32 channels_other_wanted = -1;
-static s32 channels_combined_wanted = -1;
-
-static struct ethtool_coalesce ecoal;
-static int gcoalesce_changed = 0;
-static s32 coal_stats_wanted = -1;
-static int coal_adaptive_rx_wanted = -1;
-static int coal_adaptive_tx_wanted = -1;
-static s32 coal_sample_rate_wanted = -1;
-static s32 coal_pkt_rate_low_wanted = -1;
-static s32 coal_pkt_rate_high_wanted = -1;
-static s32 coal_rx_usec_wanted = -1;
-static s32 coal_rx_frames_wanted = -1;
-static s32 coal_rx_usec_irq_wanted = -1;
-static s32 coal_rx_frames_irq_wanted = -1;
-static s32 coal_tx_usec_wanted = -1;
-static s32 coal_tx_frames_wanted = -1;
-static s32 coal_tx_usec_irq_wanted = -1;
-static s32 coal_tx_frames_irq_wanted = -1;
-static s32 coal_rx_usec_low_wanted = -1;
-static s32 coal_rx_frames_low_wanted = -1;
-static s32 coal_tx_usec_low_wanted = -1;
-static s32 coal_tx_frames_low_wanted = -1;
-static s32 coal_rx_usec_high_wanted = -1;
-static s32 coal_rx_frames_high_wanted = -1;
-static s32 coal_tx_usec_high_wanted = -1;
-static s32 coal_tx_frames_high_wanted = -1;
-
-static int speed_wanted = -1;
-static int duplex_wanted = -1;
-static int port_wanted = -1;
-static int autoneg_wanted = -1;
-static int phyad_wanted = -1;
-static int xcvr_wanted = -1;
-static int advertising_wanted = -1;
-static int gset_changed = 0; /* did anything in GSET change? */
-static u32  wol_wanted = 0;
-static int wol_change = 0;
-static u8 sopass_wanted[SOPASS_MAX];
-static int sopass_change = 0;
-static int gwol_changed = 0; /* did anything in GWOL change? */
-static int phys_id_time = 0;
-static int gregs_changed = 0;
-static int gregs_dump_raw = 0;
-static int gregs_dump_hex = 0;
-static char *gregs_dump_file = NULL;
-static int geeprom_changed = 0;
-static int geeprom_dump_raw = 0;
-static u32 geeprom_offset = 0;
-static u32 geeprom_length = -1;
-static int seeprom_changed = 0;
-static u32 seeprom_magic = 0;
-static u32 seeprom_length = -1;
-static u32 seeprom_offset = 0;
-static u8 seeprom_value = 0;
-static int seeprom_value_seen = 0;
-static int rx_fhash_get = 0;
-static int rx_fhash_set = 0;
-static u32 rx_fhash_val = 0;
-static int rxfhindir_equal = 0;
-static char **rxfhindir_weight = NULL;
-static char *flash_file = NULL;
-static int flash_region = -1;
-
-static int msglvl_changed;
-static u32 msglvl_wanted = 0;
-static u32 msglvl_mask = 0;
-static u32 dump_flag;
-static char *dump_file = NULL;
-
-static int rx_class_rule_get = -1;
-static int rx_class_rule_del = -1;
-static struct ethtool_rx_flow_spec rx_rule_fs;
-
-static enum {
-	ONLINE=0,
-	OFFLINE,
-	EXTERNAL_LB,
-} test_type = OFFLINE;
-
 typedef enum {
 	CMDL_NONE,
 	CMDL_BOOL,
@@ -429,91 +321,6 @@ struct flag_info {
 	u32 value;
 };
 
-static struct cmdline_info cmdline_gregs[] = {
-	{ "raw", CMDL_BOOL, &gregs_dump_raw, NULL },
-	{ "hex", CMDL_BOOL, &gregs_dump_hex, NULL },
-	{ "file", CMDL_STR, &gregs_dump_file, NULL },
-};
-
-static struct cmdline_info cmdline_geeprom[] = {
-	{ "offset", CMDL_U32, &geeprom_offset, NULL },
-	{ "length", CMDL_U32, &geeprom_length, NULL },
-	{ "raw", CMDL_BOOL, &geeprom_dump_raw, NULL },
-};
-
-static struct cmdline_info cmdline_seeprom[] = {
-	{ "magic", CMDL_U32, &seeprom_magic, NULL },
-	{ "offset", CMDL_U32, &seeprom_offset, NULL },
-	{ "length", CMDL_U32, &seeprom_length, NULL },
-	{ "value", CMDL_U8, &seeprom_value, NULL,
-	  0, &seeprom_value_seen },
-};
-
-static struct cmdline_info cmdline_offload[] = {
-	{ "rx", CMDL_BOOL, &off_csum_rx_wanted, NULL },
-	{ "tx", CMDL_BOOL, &off_csum_tx_wanted, NULL },
-	{ "sg", CMDL_BOOL, &off_sg_wanted, NULL },
-	{ "tso", CMDL_BOOL, &off_tso_wanted, NULL },
-	{ "ufo", CMDL_BOOL, &off_ufo_wanted, NULL },
-	{ "gso", CMDL_BOOL, &off_gso_wanted, NULL },
-	{ "lro", CMDL_FLAG, &off_flags_wanted, NULL,
-	  ETH_FLAG_LRO, &off_flags_mask },
-	{ "gro", CMDL_BOOL, &off_gro_wanted, NULL },
-	{ "rxvlan", CMDL_FLAG, &off_flags_wanted, NULL,
-	  ETH_FLAG_RXVLAN, &off_flags_mask },
-	{ "txvlan", CMDL_FLAG, &off_flags_wanted, NULL,
-	  ETH_FLAG_TXVLAN, &off_flags_mask },
-	{ "ntuple", CMDL_FLAG, &off_flags_wanted, NULL,
-	  ETH_FLAG_NTUPLE, &off_flags_mask },
-	{ "rxhash", CMDL_FLAG, &off_flags_wanted, NULL,
-	  ETH_FLAG_RXHASH, &off_flags_mask },
-};
-
-static struct cmdline_info cmdline_pause[] = {
-	{ "autoneg", CMDL_BOOL, &pause_autoneg_wanted, &epause.autoneg },
-	{ "rx", CMDL_BOOL, &pause_rx_wanted, &epause.rx_pause },
-	{ "tx", CMDL_BOOL, &pause_tx_wanted, &epause.tx_pause },
-};
-
-static struct cmdline_info cmdline_ring[] = {
-	{ "rx", CMDL_S32, &ring_rx_wanted, &ering.rx_pending },
-	{ "rx-mini", CMDL_S32, &ring_rx_mini_wanted, &ering.rx_mini_pending },
-	{ "rx-jumbo", CMDL_S32, &ring_rx_jumbo_wanted, &ering.rx_jumbo_pending },
-	{ "tx", CMDL_S32, &ring_tx_wanted, &ering.tx_pending },
-};
-
-static struct cmdline_info cmdline_channels[] = {
-	{ "rx", CMDL_S32, &channels_rx_wanted, &echannels.rx_count },
-	{ "tx", CMDL_S32, &channels_tx_wanted, &echannels.tx_count },
-	{ "other", CMDL_S32, &channels_other_wanted, &echannels.other_count },
-	{ "combined", CMDL_S32, &channels_combined_wanted, &echannels.combined_count },
-};
-
-static struct cmdline_info cmdline_coalesce[] = {
-	{ "adaptive-rx", CMDL_BOOL, &coal_adaptive_rx_wanted, &ecoal.use_adaptive_rx_coalesce },
-	{ "adaptive-tx", CMDL_BOOL, &coal_adaptive_tx_wanted, &ecoal.use_adaptive_tx_coalesce },
-	{ "sample-interval", CMDL_S32, &coal_sample_rate_wanted, &ecoal.rate_sample_interval },
-	{ "stats-block-usecs", CMDL_S32, &coal_stats_wanted, &ecoal.stats_block_coalesce_usecs },
-	{ "pkt-rate-low", CMDL_S32, &coal_pkt_rate_low_wanted, &ecoal.pkt_rate_low },
-	{ "pkt-rate-high", CMDL_S32, &coal_pkt_rate_high_wanted, &ecoal.pkt_rate_high },
-	{ "rx-usecs", CMDL_S32, &coal_rx_usec_wanted, &ecoal.rx_coalesce_usecs },
-	{ "rx-frames", CMDL_S32, &coal_rx_frames_wanted, &ecoal.rx_max_coalesced_frames },
-	{ "rx-usecs-irq", CMDL_S32, &coal_rx_usec_irq_wanted, &ecoal.rx_coalesce_usecs_irq },
-	{ "rx-frames-irq", CMDL_S32, &coal_rx_frames_irq_wanted, &ecoal.rx_max_coalesced_frames_irq },
-	{ "tx-usecs", CMDL_S32, &coal_tx_usec_wanted, &ecoal.tx_coalesce_usecs },
-	{ "tx-frames", CMDL_S32, &coal_tx_frames_wanted, &ecoal.tx_max_coalesced_frames },
-	{ "tx-usecs-irq", CMDL_S32, &coal_tx_usec_irq_wanted, &ecoal.tx_coalesce_usecs_irq },
-	{ "tx-frames-irq", CMDL_S32, &coal_tx_frames_irq_wanted, &ecoal.tx_max_coalesced_frames_irq },
-	{ "rx-usecs-low", CMDL_S32, &coal_rx_usec_low_wanted, &ecoal.rx_coalesce_usecs_low },
-	{ "rx-frames-low", CMDL_S32, &coal_rx_frames_low_wanted, &ecoal.rx_max_coalesced_frames_low },
-	{ "tx-usecs-low", CMDL_S32, &coal_tx_usec_low_wanted, &ecoal.tx_coalesce_usecs_low },
-	{ "tx-frames-low", CMDL_S32, &coal_tx_frames_low_wanted, &ecoal.tx_max_coalesced_frames_low },
-	{ "rx-usecs-high", CMDL_S32, &coal_rx_usec_high_wanted, &ecoal.rx_coalesce_usecs_high },
-	{ "rx-frames-high", CMDL_S32, &coal_rx_frames_high_wanted, &ecoal.rx_max_coalesced_frames_high },
-	{ "tx-usecs-high", CMDL_S32, &coal_tx_usec_high_wanted, &ecoal.tx_coalesce_usecs_high },
-	{ "tx-frames-high", CMDL_S32, &coal_tx_frames_high_wanted, &ecoal.tx_max_coalesced_frames_high },
-};
-
 static const struct flag_info flags_msglvl[] = {
 	{ "drv",	NETIF_MSG_DRV },
 	{ "probe",	NETIF_MSG_PROBE },
@@ -1189,7 +996,9 @@ static struct {
 	{ "st_gmac", st_gmac_dump_regs },
 };
 
-static int dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs)
+static int dump_regs(int gregs_dump_raw, int gregs_dump_hex,
+		     const char *gregs_dump_file,
+		     struct ethtool_drvinfo *info, struct ethtool_regs *regs)
 {
 	int i;
 
@@ -1231,7 +1040,8 @@ static int dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs)
 	return 0;
 }
 
-static int dump_eeprom(struct ethtool_drvinfo *info, struct ethtool_eeprom *ee)
+static int dump_eeprom(int geeprom_dump_raw, struct ethtool_drvinfo *info,
+		       struct ethtool_eeprom *ee)
 {
 	int i;
 
@@ -1264,7 +1074,7 @@ static int dump_test(struct ethtool_drvinfo *info, struct ethtool_test *test,
 	rc = test->flags & ETH_TEST_FL_FAILED;
 	fprintf(stdout, "The test result is %s\n", rc ? "FAIL" : "PASS");
 
-	if (test_type == EXTERNAL_LB)
+	if (test->flags & ETH_TEST_FL_EXTERNAL_LB)
 		fprintf(stdout, "External loopback test was %sexecuted\n",
 			(test->flags & ETH_TEST_FL_EXTERNAL_LB_DONE) ?
 			"" : "not ");
@@ -1282,15 +1092,16 @@ static int dump_test(struct ethtool_drvinfo *info, struct ethtool_test *test,
 	return rc;
 }
 
-static int dump_pause(u32 advertising, u32 lp_advertising)
+static int dump_pause(const struct ethtool_pauseparam *epause,
+		      u32 advertising, u32 lp_advertising)
 {
 	fprintf(stdout,
 		"Autonegotiate:	%s\n"
 		"RX:		%s\n"
 		"TX:		%s\n",
-		epause.autoneg ? "on" : "off",
-		epause.rx_pause ? "on" : "off",
-		epause.tx_pause ? "on" : "off");
+		epause->autoneg ? "on" : "off",
+		epause->rx_pause ? "on" : "off",
+		epause->tx_pause ? "on" : "off");
 
 	if (lp_advertising) {
 		int an_rx = 0, an_tx = 0;
@@ -1320,7 +1131,7 @@ static int dump_pause(u32 advertising, u32 lp_advertising)
 	return 0;
 }
 
-static int dump_ring(void)
+static int dump_ring(const struct ethtool_ringparam *ering)
 {
 	fprintf(stdout,
 		"Pre-set maximums:\n"
@@ -1328,10 +1139,10 @@ static int dump_ring(void)
 		"RX Mini:	%u\n"
 		"RX Jumbo:	%u\n"
 		"TX:		%u\n",
-		ering.rx_max_pending,
-		ering.rx_mini_max_pending,
-		ering.rx_jumbo_max_pending,
-		ering.tx_max_pending);
+		ering->rx_max_pending,
+		ering->rx_mini_max_pending,
+		ering->rx_jumbo_max_pending,
+		ering->tx_max_pending);
 
 	fprintf(stdout,
 		"Current hardware settings:\n"
@@ -1339,16 +1150,16 @@ static int dump_ring(void)
 		"RX Mini:	%u\n"
 		"RX Jumbo:	%u\n"
 		"TX:		%u\n",
-		ering.rx_pending,
-		ering.rx_mini_pending,
-		ering.rx_jumbo_pending,
-		ering.tx_pending);
+		ering->rx_pending,
+		ering->rx_mini_pending,
+		ering->rx_jumbo_pending,
+		ering->tx_pending);
 
 	fprintf(stdout, "\n");
 	return 0;
 }
 
-static int dump_channels(void)
+static int dump_channels(const struct ethtool_channels *echannels)
 {
 	fprintf(stdout,
 		"Pre-set maximums:\n"
@@ -1356,9 +1167,9 @@ static int dump_channels(void)
 		"TX:		%u\n"
 		"Other:		%u\n"
 		"Combined:	%u\n",
-		echannels.max_rx, echannels.max_tx,
-		echannels.max_other,
-		echannels.max_combined);
+		echannels->max_rx, echannels->max_tx,
+		echannels->max_other,
+		echannels->max_combined);
 
 	fprintf(stdout,
 		"Current hardware settings:\n"
@@ -1366,19 +1177,19 @@ static int dump_channels(void)
 		"TX:		%u\n"
 		"Other:		%u\n"
 		"Combined:	%u\n",
-		echannels.rx_count, echannels.tx_count,
-		echannels.other_count,
-		echannels.combined_count);
+		echannels->rx_count, echannels->tx_count,
+		echannels->other_count,
+		echannels->combined_count);
 
 	fprintf(stdout, "\n");
 	return 0;
 }
 
-static int dump_coalesce(void)
+static int dump_coalesce(const struct ethtool_coalesce *ecoal)
 {
 	fprintf(stdout, "Adaptive RX: %s  TX: %s\n",
-		ecoal.use_adaptive_rx_coalesce ? "on" : "off",
-		ecoal.use_adaptive_tx_coalesce ? "on" : "off");
+		ecoal->use_adaptive_rx_coalesce ? "on" : "off",
+		ecoal->use_adaptive_tx_coalesce ? "on" : "off");
 
 	fprintf(stdout,
 		"stats-block-usecs: %u\n"
@@ -1406,30 +1217,30 @@ static int dump_coalesce(void)
 		"tx-usecs-high: %u\n"
 		"tx-frame-high: %u\n"
 		"\n",
-		ecoal.stats_block_coalesce_usecs,
-		ecoal.rate_sample_interval,
-		ecoal.pkt_rate_low,
-		ecoal.pkt_rate_high,
-
-		ecoal.rx_coalesce_usecs,
-		ecoal.rx_max_coalesced_frames,
-		ecoal.rx_coalesce_usecs_irq,
-		ecoal.rx_max_coalesced_frames_irq,
-
-		ecoal.tx_coalesce_usecs,
-		ecoal.tx_max_coalesced_frames,
-		ecoal.tx_coalesce_usecs_irq,
-		ecoal.tx_max_coalesced_frames_irq,
-
-		ecoal.rx_coalesce_usecs_low,
-		ecoal.rx_max_coalesced_frames_low,
-		ecoal.tx_coalesce_usecs_low,
-		ecoal.tx_max_coalesced_frames_low,
-
-		ecoal.rx_coalesce_usecs_high,
-		ecoal.rx_max_coalesced_frames_high,
-		ecoal.tx_coalesce_usecs_high,
-		ecoal.tx_max_coalesced_frames_high);
+		ecoal->stats_block_coalesce_usecs,
+		ecoal->rate_sample_interval,
+		ecoal->pkt_rate_low,
+		ecoal->pkt_rate_high,
+
+		ecoal->rx_coalesce_usecs,
+		ecoal->rx_max_coalesced_frames,
+		ecoal->rx_coalesce_usecs_irq,
+		ecoal->rx_max_coalesced_frames_irq,
+
+		ecoal->tx_coalesce_usecs,
+		ecoal->tx_max_coalesced_frames,
+		ecoal->tx_coalesce_usecs_irq,
+		ecoal->tx_max_coalesced_frames_irq,
+
+		ecoal->rx_coalesce_usecs_low,
+		ecoal->rx_max_coalesced_frames_low,
+		ecoal->tx_coalesce_usecs_low,
+		ecoal->tx_max_coalesced_frames_low,
+
+		ecoal->rx_coalesce_usecs_high,
+		ecoal->rx_max_coalesced_frames_high,
+		ecoal->tx_coalesce_usecs_high,
+		ecoal->tx_max_coalesced_frames_high);
 
 	return 0;
 }
@@ -1532,6 +1343,7 @@ static int do_gdrv(struct cmd_context *ctx)
 
 static int do_gpause(struct cmd_context *ctx)
 {
+	struct ethtool_pauseparam epause;
 	struct ethtool_cmd ecmd;
 	int err;
 
@@ -1554,9 +1366,9 @@ static int do_gpause(struct cmd_context *ctx)
 			perror("Cannot get device settings");
 			return 1;
 		}
-		dump_pause(ecmd.advertising, ecmd.lp_advertising);
+		dump_pause(&epause, ecmd.advertising, ecmd.lp_advertising);
 	} else {
-		dump_pause(0, 0);
+		dump_pause(&epause, 0, 0);
 	}
 
 	return 0;
@@ -1593,6 +1405,17 @@ static void do_generic_set(struct cmdline_info *info,
 
 static int do_spause(struct cmd_context *ctx)
 {
+	struct ethtool_pauseparam epause;
+	int gpause_changed = 0;
+	int pause_autoneg_wanted = -1;
+	int pause_rx_wanted = -1;
+	int pause_tx_wanted = -1;
+	struct cmdline_info cmdline_pause[] = {
+		{ "autoneg", CMDL_BOOL, &pause_autoneg_wanted,
+		  &epause.autoneg },
+		{ "rx", CMDL_BOOL, &pause_rx_wanted, &epause.rx_pause },
+		{ "tx", CMDL_BOOL, &pause_tx_wanted, &epause.tx_pause },
+	};
 	int err, changed = 0;
 
 	parse_generic_cmdline(ctx, &gpause_changed,
@@ -1624,6 +1447,20 @@ static int do_spause(struct cmd_context *ctx)
 
 static int do_sring(struct cmd_context *ctx)
 {
+	struct ethtool_ringparam ering;
+	int gring_changed = 0;
+	s32 ring_rx_wanted = -1;
+	s32 ring_rx_mini_wanted = -1;
+	s32 ring_rx_jumbo_wanted = -1;
+	s32 ring_tx_wanted = -1;
+	struct cmdline_info cmdline_ring[] = {
+		{ "rx", CMDL_S32, &ring_rx_wanted, &ering.rx_pending },
+		{ "rx-mini", CMDL_S32, &ring_rx_mini_wanted,
+		  &ering.rx_mini_pending },
+		{ "rx-jumbo", CMDL_S32, &ring_rx_jumbo_wanted,
+		  &ering.rx_jumbo_pending },
+		{ "tx", CMDL_S32, &ring_tx_wanted, &ering.tx_pending },
+	};
 	int err, changed = 0;
 
 	parse_generic_cmdline(ctx, &gring_changed,
@@ -1655,6 +1492,7 @@ static int do_sring(struct cmd_context *ctx)
 
 static int do_gring(struct cmd_context *ctx)
 {
+	struct ethtool_ringparam ering;
 	int err;
 
 	if (ctx->argc != 0)
@@ -1665,7 +1503,7 @@ static int do_gring(struct cmd_context *ctx)
 	ering.cmd = ETHTOOL_GRINGPARAM;
 	err = send_ioctl(ctx, &ering);
 	if (err == 0) {
-		err = dump_ring();
+		err = dump_ring(&ering);
 		if (err)
 			return err;
 	} else {
@@ -1678,6 +1516,20 @@ static int do_gring(struct cmd_context *ctx)
 
 static int do_schannels(struct cmd_context *ctx)
 {
+	struct ethtool_channels echannels;
+	int gchannels_changed;
+	s32 channels_rx_wanted = -1;
+	s32 channels_tx_wanted = -1;
+	s32 channels_other_wanted = -1;
+	s32 channels_combined_wanted = -1;
+	struct cmdline_info cmdline_channels[] = {
+		{ "rx", CMDL_S32, &channels_rx_wanted, &echannels.rx_count },
+		{ "tx", CMDL_S32, &channels_tx_wanted, &echannels.tx_count },
+		{ "other", CMDL_S32, &channels_other_wanted,
+		  &echannels.other_count },
+		{ "combined", CMDL_S32, &channels_combined_wanted,
+		  &echannels.combined_count },
+	};
 	int err, changed = 0;
 
 	parse_generic_cmdline(ctx, &gchannels_changed,
@@ -1714,6 +1566,7 @@ static int do_schannels(struct cmd_context *ctx)
 
 static int do_gchannels(struct cmd_context *ctx)
 {
+	struct ethtool_channels echannels;
 	int err;
 
 	if (ctx->argc != 0)
@@ -1724,7 +1577,7 @@ static int do_gchannels(struct cmd_context *ctx)
 	echannels.cmd = ETHTOOL_GCHANNELS;
 	err = send_ioctl(ctx, &echannels);
 	if (err == 0) {
-		err = dump_channels();
+		err = dump_channels(&echannels);
 		if (err)
 			return err;
 	} else {
@@ -1737,6 +1590,7 @@ static int do_gchannels(struct cmd_context *ctx)
 
 static int do_gcoalesce(struct cmd_context *ctx)
 {
+	struct ethtool_coalesce ecoal;
 	int err;
 
 	if (ctx->argc != 0)
@@ -1747,7 +1601,7 @@ static int do_gcoalesce(struct cmd_context *ctx)
 	ecoal.cmd = ETHTOOL_GCOALESCE;
 	err = send_ioctl(ctx, &ecoal);
 	if (err == 0) {
-		err = dump_coalesce();
+		err = dump_coalesce(&ecoal);
 		if (err)
 			return err;
 	} else {
@@ -1760,6 +1614,76 @@ static int do_gcoalesce(struct cmd_context *ctx)
 
 static int do_scoalesce(struct cmd_context *ctx)
 {
+	struct ethtool_coalesce ecoal;
+	int gcoalesce_changed = 0;
+	s32 coal_stats_wanted = -1;
+	int coal_adaptive_rx_wanted = -1;
+	int coal_adaptive_tx_wanted = -1;
+	s32 coal_sample_rate_wanted = -1;
+	s32 coal_pkt_rate_low_wanted = -1;
+	s32 coal_pkt_rate_high_wanted = -1;
+	s32 coal_rx_usec_wanted = -1;
+	s32 coal_rx_frames_wanted = -1;
+	s32 coal_rx_usec_irq_wanted = -1;
+	s32 coal_rx_frames_irq_wanted = -1;
+	s32 coal_tx_usec_wanted = -1;
+	s32 coal_tx_frames_wanted = -1;
+	s32 coal_tx_usec_irq_wanted = -1;
+	s32 coal_tx_frames_irq_wanted = -1;
+	s32 coal_rx_usec_low_wanted = -1;
+	s32 coal_rx_frames_low_wanted = -1;
+	s32 coal_tx_usec_low_wanted = -1;
+	s32 coal_tx_frames_low_wanted = -1;
+	s32 coal_rx_usec_high_wanted = -1;
+	s32 coal_rx_frames_high_wanted = -1;
+	s32 coal_tx_usec_high_wanted = -1;
+	s32 coal_tx_frames_high_wanted = -1;
+	struct cmdline_info cmdline_coalesce[] = {
+		{ "adaptive-rx", CMDL_BOOL, &coal_adaptive_rx_wanted,
+		  &ecoal.use_adaptive_rx_coalesce },
+		{ "adaptive-tx", CMDL_BOOL, &coal_adaptive_tx_wanted,
+		  &ecoal.use_adaptive_tx_coalesce },
+		{ "sample-interval", CMDL_S32, &coal_sample_rate_wanted,
+		  &ecoal.rate_sample_interval },
+		{ "stats-block-usecs", CMDL_S32, &coal_stats_wanted,
+		  &ecoal.stats_block_coalesce_usecs },
+		{ "pkt-rate-low", CMDL_S32, &coal_pkt_rate_low_wanted,
+		  &ecoal.pkt_rate_low },
+		{ "pkt-rate-high", CMDL_S32, &coal_pkt_rate_high_wanted,
+		  &ecoal.pkt_rate_high },
+		{ "rx-usecs", CMDL_S32, &coal_rx_usec_wanted,
+		  &ecoal.rx_coalesce_usecs },
+		{ "rx-frames", CMDL_S32, &coal_rx_frames_wanted,
+		  &ecoal.rx_max_coalesced_frames },
+		{ "rx-usecs-irq", CMDL_S32, &coal_rx_usec_irq_wanted,
+		  &ecoal.rx_coalesce_usecs_irq },
+		{ "rx-frames-irq", CMDL_S32, &coal_rx_frames_irq_wanted,
+		  &ecoal.rx_max_coalesced_frames_irq },
+		{ "tx-usecs", CMDL_S32, &coal_tx_usec_wanted,
+		  &ecoal.tx_coalesce_usecs },
+		{ "tx-frames", CMDL_S32, &coal_tx_frames_wanted,
+		  &ecoal.tx_max_coalesced_frames },
+		{ "tx-usecs-irq", CMDL_S32, &coal_tx_usec_irq_wanted,
+		  &ecoal.tx_coalesce_usecs_irq },
+		{ "tx-frames-irq", CMDL_S32, &coal_tx_frames_irq_wanted,
+		  &ecoal.tx_max_coalesced_frames_irq },
+		{ "rx-usecs-low", CMDL_S32, &coal_rx_usec_low_wanted,
+		  &ecoal.rx_coalesce_usecs_low },
+		{ "rx-frames-low", CMDL_S32, &coal_rx_frames_low_wanted,
+		  &ecoal.rx_max_coalesced_frames_low },
+		{ "tx-usecs-low", CMDL_S32, &coal_tx_usec_low_wanted,
+		  &ecoal.tx_coalesce_usecs_low },
+		{ "tx-frames-low", CMDL_S32, &coal_tx_frames_low_wanted,
+		  &ecoal.tx_max_coalesced_frames_low },
+		{ "rx-usecs-high", CMDL_S32, &coal_rx_usec_high_wanted,
+		  &ecoal.rx_coalesce_usecs_high },
+		{ "rx-frames-high", CMDL_S32, &coal_rx_frames_high_wanted,
+		  &ecoal.rx_max_coalesced_frames_high },
+		{ "tx-usecs-high", CMDL_S32, &coal_tx_usec_high_wanted,
+		  &ecoal.tx_coalesce_usecs_high },
+		{ "tx-frames-high", CMDL_S32, &coal_tx_frames_high_wanted,
+		  &ecoal.tx_max_coalesced_frames_high },
+	};
 	int err, changed = 0;
 
 	parse_generic_cmdline(ctx, &gcoalesce_changed,
@@ -1889,6 +1813,35 @@ static int do_goffload(struct cmd_context *ctx)
 
 static int do_soffload(struct cmd_context *ctx)
 {
+	int goffload_changed = 0;
+	int off_csum_rx_wanted = -1;
+	int off_csum_tx_wanted = -1;
+	int off_sg_wanted = -1;
+	int off_tso_wanted = -1;
+	int off_ufo_wanted = -1;
+	int off_gso_wanted = -1;
+	u32 off_flags_wanted = 0;
+	u32 off_flags_mask = 0;
+	int off_gro_wanted = -1;
+	struct cmdline_info cmdline_offload[] = {
+		{ "rx", CMDL_BOOL, &off_csum_rx_wanted, NULL },
+		{ "tx", CMDL_BOOL, &off_csum_tx_wanted, NULL },
+		{ "sg", CMDL_BOOL, &off_sg_wanted, NULL },
+		{ "tso", CMDL_BOOL, &off_tso_wanted, NULL },
+		{ "ufo", CMDL_BOOL, &off_ufo_wanted, NULL },
+		{ "gso", CMDL_BOOL, &off_gso_wanted, NULL },
+		{ "lro", CMDL_FLAG, &off_flags_wanted, NULL,
+		  ETH_FLAG_LRO, &off_flags_mask },
+		{ "gro", CMDL_BOOL, &off_gro_wanted, NULL },
+		{ "rxvlan", CMDL_FLAG, &off_flags_wanted, NULL,
+		  ETH_FLAG_RXVLAN, &off_flags_mask },
+		{ "txvlan", CMDL_FLAG, &off_flags_wanted, NULL,
+		  ETH_FLAG_TXVLAN, &off_flags_mask },
+		{ "ntuple", CMDL_FLAG, &off_flags_wanted, NULL,
+		  ETH_FLAG_NTUPLE, &off_flags_mask },
+		{ "rxhash", CMDL_FLAG, &off_flags_wanted, NULL,
+		  ETH_FLAG_RXHASH, &off_flags_mask },
+	};
 	struct ethtool_value eval;
 	int err, changed = 0;
 
@@ -2064,6 +2017,22 @@ static int do_gset(struct cmd_context *ctx)
 
 static int do_sset(struct cmd_context *ctx)
 {
+	int speed_wanted = -1;
+	int duplex_wanted = -1;
+	int port_wanted = -1;
+	int autoneg_wanted = -1;
+	int phyad_wanted = -1;
+	int xcvr_wanted = -1;
+	int advertising_wanted = -1;
+	int gset_changed = 0; /* did anything in GSET change? */
+	u32 wol_wanted = 0;
+	int wol_change = 0;
+	u8 sopass_wanted[SOPASS_MAX];
+	int sopass_change = 0;
+	int gwol_changed = 0; /* did anything in GWOL change? */
+	int msglvl_changed = 0;
+	u32 msglvl_wanted = 0;
+	u32 msglvl_mask = 0;
 	struct cmdline_info cmdline_msglvl[ARRAY_SIZE(flags_msglvl)];
 	int argc = ctx->argc;
 	char **argp = ctx->argp;
@@ -2349,6 +2318,15 @@ static int do_sset(struct cmd_context *ctx)
 
 static int do_gregs(struct cmd_context *ctx)
 {
+	int gregs_changed = 0;
+	int gregs_dump_raw = 0;
+	int gregs_dump_hex = 0;
+	char *gregs_dump_file = NULL;
+	struct cmdline_info cmdline_gregs[] = {
+		{ "raw", CMDL_BOOL, &gregs_dump_raw, NULL },
+		{ "hex", CMDL_BOOL, &gregs_dump_hex, NULL },
+		{ "file", CMDL_STR, &gregs_dump_file, NULL },
+	};
 	int err;
 	struct ethtool_drvinfo drvinfo;
 	struct ethtool_regs *regs;
@@ -2376,7 +2354,8 @@ static int do_gregs(struct cmd_context *ctx)
 		free(regs);
 		return 74;
 	}
-	if(dump_regs(&drvinfo, regs) < 0) {
+	if (dump_regs(gregs_dump_raw, gregs_dump_hex, gregs_dump_file,
+		      &drvinfo, regs) < 0) {
 		perror("Cannot dump registers");
 		free(regs);
 		return 75;
@@ -2404,6 +2383,15 @@ static int do_nway_rst(struct cmd_context *ctx)
 
 static int do_geeprom(struct cmd_context *ctx)
 {
+	int geeprom_changed = 0;
+	int geeprom_dump_raw = 0;
+	u32 geeprom_offset = 0;
+	u32 geeprom_length = -1;
+	struct cmdline_info cmdline_geeprom[] = {
+		{ "offset", CMDL_U32, &geeprom_offset, NULL },
+		{ "length", CMDL_U32, &geeprom_length, NULL },
+		{ "raw", CMDL_BOOL, &geeprom_dump_raw, NULL },
+	};
 	int err;
 	struct ethtool_drvinfo drvinfo;
 	struct ethtool_eeprom *eeprom;
@@ -2438,7 +2426,7 @@ static int do_geeprom(struct cmd_context *ctx)
 		free(eeprom);
 		return 74;
 	}
-	err = dump_eeprom(&drvinfo, eeprom);
+	err = dump_eeprom(geeprom_dump_raw, &drvinfo, eeprom);
 	free(eeprom);
 
 	return err;
@@ -2446,6 +2434,19 @@ static int do_geeprom(struct cmd_context *ctx)
 
 static int do_seeprom(struct cmd_context *ctx)
 {
+	int seeprom_changed = 0;
+	u32 seeprom_magic = 0;
+	u32 seeprom_length = -1;
+	u32 seeprom_offset = 0;
+	u8 seeprom_value = 0;
+	int seeprom_value_seen = 0;
+	struct cmdline_info cmdline_seeprom[] = {
+		{ "magic", CMDL_U32, &seeprom_magic, NULL },
+		{ "offset", CMDL_U32, &seeprom_offset, NULL },
+		{ "length", CMDL_U32, &seeprom_length, NULL },
+		{ "value", CMDL_U8, &seeprom_value, NULL,
+		  0, &seeprom_value_seen },
+	};
 	int err;
 	struct ethtool_drvinfo drvinfo;
 	struct ethtool_eeprom *eeprom;
@@ -2497,6 +2498,11 @@ static int do_seeprom(struct cmd_context *ctx)
 
 static int do_test(struct cmd_context *ctx)
 {
+	enum {
+		ONLINE=0,
+		OFFLINE,
+		EXTERNAL_LB,
+	} test_type;
 	int err;
 	struct ethtool_drvinfo drvinfo;
 	struct ethtool_test *test;
@@ -2514,6 +2520,8 @@ static int do_test(struct cmd_context *ctx)
 		} else {
 			exit_bad_args();
 		}
+	} else {
+		test_type = OFFLINE;
 	}
 
 	drvinfo.cmd = ETHTOOL_GDRVINFO;
@@ -2573,11 +2581,14 @@ static int do_phys_id(struct cmd_context *ctx)
 {
 	int err;
 	struct ethtool_value edata;
+	int phys_id_time;
 
 	if (ctx->argc > 1)
 		exit_bad_args();
 	if (ctx->argc == 1)
 		phys_id_time = get_int(*ctx->argp, 0);
+	else
+		phys_id_time = 0;
 
 	edata.cmd = ETHTOOL_PHYS_ID;
 	edata.data = phys_id_time;
@@ -2660,10 +2671,13 @@ static int do_gstats(struct cmd_context *ctx)
 
 static int do_srxclass(struct cmd_context *ctx)
 {
-	struct ethtool_rxnfc nfccmd;
 	int err;
 
 	if (ctx->argc == 3 && !strcmp(ctx->argp[0], "rx-flow-hash")) {
+		int rx_fhash_set;
+		u32 rx_fhash_val;
+		struct ethtool_rxnfc nfccmd;
+
 		rx_fhash_set = rxflow_str_to_type(ctx->argp[1]);
 		if (!rx_fhash_set)
 			exit_bad_args();
@@ -2690,6 +2704,8 @@ static int do_grxclass(struct cmd_context *ctx)
 	int err;
 
 	if (ctx->argc == 2 && !strcmp(ctx->argp[0], "rx-flow-hash")) {
+		int rx_fhash_get;
+
 		rx_fhash_get = rxflow_str_to_type(ctx->argp[1]);
 		if (!rx_fhash_get)
 			exit_bad_args();
@@ -2755,6 +2771,8 @@ static int do_grxfhindir(struct cmd_context *ctx)
 
 static int do_srxfhindir(struct cmd_context *ctx)
 {
+	int rxfhindir_equal = 0;
+	char **rxfhindir_weight = NULL;
 	struct ethtool_rxfh_indir indir_head;
 	struct ethtool_rxfh_indir *indir;
 	u32 i;
@@ -2831,6 +2849,8 @@ static int do_srxfhindir(struct cmd_context *ctx)
 
 static int do_flash(struct cmd_context *ctx)
 {
+	char *flash_file;
+	int flash_region;
 	struct ethtool_flash efl;
 	int err;
 
@@ -2841,6 +2861,8 @@ static int do_flash(struct cmd_context *ctx)
 		flash_region = strtol(ctx->argp[1], NULL, 0);
 		if (flash_region < 0)
 			exit_bad_args();
+	} else {
+		flash_region = -1;
 	}
 
 	if (strlen(flash_file) > ETHTOOL_FLASH_MAX_FILENAME - 1) {
@@ -2964,14 +2986,15 @@ static int flow_spec_to_ntuple(struct ethtool_rx_flow_spec *fsp,
 	return 0;
 }
 
-static int do_srxntuple(struct cmd_context *ctx)
+static int do_srxntuple(struct cmd_context *ctx,
+			struct ethtool_rx_flow_spec *rx_rule_fs)
 {
 	struct ethtool_rx_ntuple ntuplecmd;
 	struct ethtool_value eval;
 	int err;
 
 	/* attempt to convert the flow classifier to an ntuple classifier */
-	err = flow_spec_to_ntuple(&rx_rule_fs, &ntuplecmd.fs);
+	err = flow_spec_to_ntuple(rx_rule_fs, &ntuplecmd.fs);
 	if (err)
 		return -1;
 
@@ -3010,14 +3033,16 @@ static int do_srxclsrule(struct cmd_context *ctx)
 	if (ctx->argc < 2)
 		exit_bad_args();
 
-	if (!strcmp(ctx->argp[0], "flow-type")) {
+	if (!strcmp(ctx->argp[0], "flow-type")) {	
+		struct ethtool_rx_flow_spec rx_rule_fs;
+
 		ctx->argc--;
 		ctx->argp++;
 		if (rxclass_parse_ruleopts(ctx, &rx_rule_fs) < 0)
 			exit_bad_args();
 
 		/* attempt to add rule via N-tuple specifier */
-		err = do_srxntuple(ctx);
+		err = do_srxntuple(ctx, &rx_rule_fs);
 		if (!err)
 			return 0;
 
@@ -3029,7 +3054,8 @@ static int do_srxclsrule(struct cmd_context *ctx)
 			return 1;
 		}
 	} else if (!strcmp(ctx->argp[0], "delete")) {
-		rx_class_rule_del = get_uint_range(ctx->argp[1], 0, INT_MAX);
+		int rx_class_rule_del =
+			get_uint_range(ctx->argp[1], 0, INT_MAX);
 
 		err = rxclass_rule_del(ctx, rx_class_rule_del);
 
@@ -3051,7 +3077,8 @@ static int do_grxclsrule(struct cmd_context *ctx)
 	int err;
 
 	if (ctx->argc == 2 && !strcmp(ctx->argp[0], "rule")) {
-		rx_class_rule_get = get_uint_range(ctx->argp[1], 0, INT_MAX);
+		int rx_class_rule_get =
+			get_uint_range(ctx->argp[1], 0, INT_MAX);
 
 		err = rxclass_rule_get(ctx, rx_class_rule_get);
 		if (err < 0)
@@ -3077,7 +3104,7 @@ static int do_grxclsrule(struct cmd_context *ctx)
 	return err ? 1 : 0;
 }
 
-static int do_writefwdump(struct ethtool_dump *dump)
+static int do_writefwdump(struct ethtool_dump *dump, const char *dump_file)
 {
 	int err = 0;
 	FILE *f;
@@ -3105,6 +3132,8 @@ static int do_writefwdump(struct ethtool_dump *dump)
 
 static int do_getfwdump(struct cmd_context *ctx)
 {
+	u32 dump_flag;
+	char *dump_file;
 	int err;
 	struct ethtool_dump edata;
 	struct ethtool_dump *data;
@@ -3112,7 +3141,10 @@ static int do_getfwdump(struct cmd_context *ctx)
 	if (ctx->argc == 2 && !strcmp(ctx->argp[0], "data")) {
 		dump_flag = ETHTOOL_GET_DUMP_DATA;
 		dump_file = ctx->argp[1];
-	} else if (ctx->argc != 0) {
+	} else if (ctx->argc == 0) {
+		dump_flag = 0;
+		dump_file = NULL;
+	} else {
 		exit_bad_args();
 	}
 
@@ -3141,7 +3173,7 @@ static int do_getfwdump(struct cmd_context *ctx)
 		err = 1;
 		goto free;
 	}
-	err = do_writefwdump(data);
+	err = do_writefwdump(data, dump_file);
 free:
 	free(data);
 	return err;
@@ -3149,6 +3181,7 @@ free:
 
 static int do_setfwdump(struct cmd_context *ctx)
 {
+	u32 dump_flag;
 	int err;
 	struct ethtool_dump dump;
 
-- 
1.7.4.4



-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH ethtool 18/21] rxclass: Replace global rmgr with automatic variable/parameter
  2011-11-01 22:35 [PATCH ethtool 00/21] ethtool refactoring and misc changes Ben Hutchings
                   ` (16 preceding siblings ...)
  2011-11-01 23:21 ` [PATCH ethtool 17/21] Change most static global variables into automatic variables Ben Hutchings
@ 2011-11-01 23:22 ` Ben Hutchings
  2011-11-01 23:22 ` [PATCH ethtool 19/21] Declare static variables const as appropriate Ben Hutchings
                   ` (3 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Ben Hutchings @ 2011-11-01 23:22 UTC (permalink / raw)
  To: netdev; +Cc: linux-net-drivers, Alexander Duyck

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 rxclass.c |   78 ++++++++++++++++++++++++++----------------------------------
 1 files changed, 34 insertions(+), 44 deletions(-)

diff --git a/rxclass.c b/rxclass.c
index 0c7b916..3b23a33 100644
--- a/rxclass.c
+++ b/rxclass.c
@@ -299,30 +299,28 @@ struct rmgr_ctrl {
 	__u32			size;
 };
 
-static struct rmgr_ctrl rmgr;
-static int rmgr_init_done = 0;
-
-static int rmgr_ins(__u32 loc)
+static int rmgr_ins(struct rmgr_ctrl *rmgr, __u32 loc)
 {
 	/* verify location is in rule manager range */
-	if (loc >= rmgr.size) {
+	if (loc >= rmgr->size) {
 		fprintf(stderr, "rmgr: Location out of range\n");
 		return -1;
 	}
 
 	/* set bit for the rule */
-	set_bit(loc, rmgr.slot);
+	set_bit(loc, rmgr->slot);
 
 	return 0;
 }
 
-static int rmgr_find_empty_slot(struct ethtool_rx_flow_spec *fsp)
+static int rmgr_find_empty_slot(struct rmgr_ctrl *rmgr,
+				struct ethtool_rx_flow_spec *fsp)
 {
 	__u32 loc;
 	__u32 slot_num;
 
 	/* start at the end of the list since it is lowest priority */
-	loc = rmgr.size - 1;
+	loc = rmgr->size - 1;
 
 	/* locate the first slot a rule can be placed in */
 	slot_num = loc / BITS_PER_LONG;
@@ -333,10 +331,10 @@ static int rmgr_find_empty_slot(struct ethtool_rx_flow_spec *fsp)
 	 * moving 1 + loc % BITS_PER_LONG we align ourselves to the last bit
 	 * in the previous word.
 	 *
-	 * If loc rolls over it should be greater than or equal to rmgr.size
+	 * If loc rolls over it should be greater than or equal to rmgr->size
 	 * and as such we know we have reached the end of the list.
 	 */
-	if (!~(rmgr.slot[slot_num] | (~1UL << rmgr.size % BITS_PER_LONG))) {
+	if (!~(rmgr->slot[slot_num] | (~1UL << rmgr->size % BITS_PER_LONG))) {
 		loc -= 1 + (loc % BITS_PER_LONG);
 		slot_num--;
 	}
@@ -345,7 +343,7 @@ static int rmgr_find_empty_slot(struct ethtool_rx_flow_spec *fsp)
 	 * Now that we are aligned with the last bit in each long we can just
 	 * go though and eliminate all the longs with no free bits
 	 */
-	while (loc < rmgr.size && !~(rmgr.slot[slot_num])) {
+	while (loc < rmgr->size && !~(rmgr->slot[slot_num])) {
 		loc -= BITS_PER_LONG;
 		slot_num--;
 	}
@@ -354,13 +352,13 @@ static int rmgr_find_empty_slot(struct ethtool_rx_flow_spec *fsp)
 	 * If we still are inside the range, test individual bits as one is
 	 * likely available for our use.
 	 */
-	while (loc < rmgr.size && test_bit(loc, rmgr.slot))
+	while (loc < rmgr->size && test_bit(loc, rmgr->slot))
 		loc--;
 
 	/* location found, insert rule */
-	if (loc < rmgr.size) {
+	if (loc < rmgr->size) {
 		fsp->location = loc;
-		return rmgr_ins(loc);
+		return rmgr_ins(rmgr, loc);
 	}
 
 	/* No space to add this rule */
@@ -369,25 +367,22 @@ static int rmgr_find_empty_slot(struct ethtool_rx_flow_spec *fsp)
 	return -1;
 }
 
-static int rmgr_init(struct cmd_context *ctx)
+static int rmgr_init(struct cmd_context *ctx, struct rmgr_ctrl *rmgr)
 {
 	struct ethtool_rxnfc *nfccmd;
 	int err, i;
 	__u32 *rule_locs;
 
-	if (rmgr_init_done)
-		return 0;
-
 	/* clear rule manager settings */
-	memset(&rmgr, 0, sizeof(struct rmgr_ctrl));
+	memset(rmgr, 0, sizeof(*rmgr));
 
-	/* request count and store in rmgr.n_rules */
-	err = rxclass_get_count(ctx, &rmgr.n_rules);
+	/* request count and store in rmgr->n_rules */
+	err = rxclass_get_count(ctx, &rmgr->n_rules);
 	if (err < 0)
 		return err;
 
 	/* alloc memory for request of location list */
-	nfccmd = calloc(1, sizeof(*nfccmd) + (rmgr.n_rules * sizeof(__u32)));
+	nfccmd = calloc(1, sizeof(*nfccmd) + (rmgr->n_rules * sizeof(__u32)));
 	if (!nfccmd) {
 		perror("rmgr: Cannot allocate memory for"
 		       " RX class rule locations");
@@ -396,7 +391,7 @@ static int rmgr_init(struct cmd_context *ctx)
 
 	/* request location list */
 	nfccmd->cmd = ETHTOOL_GRXCLSRLALL;
-	nfccmd->rule_cnt = rmgr.n_rules;
+	nfccmd->rule_cnt = rmgr->n_rules;
 	err = send_ioctl(ctx, nfccmd);
 	if (err < 0) {
 		perror("rmgr: Cannot get RX class rules");
@@ -405,61 +400,56 @@ static int rmgr_init(struct cmd_context *ctx)
 	}
 
 	/* make certain the table size is valid */
-	rmgr.size = nfccmd->data;
-	if (rmgr.size == 0 || rmgr.size < rmgr.n_rules) {
+	rmgr->size = nfccmd->data;
+	if (rmgr->size == 0 || rmgr->size < rmgr->n_rules) {
 		perror("rmgr: Invalid RX class rules table size");
 		return -1;
 	}
 
 	/* initialize bitmap for storage of valid locations */
-	rmgr.slot = calloc(1, BITS_TO_LONGS(rmgr.size) * sizeof(long));
-	if (!rmgr.slot) {
+	rmgr->slot = calloc(1, BITS_TO_LONGS(rmgr->size) * sizeof(long));
+	if (!rmgr->slot) {
 		perror("rmgr: Cannot allocate memory for RX class rules");
 		return -1;
 	}
 
 	/* write locations to bitmap */
 	rule_locs = nfccmd->rule_locs;
-	for (i = 0; i < rmgr.n_rules; i++) {
-		err = rmgr_ins(rule_locs[i]);
+	for (i = 0; i < rmgr->n_rules; i++) {
+		err = rmgr_ins(rmgr, rule_locs[i]);
 		if (err < 0)
 			break;
 	}
 
-	/* free memory and set flag to avoid reinit */
 	free(nfccmd);
-	rmgr_init_done = 1;
 
 	return err;
 }
 
-static void rmgr_cleanup(void)
+static void rmgr_cleanup(struct rmgr_ctrl *rmgr)
 {
-	if (!rmgr_init_done)
-		return;
-
-	rmgr_init_done = 0;
-
-	free(rmgr.slot);
-	rmgr.slot = NULL;
-	rmgr.size = 0;
+	free(rmgr->slot);
+	rmgr->slot = NULL;
+	rmgr->size = 0;
 }
 
 static int rmgr_set_location(struct cmd_context *ctx,
 			     struct ethtool_rx_flow_spec *fsp)
 {
+	struct rmgr_ctrl rmgr;
 	int err;
 
 	/* init table of available rules */
-	err = rmgr_init(ctx);
+	err = rmgr_init(ctx, &rmgr);
 	if (err < 0)
-		return err;
+		goto out;
 
 	/* verify rule location */
-	err = rmgr_find_empty_slot(fsp);
+	err = rmgr_find_empty_slot(&rmgr, fsp);
 
+out:
 	/* cleanup table and free resources */
-	rmgr_cleanup();
+	rmgr_cleanup(&rmgr);
 
 	return err;
 }
-- 
1.7.4.4



-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH ethtool 19/21] Declare static variables const as appropriate
  2011-11-01 22:35 [PATCH ethtool 00/21] ethtool refactoring and misc changes Ben Hutchings
                   ` (17 preceding siblings ...)
  2011-11-01 23:22 ` [PATCH ethtool 18/21] rxclass: Replace global rmgr with automatic variable/parameter Ben Hutchings
@ 2011-11-01 23:22 ` Ben Hutchings
  2011-11-01 23:23 ` [PATCH ethtool 20/21] Run tests in-process Ben Hutchings
                   ` (2 subsequent siblings)
  21 siblings, 0 replies; 24+ messages in thread
From: Ben Hutchings @ 2011-11-01 23:22 UTC (permalink / raw)
  To: netdev; +Cc: linux-net-drivers

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 ethtool.c |    4 ++--
 rxclass.c |    8 ++++----
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/ethtool.c b/ethtool.c
index 13fb0ef..8e757e9 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -104,7 +104,7 @@ static int do_permaddr(struct cmd_context *ctx);
 static int do_getfwdump(struct cmd_context *ctx);
 static int do_setfwdump(struct cmd_context *ctx);
 
-static struct option {
+static const struct option {
 	const char *opts;
 	int want_device;
 	int (*func)(struct cmd_context *);
@@ -965,7 +965,7 @@ static char *unparse_rxfhashopts(u64 opts)
 	return buf;
 }
 
-static struct {
+static const struct {
 	const char *name;
 	int (*func)(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
 
diff --git a/rxclass.c b/rxclass.c
index 3b23a33..1980d0e 100644
--- a/rxclass.c
+++ b/rxclass.c
@@ -533,7 +533,7 @@ struct rule_opts {
 	int		moffset;
 };
 
-static struct rule_opts rule_nfc_tcp_ip4[] = {
+static const struct rule_opts rule_nfc_tcp_ip4[] = {
 	{ "src-ip", OPT_IP4, NFC_FLAG_SADDR,
 	  offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip4_spec.ip4src),
 	  offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip4_spec.ip4src) },
@@ -564,7 +564,7 @@ static struct rule_opts rule_nfc_tcp_ip4[] = {
 	  offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
 };
 
-static struct rule_opts rule_nfc_esp_ip4[] = {
+static const struct rule_opts rule_nfc_esp_ip4[] = {
 	{ "src-ip", OPT_IP4, NFC_FLAG_SADDR,
 	  offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip4_spec.ip4src),
 	  offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip4_spec.ip4src) },
@@ -592,7 +592,7 @@ static struct rule_opts rule_nfc_esp_ip4[] = {
 	  offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
 };
 
-static struct rule_opts rule_nfc_usr_ip4[] = {
+static const struct rule_opts rule_nfc_usr_ip4[] = {
 	{ "src-ip", OPT_IP4, NFC_FLAG_SADDR,
 	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.ip4src),
 	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.ip4src) },
@@ -632,7 +632,7 @@ static struct rule_opts rule_nfc_usr_ip4[] = {
 	  offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
 };
 
-static struct rule_opts rule_nfc_ether[] = {
+static const struct rule_opts rule_nfc_ether[] = {
 	{ "src", OPT_MAC, NFC_FLAG_SADDR,
 	  offsetof(struct ethtool_rx_flow_spec, h_u.ether_spec.h_source),
 	  offsetof(struct ethtool_rx_flow_spec, m_u.ether_spec.h_source) },
-- 
1.7.4.4



-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH ethtool 20/21] Run tests in-process
  2011-11-01 22:35 [PATCH ethtool 00/21] ethtool refactoring and misc changes Ben Hutchings
                   ` (18 preceding siblings ...)
  2011-11-01 23:22 ` [PATCH ethtool 19/21] Declare static variables const as appropriate Ben Hutchings
@ 2011-11-01 23:23 ` Ben Hutchings
  2011-11-02 20:25   ` Ben Hutchings
  2011-11-01 23:24 ` [PATCH ethtool 21/21] Rearrange definitions and remove unnecessary forward declarations Ben Hutchings
  2011-11-03 19:17 ` [PATCH ethtool 00/21] ethtool refactoring and misc changes Ben Hutchings
  21 siblings, 1 reply; 24+ messages in thread
From: Ben Hutchings @ 2011-11-01 23:23 UTC (permalink / raw)
  To: netdev; +Cc: linux-net-drivers

Change definition of main() and use of exit() so that ethtool commands
can be tested without starting a new process.  This will allow deeper
testing that covers ioctl requests and responses.

Fix the obvious socket and memory leaks.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 Makefile.am    |    6 +---
 ethtool.c      |   25 +++++++++++++-------
 internal.h     |    5 ++++
 test-cmdline.c |    6 +++++
 test-common.c  |   65 +++++++++++++++++++++++++++++++------------------------
 5 files changed, 66 insertions(+), 41 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 4b0eb17..cfc2b79 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -12,11 +12,9 @@ ethtool_SOURCES = ethtool.c ethtool-copy.h internal.h \
 		  rxclass.c
 
 TESTS = test-cmdline
-check_PROGRAMS = test-cmdline test-one-cmdline
-test_cmdline_SOURCES = test-cmdline.c test-common.c
+check_PROGRAMS = test-cmdline
+test_cmdline_SOURCES = test-cmdline.c test-common.c $(ethtool_SOURCES) 
 test_cmdline_CFLAGS = -DTEST_ETHTOOL
-test_one_cmdline_SOURCES = $(ethtool_SOURCES)
-test_one_cmdline_CFLAGS = -DTEST_ETHTOOL
 
 dist-hook:
 	cp $(top_srcdir)/ethtool.spec $(distdir)
diff --git a/ethtool.c b/ethtool.c
index 8e757e9..f192376 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -259,7 +259,7 @@ static void exit_bad_args(void)
 	fprintf(stderr,
 		"ethtool: bad command line argument(s)\n"
 		"For more information run ethtool -h\n");
-	exit(1);
+	ethtool_exit(1);
 }
 
 static int show_usage(struct cmd_context *ctx)
@@ -2754,6 +2754,7 @@ static int do_grxfhindir(struct cmd_context *ctx)
 	err = send_ioctl(ctx, indir);
 	if (err < 0) {
 		perror("Cannot get RX flow hash indirection table");
+		free(indir);
 		return 103;
 	}
 
@@ -2766,6 +2767,8 @@ static int do_grxfhindir(struct cmd_context *ctx)
 		if (i % 8 == 7)
 			fputc('\n', stdout);
 	}
+
+	free(indir);
 	return 0;
 }
 
@@ -2817,14 +2820,16 @@ static int do_srxfhindir(struct cmd_context *ctx)
 		if (sum == 0) {
 			fprintf(stderr,
 				"At least one weight must be non-zero\n");
-			exit(1);
+			free(indir);
+			ethtool_exit(1);
 		}
 
 		if (sum > indir->size) {
 			fprintf(stderr,
 				"Total weight exceeds the size of the "
 				"indirection table\n");
-			exit(1);
+			free(indir);
+			ethtool_exit(1);
 		}
 
 		j = -1;
@@ -2844,6 +2849,7 @@ static int do_srxfhindir(struct cmd_context *ctx)
 		return 105;
 	}
 
+	free(indir);
 	return 0;
 }
 
@@ -3199,18 +3205,15 @@ static int do_setfwdump(struct cmd_context *ctx)
 	return 0;
 }
 
+#ifndef TEST_ETHTOOL
 int send_ioctl(struct cmd_context *ctx, void *cmd)
 {
-#ifndef TEST_ETHTOOL
 	ctx->ifr.ifr_data = cmd;
 	return ioctl(ctx->fd, SIOCETHTOOL, &ctx->ifr);
-#else
-	/* If we get this far then parsing succeeded */
-	exit(0);
-#endif
 }
+#endif
 
-int main(int argc, char **argp, char **envp)
+int ethtool_main(int argc, char **argp)
 {
 	int (*func)(struct cmd_context *);
 	int want_device;
@@ -3265,12 +3268,16 @@ opt_found:
 		memset(&ctx.ifr, 0, sizeof(ctx.ifr));
 		strcpy(ctx.ifr.ifr_name, ctx.devname);
 
+#ifndef TEST_ETHTOOL
 		/* Open control socket. */
 		ctx.fd = socket(AF_INET, SOCK_DGRAM, 0);
 		if (ctx.fd < 0) {
 			perror("Cannot get control socket");
 			return 70;
 		}
+#else
+		ctx.fd = -1;
+#endif
 	} else {
 		ctx.fd = -1;
 	}
diff --git a/internal.h b/internal.h
index cb126b3..8505396 100644
--- a/internal.h
+++ b/internal.h
@@ -98,7 +98,12 @@ struct cmd_context {
 };
 
 #ifdef TEST_ETHTOOL
+int ethtool_main(int argc, char **argp);
+void ethtool_exit(int rc) __attribute__((noreturn));
 int test_cmdline(const char *args);
+#else
+#define ethtool_main(...) main(__VA_ARGS__)
+#define ethtool_exit(rc) exit(rc)
 #endif
 
 int send_ioctl(struct cmd_context *ctx, void *cmd);
diff --git a/test-cmdline.c b/test-cmdline.c
index 7dd3b7c..df1aeed 100644
--- a/test-cmdline.c
+++ b/test-cmdline.c
@@ -213,6 +213,12 @@ static struct test_case {
 	{ 1, "-0" },
 };
 
+int send_ioctl(struct cmd_context *ctx, void *cmd)
+{
+	/* If we get this far then parsing succeeded */
+	ethtool_exit(0);
+}
+
 int main(void)
 {
 	struct test_case *tc;
diff --git a/test-common.c b/test-common.c
index 4ea84c8..5a06ac7 100644
--- a/test-common.c
+++ b/test-common.c
@@ -7,22 +7,27 @@
  * by the Free Software Foundation, incorporated herein by reference.
  */
 
+#include <setjmp.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/fcntl.h>
-#include <sys/wait.h>
 #include <unistd.h>
 #include "internal.h"
 
+static jmp_buf test_return;
+
+void ethtool_exit(int rc)
+{
+	longjmp(test_return, rc + 1);
+}
+
 int test_cmdline(const char *args)
 {
 	int argc, i;
 	char **argv;
 	const char *arg;
 	size_t len;
-	pid_t pid;
-	int dev_null;
-	int status;
+	int dev_null = -1, old_stdout = -1, old_stderr = -1;
 	int rc;
 
 	/* Convert line to argv */
@@ -56,35 +61,39 @@ int test_cmdline(const char *args)
 	}
 
 	fflush(NULL);
-	pid = fork();
-
-	/* Child */
-	if (pid == 0) {
-		dup2(dev_null, STDIN_FILENO);
-		if (!getenv("ETHTOOL_TEST_VERBOSE")) {
-			dup2(dev_null, STDOUT_FILENO);
-			dup2(dev_null, STDERR_FILENO);
+	dup2(dev_null, STDIN_FILENO);
+	if (!getenv("ETHTOOL_TEST_VERBOSE")) {
+		old_stdout = dup(STDOUT_FILENO);
+		if (old_stdout < 0) {
+			perror("dup stdout");
+			rc = -1;
+			goto out;
 		}
-		execv("./test-one-cmdline", argv);
-		_exit(126);
+		dup2(dev_null, STDOUT_FILENO);
+		old_stderr = dup(STDERR_FILENO);
+		if (old_stderr < 0) {
+			perror("dup stderr");
+			rc = -1;
+			goto out;
+		}
+		dup2(dev_null, STDERR_FILENO);
 	}
 
-	/* Parent */
-	if (pid < 0) {
-		perror("fork");
-		close(dev_null);
-		rc = -1;
-		goto out;
-	}
-	close(dev_null);
-	if (waitpid(pid, &status, 0) < 0) {
-		perror("waitpid");
-		rc = -1;
-		goto out;
-	}
-	rc = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
+	rc = setjmp(test_return);
+	rc = rc ? rc - 1 : ethtool_main(argc, argv);
 
 out:
+	fflush(NULL);
+	if (old_stderr >= 0) {
+		dup2(old_stderr, STDERR_FILENO);
+		close(old_stderr);
+	}
+	if (old_stdout >= 0) {
+		dup2(old_stdout, STDOUT_FILENO);
+		close(old_stdout);
+	}
+	if (dev_null >= 0)
+		close(dev_null);
 	for (i = 0; i < argc; i++)
 		free(argv[i]);
 	free(argv);
-- 
1.7.4.4



-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH ethtool 21/21] Rearrange definitions and remove unnecessary forward declarations
  2011-11-01 22:35 [PATCH ethtool 00/21] ethtool refactoring and misc changes Ben Hutchings
                   ` (19 preceding siblings ...)
  2011-11-01 23:23 ` [PATCH ethtool 20/21] Run tests in-process Ben Hutchings
@ 2011-11-01 23:24 ` Ben Hutchings
  2011-11-03 19:17 ` [PATCH ethtool 00/21] ethtool refactoring and misc changes Ben Hutchings
  21 siblings, 0 replies; 24+ messages in thread
From: Ben Hutchings @ 2011-11-01 23:24 UTC (permalink / raw)
  To: netdev; +Cc: linux-net-drivers

Most functions in ethtool.c are defined before use.  The major
exception is that the args array refers to a large number of functions
defined after it.  Move the args array and show_usage() functions down,
and move a few other functions up.

This leaves just one forward declaration in ethtool.c, which is
unavoidable because show_usage() and args refer to each other.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 ethtool.c |  447 ++++++++++++++++++++++++++++---------------------------------
 1 files changed, 204 insertions(+), 243 deletions(-)

diff --git a/ethtool.c b/ethtool.c
index f192376..d59ca31 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -64,194 +64,6 @@ enum {
 };
 #endif
 
-static int show_usage(struct cmd_context *ctx);
-static int do_version(struct cmd_context *ctx);
-static int parse_wolopts(char *optstr, u32 *data);
-static char *unparse_wolopts(int wolopts);
-static void get_mac_addr(char *src, unsigned char *dest);
-static int do_gdrv(struct cmd_context *ctx);
-static int do_gset(struct cmd_context *ctx);
-static int do_sset(struct cmd_context *ctx);
-static int do_gregs(struct cmd_context *ctx);
-static int do_nway_rst(struct cmd_context *ctx);
-static int do_geeprom(struct cmd_context *ctx);
-static int do_seeprom(struct cmd_context *ctx);
-static int do_test(struct cmd_context *ctx);
-static int do_phys_id(struct cmd_context *ctx);
-static int do_gpause(struct cmd_context *ctx);
-static int do_spause(struct cmd_context *ctx);
-static int do_gring(struct cmd_context *ctx);
-static int do_sring(struct cmd_context *ctx);
-static int do_schannels(struct cmd_context *ctx);
-static int do_gchannels(struct cmd_context *ctx);
-static int do_gcoalesce(struct cmd_context *ctx);
-static int do_scoalesce(struct cmd_context *ctx);
-static int do_goffload(struct cmd_context *ctx);
-static int do_soffload(struct cmd_context *ctx);
-static int do_gstats(struct cmd_context *ctx);
-static int rxflow_str_to_type(const char *str);
-static int parse_rxfhashopts(char *optstr, u32 *data);
-static char *unparse_rxfhashopts(u64 opts);
-static int dump_rxfhash(int fhash, u64 val);
-static int do_srxclass(struct cmd_context *ctx);
-static int do_grxclass(struct cmd_context *ctx);
-static int do_grxfhindir(struct cmd_context *ctx);
-static int do_srxfhindir(struct cmd_context *ctx);
-static int do_srxclsrule(struct cmd_context *ctx);
-static int do_grxclsrule(struct cmd_context *ctx);
-static int do_flash(struct cmd_context *ctx);
-static int do_permaddr(struct cmd_context *ctx);
-static int do_getfwdump(struct cmd_context *ctx);
-static int do_setfwdump(struct cmd_context *ctx);
-
-static const struct option {
-	const char *opts;
-	int want_device;
-	int (*func)(struct cmd_context *);
-	char *help;
-	char *opthelp;
-} args[] = {
-	{ "-s|--change", 1, do_sset, "Change generic options",
-	  "		[ speed %d ]\n"
-	  "		[ duplex half|full ]\n"
-	  "		[ port tp|aui|bnc|mii|fibre ]\n"
-	  "		[ autoneg on|off ]\n"
-	  "		[ advertise %x ]\n"
-	  "		[ phyad %d ]\n"
-	  "		[ xcvr internal|external ]\n"
-	  "		[ wol p|u|m|b|a|g|s|d... ]\n"
-	  "		[ sopass %x:%x:%x:%x:%x:%x ]\n"
-	  "		[ msglvl %d | msglvl type on|off ... ]\n" },
-	{ "-a|--show-pause", 1, do_gpause, "Show pause options" },
-	{ "-A|--pause", 1, do_spause, "Set pause options",
-	  "		[ autoneg on|off ]\n"
-	  "		[ rx on|off ]\n"
-	  "		[ tx on|off ]\n" },
-	{ "-c|--show-coalesce", 1, do_gcoalesce, "Show coalesce options" },
-	{ "-C|--coalesce", 1, do_scoalesce, "Set coalesce options",
-	  "		[adaptive-rx on|off]\n"
-	  "		[adaptive-tx on|off]\n"
-	  "		[rx-usecs N]\n"
-	  "		[rx-frames N]\n"
-	  "		[rx-usecs-irq N]\n"
-	  "		[rx-frames-irq N]\n"
-	  "		[tx-usecs N]\n"
-	  "		[tx-frames N]\n"
-	  "		[tx-usecs-irq N]\n"
-	  "		[tx-frames-irq N]\n"
-	  "		[stats-block-usecs N]\n"
-	  "		[pkt-rate-low N]\n"
-	  "		[rx-usecs-low N]\n"
-	  "		[rx-frames-low N]\n"
-	  "		[tx-usecs-low N]\n"
-	  "		[tx-frames-low N]\n"
-	  "		[pkt-rate-high N]\n"
-	  "		[rx-usecs-high N]\n"
-	  "		[rx-frames-high N]\n"
-	  "		[tx-usecs-high N]\n"
-	  "		[tx-frames-high N]\n"
-	  "		[sample-interval N]\n" },
-	{ "-g|--show-ring", 1, do_gring, "Query RX/TX ring parameters" },
-	{ "-G|--set-ring", 1, do_sring, "Set RX/TX ring parameters",
-	  "		[ rx N ]\n"
-	  "		[ rx-mini N ]\n"
-	  "		[ rx-jumbo N ]\n"
-	  "		[ tx N ]\n" },
-	{ "-k|--show-offload", 1, do_goffload,
-	  "Get protocol offload information" },
-	{ "-K|--offload", 1, do_soffload, "Set protocol offload",
-	  "		[ rx on|off ]\n"
-	  "		[ tx on|off ]\n"
-	  "		[ sg on|off ]\n"
-	  "		[ tso on|off ]\n"
-	  "		[ ufo on|off ]\n"
-	  "		[ gso on|off ]\n"
-	  "		[ gro on|off ]\n"
-	  "		[ lro on|off ]\n"
-	  "		[ rxvlan on|off ]\n"
-	  "		[ txvlan on|off ]\n"
-	  "		[ ntuple on|off ]\n"
-	  "		[ rxhash on|off ]\n"
-	},
-	{ "-i|--driver", 1, do_gdrv, "Show driver information" },
-	{ "-d|--register-dump", 1, do_gregs, "Do a register dump",
-	  "		[ raw on|off ]\n"
-	  "		[ file FILENAME ]\n" },
-	{ "-e|--eeprom-dump", 1, do_geeprom, "Do a EEPROM dump",
-	  "		[ raw on|off ]\n"
-	  "		[ offset N ]\n"
-	  "		[ length N ]\n" },
-	{ "-E|--change-eeprom", 1, do_seeprom,
-	  "Change bytes in device EEPROM",
-	  "		[ magic N ]\n"
-	  "		[ offset N ]\n"
-	  "		[ length N ]\n"
-	  "		[ value N ]\n" },
-	{ "-r|--negotiate", 1, do_nway_rst, "Restart N-WAY negotiation" },
-	{ "-p|--identify", 1, do_phys_id,
-	  "Show visible port identification (e.g. blinking)",
-	  "               [ TIME-IN-SECONDS ]\n" },
-	{ "-t|--test", 1, do_test, "Execute adapter self test",
-	  "               [ online | offline | external_lb ]\n" },
-	{ "-S|--statistics", 1, do_gstats, "Show adapter statistics" },
-	{ "-n|--show-nfc", 1, do_grxclass,
-	  "Show Rx network flow classification options",
-	  "		[ rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
-	  "tcp6|udp6|ah6|esp6|sctp6 ]\n" },
-	{ "-f|--flash", 1, do_flash,
-	  "Flash firmware image from the specified file to a region on the device",
-	  "               FILENAME [ REGION-NUMBER-TO-FLASH ]\n" },
-	{ "-N|--config-nfc", 1, do_srxclass,
-	  "Configure Rx network flow classification options",
-	  "		[ rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
-	  "tcp6|udp6|ah6|esp6|sctp6 m|v|t|s|d|f|n|r... ]\n" },
-	{ "-x|--show-rxfh-indir", 1, do_grxfhindir,
-	  "Show Rx flow hash indirection" },
-	{ "-X|--set-rxfh-indir", 1, do_srxfhindir,
-	  "Set Rx flow hash indirection",
-	  "		equal N | weight W0 W1 ...\n" },
-	{ "-U|--config-ntuple", 1, do_srxclsrule,
-	  "Configure Rx ntuple filters and actions",
-	  "		[ delete %d ] |\n"
-	  "		[ flow-type ether|ip4|tcp4|udp4|sctp4|ah4|esp4\n"
-	  "			[ src %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
-	  "			[ dst %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
-	  "			[ proto %d [m %x] ]\n"
-	  "			[ src-ip %d.%d.%d.%d [m %d.%d.%d.%d] ]\n"
-	  "			[ dst-ip %d.%d.%d.%d [m %d.%d.%d.%d] ]\n"
-	  "			[ tos %d [m %x] ]\n"
-	  "			[ l4proto %d [m %x] ]\n"
-	  "			[ src-port %d [m %x] ]\n"
-	  "			[ dst-port %d [m %x] ]\n"
-	  "			[ spi %d [m %x] ]\n"
-	  "			[ vlan-etype %x [m %x] ]\n"
-	  "			[ vlan %x [m %x] ]\n"
-	  "			[ user-def %x [m %x] ]\n"
-	  "			[ action %d ]\n"
-	  "			[ loc %d]]\n" },
-	{ "-u|--show-ntuple", 1, do_grxclsrule,
-	  "Get Rx ntuple filters and actions",
-	  "		[ rule %d ]\n"},
-	{ "-P|--show-permaddr", 1, do_permaddr,
-	  "Show permanent hardware address" },
-	{ "-w|--get-dump", 1, do_getfwdump,
-	  "Get dump flag, data",
-	  "		[ data FILENAME ]\n" },
-	{ "-W|--set-dump", 1, do_setfwdump,
-	  "Set dump flag of the device",
-	  "		N\n"},
-	{ "-l|--show-channels", 1, do_gchannels, "Query Channels" },
-	{ "-L|--set-channels", 1, do_schannels, "Set Channels",
-	  "               [ rx N ]\n"
-	  "               [ tx N ]\n"
-	  "               [ other N ]\n"
-	  "               [ combined N ]\n" },
-	{ "-h|--help", 0, show_usage, "Show this help" },
-	{ "--version", 0, do_version, "Show version number" },
-	{}
-};
-
-
 static void exit_bad_args(void) __attribute__((noreturn));
 
 static void exit_bad_args(void)
@@ -262,29 +74,6 @@ static void exit_bad_args(void)
 	ethtool_exit(1);
 }
 
-static int show_usage(struct cmd_context *ctx)
-{
-	int i;
-
-	/* ethtool -h */
-	fprintf(stdout, PACKAGE " version " VERSION "\n");
-	fprintf(stdout,
-		"Usage:\n"
-		"        ethtool DEVNAME\t"
-		"Display standard information about device\n");
-	for (i = 0; args[i].opts; i++) {
-		fputs("        ethtool ", stdout);
-		fprintf(stdout, "%s %s\t%s\n",
-			args[i].opts,
-			args[i].want_device ? "DEVNAME" : "\t",
-			args[i].help);
-		if (args[i].opthelp)
-			fputs(args[i].opthelp, stdout);
-	}
-
-	return 0;
-}
-
 typedef enum {
 	CMDL_NONE,
 	CMDL_BOOL,
@@ -379,6 +168,22 @@ static u32 get_u32(char *str, int base)
 	return get_uint_range(str, base, 0xffffffff);
 }
 
+static void get_mac_addr(char *src, unsigned char *dest)
+{
+	int count;
+	int i;
+	int buf[ETH_ALEN];
+
+	count = sscanf(src, "%2x:%2x:%2x:%2x:%2x:%2x",
+		&buf[0], &buf[1], &buf[2], &buf[3], &buf[4], &buf[5]);
+	if (count != ETH_ALEN)
+		exit_bad_args();
+
+	for (i = 0; i < count; i++) {
+		dest[i] = buf[i];
+	}
+}
+
 static void parse_generic_cmdline(struct cmd_context *ctx,
 				  int *changed,
 				  struct cmdline_info *info,
@@ -791,26 +596,6 @@ static int dump_drvinfo(struct ethtool_drvinfo *info)
 	return 0;
 }
 
-static int dump_wol(struct ethtool_wolinfo *wol)
-{
-	fprintf(stdout, "	Supports Wake-on: %s\n",
-		unparse_wolopts(wol->supported));
-	fprintf(stdout, "	Wake-on: %s\n",
-		unparse_wolopts(wol->wolopts));
-	if (wol->supported & WAKE_MAGICSECURE) {
-		int i;
-		int delim = 0;
-		fprintf(stdout, "        SecureOn password: ");
-		for (i = 0; i < SOPASS_MAX; i++) {
-			fprintf(stdout, "%s%02x", delim?":":"", wol->sopass[i]);
-			delim=1;
-		}
-		fprintf(stdout, "\n");
-	}
-
-	return 0;
-}
-
 static int parse_wolopts(char *optstr, u32 *data)
 {
 	*data = 0;
@@ -877,20 +662,24 @@ static char *unparse_wolopts(int wolopts)
 	return buf;
 }
 
-static void get_mac_addr(char *src, unsigned char *dest)
+static int dump_wol(struct ethtool_wolinfo *wol)
 {
-	int count;
-	int i;
-	int buf[ETH_ALEN];
-
-	count = sscanf(src, "%2x:%2x:%2x:%2x:%2x:%2x",
-		&buf[0], &buf[1], &buf[2], &buf[3], &buf[4], &buf[5]);
-	if (count != ETH_ALEN)
-		exit_bad_args();
-
-	for (i = 0; i < count; i++) {
-		dest[i] = buf[i];
+	fprintf(stdout, "	Supports Wake-on: %s\n",
+		unparse_wolopts(wol->supported));
+	fprintf(stdout, "	Wake-on: %s\n",
+		unparse_wolopts(wol->wolopts));
+	if (wol->supported & WAKE_MAGICSECURE) {
+		int i;
+		int delim = 0;
+		fprintf(stdout, "        SecureOn password: ");
+		for (i = 0; i < SOPASS_MAX; i++) {
+			fprintf(stdout, "%s%02x", delim?":":"", wol->sopass[i]);
+			delim=1;
+		}
+		fprintf(stdout, "\n");
 	}
+
+	return 0;
 }
 
 static int parse_rxfhashopts(char *optstr, u32 *data)
@@ -3213,6 +3002,178 @@ int send_ioctl(struct cmd_context *ctx, void *cmd)
 }
 #endif
 
+static int show_usage(struct cmd_context *ctx);
+
+static const struct option {
+	const char *opts;
+	int want_device;
+	int (*func)(struct cmd_context *);
+	char *help;
+	char *opthelp;
+} args[] = {
+	{ "-s|--change", 1, do_sset, "Change generic options",
+	  "		[ speed %d ]\n"
+	  "		[ duplex half|full ]\n"
+	  "		[ port tp|aui|bnc|mii|fibre ]\n"
+	  "		[ autoneg on|off ]\n"
+	  "		[ advertise %x ]\n"
+	  "		[ phyad %d ]\n"
+	  "		[ xcvr internal|external ]\n"
+	  "		[ wol p|u|m|b|a|g|s|d... ]\n"
+	  "		[ sopass %x:%x:%x:%x:%x:%x ]\n"
+	  "		[ msglvl %d | msglvl type on|off ... ]\n" },
+	{ "-a|--show-pause", 1, do_gpause, "Show pause options" },
+	{ "-A|--pause", 1, do_spause, "Set pause options",
+	  "		[ autoneg on|off ]\n"
+	  "		[ rx on|off ]\n"
+	  "		[ tx on|off ]\n" },
+	{ "-c|--show-coalesce", 1, do_gcoalesce, "Show coalesce options" },
+	{ "-C|--coalesce", 1, do_scoalesce, "Set coalesce options",
+	  "		[adaptive-rx on|off]\n"
+	  "		[adaptive-tx on|off]\n"
+	  "		[rx-usecs N]\n"
+	  "		[rx-frames N]\n"
+	  "		[rx-usecs-irq N]\n"
+	  "		[rx-frames-irq N]\n"
+	  "		[tx-usecs N]\n"
+	  "		[tx-frames N]\n"
+	  "		[tx-usecs-irq N]\n"
+	  "		[tx-frames-irq N]\n"
+	  "		[stats-block-usecs N]\n"
+	  "		[pkt-rate-low N]\n"
+	  "		[rx-usecs-low N]\n"
+	  "		[rx-frames-low N]\n"
+	  "		[tx-usecs-low N]\n"
+	  "		[tx-frames-low N]\n"
+	  "		[pkt-rate-high N]\n"
+	  "		[rx-usecs-high N]\n"
+	  "		[rx-frames-high N]\n"
+	  "		[tx-usecs-high N]\n"
+	  "		[tx-frames-high N]\n"
+	  "		[sample-interval N]\n" },
+	{ "-g|--show-ring", 1, do_gring, "Query RX/TX ring parameters" },
+	{ "-G|--set-ring", 1, do_sring, "Set RX/TX ring parameters",
+	  "		[ rx N ]\n"
+	  "		[ rx-mini N ]\n"
+	  "		[ rx-jumbo N ]\n"
+	  "		[ tx N ]\n" },
+	{ "-k|--show-offload", 1, do_goffload,
+	  "Get protocol offload information" },
+	{ "-K|--offload", 1, do_soffload, "Set protocol offload",
+	  "		[ rx on|off ]\n"
+	  "		[ tx on|off ]\n"
+	  "		[ sg on|off ]\n"
+	  "		[ tso on|off ]\n"
+	  "		[ ufo on|off ]\n"
+	  "		[ gso on|off ]\n"
+	  "		[ gro on|off ]\n"
+	  "		[ lro on|off ]\n"
+	  "		[ rxvlan on|off ]\n"
+	  "		[ txvlan on|off ]\n"
+	  "		[ ntuple on|off ]\n"
+	  "		[ rxhash on|off ]\n"
+	},
+	{ "-i|--driver", 1, do_gdrv, "Show driver information" },
+	{ "-d|--register-dump", 1, do_gregs, "Do a register dump",
+	  "		[ raw on|off ]\n"
+	  "		[ file FILENAME ]\n" },
+	{ "-e|--eeprom-dump", 1, do_geeprom, "Do a EEPROM dump",
+	  "		[ raw on|off ]\n"
+	  "		[ offset N ]\n"
+	  "		[ length N ]\n" },
+	{ "-E|--change-eeprom", 1, do_seeprom,
+	  "Change bytes in device EEPROM",
+	  "		[ magic N ]\n"
+	  "		[ offset N ]\n"
+	  "		[ length N ]\n"
+	  "		[ value N ]\n" },
+	{ "-r|--negotiate", 1, do_nway_rst, "Restart N-WAY negotiation" },
+	{ "-p|--identify", 1, do_phys_id,
+	  "Show visible port identification (e.g. blinking)",
+	  "               [ TIME-IN-SECONDS ]\n" },
+	{ "-t|--test", 1, do_test, "Execute adapter self test",
+	  "               [ online | offline | external_lb ]\n" },
+	{ "-S|--statistics", 1, do_gstats, "Show adapter statistics" },
+	{ "-n|--show-nfc", 1, do_grxclass,
+	  "Show Rx network flow classification options",
+	  "		[ rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
+	  "tcp6|udp6|ah6|esp6|sctp6 ]\n" },
+	{ "-f|--flash", 1, do_flash,
+	  "Flash firmware image from the specified file to a region on the device",
+	  "               FILENAME [ REGION-NUMBER-TO-FLASH ]\n" },
+	{ "-N|--config-nfc", 1, do_srxclass,
+	  "Configure Rx network flow classification options",
+	  "		[ rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
+	  "tcp6|udp6|ah6|esp6|sctp6 m|v|t|s|d|f|n|r... ]\n" },
+	{ "-x|--show-rxfh-indir", 1, do_grxfhindir,
+	  "Show Rx flow hash indirection" },
+	{ "-X|--set-rxfh-indir", 1, do_srxfhindir,
+	  "Set Rx flow hash indirection",
+	  "		equal N | weight W0 W1 ...\n" },
+	{ "-U|--config-ntuple", 1, do_srxclsrule,
+	  "Configure Rx ntuple filters and actions",
+	  "		[ delete %d ] |\n"
+	  "		[ flow-type ether|ip4|tcp4|udp4|sctp4|ah4|esp4\n"
+	  "			[ src %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
+	  "			[ dst %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
+	  "			[ proto %d [m %x] ]\n"
+	  "			[ src-ip %d.%d.%d.%d [m %d.%d.%d.%d] ]\n"
+	  "			[ dst-ip %d.%d.%d.%d [m %d.%d.%d.%d] ]\n"
+	  "			[ tos %d [m %x] ]\n"
+	  "			[ l4proto %d [m %x] ]\n"
+	  "			[ src-port %d [m %x] ]\n"
+	  "			[ dst-port %d [m %x] ]\n"
+	  "			[ spi %d [m %x] ]\n"
+	  "			[ vlan-etype %x [m %x] ]\n"
+	  "			[ vlan %x [m %x] ]\n"
+	  "			[ user-def %x [m %x] ]\n"
+	  "			[ action %d ]\n"
+	  "			[ loc %d]]\n" },
+	{ "-u|--show-ntuple", 1, do_grxclsrule,
+	  "Get Rx ntuple filters and actions",
+	  "		[ rule %d ]\n"},
+	{ "-P|--show-permaddr", 1, do_permaddr,
+	  "Show permanent hardware address" },
+	{ "-w|--get-dump", 1, do_getfwdump,
+	  "Get dump flag, data",
+	  "		[ data FILENAME ]\n" },
+	{ "-W|--set-dump", 1, do_setfwdump,
+	  "Set dump flag of the device",
+	  "		N\n"},
+	{ "-l|--show-channels", 1, do_gchannels, "Query Channels" },
+	{ "-L|--set-channels", 1, do_schannels, "Set Channels",
+	  "               [ rx N ]\n"
+	  "               [ tx N ]\n"
+	  "               [ other N ]\n"
+	  "               [ combined N ]\n" },
+	{ "-h|--help", 0, show_usage, "Show this help" },
+	{ "--version", 0, do_version, "Show version number" },
+	{}
+};
+
+static int show_usage(struct cmd_context *ctx)
+{
+	int i;
+
+	/* ethtool -h */
+	fprintf(stdout, PACKAGE " version " VERSION "\n");
+	fprintf(stdout,
+		"Usage:\n"
+		"        ethtool DEVNAME\t"
+		"Display standard information about device\n");
+	for (i = 0; args[i].opts; i++) {
+		fputs("        ethtool ", stdout);
+		fprintf(stdout, "%s %s\t%s\n",
+			args[i].opts,
+			args[i].want_device ? "DEVNAME" : "\t",
+			args[i].help);
+		if (args[i].opthelp)
+			fputs(args[i].opthelp, stdout);
+	}
+
+	return 0;
+}
+
 int ethtool_main(int argc, char **argp)
 {
 	int (*func)(struct cmd_context *);
-- 
1.7.4.4


-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: [PATCH ethtool 20/21] Run tests in-process
  2011-11-01 23:23 ` [PATCH ethtool 20/21] Run tests in-process Ben Hutchings
@ 2011-11-02 20:25   ` Ben Hutchings
  0 siblings, 0 replies; 24+ messages in thread
From: Ben Hutchings @ 2011-11-02 20:25 UTC (permalink / raw)
  To: netdev; +Cc: linux-net-drivers

On Tue, 2011-11-01 at 23:23 +0000, Ben Hutchings wrote:
> Change definition of main() and use of exit() so that ethtool commands
> can be tested without starting a new process.  This will allow deeper
> testing that covers ioctl requests and responses.
> 
> Fix the obvious socket and memory leaks.
[...]

Unfortunately there are more potential resource leaks than these.  I'll
defer this for now.

Ben.

-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH ethtool 00/21] ethtool refactoring and misc changes
  2011-11-01 22:35 [PATCH ethtool 00/21] ethtool refactoring and misc changes Ben Hutchings
                   ` (20 preceding siblings ...)
  2011-11-01 23:24 ` [PATCH ethtool 21/21] Rearrange definitions and remove unnecessary forward declarations Ben Hutchings
@ 2011-11-03 19:17 ` Ben Hutchings
  21 siblings, 0 replies; 24+ messages in thread
From: Ben Hutchings @ 2011-11-03 19:17 UTC (permalink / raw)
  To: netdev; +Cc: linux-net-drivers

I've pushed these changes, minus number 20, plus some additions
to .gitignore.

Ben.

-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2011-11-03 19:17 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-11-01 22:35 [PATCH ethtool 00/21] ethtool refactoring and misc changes Ben Hutchings
2011-11-01 23:13 ` [PATCH ethtool 01/21] Report pause frame autonegotiation result Ben Hutchings
2011-11-01 23:13 ` [PATCH ethtool 02/21] ethtool.8: Fix initial blank line/page Ben Hutchings
2011-11-01 23:14 ` [PATCH ethtool 03/21] Combine ethtool-{bitops,util}.h into internal.h Ben Hutchings
2011-11-01 23:14 ` [PATCH ethtool 04/21] Fix type of bit-number parameter to set_bit() and clear_bit() Ben Hutchings
2011-11-01 23:15 ` [PATCH ethtool 05/21] ethtool.8: Change device name metavariable from 'ethX' to 'devname' Ben Hutchings
2011-11-01 23:15 ` [PATCH ethtool 06/21] ethtool.8: Allow line-break in description of parameters after -N Ben Hutchings
2011-11-01 23:15 ` [PATCH ethtool 07/21] Fix format of help text for -f option Ben Hutchings
2011-11-01 23:15 ` [PATCH ethtool 08/21] Use standard indentation for definition of struct option args Ben Hutchings
2011-11-01 23:16 ` [PATCH ethtool 09/21] Encapsulate command context in a structure Ben Hutchings
2011-11-01 23:17 ` [PATCH ethtool 10/21] Add test cases for command-line parsing Ben Hutchings
2011-11-01 23:17 ` [PATCH ethtool 11/21] Add more " Ben Hutchings
2011-11-01 23:18 ` [PATCH ethtool 12/21] Move argument parsing to sub-command functions Ben Hutchings
2011-11-01 23:18 ` [PATCH ethtool 13/21] Support arbitrary numbers of option names for each mode Ben Hutchings
2011-11-01 23:18 ` [PATCH ethtool 14/21] Fix reference to cmdline_ring in do_schannels() Ben Hutchings
2011-11-01 23:19 ` [PATCH ethtool 15/21] Convert cmdline_msglvl into array of named flags; convert back at run-time Ben Hutchings
2011-11-01 23:20 ` [PATCH ethtool 16/21] Replace global devname variable with a field in struct cmd_context Ben Hutchings
2011-11-01 23:21 ` [PATCH ethtool 17/21] Change most static global variables into automatic variables Ben Hutchings
2011-11-01 23:22 ` [PATCH ethtool 18/21] rxclass: Replace global rmgr with automatic variable/parameter Ben Hutchings
2011-11-01 23:22 ` [PATCH ethtool 19/21] Declare static variables const as appropriate Ben Hutchings
2011-11-01 23:23 ` [PATCH ethtool 20/21] Run tests in-process Ben Hutchings
2011-11-02 20:25   ` Ben Hutchings
2011-11-01 23:24 ` [PATCH ethtool 21/21] Rearrange definitions and remove unnecessary forward declarations Ben Hutchings
2011-11-03 19:17 ` [PATCH ethtool 00/21] ethtool refactoring and misc changes Ben Hutchings

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).