Commit bb8edd90 authored by Russell King (Oracle)'s avatar Russell King (Oracle) Committed by Kalle Valo

wifi: wlcore: add pn16 support

TI Wl18xx firmware adds a "pn16" field for AES and TKIP keys as per
their patch:

https://git.ti.com/cgit/wilink8-wlan/build-utilites/tree/patches/kernel_patches/4.19.38/0023-wlcore-Fixing-PN-drift-on-encrypted-link-after-recov.patch?h=r8.9&id=a2ee50aa5190ed3b334373d6cd09b1bff56ffcf7

Add support for this, but rather than requiring the field to be
present (which would break existing firmwares), make it optional.
Signed-off-by: default avatarRussell King (Oracle) <rmk+kernel@armlinux.org.uk>
Signed-off-by: default avatarKalle Valo <kvalo@kernel.org>
Link: https://msgid.link/E1sBsy7-00E8vu-Nc@rmk-PC.armlinux.org.uk
parent 81271c2b
......@@ -332,6 +332,14 @@ int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
wl->fw_status->counters.tx_lnk_free_pkts[link];
wl->links[link].wlvif = wlvif;
/*
* Take the last sec_pn16 value from the current FW status. On recovery,
* we might not have fw_status yet, and tx_lnk_sec_pn16[] will be NULL.
*/
if (wl->fw_status->counters.tx_lnk_sec_pn16)
wl->links[link].prev_sec_pn16 =
le16_to_cpu(wl->fw_status->counters.tx_lnk_sec_pn16[link]);
/*
* Take saved value for total freed packets from wlvif, in case this is
* recovery/resume
......@@ -360,6 +368,7 @@ void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
wl->links[*hlid].allocated_pkts = 0;
wl->links[*hlid].prev_freed_pkts = 0;
wl->links[*hlid].prev_sec_pn16 = 0;
wl->links[*hlid].ba_bitmap = 0;
eth_zero_addr(wl->links[*hlid].addr);
......
......@@ -379,6 +379,8 @@ static void wl12xx_irq_update_links_status(struct wl1271 *wl,
static int wlcore_fw_status(struct wl1271 *wl, struct wl_fw_status *status)
{
struct wl12xx_vif *wlvifsta;
struct wl12xx_vif *wlvifap;
struct wl12xx_vif *wlvif;
u32 old_tx_blk_count = wl->tx_blocks_available;
int avail, freed_blocks;
......@@ -410,23 +412,100 @@ static int wlcore_fw_status(struct wl1271 *wl, struct wl_fw_status *status)
wl->tx_pkts_freed[i] = status->counters.tx_released_pkts[i];
}
/* Find an authorized STA vif */
wlvifsta = NULL;
wl12xx_for_each_wlvif_sta(wl, wlvif) {
if (wlvif->sta.hlid != WL12XX_INVALID_LINK_ID &&
test_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags)) {
wlvifsta = wlvif;
break;
}
}
/* Find a started AP vif */
wlvifap = NULL;
wl12xx_for_each_wlvif(wl, wlvif) {
if (wlvif->bss_type == BSS_TYPE_AP_BSS &&
wlvif->inconn_count == 0 &&
test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
wlvifap = wlvif;
break;
}
}
for_each_set_bit(i, wl->links_map, wl->num_links) {
u16 diff16, sec_pn16;
u8 diff, tx_lnk_free_pkts;
lnk = &wl->links[i];
/* prevent wrap-around in freed-packets counter */
tx_lnk_free_pkts = status->counters.tx_lnk_free_pkts[i];
diff = (tx_lnk_free_pkts - lnk->prev_freed_pkts) & 0xff;
if (diff == 0)
if (diff) {
lnk->allocated_pkts -= diff;
lnk->prev_freed_pkts = tx_lnk_free_pkts;
}
/* Get the current sec_pn16 value if present */
if (status->counters.tx_lnk_sec_pn16)
sec_pn16 = __le16_to_cpu(status->counters.tx_lnk_sec_pn16[i]);
else
sec_pn16 = 0;
/* prevent wrap-around in pn16 counter */
diff16 = (sec_pn16 - lnk->prev_sec_pn16) & 0xffff;
/* FIXME: since free_pkts is a 8-bit counter of packets that
* rolls over, it can become zero. If it is zero, then we
* omit processing below. Is that really correct?
*/
if (tx_lnk_free_pkts <= 0)
continue;
lnk->allocated_pkts -= diff;
lnk->prev_freed_pkts = tx_lnk_free_pkts;
/* For a station that has an authorized link: */
if (wlvifsta && wlvifsta->sta.hlid == i) {
if (wlvifsta->encryption_type == KEY_TKIP ||
wlvifsta->encryption_type == KEY_AES) {
if (diff16) {
lnk->prev_sec_pn16 = sec_pn16;
/* accumulate the prev_freed_pkts
* counter according to the PN from
* firmware
*/
lnk->total_freed_pkts += diff16;
}
} else {
if (diff)
/* accumulate the prev_freed_pkts
* counter according to the free packets
* count from firmware
*/
lnk->total_freed_pkts += diff;
}
}
/* accumulate the prev_freed_pkts counter */
lnk->total_freed_pkts += diff;
/* For an AP that has been started */
if (wlvifap && test_bit(i, wlvifap->ap.sta_hlid_map)) {
if (wlvifap->encryption_type == KEY_TKIP ||
wlvifap->encryption_type == KEY_AES) {
if (diff16) {
lnk->prev_sec_pn16 = sec_pn16;
/* accumulate the prev_freed_pkts
* counter according to the PN from
* firmware
*/
lnk->total_freed_pkts += diff16;
}
} else {
if (diff)
/* accumulate the prev_freed_pkts
* counter according to the free packets
* count from firmware
*/
lnk->total_freed_pkts += diff;
}
}
}
/* prevent wrap-around in total blocks counter */
......
......@@ -151,6 +151,9 @@ struct wl_fw_status {
*/
u8 *tx_lnk_free_pkts;
/* PN16 of last TKIP/AES seq-num per HLID */
__le16 *tx_lnk_sec_pn16;
/* Cumulative counter of released Voice memory blocks */
u8 tx_voice_released_blks;
......@@ -259,6 +262,7 @@ struct wl1271_link {
/* accounting for allocated / freed packets in FW */
u8 allocated_pkts;
u8 prev_freed_pkts;
u16 prev_sec_pn16;
u8 addr[ETH_ALEN];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment