wl12xx: fix Tx security sequence number handling
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>
This commit is contained in:
parent
95dac04f88
commit
b992c68228
|
@ -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;
|
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",
|
wl1271_debug(DEBUG_CMD, "cmd join: basic_rate_set=0x%x, rate_set=0x%x",
|
||||||
join->basic_rate_set, join->supported_rate_set);
|
join->basic_rate_set, join->supported_rate_set);
|
||||||
|
|
||||||
|
|
|
@ -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[1]);
|
||||||
DRIVER_STATE_PRINT_INT(tx_blocks_freed[2]);
|
DRIVER_STATE_PRINT_INT(tx_blocks_freed[2]);
|
||||||
DRIVER_STATE_PRINT_INT(tx_blocks_freed[3]);
|
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(rx_counter);
|
||||||
DRIVER_STATE_PRINT_INT(session_counter);
|
DRIVER_STATE_PRINT_INT(session_counter);
|
||||||
DRIVER_STATE_PRINT_INT(state);
|
DRIVER_STATE_PRINT_INT(state);
|
||||||
|
|
|
@ -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",
|
wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
|
||||||
wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
|
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))
|
if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
|
||||||
ieee80211_connection_loss(wl->vif);
|
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_allocated_blocks = 0;
|
||||||
wl->tx_results_count = 0;
|
wl->tx_results_count = 0;
|
||||||
wl->tx_packets_count = 0;
|
wl->tx_packets_count = 0;
|
||||||
wl->tx_security_last_seq = 0;
|
|
||||||
wl->tx_security_seq = 0;
|
|
||||||
wl->time_offset = 0;
|
wl->time_offset = 0;
|
||||||
wl->session_counter = 0;
|
wl->session_counter = 0;
|
||||||
wl->rate_set = CONF_TX_RATE_MASK_BASIC;
|
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);
|
clear_bit(WL1271_FLAG_JOINED, &wl->flags);
|
||||||
memset(wl->bssid, 0, ETH_ALEN);
|
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 */
|
/* stop filtering packets based on bssid */
|
||||||
wl1271_configure_filters(wl, FIF_OTHER_BSS);
|
wl1271_configure_filters(wl, FIF_OTHER_BSS);
|
||||||
|
|
||||||
|
@ -4327,6 +4338,9 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
|
||||||
wl->quirks = 0;
|
wl->quirks = 0;
|
||||||
wl->platform_quirks = 0;
|
wl->platform_quirks = 0;
|
||||||
wl->sched_scanning = false;
|
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,
|
setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
|
||||||
(unsigned long) wl);
|
(unsigned long) wl);
|
||||||
wl->fwlog_size = 0;
|
wl->fwlog_size = 0;
|
||||||
|
|
|
@ -704,10 +704,24 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
|
||||||
|
|
||||||
wl->stats.retry_count += result->ack_failures;
|
wl->stats.retry_count += result->ack_failures;
|
||||||
|
|
||||||
/* update security sequence number */
|
/*
|
||||||
wl->tx_security_seq += (result->lsb_security_sequence_number -
|
* update sequence number only when relevant, i.e. only in
|
||||||
wl->tx_security_last_seq);
|
* sessions of TKIP, AES and GEM (not in open or WEP sessions)
|
||||||
wl->tx_security_last_seq = result->lsb_security_sequence_number;
|
*/
|
||||||
|
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 */
|
/* remove private header from packet */
|
||||||
skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
|
skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
|
||||||
|
|
|
@ -150,7 +150,7 @@ struct wl1271_tx_hw_res_descr {
|
||||||
(from 1st EDCA AIFS counter until TX Complete). */
|
(from 1st EDCA AIFS counter until TX Complete). */
|
||||||
__le32 medium_delay;
|
__le32 medium_delay;
|
||||||
/* LS-byte of last TKIP seq-num (saved per AC for recovery). */
|
/* 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.*/
|
/* Retry count - number of transmissions without successful ACK.*/
|
||||||
u8 ack_failures;
|
u8 ack_failures;
|
||||||
/* The rate that succeeded getting ACK
|
/* The rate that succeeded getting ACK
|
||||||
|
|
|
@ -144,6 +144,7 @@ extern u32 wl12xx_debug_level;
|
||||||
|
|
||||||
#define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff))
|
#define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff))
|
||||||
#define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff))
|
#define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff))
|
||||||
|
#define WL1271_TX_SQN_POST_RECOVERY_PADDING 0xff
|
||||||
|
|
||||||
#define WL1271_CIPHER_SUITE_GEM 0x00147201
|
#define WL1271_CIPHER_SUITE_GEM 0x00147201
|
||||||
|
|
||||||
|
@ -454,9 +455,16 @@ struct wl1271 {
|
||||||
struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS];
|
struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS];
|
||||||
int tx_frames_cnt;
|
int tx_frames_cnt;
|
||||||
|
|
||||||
/* Security sequence number counters */
|
/*
|
||||||
u8 tx_security_last_seq;
|
* Security sequence number
|
||||||
s64 tx_security_seq;
|
* 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 */
|
/* FW Rx counter */
|
||||||
u32 rx_counter;
|
u32 rx_counter;
|
||||||
|
|
Loading…
Reference in New Issue