@@ -3273,7 +3273,7 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
- if (!priv->media_connected) {
+ if (!priv->media_connected && !wowlan->nd_config) {
mwifiex_dbg(adapter, ERROR,
"Can not configure WOWLAN in disconnected state\n");
return 0;
@@ -3285,22 +3285,32 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
return ret;
}
+ memset(&hs_cfg, 0, sizeof(hs_cfg));
+ hs_cfg.conditions = le32_to_cpu(adapter->hs_cfg.conditions);
+
+ if (wowlan->nd_config) {
+ mwifiex_dbg(adapter, INFO, "Wake on net detect\n");
+ hs_cfg.conditions |= HS_CFG_COND_MAC_EVENT;
+ mwifiex_cfg80211_sched_scan_start(wiphy, priv->netdev,
+ wowlan->nd_config);
+ }
+
if (wowlan->disconnect) {
- memset(&hs_cfg, 0, sizeof(hs_cfg));
- hs_cfg.is_invoke_hostcmd = false;
- hs_cfg.conditions = HS_CFG_COND_MAC_EVENT;
- hs_cfg.gpio = adapter->hs_cfg.gpio;
- hs_cfg.gap = adapter->hs_cfg.gap;
- ret = mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,
- MWIFIEX_SYNC_CMD, &hs_cfg);
- if (ret) {
- mwifiex_dbg(adapter, ERROR,
- "Failed to set HS params\n");
- return ret;
- }
+ hs_cfg.conditions |= HS_CFG_COND_MAC_EVENT;
mwifiex_dbg(priv->adapter, INFO, "Wake on device disconnect\n");
}
+ hs_cfg.is_invoke_hostcmd = false;
+ hs_cfg.gpio = adapter->hs_cfg.gpio;
+ hs_cfg.gap = adapter->hs_cfg.gap;
+ ret = mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,
+ MWIFIEX_SYNC_CMD, &hs_cfg);
+ if (ret) {
+ mwifiex_dbg(adapter, ERROR,
+ "Failed to set HS params\n");
+ return ret;
+ }
+
return ret;
}
@@ -3853,11 +3863,13 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
#ifdef CONFIG_PM
static const struct wiphy_wowlan_support mwifiex_wowlan_support = {
- .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
+ .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT |
+ WIPHY_WOWLAN_NET_DETECT,
.n_patterns = MWIFIEX_MEF_MAX_FILTERS,
.pattern_min_len = 1,
.pattern_max_len = MWIFIEX_MAX_PATTERN_LEN,
.max_pkt_offset = MWIFIEX_MAX_OFFSET_LEN,
+ .max_nd_match_sets = MWIFIEX_MAX_ND_MATCH_SETS,
};
#endif
@@ -543,6 +543,8 @@ enum P2P_MODES {
#define MWIFIEX_MAX_PATTERN_LEN 40
#define MWIFIEX_MAX_OFFSET_LEN 100
+#define MWIFIEX_MAX_ND_MATCH_SETS 10
+
#define STACK_NBYTES 100
#define TYPE_DNUM 1
#define TYPE_BYTESEQ 2
@@ -132,6 +132,13 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter)
}
}
+ if (adapter->nd_info) {
+ for (i = 0 ; i < adapter->nd_info->n_matches ; i++)
+ kfree(adapter->nd_info->matches[i]);
+ kfree(adapter->nd_info);
+ adapter->nd_info = NULL;
+ }
+
vfree(adapter->chan_stats);
kfree(adapter);
return 0;
@@ -1002,6 +1002,7 @@ struct mwifiex_adapter {
u8 active_scan_triggered;
bool usb_mc_status;
bool usb_mc_setup;
+ struct cfg80211_wowlan_nd_info *nd_info;
};
void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter);
@@ -2092,6 +2092,8 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
u8 is_bgscan_resp;
__le64 fw_tsf = 0;
u8 *radio_type;
+ struct cfg80211_wowlan_nd_match *pmatch;
+ struct cfg80211_sched_scan_request *nd_config = NULL;
is_bgscan_resp = (le16_to_cpu(resp->command)
== HostCmd_CMD_802_11_BG_SCAN_QUERY);
@@ -2154,6 +2156,21 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
(struct mwifiex_ie_types_data **)
&chan_band_tlv);
+#ifdef CONFIG_PM
+ if (priv->wdev.wiphy->wowlan_config)
+ nd_config = priv->wdev.wiphy->wowlan_config->nd_config;
+#endif
+
+ if (nd_config) {
+ adapter->nd_info =
+ kzalloc(sizeof(struct cfg80211_wowlan_nd_match) +
+ sizeof(struct cfg80211_wowlan_nd_match *) *
+ scan_rsp->number_of_sets, GFP_ATOMIC);
+
+ if (adapter->nd_info)
+ adapter->nd_info->n_matches = scan_rsp->number_of_sets;
+ }
+
for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) {
/*
* If the TSF TLV was appended to the scan results, save this
@@ -2172,6 +2189,23 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
radio_type = NULL;
}
+ if (chan_band_tlv && adapter->nd_info) {
+ adapter->nd_info->matches[idx] =
+ kzalloc(sizeof(*pmatch) +
+ sizeof(u32), GFP_ATOMIC);
+
+ pmatch = adapter->nd_info->matches[idx];
+
+ if (!pmatch) {
+ memset(pmatch, 0, sizeof(*pmatch));
+ if (chan_band_tlv) {
+ pmatch->n_channels = 1;
+ pmatch->channels[0] =
+ chan_band->chan_number;
+ }
+ }
+ }
+
ret = mwifiex_parse_single_response_buf(priv, &bss_info,
&bytes_left,
le64_to_cpu(fw_tsf),
@@ -505,10 +505,17 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter)
}
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
+
if (priv && priv->sched_scanning) {
- dev_dbg(adapter->dev, "aborting bgscan!\n");
- mwifiex_stop_bg_scan(priv);
- cfg80211_sched_scan_stopped(priv->wdev.wiphy);
+#ifdef CONFIG_PM
+ if (!priv->wdev.wiphy->wowlan_config->nd_config) {
+#endif
+ mwifiex_dbg(adapter, CMD, "aborting bgscan!\n");
+ mwifiex_stop_bg_scan(priv);
+ cfg80211_sched_scan_stopped(priv->wdev.wiphy);
+#ifdef CONFIG_PM
+ }
+#endif
}
if (adapter->hs_activated) {