aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/mwifiex
diff options
context:
space:
mode:
authorMaithili Hinge <maithili@marvell.com>2015-03-12 03:38:39 -0400
committerKalle Valo <kvalo@codeaurora.org>2015-03-16 12:04:59 -0400
commitb533be189732e93c6d3306773b7120722568444d (patch)
tree135c765adbfa11f2f56b76d8ffb1d861b25bd66d /drivers/net/wireless/mwifiex
parent2c11ab90067a8bb9d7dca3e65ace950fcd9c2f1b (diff)
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: Maithili Hinge <maithili@marvell.com> Signed-off-by: Amitkumar Karwar <akarwar@marvell.com> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Diffstat (limited to 'drivers/net/wireless/mwifiex')
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c120
-rw-r--r--drivers/net/wireless/mwifiex/fw.h2
-rw-r--r--drivers/net/wireless/mwifiex/main.h1
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmd.c21
4 files changed, 113 insertions, 31 deletions
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index 8e1f681f960b..b0778a699bbc 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -2732,24 +2732,71 @@ mwifiex_is_pattern_supported(struct cfg80211_pkt_pattern *pat, s8 *byte_seq,
2732} 2732}
2733 2733
2734#ifdef CONFIG_PM 2734#ifdef CONFIG_PM
2735static int mwifiex_set_mef_filter(struct mwifiex_private *priv, 2735static void mwifiex_set_auto_arp_mef_entry(struct mwifiex_private *priv,
2736 struct cfg80211_wowlan *wowlan) 2736 struct mwifiex_mef_entry *mef_entry)
2737{
2738 int i, filt_num = 0, num_ipv4 = 0;
2739 struct in_device *in_dev;
2740 struct in_ifaddr *ifa;
2741 __be32 ips[MWIFIEX_MAX_SUPPORTED_IPADDR];
2742 struct mwifiex_adapter *adapter = priv->adapter;
2743
2744 mef_entry->mode = MEF_MODE_HOST_SLEEP;
2745 mef_entry->action = MEF_ACTION_AUTO_ARP;
2746
2747 /* Enable ARP offload feature */
2748 memset(ips, 0, sizeof(ips));
2749 for (i = 0; i < MWIFIEX_MAX_BSS_NUM; i++) {
2750 if (adapter->priv[i]->netdev) {
2751 in_dev = __in_dev_get_rtnl(adapter->priv[i]->netdev);
2752 if (!in_dev)
2753 continue;
2754 ifa = in_dev->ifa_list;
2755 if (!ifa || !ifa->ifa_local)
2756 continue;
2757 ips[i] = ifa->ifa_local;
2758 num_ipv4++;
2759 }
2760 }
2761
2762 for (i = 0; i < num_ipv4; i++) {
2763 if (!ips[i])
2764 continue;
2765 mef_entry->filter[filt_num].repeat = 1;
2766 memcpy(mef_entry->filter[filt_num].byte_seq,
2767 (u8 *)&ips[i], sizeof(ips[i]));
2768 mef_entry->filter[filt_num].
2769 byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] =
2770 sizeof(ips[i]);
2771 mef_entry->filter[filt_num].offset = 46;
2772 mef_entry->filter[filt_num].filt_type = TYPE_EQ;
2773 if (filt_num) {
2774 mef_entry->filter[filt_num].filt_action =
2775 TYPE_OR;
2776 }
2777 filt_num++;
2778 }
2779
2780 mef_entry->filter[filt_num].repeat = 1;
2781 mef_entry->filter[filt_num].byte_seq[0] = 0x08;
2782 mef_entry->filter[filt_num].byte_seq[1] = 0x06;
2783 mef_entry->filter[filt_num].byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] = 2;
2784 mef_entry->filter[filt_num].offset = 20;
2785 mef_entry->filter[filt_num].filt_type = TYPE_EQ;
2786 mef_entry->filter[filt_num].filt_action = TYPE_AND;
2787}
2788
2789static int mwifiex_set_wowlan_mef_entry(struct mwifiex_private *priv,
2790 struct mwifiex_ds_mef_cfg *mef_cfg,
2791 struct mwifiex_mef_entry *mef_entry,
2792 struct cfg80211_wowlan *wowlan)
2737{ 2793{
2738 int i, filt_num = 0, ret = 0; 2794 int i, filt_num = 0, ret = 0;
2739 bool first_pat = true; 2795 bool first_pat = true;
2740 u8 byte_seq[MWIFIEX_MEF_MAX_BYTESEQ + 1]; 2796 u8 byte_seq[MWIFIEX_MEF_MAX_BYTESEQ + 1];
2741 const u8 ipv4_mc_mac[] = {0x33, 0x33}; 2797 const u8 ipv4_mc_mac[] = {0x33, 0x33};
2742 const u8 ipv6_mc_mac[] = {0x01, 0x00, 0x5e}; 2798 const u8 ipv6_mc_mac[] = {0x01, 0x00, 0x5e};
2743 struct mwifiex_ds_mef_cfg mef_cfg;
2744 struct mwifiex_mef_entry *mef_entry;
2745
2746 mef_entry = kzalloc(sizeof(*mef_entry), GFP_KERNEL);
2747 if (!mef_entry)
2748 return -ENOMEM;
2749 2799
2750 memset(&mef_cfg, 0, sizeof(mef_cfg));
2751 mef_cfg.num_entries = 1;
2752 mef_cfg.mef_entry = mef_entry;
2753 mef_entry->mode = MEF_MODE_HOST_SLEEP; 2800 mef_entry->mode = MEF_MODE_HOST_SLEEP;
2754 mef_entry->action = MEF_ACTION_ALLOW_AND_WAKEUP_HOST; 2801 mef_entry->action = MEF_ACTION_ALLOW_AND_WAKEUP_HOST;
2755 2802
@@ -2766,20 +2813,19 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv,
2766 if (!wowlan->patterns[i].pkt_offset) { 2813 if (!wowlan->patterns[i].pkt_offset) {
2767 if (!(byte_seq[0] & 0x01) && 2814 if (!(byte_seq[0] & 0x01) &&
2768 (byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] == 1)) { 2815 (byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] == 1)) {
2769 mef_cfg.criteria |= MWIFIEX_CRITERIA_UNICAST; 2816 mef_cfg->criteria |= MWIFIEX_CRITERIA_UNICAST;
2770 continue; 2817 continue;
2771 } else if (is_broadcast_ether_addr(byte_seq)) { 2818 } else if (is_broadcast_ether_addr(byte_seq)) {
2772 mef_cfg.criteria |= MWIFIEX_CRITERIA_BROADCAST; 2819 mef_cfg->criteria |= MWIFIEX_CRITERIA_BROADCAST;
2773 continue; 2820 continue;
2774 } else if ((!memcmp(byte_seq, ipv4_mc_mac, 2) && 2821 } else if ((!memcmp(byte_seq, ipv4_mc_mac, 2) &&
2775 (byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] == 2)) || 2822 (byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] == 2)) ||
2776 (!memcmp(byte_seq, ipv6_mc_mac, 3) && 2823 (!memcmp(byte_seq, ipv6_mc_mac, 3) &&
2777 (byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] == 3))) { 2824 (byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] == 3))) {
2778 mef_cfg.criteria |= MWIFIEX_CRITERIA_MULTICAST; 2825 mef_cfg->criteria |= MWIFIEX_CRITERIA_MULTICAST;
2779 continue; 2826 continue;
2780 } 2827 }
2781 } 2828 }
2782
2783 mef_entry->filter[filt_num].repeat = 1; 2829 mef_entry->filter[filt_num].repeat = 1;
2784 mef_entry->filter[filt_num].offset = 2830 mef_entry->filter[filt_num].offset =
2785 wowlan->patterns[i].pkt_offset; 2831 wowlan->patterns[i].pkt_offset;
@@ -2796,7 +2842,7 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv,
2796 } 2842 }
2797 2843
2798 if (wowlan->magic_pkt) { 2844 if (wowlan->magic_pkt) {
2799 mef_cfg.criteria |= MWIFIEX_CRITERIA_UNICAST; 2845 mef_cfg->criteria |= MWIFIEX_CRITERIA_UNICAST;
2800 mef_entry->filter[filt_num].repeat = 16; 2846 mef_entry->filter[filt_num].repeat = 16;
2801 memcpy(mef_entry->filter[filt_num].byte_seq, priv->curr_addr, 2847 memcpy(mef_entry->filter[filt_num].byte_seq, priv->curr_addr,
2802 ETH_ALEN); 2848 ETH_ALEN);
@@ -2817,6 +2863,34 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv,
2817 mef_entry->filter[filt_num].filt_type = TYPE_EQ; 2863 mef_entry->filter[filt_num].filt_type = TYPE_EQ;
2818 mef_entry->filter[filt_num].filt_action = TYPE_OR; 2864 mef_entry->filter[filt_num].filt_action = TYPE_OR;
2819 } 2865 }
2866 return ret;
2867}
2868
2869static int mwifiex_set_mef_filter(struct mwifiex_private *priv,
2870 struct cfg80211_wowlan *wowlan)
2871{
2872 int ret = 0, num_entries = 1;
2873 struct mwifiex_ds_mef_cfg mef_cfg;
2874 struct mwifiex_mef_entry *mef_entry;
2875
2876 if (wowlan->n_patterns || wowlan->magic_pkt)
2877 num_entries++;
2878
2879 mef_entry = kcalloc(num_entries, sizeof(*mef_entry), GFP_KERNEL);
2880 if (!mef_entry)
2881 return -ENOMEM;
2882
2883 memset(&mef_cfg, 0, sizeof(mef_cfg));
2884 mef_cfg.criteria |= MWIFIEX_CRITERIA_BROADCAST |
2885 MWIFIEX_CRITERIA_UNICAST;
2886 mef_cfg.num_entries = num_entries;
2887 mef_cfg.mef_entry = mef_entry;
2888
2889 mwifiex_set_auto_arp_mef_entry(priv, &mef_entry[0]);
2890
2891 if (wowlan->n_patterns || wowlan->magic_pkt)
2892 ret = mwifiex_set_wowlan_mef_entry(priv, &mef_cfg,
2893 &mef_entry[1], wowlan);
2820 2894
2821 if (!mef_cfg.criteria) 2895 if (!mef_cfg.criteria)
2822 mef_cfg.criteria = MWIFIEX_CRITERIA_BROADCAST | 2896 mef_cfg.criteria = MWIFIEX_CRITERIA_BROADCAST |
@@ -2824,8 +2898,8 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv,
2824 MWIFIEX_CRITERIA_MULTICAST; 2898 MWIFIEX_CRITERIA_MULTICAST;
2825 2899
2826 ret = mwifiex_send_cmd(priv, HostCmd_CMD_MEF_CFG, 2900 ret = mwifiex_send_cmd(priv, HostCmd_CMD_MEF_CFG,
2827 HostCmd_ACT_GEN_SET, 0, &mef_cfg, true); 2901 HostCmd_ACT_GEN_SET, 0,
2828 2902 &mef_cfg, true);
2829 kfree(mef_entry); 2903 kfree(mef_entry);
2830 return ret; 2904 return ret;
2831} 2905}
@@ -2850,12 +2924,10 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
2850 return 0; 2924 return 0;
2851 } 2925 }
2852 2926
2853 if (wowlan->n_patterns || wowlan->magic_pkt) { 2927 ret = mwifiex_set_mef_filter(priv, wowlan);
2854 ret = mwifiex_set_mef_filter(priv, wowlan); 2928 if (ret) {
2855 if (ret) { 2929 dev_err(adapter->dev, "Failed to set MEF filter\n");
2856 dev_err(adapter->dev, "Failed to set MEF filter\n"); 2930 return ret;
2857 return ret;
2858 }
2859 } 2931 }
2860 2932
2861 if (wowlan->disconnect) { 2933 if (wowlan->disconnect) {
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index df553e86a0ad..21a942fd2226 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -523,9 +523,11 @@ enum P2P_MODES {
523#define TYPE_OR (MAX_OPERAND+5) 523#define TYPE_OR (MAX_OPERAND+5)
524#define MEF_MODE_HOST_SLEEP 1 524#define MEF_MODE_HOST_SLEEP 1
525#define MEF_ACTION_ALLOW_AND_WAKEUP_HOST 3 525#define MEF_ACTION_ALLOW_AND_WAKEUP_HOST 3
526#define MEF_ACTION_AUTO_ARP 0x10
526#define MWIFIEX_CRITERIA_BROADCAST BIT(0) 527#define MWIFIEX_CRITERIA_BROADCAST BIT(0)
527#define MWIFIEX_CRITERIA_UNICAST BIT(1) 528#define MWIFIEX_CRITERIA_UNICAST BIT(1)
528#define MWIFIEX_CRITERIA_MULTICAST BIT(3) 529#define MWIFIEX_CRITERIA_MULTICAST BIT(3)
530#define MWIFIEX_MAX_SUPPORTED_IPADDR 4
529 531
530#define ACT_TDLS_DELETE 0x00 532#define ACT_TDLS_DELETE 0x00
531#define ACT_TDLS_CREATE 0x01 533#define ACT_TDLS_CREATE 0x01
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 16be45e9a66a..a0908c64103a 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -35,6 +35,7 @@
35#include <linux/ctype.h> 35#include <linux/ctype.h>
36#include <linux/of.h> 36#include <linux/of.h>
37#include <linux/idr.h> 37#include <linux/idr.h>
38#include <linux/inetdevice.h>
38 39
39#include "decl.h" 40#include "decl.h"
40#include "ioctl.h" 41#include "ioctl.h"
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index f7d204ffd6e9..b23eaed84701 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -1370,22 +1370,29 @@ mwifiex_cmd_mef_cfg(struct mwifiex_private *priv,
1370 struct mwifiex_ds_mef_cfg *mef) 1370 struct mwifiex_ds_mef_cfg *mef)
1371{ 1371{
1372 struct host_cmd_ds_mef_cfg *mef_cfg = &cmd->params.mef_cfg; 1372 struct host_cmd_ds_mef_cfg *mef_cfg = &cmd->params.mef_cfg;
1373 struct mwifiex_fw_mef_entry *mef_entry = NULL;
1373 u8 *pos = (u8 *)mef_cfg; 1374 u8 *pos = (u8 *)mef_cfg;
1375 u16 i;
1374 1376
1375 cmd->command = cpu_to_le16(HostCmd_CMD_MEF_CFG); 1377 cmd->command = cpu_to_le16(HostCmd_CMD_MEF_CFG);
1376 1378
1377 mef_cfg->criteria = cpu_to_le32(mef->criteria); 1379 mef_cfg->criteria = cpu_to_le32(mef->criteria);
1378 mef_cfg->num_entries = cpu_to_le16(mef->num_entries); 1380 mef_cfg->num_entries = cpu_to_le16(mef->num_entries);
1379 pos += sizeof(*mef_cfg); 1381 pos += sizeof(*mef_cfg);
1380 mef_cfg->mef_entry->mode = mef->mef_entry->mode;
1381 mef_cfg->mef_entry->action = mef->mef_entry->action;
1382 pos += sizeof(*(mef_cfg->mef_entry));
1383 1382
1384 if (mwifiex_cmd_append_rpn_expression(priv, mef->mef_entry, &pos)) 1383 for (i = 0; i < mef->num_entries; i++) {
1385 return -1; 1384 mef_entry = (struct mwifiex_fw_mef_entry *)pos;
1385 mef_entry->mode = mef->mef_entry[i].mode;
1386 mef_entry->action = mef->mef_entry[i].action;
1387 pos += sizeof(*mef_cfg->mef_entry);
1388
1389 if (mwifiex_cmd_append_rpn_expression(priv,
1390 &mef->mef_entry[i], &pos))
1391 return -1;
1386 1392
1387 mef_cfg->mef_entry->exprsize = 1393 mef_entry->exprsize =
1388 cpu_to_le16(pos - mef_cfg->mef_entry->expr); 1394 cpu_to_le16(pos - mef_entry->expr);
1395 }
1389 cmd->size = cpu_to_le16((u16) (pos - (u8 *)mef_cfg) + S_DS_GEN); 1396 cmd->size = cpu_to_le16((u16) (pos - (u8 *)mef_cfg) + S_DS_GEN);
1390 1397
1391 return 0; 1398 return 0;