Commit b533be18 authored by Maithili Hinge's avatar Maithili Hinge Committed by Kalle Valo

mwifiex: Add support for auto ARP in mwifiex.

This patch adds support for auto ARP feature in mwifiex.
The device will respond to ARP requests from the network
with ARP response in suspended state without waking up the host.
This feature is enabled in the driver by default.
Signed-off-by: default avatarMaithili Hinge <maithili@marvell.com>
Signed-off-by: default avatarAmitkumar Karwar <akarwar@marvell.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 2c11ab90
...@@ -2732,7 +2732,63 @@ mwifiex_is_pattern_supported(struct cfg80211_pkt_pattern *pat, s8 *byte_seq, ...@@ -2732,7 +2732,63 @@ mwifiex_is_pattern_supported(struct cfg80211_pkt_pattern *pat, s8 *byte_seq,
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int mwifiex_set_mef_filter(struct mwifiex_private *priv, static void mwifiex_set_auto_arp_mef_entry(struct mwifiex_private *priv,
struct mwifiex_mef_entry *mef_entry)
{
int i, filt_num = 0, num_ipv4 = 0;
struct in_device *in_dev;
struct in_ifaddr *ifa;
__be32 ips[MWIFIEX_MAX_SUPPORTED_IPADDR];
struct mwifiex_adapter *adapter = priv->adapter;
mef_entry->mode = MEF_MODE_HOST_SLEEP;
mef_entry->action = MEF_ACTION_AUTO_ARP;
/* Enable ARP offload feature */
memset(ips, 0, sizeof(ips));
for (i = 0; i < MWIFIEX_MAX_BSS_NUM; i++) {
if (adapter->priv[i]->netdev) {
in_dev = __in_dev_get_rtnl(adapter->priv[i]->netdev);
if (!in_dev)
continue;
ifa = in_dev->ifa_list;
if (!ifa || !ifa->ifa_local)
continue;
ips[i] = ifa->ifa_local;
num_ipv4++;
}
}
for (i = 0; i < num_ipv4; i++) {
if (!ips[i])
continue;
mef_entry->filter[filt_num].repeat = 1;
memcpy(mef_entry->filter[filt_num].byte_seq,
(u8 *)&ips[i], sizeof(ips[i]));
mef_entry->filter[filt_num].
byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] =
sizeof(ips[i]);
mef_entry->filter[filt_num].offset = 46;
mef_entry->filter[filt_num].filt_type = TYPE_EQ;
if (filt_num) {
mef_entry->filter[filt_num].filt_action =
TYPE_OR;
}
filt_num++;
}
mef_entry->filter[filt_num].repeat = 1;
mef_entry->filter[filt_num].byte_seq[0] = 0x08;
mef_entry->filter[filt_num].byte_seq[1] = 0x06;
mef_entry->filter[filt_num].byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] = 2;
mef_entry->filter[filt_num].offset = 20;
mef_entry->filter[filt_num].filt_type = TYPE_EQ;
mef_entry->filter[filt_num].filt_action = TYPE_AND;
}
static int mwifiex_set_wowlan_mef_entry(struct mwifiex_private *priv,
struct mwifiex_ds_mef_cfg *mef_cfg,
struct mwifiex_mef_entry *mef_entry,
struct cfg80211_wowlan *wowlan) struct cfg80211_wowlan *wowlan)
{ {
int i, filt_num = 0, ret = 0; int i, filt_num = 0, ret = 0;
...@@ -2740,16 +2796,7 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv, ...@@ -2740,16 +2796,7 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv,
u8 byte_seq[MWIFIEX_MEF_MAX_BYTESEQ + 1]; u8 byte_seq[MWIFIEX_MEF_MAX_BYTESEQ + 1];
const u8 ipv4_mc_mac[] = {0x33, 0x33}; const u8 ipv4_mc_mac[] = {0x33, 0x33};
const u8 ipv6_mc_mac[] = {0x01, 0x00, 0x5e}; const u8 ipv6_mc_mac[] = {0x01, 0x00, 0x5e};
struct mwifiex_ds_mef_cfg mef_cfg;
struct mwifiex_mef_entry *mef_entry;
mef_entry = kzalloc(sizeof(*mef_entry), GFP_KERNEL);
if (!mef_entry)
return -ENOMEM;
memset(&mef_cfg, 0, sizeof(mef_cfg));
mef_cfg.num_entries = 1;
mef_cfg.mef_entry = mef_entry;
mef_entry->mode = MEF_MODE_HOST_SLEEP; mef_entry->mode = MEF_MODE_HOST_SLEEP;
mef_entry->action = MEF_ACTION_ALLOW_AND_WAKEUP_HOST; mef_entry->action = MEF_ACTION_ALLOW_AND_WAKEUP_HOST;
...@@ -2766,20 +2813,19 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv, ...@@ -2766,20 +2813,19 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv,
if (!wowlan->patterns[i].pkt_offset) { if (!wowlan->patterns[i].pkt_offset) {
if (!(byte_seq[0] & 0x01) && if (!(byte_seq[0] & 0x01) &&
(byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] == 1)) { (byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] == 1)) {
mef_cfg.criteria |= MWIFIEX_CRITERIA_UNICAST; mef_cfg->criteria |= MWIFIEX_CRITERIA_UNICAST;
continue; continue;
} else if (is_broadcast_ether_addr(byte_seq)) { } else if (is_broadcast_ether_addr(byte_seq)) {
mef_cfg.criteria |= MWIFIEX_CRITERIA_BROADCAST; mef_cfg->criteria |= MWIFIEX_CRITERIA_BROADCAST;
continue; continue;
} else if ((!memcmp(byte_seq, ipv4_mc_mac, 2) && } else if ((!memcmp(byte_seq, ipv4_mc_mac, 2) &&
(byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] == 2)) || (byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] == 2)) ||
(!memcmp(byte_seq, ipv6_mc_mac, 3) && (!memcmp(byte_seq, ipv6_mc_mac, 3) &&
(byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] == 3))) { (byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] == 3))) {
mef_cfg.criteria |= MWIFIEX_CRITERIA_MULTICAST; mef_cfg->criteria |= MWIFIEX_CRITERIA_MULTICAST;
continue; continue;
} }
} }
mef_entry->filter[filt_num].repeat = 1; mef_entry->filter[filt_num].repeat = 1;
mef_entry->filter[filt_num].offset = mef_entry->filter[filt_num].offset =
wowlan->patterns[i].pkt_offset; wowlan->patterns[i].pkt_offset;
...@@ -2796,7 +2842,7 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv, ...@@ -2796,7 +2842,7 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv,
} }
if (wowlan->magic_pkt) { if (wowlan->magic_pkt) {
mef_cfg.criteria |= MWIFIEX_CRITERIA_UNICAST; mef_cfg->criteria |= MWIFIEX_CRITERIA_UNICAST;
mef_entry->filter[filt_num].repeat = 16; mef_entry->filter[filt_num].repeat = 16;
memcpy(mef_entry->filter[filt_num].byte_seq, priv->curr_addr, memcpy(mef_entry->filter[filt_num].byte_seq, priv->curr_addr,
ETH_ALEN); ETH_ALEN);
...@@ -2817,6 +2863,34 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv, ...@@ -2817,6 +2863,34 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv,
mef_entry->filter[filt_num].filt_type = TYPE_EQ; mef_entry->filter[filt_num].filt_type = TYPE_EQ;
mef_entry->filter[filt_num].filt_action = TYPE_OR; mef_entry->filter[filt_num].filt_action = TYPE_OR;
} }
return ret;
}
static int mwifiex_set_mef_filter(struct mwifiex_private *priv,
struct cfg80211_wowlan *wowlan)
{
int ret = 0, num_entries = 1;
struct mwifiex_ds_mef_cfg mef_cfg;
struct mwifiex_mef_entry *mef_entry;
if (wowlan->n_patterns || wowlan->magic_pkt)
num_entries++;
mef_entry = kcalloc(num_entries, sizeof(*mef_entry), GFP_KERNEL);
if (!mef_entry)
return -ENOMEM;
memset(&mef_cfg, 0, sizeof(mef_cfg));
mef_cfg.criteria |= MWIFIEX_CRITERIA_BROADCAST |
MWIFIEX_CRITERIA_UNICAST;
mef_cfg.num_entries = num_entries;
mef_cfg.mef_entry = mef_entry;
mwifiex_set_auto_arp_mef_entry(priv, &mef_entry[0]);
if (wowlan->n_patterns || wowlan->magic_pkt)
ret = mwifiex_set_wowlan_mef_entry(priv, &mef_cfg,
&mef_entry[1], wowlan);
if (!mef_cfg.criteria) if (!mef_cfg.criteria)
mef_cfg.criteria = MWIFIEX_CRITERIA_BROADCAST | mef_cfg.criteria = MWIFIEX_CRITERIA_BROADCAST |
...@@ -2824,8 +2898,8 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv, ...@@ -2824,8 +2898,8 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv,
MWIFIEX_CRITERIA_MULTICAST; MWIFIEX_CRITERIA_MULTICAST;
ret = mwifiex_send_cmd(priv, HostCmd_CMD_MEF_CFG, ret = mwifiex_send_cmd(priv, HostCmd_CMD_MEF_CFG,
HostCmd_ACT_GEN_SET, 0, &mef_cfg, true); HostCmd_ACT_GEN_SET, 0,
&mef_cfg, true);
kfree(mef_entry); kfree(mef_entry);
return ret; return ret;
} }
...@@ -2850,13 +2924,11 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, ...@@ -2850,13 +2924,11 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
return 0; return 0;
} }
if (wowlan->n_patterns || wowlan->magic_pkt) {
ret = mwifiex_set_mef_filter(priv, wowlan); ret = mwifiex_set_mef_filter(priv, wowlan);
if (ret) { if (ret) {
dev_err(adapter->dev, "Failed to set MEF filter\n"); dev_err(adapter->dev, "Failed to set MEF filter\n");
return ret; return ret;
} }
}
if (wowlan->disconnect) { if (wowlan->disconnect) {
memset(&hs_cfg, 0, sizeof(hs_cfg)); memset(&hs_cfg, 0, sizeof(hs_cfg));
......
...@@ -523,9 +523,11 @@ enum P2P_MODES { ...@@ -523,9 +523,11 @@ enum P2P_MODES {
#define TYPE_OR (MAX_OPERAND+5) #define TYPE_OR (MAX_OPERAND+5)
#define MEF_MODE_HOST_SLEEP 1 #define MEF_MODE_HOST_SLEEP 1
#define MEF_ACTION_ALLOW_AND_WAKEUP_HOST 3 #define MEF_ACTION_ALLOW_AND_WAKEUP_HOST 3
#define MEF_ACTION_AUTO_ARP 0x10
#define MWIFIEX_CRITERIA_BROADCAST BIT(0) #define MWIFIEX_CRITERIA_BROADCAST BIT(0)
#define MWIFIEX_CRITERIA_UNICAST BIT(1) #define MWIFIEX_CRITERIA_UNICAST BIT(1)
#define MWIFIEX_CRITERIA_MULTICAST BIT(3) #define MWIFIEX_CRITERIA_MULTICAST BIT(3)
#define MWIFIEX_MAX_SUPPORTED_IPADDR 4
#define ACT_TDLS_DELETE 0x00 #define ACT_TDLS_DELETE 0x00
#define ACT_TDLS_CREATE 0x01 #define ACT_TDLS_CREATE 0x01
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/idr.h> #include <linux/idr.h>
#include <linux/inetdevice.h>
#include "decl.h" #include "decl.h"
#include "ioctl.h" #include "ioctl.h"
......
...@@ -1370,22 +1370,29 @@ mwifiex_cmd_mef_cfg(struct mwifiex_private *priv, ...@@ -1370,22 +1370,29 @@ mwifiex_cmd_mef_cfg(struct mwifiex_private *priv,
struct mwifiex_ds_mef_cfg *mef) struct mwifiex_ds_mef_cfg *mef)
{ {
struct host_cmd_ds_mef_cfg *mef_cfg = &cmd->params.mef_cfg; struct host_cmd_ds_mef_cfg *mef_cfg = &cmd->params.mef_cfg;
struct mwifiex_fw_mef_entry *mef_entry = NULL;
u8 *pos = (u8 *)mef_cfg; u8 *pos = (u8 *)mef_cfg;
u16 i;
cmd->command = cpu_to_le16(HostCmd_CMD_MEF_CFG); cmd->command = cpu_to_le16(HostCmd_CMD_MEF_CFG);
mef_cfg->criteria = cpu_to_le32(mef->criteria); mef_cfg->criteria = cpu_to_le32(mef->criteria);
mef_cfg->num_entries = cpu_to_le16(mef->num_entries); mef_cfg->num_entries = cpu_to_le16(mef->num_entries);
pos += sizeof(*mef_cfg); pos += sizeof(*mef_cfg);
mef_cfg->mef_entry->mode = mef->mef_entry->mode;
mef_cfg->mef_entry->action = mef->mef_entry->action;
pos += sizeof(*(mef_cfg->mef_entry));
if (mwifiex_cmd_append_rpn_expression(priv, mef->mef_entry, &pos)) for (i = 0; i < mef->num_entries; i++) {
mef_entry = (struct mwifiex_fw_mef_entry *)pos;
mef_entry->mode = mef->mef_entry[i].mode;
mef_entry->action = mef->mef_entry[i].action;
pos += sizeof(*mef_cfg->mef_entry);
if (mwifiex_cmd_append_rpn_expression(priv,
&mef->mef_entry[i], &pos))
return -1; return -1;
mef_cfg->mef_entry->exprsize = mef_entry->exprsize =
cpu_to_le16(pos - mef_cfg->mef_entry->expr); cpu_to_le16(pos - mef_entry->expr);
}
cmd->size = cpu_to_le16((u16) (pos - (u8 *)mef_cfg) + S_DS_GEN); cmd->size = cpu_to_le16((u16) (pos - (u8 *)mef_cfg) + S_DS_GEN);
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment