summaryrefslogtreecommitdiff
path: root/ethtool.c
diff options
context:
space:
mode:
Diffstat (limited to 'ethtool.c')
-rw-r--r--ethtool.c105
1 files changed, 103 insertions, 2 deletions
diff --git a/ethtool.c b/ethtool.c
index f0c9d08..d21eaea 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -583,7 +583,8 @@ static int dump_drvinfo(struct ethtool_drvinfo *info)
"supports-statistics: %s\n"
"supports-test: %s\n"
"supports-eeprom-access: %s\n"
- "supports-register-dump: %s\n",
+ "supports-register-dump: %s\n"
+ "supports-priv-flags: %s\n",
info->driver,
info->version,
info->fw_version,
@@ -591,7 +592,8 @@ static int dump_drvinfo(struct ethtool_drvinfo *info)
info->n_stats ? "yes" : "no",
info->testinfo_len ? "yes" : "no",
info->eedump_len ? "yes" : "no",
- info->regdump_len ? "yes" : "no");
+ info->regdump_len ? "yes" : "no",
+ info->n_priv_flags ? "yes" : "no");
return 0;
}
@@ -3001,6 +3003,102 @@ static int do_setfwdump(struct cmd_context *ctx)
return 0;
}
+static int do_gprivflags(struct cmd_context *ctx)
+{
+ struct ethtool_gstrings *strings;
+ struct ethtool_value flags;
+ unsigned int i;
+
+ if (ctx->argc != 0)
+ exit_bad_args();
+
+ strings = get_stringset(ctx, ETH_SS_PRIV_FLAGS,
+ offsetof(struct ethtool_drvinfo, n_priv_flags));
+ if (!strings) {
+ perror("Cannot get private flag names");
+ return 1;
+ }
+ if (strings->len == 0) {
+ fprintf(stderr, "No private flags defined\n");
+ return 1;
+ }
+ if (strings->len > 32) {
+ /* ETHTOOL_GPFLAGS can only cover 32 flags */
+ fprintf(stderr, "Only showing first 32 private flags\n");
+ strings->len = 32;
+ }
+
+ flags.cmd = ETHTOOL_GPFLAGS;
+ if (send_ioctl(ctx, &flags)) {
+ perror("Cannot get private flags");
+ return 1;
+ }
+
+ printf("Private flags for %s:\n", ctx->devname);
+ for (i = 0; i < strings->len; i++)
+ printf("%s: %s\n",
+ (const char *)strings->data + i * ETH_GSTRING_LEN,
+ (flags.data & (1U << i)) ? "on" : "off");
+
+ return 0;
+}
+
+static int do_sprivflags(struct cmd_context *ctx)
+{
+ struct ethtool_gstrings *strings;
+ struct cmdline_info *cmdline;
+ struct ethtool_value flags;
+ u32 wanted_flags = 0, seen_flags = 0;
+ int any_changed;
+ unsigned int i;
+
+ strings = get_stringset(ctx, ETH_SS_PRIV_FLAGS,
+ offsetof(struct ethtool_drvinfo, n_priv_flags));
+ if (!strings) {
+ perror("Cannot get private flag names");
+ return 1;
+ }
+ if (strings->len == 0) {
+ fprintf(stderr, "No private flags defined\n");
+ return 1;
+ }
+ if (strings->len > 32) {
+ /* ETHTOOL_{G,S}PFLAGS can only cover 32 flags */
+ fprintf(stderr, "Only setting first 32 private flags\n");
+ strings->len = 32;
+ }
+
+ cmdline = calloc(strings->len, sizeof(*cmdline));
+ if (!cmdline) {
+ perror("Cannot parse arguments");
+ return 1;
+ }
+ for (i = 0; i < strings->len; i++) {
+ cmdline[i].name = ((const char *)strings->data +
+ i * ETH_GSTRING_LEN);
+ cmdline[i].type = CMDL_FLAG;
+ cmdline[i].wanted_val = &wanted_flags;
+ cmdline[i].flag_val = 1U << i;
+ cmdline[i].seen_val = &seen_flags;
+ }
+ parse_generic_cmdline(ctx, &any_changed, cmdline, strings->len);
+
+ flags.cmd = ETHTOOL_GPFLAGS;
+ if (send_ioctl(ctx, &flags)) {
+ perror("Cannot get private flags");
+ return 1;
+ }
+
+ flags.cmd = ETHTOOL_SPFLAGS;
+ flags.data = (flags.data & ~seen_flags) | wanted_flags;
+ if (send_ioctl(ctx, &flags)) {
+ perror("Cannot set private flags");
+ return 1;
+ }
+
+ return 0;
+}
+
int send_ioctl(struct cmd_context *ctx, void *cmd)
{
#ifndef TEST_ETHTOOL
@@ -3156,6 +3254,9 @@ static const struct option {
" [ tx N ]\n"
" [ other N ]\n"
" [ combined N ]\n" },
+ { "--show-priv-flags" , 1, do_gprivflags, "Query private flags" },
+ { "--set-priv-flags", 1, do_sprivflags, "Set private flags",
+ " FLAG on|off ...\n" },
{ "-h|--help", 0, show_usage, "Show this help" },
{ "--version", 0, do_version, "Show version number" },
{}