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 <[EMAIL PROTECTED]> 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 [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html