iwlwifi: mvm: support beacon IE injection
authorSara Sharon <sara.sharon@intel.com>
Thu, 8 Nov 2018 07:53:48 +0000 (09:53 +0200)
committerLuca Coelho <luciano.coelho@intel.com>
Thu, 14 Feb 2019 09:29:46 +0000 (11:29 +0200)
This is useful for automated tests.

Signed-off-by: Sara Sharon <sara.sharon@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h

index e136475a34f616968c47f3be42f7a80e64bddb4b..80b0b2ed69bb02fd7cbafe670a0c8934906fec4b 100644 (file)
@@ -1188,6 +1188,108 @@ out:
        return ret ?: count;
 }
 
+static int _iwl_dbgfs_inject_beacon_ie(struct iwl_mvm *mvm, char *bin, int len)
+{
+       struct ieee80211_vif *vif;
+       struct iwl_mvm_vif *mvmvif;
+       struct sk_buff *beacon;
+       struct ieee80211_tx_info *info;
+       struct iwl_mac_beacon_cmd beacon_cmd = {};
+       u8 rate;
+       u16 flags;
+       int i;
+
+       len /= 2;
+
+       /* Element len should be represented by u8 */
+       if (len >= U8_MAX)
+               return -EINVAL;
+
+       if (!iwl_mvm_firmware_running(mvm))
+               return -EIO;
+
+       if (!iwl_mvm_has_new_tx_api(mvm) &&
+           !fw_has_api(&mvm->fw->ucode_capa,
+                       IWL_UCODE_TLV_API_NEW_BEACON_TEMPLATE))
+               return -EINVAL;
+
+       rcu_read_lock();
+
+       for (i = 0; i < NUM_MAC_INDEX_DRIVER; i++) {
+               vif = iwl_mvm_rcu_dereference_vif_id(mvm, i, true);
+               if (!vif)
+                       continue;
+
+               if (vif->type == NL80211_IFTYPE_AP)
+                       break;
+       }
+
+       if (i == NUM_MAC_INDEX_DRIVER || !vif)
+               goto out_err;
+
+       mvm->hw->extra_beacon_tailroom = len;
+
+       beacon = ieee80211_beacon_get_template(mvm->hw, vif, NULL);
+       if (!beacon)
+               goto out_err;
+
+       if (len && hex2bin(skb_put_zero(beacon, len), bin, len)) {
+               dev_kfree_skb(beacon);
+               goto out_err;
+       }
+
+       mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       info = IEEE80211_SKB_CB(beacon);
+       rate = iwl_mvm_mac_ctxt_get_lowest_rate(info, vif);
+       flags = iwl_mvm_mac80211_idx_to_hwrate(rate);
+
+       if (rate == IWL_FIRST_CCK_RATE)
+               flags |= IWL_MAC_BEACON_CCK;
+
+       beacon_cmd.flags = cpu_to_le16(flags);
+       beacon_cmd.byte_cnt = cpu_to_le16((u16)beacon->len);
+       beacon_cmd.template_id = cpu_to_le32((u32)mvmvif->id);
+
+       iwl_mvm_mac_ctxt_set_tim(mvm, &beacon_cmd.tim_idx,
+                                &beacon_cmd.tim_size,
+                                beacon->data, beacon->len);
+
+       mutex_lock(&mvm->mutex);
+       iwl_mvm_mac_ctxt_send_beacon_cmd(mvm, beacon, &beacon_cmd,
+                                        sizeof(beacon_cmd));
+       mutex_unlock(&mvm->mutex);
+
+       dev_kfree_skb(beacon);
+
+       rcu_read_unlock();
+       return 0;
+
+out_err:
+       rcu_read_unlock();
+       return -EINVAL;
+}
+
+static ssize_t iwl_dbgfs_inject_beacon_ie_write(struct iwl_mvm *mvm,
+                                               char *buf, size_t count,
+                                               loff_t *ppos)
+{
+       int ret = _iwl_dbgfs_inject_beacon_ie(mvm, buf, count);
+
+       mvm->hw->extra_beacon_tailroom = 0;
+       return ret ?: count;
+}
+
+static ssize_t iwl_dbgfs_inject_beacon_ie_restore_write(struct iwl_mvm *mvm,
+                                                       char *buf,
+                                                       size_t count,
+                                                       loff_t *ppos)
+{
+       int ret = _iwl_dbgfs_inject_beacon_ie(mvm, NULL, 0);
+
+       mvm->hw->extra_beacon_tailroom = 0;
+       return ret ?: count;
+}
+
 static ssize_t iwl_dbgfs_fw_dbg_conf_read(struct file *file,
                                          char __user *user_buf,
                                          size_t count, loff_t *ppos)
@@ -1806,6 +1908,8 @@ MVM_DEBUGFS_WRITE_FILE_OPS(max_amsdu_len, 8);
 MVM_DEBUGFS_WRITE_FILE_OPS(indirection_tbl,
                           (IWL_RSS_INDIRECTION_TABLE_SIZE * 2));
 MVM_DEBUGFS_WRITE_FILE_OPS(inject_packet, 512);
+MVM_DEBUGFS_WRITE_FILE_OPS(inject_beacon_ie, 512);
+MVM_DEBUGFS_WRITE_FILE_OPS(inject_beacon_ie_restore, 512);
 
 MVM_DEBUGFS_READ_FILE_OPS(uapsd_noagg_bssids);
 
@@ -2007,6 +2111,8 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
        MVM_DEBUGFS_ADD_FILE(send_echo_cmd, mvm->debugfs_dir, 0200);
        MVM_DEBUGFS_ADD_FILE(indirection_tbl, mvm->debugfs_dir, 0200);
        MVM_DEBUGFS_ADD_FILE(inject_packet, mvm->debugfs_dir, 0200);
+       MVM_DEBUGFS_ADD_FILE(inject_beacon_ie, mvm->debugfs_dir, 0200);
+       MVM_DEBUGFS_ADD_FILE(inject_beacon_ie_restore, mvm->debugfs_dir, 0200);
 #ifdef CONFIG_ACPI
        MVM_DEBUGFS_ADD_FILE(sar_geo_profile, dbgfs_dir, 0400);
 #endif
index 83711b555036cfe5d04ddd9edc98a7f749cd317e..9bd4376cad9bfae3145012214629a729270bd0c5 100644 (file)
@@ -811,9 +811,9 @@ static int iwl_mvm_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm,
        return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
 }
 
-static void iwl_mvm_mac_ctxt_set_tim(struct iwl_mvm *mvm,
-                                    __le32 *tim_index, __le32 *tim_size,
-                                    u8 *beacon, u32 frame_size)
+void iwl_mvm_mac_ctxt_set_tim(struct iwl_mvm *mvm,
+                             __le32 *tim_index, __le32 *tim_size,
+                             u8 *beacon, u32 frame_size)
 {
        u32 tim_idx;
        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)beacon;
@@ -853,8 +853,8 @@ static u32 iwl_mvm_find_ie_offset(u8 *beacon, u8 eid, u32 frame_size)
        return ie - beacon;
 }
 
-static u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct ieee80211_tx_info *info,
-                                          struct ieee80211_vif *vif)
+u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct ieee80211_tx_info *info,
+                                   struct ieee80211_vif *vif)
 {
        u8 rate;
 
@@ -904,9 +904,9 @@ static void iwl_mvm_mac_ctxt_set_tx(struct iwl_mvm *mvm,
 
 }
 
-static int iwl_mvm_mac_ctxt_send_beacon_cmd(struct iwl_mvm *mvm,
-                                           struct sk_buff *beacon,
-                                           void *data, int len)
+int iwl_mvm_mac_ctxt_send_beacon_cmd(struct iwl_mvm *mvm,
+                                    struct sk_buff *beacon,
+                                    void *data, int len)
 {
        struct iwl_host_cmd cmd = {
                .id = BEACON_TEMPLATE_CMD,
@@ -1009,9 +1009,9 @@ static int iwl_mvm_mac_ctxt_send_beacon_v9(struct iwl_mvm *mvm,
                                                sizeof(beacon_cmd));
 }
 
-static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
-                                       struct ieee80211_vif *vif,
-                                       struct sk_buff *beacon)
+int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
+                                struct ieee80211_vif *vif,
+                                struct sk_buff *beacon)
 {
        if (WARN_ON(!beacon))
                return -EINVAL;
index c70fc90680af4a1f41ba0fa2aeec98be7fcf02aa..f4fc81695df197c55dc0e2ae297aedc29bff7252 100644 (file)
@@ -1693,6 +1693,17 @@ int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
 int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
                                    struct ieee80211_vif *vif);
+int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
+                                struct ieee80211_vif *vif,
+                                struct sk_buff *beacon);
+int iwl_mvm_mac_ctxt_send_beacon_cmd(struct iwl_mvm *mvm,
+                                    struct sk_buff *beacon,
+                                    void *data, int len);
+u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct ieee80211_tx_info *info,
+                                   struct ieee80211_vif *vif);
+void iwl_mvm_mac_ctxt_set_tim(struct iwl_mvm *mvm,
+                             __le32 *tim_index, __le32 *tim_size,
+                             u8 *beacon, u32 frame_size);
 void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
                             struct iwl_rx_cmd_buffer *rxb);
 void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm,