iwlwifi: mvm: add debugfs entry to configure netdetect SSIDs
authorLuciano Coelho <luciano.coelho@intel.com>
Wed, 24 Sep 2014 05:29:11 +0000 (08:29 +0300)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Wed, 29 Oct 2014 10:49:13 +0000 (12:49 +0200)
Before we get all the chain (ie. mac80211, cfg80211, nl80211 and
userspace) changed to support net-detect, we can use this debugfs
entry for easy testing and as a proof of concept.

Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
drivers/net/wireless/iwlwifi/mvm/d3.c
drivers/net/wireless/iwlwifi/mvm/debugfs.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/ops.c

index 7a66a0903515c161ff54b8000704e8433dff9003..0b3295e3f6a60958709f790cfb06c912f7632ce6 100644 (file)
@@ -1061,6 +1061,15 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
                                            vif, mvmvif, ap_sta);
                if (ret)
                        goto out;
+       } else if (mvm->nd_config) {
+               ret = iwl_mvm_switch_to_d3(mvm);
+               if (ret)
+                       goto out;
+
+               ret = iwl_mvm_scan_offload_start(mvm, vif, mvm->nd_config,
+                                                mvm->nd_ies);
+               if (ret)
+                       goto out;
        } else {
                ret = 1;
                goto out_noreset;
index 50527a9bb26739b572e1b0faad8b7afa5114662d..2a61baca508120e086352be85cc2f098226429b1 100644 (file)
@@ -1250,6 +1250,126 @@ static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf,
 
        return ret;
 }
+
+#define MAX_NUM_ND_MATCHSETS 10
+
+static ssize_t iwl_dbgfs_netdetect_write(struct iwl_mvm *mvm, char *buf,
+                                        size_t count, loff_t *ppos)
+{
+       const char *seps = ",\n";
+       char *buf_ptr = buf;
+       char *value_str = NULL;
+       int ret, i;
+
+       /* TODO: don't free if write is being called several times in one go */
+       if (mvm->nd_config) {
+               kfree(mvm->nd_config->match_sets);
+               kfree(mvm->nd_config);
+               mvm->nd_config = NULL;
+               kfree(mvm->nd_ies);
+               mvm->nd_ies = NULL;
+       }
+
+       mvm->nd_ies = kzalloc(sizeof(*mvm->nd_ies), GFP_KERNEL);
+       if (!mvm->nd_ies)
+               return -ENOMEM;
+
+       mvm->nd_config = kzalloc(sizeof(*mvm->nd_config) +
+                                (11 * sizeof(struct ieee80211_channel *)),
+                                GFP_KERNEL);
+       if (!mvm->nd_config) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+
+       mvm->nd_config->n_channels = 11;
+       mvm->nd_config->scan_width = NL80211_BSS_CHAN_WIDTH_20;
+       mvm->nd_config->interval = 5;
+       mvm->nd_config->min_rssi_thold = -80;
+       for (i = 0; i < mvm->nd_config->n_channels; i++)
+               mvm->nd_config->channels[i] = &mvm->nvm_data->channels[i];
+
+       mvm->nd_config->match_sets =
+               kcalloc(MAX_NUM_ND_MATCHSETS,
+                       sizeof(*mvm->nd_config->match_sets),
+                       GFP_KERNEL);
+       if (!mvm->nd_config->match_sets) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+
+       while ((value_str = strsep(&buf_ptr, seps)) &&
+              strlen(value_str)) {
+               struct cfg80211_match_set *set;
+
+               if (mvm->nd_config->n_match_sets >= MAX_NUM_ND_MATCHSETS) {
+                       ret = -EINVAL;
+                       goto out_free;
+               }
+
+               set = &mvm->nd_config->match_sets[mvm->nd_config->n_match_sets];
+               set->ssid.ssid_len = strlen(value_str);
+
+               if (set->ssid.ssid_len > IEEE80211_MAX_SSID_LEN) {
+                       ret = -EINVAL;
+                       goto out_free;
+               }
+
+               memcpy(set->ssid.ssid, value_str, set->ssid.ssid_len);
+
+               mvm->nd_config->n_match_sets++;
+       }
+
+       ret = count;
+
+       if (mvm->nd_config->n_match_sets)
+               goto out;
+
+out_free:
+       if (mvm->nd_config)
+               kfree(mvm->nd_config->match_sets);
+       kfree(mvm->nd_config);
+       mvm->nd_config = NULL;
+       kfree(mvm->nd_ies);
+       mvm->nd_ies = NULL;
+out:
+       return ret;
+}
+
+static ssize_t
+iwl_dbgfs_netdetect_read(struct file *file, char __user *user_buf,
+                        size_t count, loff_t *ppos)
+{
+       struct iwl_mvm *mvm = file->private_data;
+       size_t bufsz, ret;
+       char *buf;
+       int i, n_match_sets, pos = 0;
+
+       n_match_sets = mvm->nd_config ? mvm->nd_config->n_match_sets : 0;
+
+       bufsz = n_match_sets * (IEEE80211_MAX_SSID_LEN + 1) + 1;
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       for (i = 0; i < n_match_sets; i++) {
+               if (pos +
+                   mvm->nd_config->match_sets[i].ssid.ssid_len + 2 > bufsz) {
+                       ret = -EIO;
+                       goto out;
+               }
+
+               memcpy(buf + pos, mvm->nd_config->match_sets[i].ssid.ssid,
+                      mvm->nd_config->match_sets[i].ssid.ssid_len);
+               pos += mvm->nd_config->match_sets[i].ssid.ssid_len;
+               buf[pos++] = '\n';
+       }
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+out:
+       kfree(buf);
+       return ret;
+}
 #endif
 
 #define PRINT_MVM_REF(ref) do {                                                \
@@ -1428,6 +1548,7 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256);
 
 #ifdef CONFIG_PM_SLEEP
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8);
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(netdetect, 384);
 #endif
 
 int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
@@ -1487,6 +1608,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
        if (!debugfs_create_bool("d3_wake_sysassert", S_IRUSR | S_IWUSR,
                                 mvm->debugfs_dir, &mvm->d3_wake_sysassert))
                goto err;
+       MVM_DEBUGFS_ADD_FILE(netdetect, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
 #endif
 
        if (!debugfs_create_u8("low_latency_agg_frame_limit", S_IRUSR | S_IWUSR,
index 14ec67864bf2bce89a2a959a8af33e6b01ce13f1..60aee625b966b4de168805cacd5ce7079ad49126 100644 (file)
@@ -659,6 +659,10 @@ struct iwl_mvm {
 #ifdef CONFIG_PM_SLEEP
        struct wiphy_wowlan_support wowlan;
        int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen;
+
+       /* sched scan settings for net detect */
+       struct cfg80211_sched_scan_request *nd_config;
+       struct ieee80211_scan_ies *nd_ies;
 #ifdef CONFIG_IWLWIFI_DEBUGFS
        u32 d3_wake_sysassert; /* must be u32 for debugfs_create_bool */
        bool d3_test_active;
index 48cb25a93591a44678fd051e390dc15c02078744..047d83d8b25a75162b95764fb0ffd543225df8fc 100644 (file)
@@ -594,6 +594,13 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
 
 #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS)
        kfree(mvm->d3_resume_sram);
+       if (mvm->nd_config) {
+               kfree(mvm->nd_config->match_sets);
+               kfree(mvm->nd_config);
+               mvm->nd_config = NULL;
+               kfree(mvm->nd_ies);
+               mvm->nd_ies = NULL;
+       }
 #endif
 
        iwl_trans_op_mode_leave(mvm->trans);