Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b992c682 authored by Oz Krakowski's avatar Oz Krakowski Committed by Luciano Coelho
Browse files

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: default avatarOz Krakowski <ozk@ti.com>
Signed-off-by: default avatarArik Nemtsov <arik@wizery.com>
Signed-off-by: default avatarLuciano Coelho <coelho@ti.com>
parent 95dac04f
Loading
Loading
Loading
Loading
+0 −4
Original line number Diff line number Diff line
@@ -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);

+1 −1
Original line number Diff line number Diff line
@@ -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);
+16 −2
Original line number Diff line number Diff line
@@ -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;
+18 −4
Original line number Diff line number Diff line
@@ -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));
+1 −1
Original line number Diff line number Diff line
@@ -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
Loading