diff options
author | Shailendra Govardhan <shailen@marvell.com> | 2008-08-12 14:01:18 -0700 |
---|---|---|
committer | Deepak Saxena <dsaxena@laptop.org> | 2008-08-12 14:01:18 -0700 |
commit | 9b42ff8eb9564f72d12f64af100e17be8a0ee395 (patch) | |
tree | 31280df2497de47b14ed9a4f5cd446e2ba76a378 | |
parent | 327b50a26b2858d72bf20a208bd2b66133ae9b1c (diff) | |
download | lwn-9b42ff8eb9564f72d12f64af100e17be8a0ee395.tar.gz lwn-9b42ff8eb9564f72d12f64af100e17be8a0ee395.zip |
Add support for WOL signatures
This patch from Marvell adds support for enabling WOL based on
matching packet headers to signatures provided via the an iwpriv
call. See http://dev.laptop.org/ticket/6993 for details.
Signed-off-by: Shailendra Govardhan <shailen@marvell.com>
Signed-off-by: Deepak Saxena <dsaxena@laptop.org>
-rw-r--r-- | drivers/net/wireless/libertas/cmd.c | 20 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/cmd.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/defs.h | 9 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/ethtool.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/host.h | 8 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/hostcmd.h | 27 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/if_usb.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/ioctl.c | 394 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/ioctl.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/wext.c | 9 |
10 files changed, 473 insertions, 9 deletions
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index c5e3c9ce7f78..41f51a241eff 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -162,7 +162,8 @@ out: return ret; } -int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria) +int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria, + struct wol_config *p_wol_config) { struct cmd_ds_host_sleep cmd_config; int ret; @@ -172,10 +173,23 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria) cmd_config.gpio = priv->wol_gpio; cmd_config.gap = priv->wol_gap; + if (p_wol_config != NULL) { + memcpy((uint8_t *)&cmd_config.wol_conf, (uint8_t *)p_wol_config, + sizeof(struct wol_config)); + } else { + cmd_config.wol_conf.action = CMD_ACT_ACTION_NONE; + } + ret = lbs_cmd_with_response(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config); if (!ret) { - lbs_deb_cmd("Set WOL criteria to %x\n", criteria); - priv->wol_criteria = criteria; + if (criteria) { + lbs_deb_cmd("Set WOL criteria to %x\n", criteria); + priv->wol_criteria = criteria; + } else { + memcpy((uint8_t *) p_wol_config, + (uint8_t *)&cmd_config.wol_conf, + sizeof(struct wol_config)); + } } else { lbs_pr_info("HOST_SLEEP_CFG failed %d\n", ret); } diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index 0698a36f0308..12cb08950978 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -45,7 +45,8 @@ int lbs_mesh_config_send(struct lbs_private *priv, uint16_t action, uint16_t type); int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan); -int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria); +int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria, + struct wol_config *p_wol_config); int lbs_suspend(struct lbs_private *priv); int lbs_resume(struct lbs_private *priv); diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index 42a6db31cb3a..aef29041cb3b 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -149,6 +149,15 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define EHS_WAKE_ON_MAC_EVENT 0x0004 #define EHS_WAKE_ON_MULTICAST_DATA 0x0008 #define EHS_REMOVE_WAKEUP 0xFFFFFFFF +/* Wake rules for Host_Sleep_CFG command */ +#define WOL_RULE_INFRA_OR_IBSS 0x00 +#define WOL_RULE_MESH 0x10 +#define WOL_RULE_BC 0x01 +#define WOL_RULE_MC 0x08 +#define WOL_RULE_UC 0x02 +#define WOL_RULE_AND 0x01 +#define WOL_RULE_OR 0x02 +#define WOL_RULE_INVALID 0xFF /** Misc constants */ /* This section defines 802.11 specific contants */ diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c index cede0d22f881..97a692f13ec7 100644 --- a/drivers/net/wireless/libertas/ethtool.c +++ b/drivers/net/wireless/libertas/ethtool.c @@ -213,7 +213,7 @@ static int lbs_ethtool_set_wol(struct net_device *dev, if (wol->wolopts & WAKE_BCAST) criteria |= EHS_WAKE_ON_BROADCAST_DATA; if (wol->wolopts & WAKE_PHY) criteria |= EHS_WAKE_ON_MAC_EVENT; - return lbs_host_sleep_cfg(priv, criteria); + return lbs_host_sleep_cfg(priv, criteria, (struct wol_config *)NULL); } struct ethtool_ops lbs_ethtool_ops = { diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index f734b4bdb3ca..63f4dee33296 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -241,6 +241,14 @@ enum cmd_fwt_access_opts { CMD_ACT_FWT_ACCESS_TIME, }; +/* Define action or option for CMD_802_11_HOST_SLEEP_CFG */ +enum cmd_wol_cfg_opts { + CMD_ACT_ACTION_NONE = 0, + CMD_ACT_SET_WOL_RULE, + CMD_ACT_GET_WOL_RULE, + CMD_ACT_RESET_WOL_RULE, +}; + /* Define action or option for CMD_MESH_ACCESS */ enum cmd_mesh_access_opts { CMD_ACT_MESH_GET_TTL = 1, diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index cafa9a27fa5d..f2dad511bf04 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -566,13 +566,38 @@ struct MrvlIEtype_keyParamSet { u8 key[32]; }; +#define MAX_WOL_RULES 8 +#define MAX_WOL_SIG_LEN 4 + +struct host_wol_rule { + uint8_t rule_no; + uint8_t rule_ops; + __le16 sig_offset; + __le16 sig_length; + __le16 reserve; + uint8_t sig_mask[MAX_WOL_SIG_LEN]; + uint8_t signature[MAX_WOL_SIG_LEN]; +}; + +struct wol_config { + uint8_t action; + uint8_t pattern; + uint8_t no_rules_in_cmd; + uint8_t result; + struct host_wol_rule wol_filter_config[MAX_WOL_RULES]; +}; + + struct cmd_ds_host_sleep { struct cmd_header hdr; __le32 criteria; uint8_t gpio; - uint8_t gap; + uint16_t gap; + struct wol_config wol_conf; } __attribute__ ((packed)); + + struct cmd_ds_802_11_key_material { __le16 action; struct MrvlIEtype_keyParamSet keyParamSet[2]; diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index b4b1753113b4..dd2e6c2e9ee2 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -177,7 +177,8 @@ static void if_usb_setup_firmware(struct lbs_private *priv) priv->wol_gpio = 2; /* Wake via GPIO2... */ priv->wol_gap = 20; /* ... after 20ms */ - lbs_host_sleep_cfg(priv, EHS_WAKE_ON_UNICAST_DATA); + lbs_host_sleep_cfg(priv, EHS_WAKE_ON_UNICAST_DATA, + (struct wol_config *) NULL); wake_method.hdr.size = cpu_to_le16(sizeof(wake_method)); wake_method.action = cpu_to_le16(CMD_ACT_GET); diff --git a/drivers/net/wireless/libertas/ioctl.c b/drivers/net/wireless/libertas/ioctl.c index 83cc45474296..f09655e92eb6 100644 --- a/drivers/net/wireless/libertas/ioctl.c +++ b/drivers/net/wireless/libertas/ioctl.c @@ -1087,6 +1087,382 @@ out: return ret; } +static unsigned short str_to_byte_array(unsigned char *ptr, unsigned char **ep, + unsigned char *dst, int max_len) +{ + unsigned char nibble_high, nibble_low, c; + unsigned short int len = 0; + nibble_high = nibble_low = 0; + + while (isxdigit(*ptr) && len < max_len) { + if (isdigit(*ptr)) + nibble_high = *ptr - '0'; + else + nibble_high = (toupper(*ptr) - 'A') + 0x0A; + + ptr++; + + if (*ptr == ' ' || *ptr == '\t' || *ptr == '\0') { + *ep = (unsigned char *)ptr; + *dst = nibble_high; + len++; + return len; + } + nibble_high <<= 4; + if (isdigit(*ptr)) + nibble_low = *ptr - '0'; + else + nibble_low = (toupper(*ptr) - 'A') + 0x0A; + + c = nibble_high | nibble_low; + *dst = c; + dst++; + len++; + ptr++; + } + + if (ptr) + *ep = (unsigned char *)ptr; + return len; +} + +static int lbs_wol_config_ioctl(struct lbs_private *priv, struct ifreq *req, + int subcmd) +{ + + struct iwreq *wrq = (struct iwreq *)req; + int i, j, ret = 0; + int rule_no; + int len = wrq->u.data.length; + struct wol_config wol_rule; + unsigned char data[1024], *ptr; + unsigned char tmp[MAX_WOL_SIG_LEN]; + unsigned short sig_len, sig_mask_len, sig_offset; + struct host_wol_rule *p_rule; + ptr = &data[0]; + memset(&data[0], 0, sizeof(data)); + memset(&wol_rule, 0, sizeof(struct wol_config)); + + lbs_deb_enter(LBS_DEB_IOCTL); + if (copy_from_user(data, wrq->u.data.pointer, len)) { + lbs_deb_ioctl("WOL_CONFIG: Copy from user failed\n"); + ret = -EFAULT; + } + lbs_deb_ioctl("Received subcmd %d\n", subcmd); + + + switch (subcmd) { + case CMD_ACT_SET_WOL_RULE: + ptr = next_param(ptr); + if (!ptr) { + return -EINVAL; + } + + if (*ptr == 'b' || *ptr == 'B') { + wol_rule.pattern |= WOL_RULE_BC; + } else if (*ptr == 'm' || *ptr == 'M') { + wol_rule.pattern |= WOL_RULE_MC; + } else if (*ptr == 'u' || *ptr == 'U') { + wol_rule.pattern |= WOL_RULE_UC; + } else { + return -EINVAL; + } + ptr++; + + ptr = next_param(ptr); + if (!ptr) { + return -EINVAL; + } + + if (*ptr == 'm' || *ptr == 'M') { + wol_rule.pattern |= WOL_RULE_MESH; + ptr++; + } else { + wol_rule.pattern |= WOL_RULE_INFRA_OR_IBSS; + } + + lbs_deb_ioctl("Received WOL pattern %X\n", wol_rule.pattern); + + for (rule_no = 0; *ptr != (char)NULL || + rule_no < MAX_WOL_RULES; ptr++, rule_no++) { + + ptr = next_param(ptr); + if (!ptr) { + return -EINVAL; + } + + wol_rule.wol_filter_config[rule_no].rule_no = rule_no; + + if (*ptr == '0' && (*(ptr+1) == 'x' || + *(ptr+1) == 'X')) { + ptr += 2; + + memset(&tmp[0], 0, MAX_WOL_SIG_LEN); + sig_len = str_to_byte_array(ptr, &ptr, &tmp[0], + MAX_WOL_SIG_LEN); + if (0 == sig_len) { + return -EINVAL; + } + memcpy(&(wol_rule.wol_filter_config[rule_no] + .signature[0]), + &tmp[0], MAX_WOL_SIG_LEN); + + if (*ptr != '.') { + return -EINVAL; + } else { + ptr++; + } + + memset(&tmp[0], 0, MAX_WOL_SIG_LEN); + + sig_mask_len = str_to_byte_array(ptr, &ptr, + &tmp[0], MAX_WOL_SIG_LEN); + if (0 == sig_mask_len ) { + return -EINVAL; + } + + memcpy(&(wol_rule.wol_filter_config[rule_no]. + sig_mask[0]), &tmp[0], + MAX_WOL_SIG_LEN); + + if (*ptr != '@') { + return -EINVAL; + } else { + ptr++; + } + + memset(&tmp[0], 0, MAX_WOL_SIG_LEN); + + if (0 == str_to_byte_array(ptr, &ptr, + &tmp[0], 2)) { + return -EINVAL; + } + + if (0 != tmp[1]) { + sig_offset = ntohs(*(unsigned short *) + (&tmp[0])); + } else { + sig_offset = (unsigned short)tmp[0]; + } + + if (sig_offset > (IEEE80211_DATA_LEN - + MAX_WOL_SIG_LEN)) { + return -EINVAL; + } + + wol_rule.wol_filter_config[rule_no].sig_offset + = cpu_to_le16(sig_offset); + + if (sig_len < sig_mask_len) { + wol_rule.wol_filter_config[rule_no]. + sig_length = cpu_to_le16(sig_len); + } else { + wol_rule.wol_filter_config[rule_no]. + sig_length = cpu_to_le16(sig_mask_len); + } + + ptr = next_param(ptr); + if (!ptr) { + wol_rule.wol_filter_config[rule_no]. + rule_ops = WOL_RULE_INVALID; + rule_no++; + break; + } + + if ((*ptr == '|') && (*(ptr+1) == '|')) { + wol_rule.wol_filter_config[rule_no]. + rule_ops = WOL_RULE_OR; + ptr += 2; + } else if ((*ptr == '&') && + (*(ptr+1) == '&')) { + wol_rule.wol_filter_config[rule_no]. + rule_ops = WOL_RULE_AND; + ptr += 2; + } else { + return -EINVAL; + } + + } else { + return -EINVAL; + } + } + + wol_rule.no_rules_in_cmd = rule_no; + break; + + case CMD_ACT_GET_WOL_RULE: + + ptr = next_param(ptr); + if (!ptr) { + wol_rule.pattern = 0x00; + break; + } + + ptr = next_param(ptr); + if (ptr) { + if (*ptr == 'b' || *ptr == 'B') { + wol_rule.pattern |= WOL_RULE_BC; + } else if (*ptr == 'm' || *ptr == 'M') { + wol_rule.pattern |= WOL_RULE_MC; + } else if (*ptr == 'u' || *ptr == 'U') { + wol_rule.pattern |= WOL_RULE_UC; + } else { + wol_rule.pattern = 0x00; + } + ptr++; + + ptr = next_param(ptr); + if (!ptr ) { + break; + } + + if (*ptr == 'm' || *ptr == 'M') { + wol_rule.pattern |= WOL_RULE_MESH; + ptr++; + } else { + wol_rule.pattern |= WOL_RULE_INFRA_OR_IBSS; + } + } + break; + case CMD_ACT_RESET_WOL_RULE: + break; + default: + return -EINVAL; + } + wol_rule.action = subcmd; + lbs_deb_ioctl("Sending Command %02x for pattern %02x with %03d", + subcmd, wol_rule.pattern, wol_rule.no_rules_in_cmd); + lbs_deb_ioctl("no of rules\n"); + ret = lbs_host_sleep_cfg(priv, 0, &wol_rule); + lbs_deb_ioctl("Received response with %d return code and result %d\n", + ret, wol_rule.result); + + memset(&data[0], '\0', sizeof(data)); + ptr = &data[0]; + if (ret != 0) { + ptr += sprintf(ptr, "Command HOST_SLEEP_CFG Failed"); + *ptr = '\0'; + lbs_deb_ioctl("%s", ptr); + wrq->u.data.length = strlen(data); + ptr = &data[0]; + if (copy_to_user(wrq->u.data.pointer, (char *)ptr, + wrq->u.data.length)) { + lbs_deb_ioctl("WOL_CONFIG: Copy to user failed!\n"); + return -EFAULT; + } + lbs_deb_leave(LBS_DEB_IOCTL); + return ret; + } + switch (subcmd) { + case CMD_ACT_SET_WOL_RULE: + switch (wol_rule.result) { + case 0: + ptr += sprintf(ptr, "Command SET_WOL_RULE "); + ptr += sprintf(ptr, "successful\n"); + break; + case 1: + ptr += sprintf(ptr, "Command SET_WOL_RULE failed: Not"); + ptr += sprintf(ptr, " enough space for rules\n"); + break; + case 2: + ptr += sprintf(ptr, "Command SET_WOL_RULE failed:"); + ptr += sprintf(ptr, " rule already exists\n"); + break; + default: + ptr += sprintf(ptr, "Command SET_WOL_RULE failed:"); + ptr += sprintf(ptr, " Unknown Reason\n"); + break; + } + break; + case CMD_ACT_GET_WOL_RULE: + if (wol_rule.result == 1) { + ptr += sprintf(ptr, "Command GET_WOL_RULE failed:"); + ptr += sprintf(ptr, " Rule not found\n"); + } else if (wol_rule.pattern == 0 && wol_rule.result == 0) { + ptr += sprintf(ptr, "Total available free rule slot s"); + ptr += sprintf(ptr, " are %d\n", + wol_rule.no_rules_in_cmd); + } else { + ptr += sprintf(ptr, "Total %d Rules found for", + wol_rule.no_rules_in_cmd); + switch (wol_rule.pattern & 0xF0) { + case WOL_RULE_INFRA_OR_IBSS: + ptr += sprintf(ptr, " Infra or Ibss"); + break; + case WOL_RULE_MESH: + ptr += sprintf(ptr, " Mesh"); + break; + default: + break; + } + switch (wol_rule.pattern & 0x0F) { + case WOL_RULE_BC: + ptr += sprintf(ptr, " Broadcast Rule\n"); + break; + case WOL_RULE_MC: + ptr += sprintf(ptr, " Multicast Rule\n"); + break; + case WOL_RULE_UC: + ptr += sprintf(ptr, " Unicastcast Rule\n"); + break; + default: + break; + } + ptr += sprintf(ptr, "RuleNo\tSignature\tSig Mask\t"); + ptr += sprintf(ptr, "Location\tRule Op\n"); + i = 0; + for (i = 0; i < wol_rule.no_rules_in_cmd; i++) { + p_rule = &wol_rule.wol_filter_config[i]; + sig_len = le16_to_cpu(p_rule->sig_length); + ptr += sprintf(ptr, "%03d\t", p_rule->rule_no); + ptr += sprintf(ptr, "0X"); + for (j = 0; j < sig_len; j++) { + ptr += sprintf(ptr, "%02x", + (unsigned char)p_rule->signature[j]); + } + ptr += sprintf(ptr, "\t"); + ptr += sprintf(ptr, "0X"); + for (j = 0; j < sig_len; j++) { + ptr += sprintf(ptr, "%02x", + (unsigned char)p_rule->sig_mask[j]); + } + ptr += sprintf(ptr, "\t0X%04x\t\t", + le16_to_cpu(p_rule->sig_offset)); + if (p_rule->rule_ops == 2) { + ptr += sprintf(ptr, "OR\n"); + } else if (p_rule->rule_ops == 1) { + ptr += sprintf(ptr, "AND\n"); + } else { + ptr += sprintf(ptr, "Not Available\n"); + } + } + } + break; + case CMD_ACT_RESET_WOL_RULE: + if (wol_rule.result == 0) { + ptr += sprintf(ptr, " Reset Done\n"); + } else { + ptr += sprintf(ptr, " Reset Failed\n"); + } + + break; + } + + *ptr = '\0'; + + ptr = &data[0]; + lbs_deb_ioctl("%s", ptr); + wrq->u.data.length = strlen(data); + ptr = &data[0]; + if (copy_to_user(wrq->u.data.pointer, (char *)ptr, + wrq->u.data.length)) { + lbs_deb_ioctl("WOL_CONFIG: Copy to user failed!\n"); + return -EFAULT; + } + lbs_deb_leave(LBS_DEB_IOCTL); + return ret; +} + /** * @brief ioctl function - entry point * @@ -1240,12 +1616,26 @@ int lbs_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd) break; } break; - + case LBS_SET256CHAR_GET256CHAR: + switch ((int)wrq->u.data.flags) { + case LBS_SUBCMD_SET_WOL_RULE: + ret = lbs_wol_config_ioctl(priv, req, + CMD_ACT_SET_WOL_RULE); + break; + case LBS_SUBCMD_GET_WOL_RULE: + ret = lbs_wol_config_ioctl(priv, req, + CMD_ACT_GET_WOL_RULE); + break; + case LBS_SUBCMD_RESET_WOL_RULE: + ret = lbs_wol_config_ioctl(priv, req, + CMD_ACT_RESET_WOL_RULE); + break; + } + break; default: ret = -EINVAL; break; } - lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret); return ret; } diff --git a/drivers/net/wireless/libertas/ioctl.h b/drivers/net/wireless/libertas/ioctl.h index 811ecf23c69b..e296ab8005ba 100644 --- a/drivers/net/wireless/libertas/ioctl.h +++ b/drivers/net/wireless/libertas/ioctl.h @@ -42,9 +42,16 @@ #define LBS_SUBCMD_MESH_SET_LINK_COSTS 27 #define LBS_SUBCMD_MESH_GET_LINK_COSTS 28 + + #define LBS_SET_GET_SIXTEEN_INT (SIOCIWFIRSTPRIV + 29) #define LBS_LED_GPIO_CTRL 5 #define LBS_BCN_CTRL 6 #define LBS_LED_BEHAVIOR_CTRL 7 +#define LBS_SET256CHAR_GET256CHAR (SIOCIWFIRSTPRIV + 31) +#define LBS_SUBCMD_SET_WOL_RULE 1 +#define LBS_SUBCMD_GET_WOL_RULE 2 +#define LBS_SUBCMD_RESET_WOL_RULE 3 + int lbs_do_ioctl(struct net_device *dev, struct ifreq *req, int i); diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 74918ae8b718..0bd2fbf82d31 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -2205,6 +2205,7 @@ static const iw_handler mesh_wlan_handler[] = { #define INT_PARAM (IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1) #define INT16_PARAM (IW_PRIV_TYPE_INT | 16) #define CHAR128_PARAM (IW_PRIV_TYPE_CHAR | 128) +#define CHAR256_PARAM (IW_PRIV_TYPE_CHAR | 256) static const struct iw_priv_args lbs_private_args[] = { /* { cmd, set_args, get_args, name } */ @@ -2245,6 +2246,14 @@ static const struct iw_priv_args lbs_private_args[] = { { LBS_LED_GPIO_CTRL, INT16_PARAM, INT16_PARAM, "ledgpio"}, { LBS_BCN_CTRL, INT16_PARAM, INT16_PARAM, "bcn_control"}, { LBS_LED_BEHAVIOR_CTRL, INT16_PARAM, INT16_PARAM, "ledbhv"}, + { LBS_SET256CHAR_GET256CHAR, CHAR256_PARAM, CHAR256_PARAM, ""}, + {LBS_SUBCMD_SET_WOL_RULE, CHAR256_PARAM, CHAR256_PARAM, + "set_wol_rule"}, + {LBS_SUBCMD_GET_WOL_RULE, CHAR256_PARAM, CHAR256_PARAM, + "get_wol_rule"}, + {LBS_SUBCMD_RESET_WOL_RULE, CHAR256_PARAM, CHAR256_PARAM, + "reset_wol_rule"}, + }; |