wl1251: configure hardware en-/decryption for monitor mode
authorDavid Gnedt <david.gnedt@davizone.at>
Tue, 7 Jan 2014 12:07:52 +0000 (13:07 +0100)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 9 Jan 2014 15:54:58 +0000 (10:54 -0500)
Disable hardware encryption (DF_ENCRYPTION_DISABLE) and decryption
(DF_SNIFF_MODE_ENABLE) via wl1251_acx_feature_cfg while monitor interface is
present.

Signed-off-by: David Gnedt <david.gnedt@davizone.at>
Signed-off-by: Pali Rohár <pali.rohar@gmail.com>
Signed-off-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ti/wl1251/acx.c
drivers/net/wireless/ti/wl1251/acx.h
drivers/net/wireless/ti/wl1251/init.c
drivers/net/wireless/ti/wl1251/main.c
drivers/net/wireless/ti/wl1251/rx.c
drivers/net/wireless/ti/wl1251/tx.c
drivers/net/wireless/ti/wl1251/wl1251.h

index eaf2d5dadcb960d64fe5bb24e1d61c7ed07e1399..b390adfb5d893713d7220f231116c88f8047cfaa 100644 (file)
@@ -194,7 +194,7 @@ out:
        return ret;
 }
 
-int wl1251_acx_feature_cfg(struct wl1251 *wl)
+int wl1251_acx_feature_cfg(struct wl1251 *wl, u32 data_flow_options)
 {
        struct acx_feature_config *feature;
        int ret;
@@ -205,8 +205,8 @@ int wl1251_acx_feature_cfg(struct wl1251 *wl)
        if (!feature)
                return -ENOMEM;
 
-       /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */
-       feature->data_flow_options = 0;
+       /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE can be set */
+       feature->data_flow_options = data_flow_options;
        feature->options = 0;
 
        ret = wl1251_cmd_configure(wl, ACX_FEATURE_CFG,
index ba9ddc05e47afc2a8a6cb54fd6220f818b62a772..5360bbecd073bd61ab99f875a3bfb43a001e79ac 100644 (file)
@@ -1454,7 +1454,7 @@ int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event,
 int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth);
 int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len);
 int wl1251_acx_tx_power(struct wl1251 *wl, int power);
-int wl1251_acx_feature_cfg(struct wl1251 *wl);
+int wl1251_acx_feature_cfg(struct wl1251 *wl, u32 data_flow_options);
 int wl1251_acx_mem_map(struct wl1251 *wl,
                       struct acx_header *mem_map, size_t len);
 int wl1251_acx_data_path_params(struct wl1251 *wl,
index 1641e4c8fa527a371ea7c6be290c5fd0197dd094..4b78965ebf6f325154ff1567bc83d3fa8accd4fc 100644 (file)
@@ -33,7 +33,7 @@ int wl1251_hw_init_hwenc_config(struct wl1251 *wl)
 {
        int ret;
 
-       ret = wl1251_acx_feature_cfg(wl);
+       ret = wl1251_acx_feature_cfg(wl, 0);
        if (ret < 0) {
                wl1251_warning("couldn't set feature config");
                return ret;
index 9fee7f4d1152c5ebcbf23d3c029bdd0bf6adef64..afd79aa69869e7ad1719676ddf72854d9357f8dc 100644 (file)
@@ -484,6 +484,7 @@ static void wl1251_op_stop(struct ieee80211_hw *hw)
        wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
        wl->rssi_thold = 0;
        wl->channel = WL1251_DEFAULT_CHANNEL;
+       wl->monitor_present = false;
 
        wl1251_debugfs_reset(wl);
 
@@ -576,8 +577,10 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
        channel = ieee80211_frequency_to_channel(
                        conf->chandef.chan->center_freq);
 
-       wl1251_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
+       wl1251_debug(DEBUG_MAC80211,
+                    "mac80211 config ch %d monitor %s psm %s power %d",
                     channel,
+                    conf->flags & IEEE80211_CONF_MONITOR ? "on" : "off",
                     conf->flags & IEEE80211_CONF_PS ? "on" : "off",
                     conf->power_level);
 
@@ -587,6 +590,22 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
        if (ret < 0)
                goto out;
 
+       if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
+               u32 mode;
+
+               if (conf->flags & IEEE80211_CONF_MONITOR) {
+                       wl->monitor_present = true;
+                       mode = DF_SNIFF_MODE_ENABLE | DF_ENCRYPTION_DISABLE;
+               } else {
+                       wl->monitor_present = false;
+                       mode = 0;
+               }
+
+               ret = wl1251_acx_feature_cfg(wl, mode);
+               if (ret < 0)
+                       goto out_sleep;
+       }
+
        if (channel != wl->channel) {
                wl->channel = channel;
 
@@ -803,12 +822,12 @@ static int wl1251_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 
        mutex_lock(&wl->mutex);
 
-       ret = wl1251_ps_elp_wakeup(wl);
-       if (ret < 0)
-               goto out_unlock;
-
        switch (cmd) {
        case SET_KEY:
+               if (wl->monitor_present) {
+                       ret = -EOPNOTSUPP;
+                       goto out_unlock;
+               }
                wl_cmd->key_action = KEY_ADD_OR_REPLACE;
                break;
        case DISABLE_KEY:
@@ -819,6 +838,10 @@ static int wl1251_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                break;
        }
 
+       ret = wl1251_ps_elp_wakeup(wl);
+       if (ret < 0)
+               goto out_unlock;
+
        ret = wl1251_set_key_type(wl, wl_cmd, cmd, key, addr);
        if (ret < 0) {
                wl1251_error("Set KEY type failed");
@@ -1415,6 +1438,7 @@ struct ieee80211_hw *wl1251_alloc_hw(void)
 
        INIT_DELAYED_WORK(&wl->elp_work, wl1251_elp_work);
        wl->channel = WL1251_DEFAULT_CHANNEL;
+       wl->monitor_present = false;
        wl->scanning = false;
        wl->default_key = 0;
        wl->listen_int = 1;
index 23289d49dd31806210566fe2aa737154eecf482e..123c4bb50e0a0c2eff220c4509c2ece5aab7b365 100644 (file)
@@ -83,7 +83,7 @@ static void wl1251_rx_status(struct wl1251 *wl,
 
        status->flag |= RX_FLAG_MACTIME_START;
 
-       if (desc->flags & RX_DESC_ENCRYPTION_MASK) {
+       if (!wl->monitor_present && (desc->flags & RX_DESC_ENCRYPTION_MASK)) {
                status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;
 
                if (likely(!(desc->flags & RX_DESC_DECRYPT_FAIL)))
index 28121c590a2b1a62effa4c17b335b83264c99acf..466cd25c022b552eae797749e254c003f3c3a5fb 100644 (file)
@@ -287,6 +287,9 @@ static int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb)
        info = IEEE80211_SKB_CB(skb);
 
        if (info->control.hw_key) {
+               if (unlikely(wl->monitor_present))
+                       return -EINVAL;
+
                idx = info->control.hw_key->hw_key_idx;
                if (unlikely(wl->default_key != idx)) {
                        ret = wl1251_acx_default_key(wl, idx);
index 24869458cf748299e28f7745f2416ccfd6de4966..58bb414c51e57b5599c89b5c764ae28f7bcb7e6a 100644 (file)
@@ -303,6 +303,7 @@ struct wl1251 {
        u8 bss_type;
        u8 listen_int;
        int channel;
+       bool monitor_present;
 
        void *target_mem_map;
        struct acx_data_path_params_resp *data_path;