2011-06-19 06:05:03

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH 1/3] wl12xx: fix Tx security sequence number handling

From: Oz Krakowski <[email protected]>

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 <[email protected]>
Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/wl12xx/cmd.c | 4 ----
drivers/net/wireless/wl12xx/debugfs.c | 2 +-
drivers/net/wireless/wl12xx/main.c | 18 ++++++++++++++++--
drivers/net/wireless/wl12xx/tx.c | 22 ++++++++++++++++++----
drivers/net/wireless/wl12xx/tx.h | 2 +-
drivers/net/wireless/wl12xx/wl12xx.h | 14 +++++++++++---
6 files changed, 47 insertions(+), 15 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index b3a4f58..0a9079e 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -395,10 +395,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);

diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
index c3f19463..c52e61c 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/debugfs.c
@@ -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);
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index fb0f764..547e5d9 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -1099,6 +1099,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);

@@ -1834,8 +1843,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;
@@ -2008,6 +2015,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);

@@ -4106,6 +4117,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);

diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 6603e60..6dab9c9 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -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 + 0xFF) % 0xFF;
+ wl->tx_security_last_seq_lsb = fw_lsb;
+ }

/* remove private header from packet */
skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h
index 832f925..7ed3c01 100644
--- a/drivers/net/wireless/wl12xx/tx.h
+++ b/drivers/net/wireless/wl12xx/tx.h
@@ -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
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 1cafb08..daf6964 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -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

@@ -451,9 +452,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;
--
1.7.4.1



2011-06-19 06:05:04

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH 2/3] wl12xx: AP mode - support FW TX inactivity triggers

In AP mode we register for the MAX_TX_RETRY and INACTIVE_STA events.
Both are reported to the upper layers as a TX failure in the offending
stations.

Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/wl12xx/acx.c | 10 ++++----
drivers/net/wireless/wl12xx/acx.h | 4 +-
drivers/net/wireless/wl12xx/boot.c | 4 ++-
drivers/net/wireless/wl12xx/cmd.c | 2 +-
drivers/net/wireless/wl12xx/conf.h | 10 +++++++-
drivers/net/wireless/wl12xx/event.c | 42 ++++++++++++++++++++++++++++++++++
drivers/net/wireless/wl12xx/event.h | 12 +++++++++-
drivers/net/wireless/wl12xx/init.c | 2 +-
drivers/net/wireless/wl12xx/main.c | 9 ++++++-
drivers/net/wireless/wl12xx/wl12xx.h | 1 -
10 files changed, 82 insertions(+), 14 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index b5880eb..91fd7cc 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -1623,22 +1623,22 @@ out:
return ret;
}

-int wl1271_acx_max_tx_retry(struct wl1271 *wl)
+int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl)
{
- struct wl1271_acx_max_tx_retry *acx = NULL;
+ struct wl1271_acx_ap_max_tx_retry *acx = NULL;
int ret;

- wl1271_debug(DEBUG_ACX, "acx max tx retry");
+ wl1271_debug(DEBUG_ACX, "acx ap max tx retry");

acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx)
return -ENOMEM;

- acx->max_tx_retry = cpu_to_le16(wl->conf.tx.ap_max_tx_retries);
+ acx->max_tx_retry = cpu_to_le16(wl->conf.tx.max_tx_retries);

ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx));
if (ret < 0) {
- wl1271_warning("acx max tx retry failed: %d", ret);
+ wl1271_warning("acx ap max tx retry failed: %d", ret);
goto out;
}

diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h
index f1d55313..a30cc7be 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/acx.h
@@ -1166,7 +1166,7 @@ struct wl1271_acx_ps_rx_streaming {
u8 timeout;
} __packed;

-struct wl1271_acx_max_tx_retry {
+struct wl1271_acx_ap_max_tx_retry {
struct acx_header header;

/*
@@ -1398,7 +1398,7 @@ int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
bool enable);
int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable);
-int wl1271_acx_max_tx_retry(struct wl1271 *wl);
+int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl);
int wl1271_acx_config_ps(struct wl1271 *wl);
int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable);
diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c
index b07f8b7..651c30d 100644
--- a/drivers/net/wireless/wl12xx/boot.c
+++ b/drivers/net/wireless/wl12xx/boot.c
@@ -483,7 +483,9 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
PERIODIC_SCAN_COMPLETE_EVENT_ID;

if (wl->bss_type == BSS_TYPE_AP_BSS)
- wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID;
+ wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID |
+ INACTIVE_STA_EVENT_ID |
+ MAX_TX_RETRY_EVENT_ID;
else
wl->event_mask |= DUMMY_PACKET_EVENT_ID;

diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index 0a9079e..bafb6b7 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -1075,7 +1075,7 @@ int wl1271_cmd_start_bss(struct wl1271 *wl)

memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN);

- cmd->aging_period = cpu_to_le16(WL1271_AP_DEF_INACTIV_SEC);
+ cmd->aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period);
cmd->bss_index = WL1271_AP_BSS_INDEX;
cmd->global_hlid = WL1271_AP_GLOBAL_HLID;
cmd->broadcast_hlid = WL1271_AP_BROADCAST_HLID;
diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h
index 510c2f7..c408759 100644
--- a/drivers/net/wireless/wl12xx/conf.h
+++ b/drivers/net/wireless/wl12xx/conf.h
@@ -713,8 +713,16 @@ struct conf_tx_settings {
/*
* AP-mode - allow this number of TX retries to a station before an
* event is triggered from FW.
+ * In AP-mode the hlids of unreachable stations are given in the
+ * "sta_tx_retry_exceeded" member in the event mailbox.
*/
- u16 ap_max_tx_retries;
+ u8 max_tx_retries;
+
+ /*
+ * AP-mode - after this number of seconds a connected station is
+ * considered inactive.
+ */
+ u16 ap_aging_period;

/*
* Configuration for TID parameters.
diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c
index 9102443..cf2ba99 100644
--- a/drivers/net/wireless/wl12xx/event.c
+++ b/drivers/net/wireless/wl12xx/event.c
@@ -199,6 +199,8 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
u32 vector;
bool beacon_loss = false;
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
+ bool disconnect_sta = false;
+ unsigned long sta_bitmap = 0;

wl1271_event_mbox_dump(mbox);

@@ -272,6 +274,46 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
wl1271_tx_dummy_packet(wl);
}

+ /*
+ * "TX retries exceeded" has a different meaning according to mode.
+ * In AP mode the offending station is disconnected.
+ */
+ if ((vector & MAX_TX_RETRY_EVENT_ID) && is_ap) {
+ wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID");
+ sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded);
+ disconnect_sta = true;
+ }
+
+ if ((vector & INACTIVE_STA_EVENT_ID) && is_ap) {
+ wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID");
+ sta_bitmap |= le16_to_cpu(mbox->sta_aging_status);
+ disconnect_sta = true;
+ }
+
+ if (is_ap && disconnect_sta) {
+ u32 num_packets = wl->conf.tx.max_tx_retries;
+ struct ieee80211_sta *sta;
+ const u8 *addr;
+ int h;
+
+ for (h = find_first_bit(&sta_bitmap, AP_MAX_LINKS);
+ h < AP_MAX_LINKS;
+ h = find_next_bit(&sta_bitmap, AP_MAX_LINKS, h+1)) {
+ if (!wl1271_is_active_sta(wl, h))
+ continue;
+
+ addr = wl->links[h].addr;
+
+ rcu_read_lock();
+ sta = ieee80211_find_sta(wl->vif, addr);
+ if (sta) {
+ wl1271_debug(DEBUG_EVENT, "remove sta %d", h);
+ ieee80211_report_low_ack(sta, num_packets);
+ }
+ rcu_read_unlock();
+ }
+ }
+
if (wl->vif && beacon_loss)
ieee80211_connection_loss(wl->vif);

diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h
index b6cf06e..7ae5a08 100644
--- a/drivers/net/wireless/wl12xx/event.h
+++ b/drivers/net/wireless/wl12xx/event.h
@@ -58,13 +58,16 @@ enum {
CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17),
BSS_LOSE_EVENT_ID = BIT(18),
REGAINED_BSS_EVENT_ID = BIT(19),
- ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(20),
+ MAX_TX_RETRY_EVENT_ID = BIT(20),
/* STA: dummy paket for dynamic mem blocks */
DUMMY_PACKET_EVENT_ID = BIT(21),
/* AP: STA remove complete */
STA_REMOVE_COMPLETE_EVENT_ID = BIT(21),
SOFT_GEMINI_SENSE_EVENT_ID = BIT(22),
+ /* STA: SG prediction */
SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23),
+ /* AP: Inactive STA */
+ INACTIVE_STA_EVENT_ID = BIT(23),
SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24),
PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25),
DBG_EVENT_ID = BIT(26),
@@ -119,7 +122,11 @@ struct event_mailbox {

/* AP FW only */
u8 hlid_removed;
+
+ /* a bitmap of hlids for stations that have been inactive too long */
__le16 sta_aging_status;
+
+ /* a bitmap of hlids for stations which didn't respond to TX */
__le16 sta_tx_retry_exceeded;

u8 reserved_5[24];
@@ -130,4 +137,7 @@ void wl1271_event_mbox_config(struct wl1271 *wl);
int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
void wl1271_pspoll_work(struct work_struct *work);

+/* Functions from main.c */
+bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid);
+
#endif
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
index b85edcc..1698645 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -433,7 +433,7 @@ static int wl1271_ap_hw_init(struct wl1271 *wl)
if (ret < 0)
return ret;

- ret = wl1271_acx_max_tx_retry(wl);
+ ret = wl1271_acx_ap_max_tx_retry(wl);
if (ret < 0)
return ret;

diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 547e5d9..e84a662 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -209,7 +209,8 @@ static struct conf_drv_settings default_conf = {
.tx_op_limit = 1504,
},
},
- .ap_max_tx_retries = 100,
+ .max_tx_retries = 100,
+ .ap_aging_period = 300,
.tid_conf_count = 4,
.tid_conf = {
[CONF_TX_AC_BE] = {
@@ -3379,6 +3380,12 @@ static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
__clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
}

+bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
+{
+ int id = hlid - WL1271_AP_STA_HLID_START;
+ return test_bit(id, wl->ap_hlid_map);
+}
+
static int wl1271_op_sta_add(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index daf6964..15e3337 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -173,7 +173,6 @@ extern u32 wl12xx_debug_level;
#define WL1271_PS_STA_MAX_BLOCKS (2 * 9)

#define WL1271_AP_BSS_INDEX 0
-#define WL1271_AP_DEF_INACTIV_SEC 300
#define WL1271_AP_DEF_BEACON_EXP 20

#define ACX_TX_DESCRIPTORS 32
--
1.7.4.1


2011-06-19 06:05:05

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH 3/3] wl12xx: use 802.11 header location after relocation to frame start

When operating with TKIP encryption, the function wl1271_tx_fill_hdr()
relocates the 802.11 header to the start of the frame, and leaves room
for the security header.

Some functions in the Tx path rely on the location of the header,
namely, for purposes of roaming in STA mode and connecting new stations
in AP mode. Call these functions only after the header is relocated.

Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/wl12xx/tx.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 6dab9c9..39f4292 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -383,6 +383,8 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
if (ret < 0)
return ret;

+ wl1271_tx_fill_hdr(wl, skb, extra, info, hlid);
+
if (wl->bss_type == BSS_TYPE_AP_BSS) {
wl1271_tx_ap_update_inconnection_sta(wl, skb);
wl1271_tx_regulate_link(wl, hlid);
@@ -390,8 +392,6 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
wl1271_tx_update_filters(wl, skb);
}

- wl1271_tx_fill_hdr(wl, skb, extra, info, hlid);
-
/*
* The length of each packet is stored in terms of
* words. Thus, we must pad the skb data to make sure its
--
1.7.4.1


2011-07-05 17:43:48

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 1/3] wl12xx: fix Tx security sequence number handling

On Sun, 2011-06-19 at 09:04 +0300, Arik Nemtsov wrote:
> From: Oz Krakowski <[email protected]>
>
> 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 <[email protected]>
> Signed-off-by: Arik Nemtsov <[email protected]>
> ---

Applied the series, thanks!

Oz, nice to see a patch from you! :)

--
Cheers,
Luca.