summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShailendra Govardhan <shailen@marvell.com>2008-08-12 14:01:18 -0700
committerDeepak Saxena <dsaxena@laptop.org>2008-08-12 14:01:18 -0700
commit9b42ff8eb9564f72d12f64af100e17be8a0ee395 (patch)
tree31280df2497de47b14ed9a4f5cd446e2ba76a378
parent327b50a26b2858d72bf20a208bd2b66133ae9b1c (diff)
downloadlwn-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.c20
-rw-r--r--drivers/net/wireless/libertas/cmd.h3
-rw-r--r--drivers/net/wireless/libertas/defs.h9
-rw-r--r--drivers/net/wireless/libertas/ethtool.c2
-rw-r--r--drivers/net/wireless/libertas/host.h8
-rw-r--r--drivers/net/wireless/libertas/hostcmd.h27
-rw-r--r--drivers/net/wireless/libertas/if_usb.c3
-rw-r--r--drivers/net/wireless/libertas/ioctl.c394
-rw-r--r--drivers/net/wireless/libertas/ioctl.h7
-rw-r--r--drivers/net/wireless/libertas/wext.c9
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"},
+
};