wl12xx: fix Tx security sequence number handling
authorOz Krakowski <ozk@ti.com>
Sun, 26 Jun 2011 07:36:02 +0000 (10:36 +0300)
committerLuciano Coelho <coelho@ti.com>
Tue, 5 Jul 2011 18:33:19 +0000 (21:33 +0300)
Do not reset the security sequence number when issuing a join command or
interface is removed. Instead, reset the counter only during the unjoin
command.

Added the notion of counter wrap-around to the LSB number in
wl1271_tx_complete_packet.

Added post recovery padding to adjust for potential security number
progress during the recovery process by the firmware and avoid
potential interop issues in encrypted networks.

Signed-off-by: Oz Krakowski <ozk@ti.com>
Signed-off-by: Arik Nemtsov <arik@wizery.com>
Signed-off-by: Luciano Coelho <coelho@ti.com>
drivers/net/wireless/wl12xx/cmd.c
drivers/net/wireless/wl12xx/debugfs.c
drivers/net/wireless/wl12xx/main.c
drivers/net/wireless/wl12xx/tx.c
drivers/net/wireless/wl12xx/tx.h
drivers/net/wireless/wl12xx/wl12xx.h

index c9a1fa523274972fa7e8120e3b96f704c152d232..a712a0f7b370d6b3ab3b6c350f22d31b3c95c538 100644 (file)
@@ -400,10 +400,6 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)
 
        join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET;
 
-       /* reset TX security counters */
-       wl->tx_security_last_seq = 0;
-       wl->tx_security_seq = 0;
-
        wl1271_debug(DEBUG_CMD, "cmd join: basic_rate_set=0x%x, rate_set=0x%x",
                join->basic_rate_set, join->supported_rate_set);
 
index da21270183003f7202549310c36705132b13dd8f..3f6314143ef801837467c86ed1c513374218420f 100644 (file)
@@ -349,7 +349,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
        DRIVER_STATE_PRINT_INT(tx_blocks_freed[1]);
        DRIVER_STATE_PRINT_INT(tx_blocks_freed[2]);
        DRIVER_STATE_PRINT_INT(tx_blocks_freed[3]);
-       DRIVER_STATE_PRINT_INT(tx_security_last_seq);
+       DRIVER_STATE_PRINT_INT(tx_security_last_seq_lsb);
        DRIVER_STATE_PRINT_INT(rx_counter);
        DRIVER_STATE_PRINT_INT(session_counter);
        DRIVER_STATE_PRINT_INT(state);
index a3734bdf5119b0d2e8fb09d63021e8416a572826..b896f5956d9ec206816333ef55933eb87ce201d0 100644 (file)
@@ -1227,6 +1227,15 @@ static void wl1271_recovery_work(struct work_struct *work)
        wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
                    wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
 
+       /*
+        * Advance security sequence number to overcome potential progress
+        * in the firmware during recovery. This doens't hurt if the network is
+        * not encrypted.
+        */
+       if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
+           test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
+               wl->tx_security_seq += WL1271_TX_SQN_POST_RECOVERY_PADDING;
+
        if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
                ieee80211_connection_loss(wl->vif);
 
@@ -1980,8 +1989,6 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
        wl->tx_allocated_blocks = 0;
        wl->tx_results_count = 0;
        wl->tx_packets_count = 0;
-       wl->tx_security_last_seq = 0;
-       wl->tx_security_seq = 0;
        wl->time_offset = 0;
        wl->session_counter = 0;
        wl->rate_set = CONF_TX_RATE_MASK_BASIC;
@@ -2154,6 +2161,10 @@ static int wl1271_unjoin(struct wl1271 *wl)
        clear_bit(WL1271_FLAG_JOINED, &wl->flags);
        memset(wl->bssid, 0, ETH_ALEN);
 
+       /* reset TX security counters on a clean disconnect */
+       wl->tx_security_last_seq_lsb = 0;
+       wl->tx_security_seq = 0;
+
        /* stop filtering packets based on bssid */
        wl1271_configure_filters(wl, FIF_OTHER_BSS);
 
@@ -4327,6 +4338,9 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
        wl->quirks = 0;
        wl->platform_quirks = 0;
        wl->sched_scanning = false;
+       wl->tx_security_seq = 0;
+       wl->tx_security_last_seq_lsb = 0;
+
        setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
                    (unsigned long) wl);
        wl->fwlog_size = 0;
index 200590c0d9e3484ef2192d6e89a8c7ba4e0cdb3e..003f9e08691bcbae29f6138f04fb46589cdcb7b9 100644 (file)
@@ -704,10 +704,24 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
 
        wl->stats.retry_count += result->ack_failures;
 
-       /* update security sequence number */
-       wl->tx_security_seq += (result->lsb_security_sequence_number -
-                               wl->tx_security_last_seq);
-       wl->tx_security_last_seq = result->lsb_security_sequence_number;
+       /*
+        * update sequence number only when relevant, i.e. only in
+        * sessions of TKIP, AES and GEM (not in open or WEP sessions)
+        */
+       if (info->control.hw_key &&
+           (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP ||
+            info->control.hw_key->cipher == WLAN_CIPHER_SUITE_CCMP ||
+            info->control.hw_key->cipher == WL1271_CIPHER_SUITE_GEM)) {
+               u8 fw_lsb = result->tx_security_sequence_number_lsb;
+               u8 cur_lsb = wl->tx_security_last_seq_lsb;
+
+               /*
+                * update security sequence number, taking care of potential
+                * wrap-around
+                */
+               wl->tx_security_seq += (fw_lsb - cur_lsb + 256) % 256;
+               wl->tx_security_last_seq_lsb = fw_lsb;
+       }
 
        /* remove private header from packet */
        skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
index 832f9258d67563f6cb1a23c6811a12a39dbaa252..7ed3c01f365149145b5f7a27f7ff43aea765bbb2 100644 (file)
@@ -150,7 +150,7 @@ struct wl1271_tx_hw_res_descr {
           (from 1st EDCA AIFS counter until TX Complete). */
        __le32 medium_delay;
        /* LS-byte of last TKIP seq-num (saved per AC for recovery). */
-       u8 lsb_security_sequence_number;
+       u8 tx_security_sequence_number_lsb;
        /* Retry count - number of transmissions without successful ACK.*/
        u8 ack_failures;
        /* The rate that succeeded getting ACK
index d7db6e77047a684538c8ba2ee99f578ef29b2e99..002d9c53e373ba9f0e4995dc8adb39091d8cd6b8 100644 (file)
@@ -144,6 +144,7 @@ extern u32 wl12xx_debug_level;
 
 #define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff))
 #define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff))
+#define WL1271_TX_SQN_POST_RECOVERY_PADDING 0xff
 
 #define WL1271_CIPHER_SUITE_GEM 0x00147201
 
@@ -454,9 +455,16 @@ struct wl1271 {
        struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS];
        int tx_frames_cnt;
 
-       /* Security sequence number counters */
-       u8 tx_security_last_seq;
-       s64 tx_security_seq;
+       /*
+        * Security sequence number
+        *     bits 0-15: lower 16 bits part of sequence number
+        *     bits 16-47: higher 32 bits part of sequence number
+        *     bits 48-63: not in use
+        */
+       u64 tx_security_seq;
+
+       /* 8 bits of the last sequence number in use */
+       u8 tx_security_last_seq_lsb;
 
        /* FW Rx counter */
        u32 rx_counter;