[<prev] [next>] [day] [month] [year] [list]
Message-Id: <1201640536.11148.34.camel@strongmad.jf.intel.com>
Date: Tue, 29 Jan 2008 13:02:16 -0800
From: Mitch Williams <mitch.a.williams@...el.com>
To: netdev@...r.kernel.org
Cc: jgarzik@...ox.com, davem@...emloft.net
Subject: [PATCH 3/3] Add flexible wake filter support to ethtool-6
Add support for Wake-on-Lan flexible filters to ethtool.To set a filter:
$ ethtool -F ethx <filter num> <filter spec>
where <filter spec> is a string of hex digits (or xx for ignore)
describing bytes from the beginning of the expected packet.
For example: $ ethtool -F eth0 0 00a055667788xxxx449976xx32
To show a filter:
$ ethtool -f ethx <filter num>
Signed-off-by: Mitch Williams <mitch.a.williams@...el.com>
diff --git a/ethtool-copy.h b/ethtool-copy.h
index 3a63224..dbad8dc 100644
--- a/ethtool-copy.h
+++ b/ethtool-copy.h
@@ -55,6 +55,16 @@ struct ethtool_wolinfo {
__u8 sopass[SOPASS_MAX]; /* SecureOn(tm) password */
};
+#define WOL_FILTER_MAX_LEN 256
+#define WOL_FILTER_IGNORE_OCTET 0x100
+/* wake-on-lan flexible filters */
+struct ethtool_wol_filter {
+ u32 cmd;
+ u32 index;
+ u32 len;
+ u16 mask_val[0];
+};
+
/* for passing single values */
struct ethtool_value {
__u32 cmd;
@@ -414,6 +424,9 @@ struct ethtool_ops {
#define ETHTOOL_SUFO 0x00000022 /* Set UFO enable (ethtool_value) */
#define ETHTOOL_GGSO 0x00000023 /* Get GSO enable (ethtool_value) */
#define ETHTOOL_SGSO 0x00000024 /* Set GSO enable (ethtool_value) */
+#define ETHTOOL_GNUMWOLFILT 0x00000029
+#define ETHTOOL_GWOLFILTER 0x0000002a /* Get WOL flex filter */
+#define ETHTOOL_SWOLFILTER 0x0000002b /* Set WOL flex filter */
/* compatibility with older code */
#define SPARC_ETH_GSET ETHTOOL_GSET
@@ -500,5 +513,6 @@ struct ethtool_ops {
#define WAKE_ARP (1 << 4)
#define WAKE_MAGIC (1 << 5)
#define WAKE_MAGICSECURE (1 << 6) /* only meaningful if WAKE_MAGIC */
+#define WAKE_FILTER (1 << 7)
#endif /* _LINUX_ETHTOOL_H */
diff --git a/ethtool.c b/ethtool.c
index a668b49..febd7e6 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -69,6 +69,9 @@ 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_gwolfilter(int fd, struct ifreq *ifr);
+static int do_swolfilter(int fd, struct ifreq *ifr);
+static void parse_filter(char *cmdline);
static enum {
MODE_HELP = -1,
@@ -90,6 +93,8 @@ static enum {
MODE_GOFFLOAD,
MODE_SOFFLOAD,
MODE_GSTATS,
+ MODE_GFILTER,
+ MODE_SFILTER,
} mode = MODE_GSET;
static struct option {
@@ -170,6 +175,8 @@ static struct option {
{ "-t", "--test", MODE_TEST, "Execute adapter self test",
" [ online | offline ]\n" },
{ "-S", "--statistics", MODE_GSTATS, "Show adapter statistics" },
+ { "-f", "--show-filter", MODE_GFILTER, "Show WOL filter N\n"},
+ { "-F", "--change-filter", MODE_SFILTER, "Set WOL filter N\n"},
{ "-h", "--help", MODE_HELP, "Show this help" },
{}
};
@@ -266,6 +273,10 @@ static int seeprom_changed = 0;
static int seeprom_magic = 0;
static int seeprom_offset = -1;
static int seeprom_value = 0;
+static int gfilter_num = 0;
+static int sfilter_num = 0;
+static u16 filter[WOL_FILTER_MAX_LEN];
+static int filter_len = 0;
static enum {
ONLINE=0,
OFFLINE,
@@ -430,6 +441,8 @@ static void parse_cmdline(int argc, char **argp)
(mode == MODE_GOFFLOAD) ||
(mode == MODE_SOFFLOAD) ||
(mode == MODE_GSTATS) ||
+ (mode == MODE_GFILTER) ||
+ (mode == MODE_SFILTER) ||
(mode == MODE_PHYS_ID)) {
devname = argp[i];
break;
@@ -509,6 +522,26 @@ static void parse_cmdline(int argc, char **argp)
i = argc;
break;
}
+ if (mode == MODE_GFILTER) {
+ long v;
+ v = strtol(argp[i], NULL, 0);
+ if (v < 0)
+ show_usage(1);
+ gfilter_num = (int) v;
+ break;
+ }
+ if (mode == MODE_SFILTER) {
+ long v;
+ v = strtol(argp[i], NULL, 0);
+ if (v < 0)
+ show_usage(1);
+ sfilter_num = (int) v;
+ i += 1;
+ if (i >= argc)
+ show_usage(1);
+ parse_filter(argp[i]);
+ break;
+ }
if (mode != MODE_SSET)
show_usage(1);
if (!strcmp(argp[i], "speed")) {
@@ -942,6 +975,9 @@ static int parse_wolopts(char *optstr, u32 *data)
case 's':
*data |= WAKE_MAGICSECURE;
break;
+ case 'f':
+ *data |= WAKE_FILTER;
+ break;
case 'd':
*data = 0;
break;
@@ -973,6 +1009,8 @@ static char *unparse_wolopts(int wolopts)
*p++ = 'a';
if (wolopts & WAKE_MAGIC)
*p++ = 'g';
+ if (wolopts & WAKE_FILTER)
+ *p++ = 'f';
if (wolopts & WAKE_MAGICSECURE)
*p++ = 's';
} else {
@@ -982,6 +1020,75 @@ static char *unparse_wolopts(int wolopts)
return buf;
}
+static void parse_filter(char *cmdline)
+{
+ int i = 0;
+ int j = 0;
+ u16 temp = 0;
+ while (i < strlen(cmdline)) {
+ if (i & 1) /* i is odd */
+ temp = temp << 4;
+ else
+ temp = 0;
+
+ switch (cmdline[i]) {
+ case '0' ... '9':
+ temp |= (cmdline[i] - '0');
+ break;
+ case 'a' ... 'f':
+ temp |= (cmdline[i] - 'a' + 0xa);
+ break;
+ case 'A' ... 'F':
+ temp |= (cmdline[i] - 'A' + 0xa);
+ break;
+ case 'X':
+ case 'x':
+ if (i & 1)
+ show_usage(1);
+ i++;
+ if ((cmdline[i] != 'x') && (cmdline[i] != 'X'))
+ show_usage(1);
+ temp = WOL_FILTER_IGNORE_OCTET;
+ break;
+ default:
+ show_usage(1);
+ break;
+ } /* switch */
+ if (i & 1) {
+ filter[j++] = temp;
+ }
+ i++;
+ }
+ filter_len = j;
+}
+
+static int dump_wol_filter(struct ethtool_wol_filter *wolfilt)
+{
+ int i = 0;
+ u16 *mask_val;
+
+ mask_val = (u16 *)((void *)wolfilt + sizeof(struct ethtool_wol_filter));
+
+ fprintf(stdout, "Wake-on-LAN filter %d, length %d\n",wolfilt->index, wolfilt->len);
+ if (wolfilt->mask_val[i] & WOL_FILTER_IGNORE_OCTET)
+ fprintf(stdout, "\txx");
+ else
+ fprintf(stdout, "\t%2.2x", wolfilt->mask_val[i]);
+ for (i = 1; i < wolfilt->len; i++) {
+ if (wolfilt->mask_val[i] & 0xFF00)
+ fprintf(stdout, ":xx");
+ else
+ fprintf(stdout, ":%2.2x", wolfilt->mask_val[i]);
+ if ((i % 22) == 0)
+ fprintf(stdout, "\n\t");
+ }
+
+ fprintf(stdout, "\n");
+
+ return 0;
+}
+
+
static int parse_sopass(char *src, unsigned char *dest)
{
int count;
@@ -1289,6 +1396,10 @@ static int doit(void)
return do_soffload(fd, &ifr);
} else if (mode == MODE_GSTATS) {
return do_gstats(fd, &ifr);
+ } else if (mode == MODE_GFILTER) {
+ return do_gwolfilter(fd, &ifr);
+ } else if (mode == MODE_SFILTER) {
+ return do_swolfilter(fd, &ifr);
}
return 69;
@@ -1653,6 +1764,7 @@ static int do_gset(int fd, struct ifreq *ifr)
int err;
struct ethtool_cmd ecmd;
struct ethtool_wolinfo wolinfo;
+ struct ethtool_wol_filter wolfilt;
struct ethtool_value edata;
int allfail = 1;
@@ -1682,6 +1794,18 @@ static int do_gset(int fd, struct ifreq *ifr)
perror("Cannot get wake-on-lan settings");
}
+ if (wolinfo.supported | WAKE_FILTER) {
+ wolfilt.cmd = ETHTOOL_GNUMWOLFILT;
+ ifr->ifr_data = (caddr_t)&wolfilt;
+ err = ioctl(fd, SIOCETHTOOL, ifr);
+ if (err == 0) {
+ fprintf(stdout, " Wake filters supported: %d\n", wolfilt.index);
+ allfail = 0;
+ } else {
+ perror("Cannot get wake filter settings");
+ }
+ }
+
edata.cmd = ETHTOOL_GMSGLVL;
ifr->ifr_data = (caddr_t)&edata;
err = ioctl(fd, SIOCETHTOOL, ifr);
@@ -1940,6 +2064,46 @@ static int do_seeprom(int fd, struct ifreq *ifr)
return err;
}
+static int do_gwolfilter(int fd, struct ifreq *ifr)
+{
+ int err;
+ struct ethtool_wol_filter *gfilter;
+
+ gfilter = calloc(1, sizeof(struct ethtool_wol_filter)+ WOL_FILTER_MAX_LEN * 2);
+ if (!gfilter) {
+ perror("Cannot allocate memory for filter data");
+ return 75;
+ }
+ gfilter->cmd = ETHTOOL_GWOLFILTER;
+ gfilter->index = gfilter_num;
+ ifr->ifr_data = (caddr_t)gfilter;
+ err = ioctl(fd, SIOCETHTOOL, ifr);
+ dump_wol_filter(gfilter);
+ free(gfilter);
+ return err;
+}
+
+static int do_swolfilter(int fd, struct ifreq *ifr)
+{
+ int err;
+ struct ethtool_wol_filter *sfilter;
+
+ sfilter = calloc(1, sizeof(*sfilter)+ WOL_FILTER_MAX_LEN * 2);
+ if (!filter) {
+ perror("Cannot allocate memory for filter data");
+ return 75;
+ }
+ sfilter->cmd = ETHTOOL_SWOLFILTER;
+ sfilter->index = sfilter_num;
+ sfilter->len = filter_len;
+ memcpy((void *)sfilter + sizeof(struct ethtool_wol_filter), filter, filter_len * 2);
+ ifr->ifr_data = (caddr_t)sfilter;
+ err = ioctl(fd, SIOCETHTOOL, ifr);
+ free(sfilter);
+ return err;
+}
+
+
static int do_test(int fd, struct ifreq *ifr)
{
int err;
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists