diff -urpN ethtool-4/ethtool.c ethtool-4-ff/ethtool.c --- ethtool-4/ethtool.c 2006-07-18 19:21:38.000000000 -0700 +++ ethtool-4-ff/ethtool.c 2006-08-21 14:12:02.000000000 -0700 @@ -65,6 +65,9 @@ static int do_scoalesce(int fd, struct i 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, @@ -86,6 +89,8 @@ static enum { MODE_GOFFLOAD, MODE_SOFFLOAD, MODE_GSTATS, + MODE_GFILTER, + MODE_SFILTER, } mode = MODE_GSET; static struct option { @@ -162,6 +167,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" }, {} }; @@ -255,6 +262,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]; +static int filter_len = 0; static enum { ONLINE=0, OFFLINE, @@ -407,6 +418,8 @@ static void parse_cmdline(int argc, char (mode == MODE_GOFFLOAD) || (mode == MODE_SOFFLOAD) || (mode == MODE_GSTATS) || + (mode == MODE_GFILTER) || + (mode == MODE_SFILTER) || (mode == MODE_PHYS_ID)) { devname = argp[i]; break; @@ -486,6 +499,26 @@ static void parse_cmdline(int argc, char 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")) { @@ -865,6 +898,9 @@ static int parse_wolopts(char *optstr, u case 's': *data |= WAKE_MAGICSECURE; break; + case 'f': + *data |= WAKE_FILTER; + break; case 'd': *data = 0; break; @@ -896,6 +932,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 { @@ -905,6 +943,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 = 0x100; + 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] & 0xFF00) + 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; @@ -1185,6 +1292,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; @@ -1813,6 +1924,46 @@ static int do_seeprom(int fd, struct 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 * 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 * 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; diff -urpN ethtool-4/ethtool-copy.h ethtool-4-ff/ethtool-copy.h --- ethtool-4/ethtool-copy.h 2006-07-18 19:21:38.000000000 -0700 +++ ethtool-4-ff/ethtool-copy.h 2006-08-16 11:16:43.000000000 -0700 @@ -52,9 +52,19 @@ struct ethtool_wolinfo { u32 cmd; u32 supported; u32 wolopts; + u32 n_filters; u8 sopass[SOPASS_MAX]; /* SecureOn(tm) password */ }; +#define WOL_FILTER_MAX 256 +/* 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; @@ -285,6 +295,8 @@ struct ethtool_stats { #define ETHTOOL_STSO 0x0000001f /* Set TSO enable (ethtool_value) */ #define ETHTOOL_GUFO 0x00000021 /* Get UFO enable (ethtool_value) */ #define ETHTOOL_SUFO 0x00000022 /* Set UFO enable (ethtool_value) */ +#define ETHTOOL_GWOLFILTER 0x00000025 /* Get WOL flex filter */ +#define ETHTOOL_SWOLFILTER 0x00000026 /* Set WOL flex filter */ /* compatibility with older code */ #define SPARC_ETH_GSET ETHTOOL_GSET @@ -364,5 +376,6 @@ struct ethtool_stats { #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 */