Skip to content

Commit a16d9b5

Browse files
ygbluekvalo
authored andcommitted
ath11k: support GTK rekey offload
Host sets GTK related info to firmware before WoW is enabled, and gets rekey replay_count and then disables GTK rekey when WoW quits. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Signed-off-by: Carl Huang <[email protected]> Signed-off-by: Kalle Valo <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent c3c36bf commit a16d9b5

File tree

5 files changed

+258
-1
lines changed

5 files changed

+258
-1
lines changed

drivers/net/wireless/ath/ath11k/core.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,13 @@ struct ath11k_arp_ns_offload {
230230
u8 mac_addr[ETH_ALEN];
231231
};
232232

233+
struct ath11k_rekey_data {
234+
u8 kck[NL80211_KCK_LEN];
235+
u8 kek[NL80211_KCK_LEN];
236+
u64 replay_ctr;
237+
bool enable_offload;
238+
};
239+
233240
struct ath11k_vif {
234241
u32 vdev_id;
235242
enum wmi_vdev_type vdev_type;
@@ -282,6 +289,7 @@ struct ath11k_vif {
282289
bool do_not_send_tmpl;
283290
struct ieee80211_chanctx_conf chanctx;
284291
struct ath11k_arp_ns_offload arp_ns_offload;
292+
struct ath11k_rekey_data rekey_data;
285293

286294
#ifdef CONFIG_ATH11K_DEBUGFS
287295
struct dentry *debugfs_twt;

drivers/net/wireless/ath/ath11k/mac.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2757,6 +2757,7 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw,
27572757
}
27582758

27592759
arvif->is_up = true;
2760+
arvif->rekey_data.enable_offload = false;
27602761

27612762
ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
27622763
"mac vdev %d up (associated) bssid %pM aid %d\n",
@@ -2814,6 +2815,8 @@ static void ath11k_bss_disassoc(struct ieee80211_hw *hw,
28142815

28152816
arvif->is_up = false;
28162817

2818+
memset(&arvif->rekey_data, 0, sizeof(arvif->rekey_data));
2819+
28172820
cancel_delayed_work_sync(&arvif->connection_loss_work);
28182821
}
28192822

@@ -8200,6 +8203,39 @@ static void ath11k_mac_op_ipv6_changed(struct ieee80211_hw *hw,
82008203
ath11k_generate_ns_mc_addr(ar, offload);
82018204
}
82028205

8206+
static void ath11k_mac_op_set_rekey_data(struct ieee80211_hw *hw,
8207+
struct ieee80211_vif *vif,
8208+
struct cfg80211_gtk_rekey_data *data)
8209+
{
8210+
struct ath11k *ar = hw->priv;
8211+
struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
8212+
struct ath11k_rekey_data *rekey_data = &arvif->rekey_data;
8213+
8214+
ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac set rekey data vdev %d\n",
8215+
arvif->vdev_id);
8216+
8217+
mutex_lock(&ar->conf_mutex);
8218+
8219+
memcpy(rekey_data->kck, data->kck, NL80211_KCK_LEN);
8220+
memcpy(rekey_data->kek, data->kek, NL80211_KEK_LEN);
8221+
8222+
/* The supplicant works on big-endian, the firmware expects it on
8223+
* little endian.
8224+
*/
8225+
rekey_data->replay_ctr = get_unaligned_be64(data->replay_ctr);
8226+
8227+
arvif->rekey_data.enable_offload = true;
8228+
8229+
ath11k_dbg_dump(ar->ab, ATH11K_DBG_MAC, "kck", NULL,
8230+
rekey_data->kck, NL80211_KCK_LEN);
8231+
ath11k_dbg_dump(ar->ab, ATH11K_DBG_MAC, "kek", NULL,
8232+
rekey_data->kck, NL80211_KEK_LEN);
8233+
ath11k_dbg_dump(ar->ab, ATH11K_DBG_MAC, "replay ctr", NULL,
8234+
&rekey_data->replay_ctr, sizeof(rekey_data->replay_ctr));
8235+
8236+
mutex_unlock(&ar->conf_mutex);
8237+
}
8238+
82038239
static const struct ieee80211_ops ath11k_ops = {
82048240
.tx = ath11k_mac_op_tx,
82058241
.start = ath11k_mac_op_start,
@@ -8214,6 +8250,7 @@ static const struct ieee80211_ops ath11k_ops = {
82148250
.hw_scan = ath11k_mac_op_hw_scan,
82158251
.cancel_hw_scan = ath11k_mac_op_cancel_hw_scan,
82168252
.set_key = ath11k_mac_op_set_key,
8253+
.set_rekey_data = ath11k_mac_op_set_rekey_data,
82178254
.sta_state = ath11k_mac_op_sta_state,
82188255
.sta_set_4addr = ath11k_mac_op_sta_set_4addr,
82198256
.sta_set_txpwr = ath11k_mac_op_sta_set_txpwr,

drivers/net/wireless/ath/ath11k/wmi.c

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7765,6 +7765,56 @@ static void ath11k_wmi_twt_add_dialog_event(struct ath11k_base *ab,
77657765
kfree(tb);
77667766
}
77677767

7768+
static void ath11k_wmi_gtk_offload_status_event(struct ath11k_base *ab,
7769+
struct sk_buff *skb)
7770+
{
7771+
const void **tb;
7772+
const struct wmi_gtk_offload_status_event *ev;
7773+
struct ath11k_vif *arvif;
7774+
__be64 replay_ctr_be;
7775+
u64 replay_ctr;
7776+
int ret;
7777+
7778+
tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
7779+
if (IS_ERR(tb)) {
7780+
ret = PTR_ERR(tb);
7781+
ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
7782+
return;
7783+
}
7784+
7785+
ev = tb[WMI_TAG_GTK_OFFLOAD_STATUS_EVENT];
7786+
if (!ev) {
7787+
ath11k_warn(ab, "failed to fetch gtk offload status ev");
7788+
kfree(tb);
7789+
return;
7790+
}
7791+
7792+
arvif = ath11k_mac_get_arvif_by_vdev_id(ab, ev->vdev_id);
7793+
if (!arvif) {
7794+
ath11k_warn(ab, "failed to get arvif for vdev_id:%d\n",
7795+
ev->vdev_id);
7796+
kfree(tb);
7797+
return;
7798+
}
7799+
7800+
ath11k_dbg(ab, ATH11K_DBG_WMI, "wmi gtk offload event refresh_cnt %d\n",
7801+
ev->refresh_cnt);
7802+
ath11k_dbg_dump(ab, ATH11K_DBG_WMI, "replay_cnt",
7803+
NULL, ev->replay_ctr.counter, GTK_REPLAY_COUNTER_BYTES);
7804+
7805+
replay_ctr = ev->replay_ctr.word1;
7806+
replay_ctr = (replay_ctr << 32) | ev->replay_ctr.word0;
7807+
arvif->rekey_data.replay_ctr = replay_ctr;
7808+
7809+
/* supplicant expects big-endian replay counter */
7810+
replay_ctr_be = cpu_to_be64(replay_ctr);
7811+
7812+
ieee80211_gtk_rekey_notify(arvif->vif, arvif->bssid,
7813+
(void *)&replay_ctr_be, GFP_KERNEL);
7814+
7815+
kfree(tb);
7816+
}
7817+
77687818
static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb)
77697819
{
77707820
struct wmi_cmd_hdr *cmd_hdr;
@@ -7896,6 +7946,9 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb)
78967946
case WMI_DIAG_EVENTID:
78977947
ath11k_wmi_diag_event(ab, skb);
78987948
break;
7949+
case WMI_GTK_OFFLOAD_STATUS_EVENTID:
7950+
ath11k_wmi_gtk_offload_status_event(ab, skb);
7951+
break;
78997952
/* TODO: Add remaining events */
79007953
default:
79017954
ath11k_dbg(ab, ATH11K_DBG_WMI, "Unknown eventid: 0x%x\n", id);
@@ -8735,3 +8788,69 @@ int ath11k_wmi_arp_ns_offload(struct ath11k *ar,
87358788

87368789
return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_SET_ARP_NS_OFFLOAD_CMDID);
87378790
}
8791+
8792+
int ath11k_wmi_gtk_rekey_offload(struct ath11k *ar,
8793+
struct ath11k_vif *arvif, bool enable)
8794+
{
8795+
struct wmi_gtk_rekey_offload_cmd *cmd;
8796+
struct ath11k_rekey_data *rekey_data = &arvif->rekey_data;
8797+
int len;
8798+
struct sk_buff *skb;
8799+
__le64 replay_ctr;
8800+
8801+
len = sizeof(*cmd);
8802+
skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len);
8803+
if (!skb)
8804+
return -ENOMEM;
8805+
8806+
cmd = (struct wmi_gtk_rekey_offload_cmd *)skb->data;
8807+
cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_GTK_OFFLOAD_CMD) |
8808+
FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
8809+
8810+
cmd->vdev_id = arvif->vdev_id;
8811+
8812+
if (enable) {
8813+
cmd->flags = GTK_OFFLOAD_ENABLE_OPCODE;
8814+
8815+
/* the length in rekey_data and cmd is equal */
8816+
memcpy(cmd->kck, rekey_data->kck, sizeof(cmd->kck));
8817+
ath11k_ce_byte_swap(cmd->kck, GTK_OFFLOAD_KEK_BYTES);
8818+
memcpy(cmd->kek, rekey_data->kek, sizeof(cmd->kek));
8819+
ath11k_ce_byte_swap(cmd->kek, GTK_OFFLOAD_KEK_BYTES);
8820+
8821+
replay_ctr = cpu_to_le64(rekey_data->replay_ctr);
8822+
memcpy(cmd->replay_ctr, &replay_ctr,
8823+
sizeof(replay_ctr));
8824+
ath11k_ce_byte_swap(cmd->replay_ctr, GTK_REPLAY_COUNTER_BYTES);
8825+
} else {
8826+
cmd->flags = GTK_OFFLOAD_DISABLE_OPCODE;
8827+
}
8828+
8829+
ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "offload gtk rekey vdev: %d %d\n",
8830+
arvif->vdev_id, enable);
8831+
return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_GTK_OFFLOAD_CMDID);
8832+
}
8833+
8834+
int ath11k_wmi_gtk_rekey_getinfo(struct ath11k *ar,
8835+
struct ath11k_vif *arvif)
8836+
{
8837+
struct wmi_gtk_rekey_offload_cmd *cmd;
8838+
int len;
8839+
struct sk_buff *skb;
8840+
8841+
len = sizeof(*cmd);
8842+
skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len);
8843+
if (!skb)
8844+
return -ENOMEM;
8845+
8846+
cmd = (struct wmi_gtk_rekey_offload_cmd *)skb->data;
8847+
cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_GTK_OFFLOAD_CMD) |
8848+
FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
8849+
8850+
cmd->vdev_id = arvif->vdev_id;
8851+
cmd->flags = GTK_OFFLOAD_REQUEST_STATUS_OPCODE;
8852+
8853+
ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "get gtk rekey vdev_id: %d\n",
8854+
arvif->vdev_id);
8855+
return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_GTK_OFFLOAD_CMDID);
8856+
}

drivers/net/wireless/ath/ath11k/wmi.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5840,6 +5840,51 @@ struct wmi_set_arp_ns_offload_cmd {
58405840
*/
58415841
} __packed;
58425842

5843+
#define GTK_OFFLOAD_OPCODE_MASK 0xFF000000
5844+
#define GTK_OFFLOAD_ENABLE_OPCODE 0x01000000
5845+
#define GTK_OFFLOAD_DISABLE_OPCODE 0x02000000
5846+
#define GTK_OFFLOAD_REQUEST_STATUS_OPCODE 0x04000000
5847+
5848+
#define GTK_OFFLOAD_KEK_BYTES 16
5849+
#define GTK_OFFLOAD_KCK_BYTES 16
5850+
#define GTK_REPLAY_COUNTER_BYTES 8
5851+
#define WMI_MAX_KEY_LEN 32
5852+
#define IGTK_PN_SIZE 6
5853+
5854+
struct wmi_replayc_cnt {
5855+
union {
5856+
u8 counter[GTK_REPLAY_COUNTER_BYTES];
5857+
struct {
5858+
u32 word0;
5859+
u32 word1;
5860+
} __packed;
5861+
} __packed;
5862+
} __packed;
5863+
5864+
struct wmi_gtk_offload_status_event {
5865+
u32 vdev_id;
5866+
u32 flags;
5867+
u32 refresh_cnt;
5868+
struct wmi_replayc_cnt replay_ctr;
5869+
u8 igtk_key_index;
5870+
u8 igtk_key_length;
5871+
u8 igtk_key_rsc[IGTK_PN_SIZE];
5872+
u8 igtk_key[WMI_MAX_KEY_LEN];
5873+
u8 gtk_key_index;
5874+
u8 gtk_key_length;
5875+
u8 gtk_key_rsc[GTK_REPLAY_COUNTER_BYTES];
5876+
u8 gtk_key[WMI_MAX_KEY_LEN];
5877+
} __packed;
5878+
5879+
struct wmi_gtk_rekey_offload_cmd {
5880+
u32 tlv_header;
5881+
u32 vdev_id;
5882+
u32 flags;
5883+
u8 kek[GTK_OFFLOAD_KEK_BYTES];
5884+
u8 kck[GTK_OFFLOAD_KCK_BYTES];
5885+
u8 replay_ctr[GTK_REPLAY_COUNTER_BYTES];
5886+
} __packed;
5887+
58435888
int ath11k_wmi_cmd_send(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb,
58445889
u32 cmd_id);
58455890
struct sk_buff *ath11k_wmi_alloc_skb(struct ath11k_wmi_base *wmi_sc, u32 len);
@@ -6014,5 +6059,9 @@ int ath11k_wmi_hw_data_filter_cmd(struct ath11k *ar, u32 vdev_id,
60146059
u32 filter_bitmap, bool enable);
60156060
int ath11k_wmi_arp_ns_offload(struct ath11k *ar,
60166061
struct ath11k_vif *arvif, bool enable);
6062+
int ath11k_wmi_gtk_rekey_offload(struct ath11k *ar,
6063+
struct ath11k_vif *arvif, bool enable);
6064+
int ath11k_wmi_gtk_rekey_getinfo(struct ath11k *ar,
6065+
struct ath11k_vif *arvif);
60176066

60186067
#endif

drivers/net/wireless/ath/ath11k/wow.c

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717

1818
static const struct wiphy_wowlan_support ath11k_wowlan_support = {
1919
.flags = WIPHY_WOWLAN_DISCONNECT |
20-
WIPHY_WOWLAN_MAGIC_PKT,
20+
WIPHY_WOWLAN_MAGIC_PKT |
21+
WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
22+
WIPHY_WOWLAN_GTK_REKEY_FAILURE,
2123
.pattern_min_len = WOW_MIN_PATTERN_SIZE,
2224
.pattern_max_len = WOW_MAX_PATTERN_SIZE,
2325
.max_pkt_offset = WOW_MAX_PKT_OFFSET,
@@ -582,6 +584,41 @@ static int ath11k_wow_arp_ns_offload(struct ath11k *ar, bool enable)
582584
return 0;
583585
}
584586

587+
static int ath11k_gtk_rekey_offload(struct ath11k *ar, bool enable)
588+
{
589+
struct ath11k_vif *arvif;
590+
int ret;
591+
592+
lockdep_assert_held(&ar->conf_mutex);
593+
594+
list_for_each_entry(arvif, &ar->arvifs, list) {
595+
if (arvif->vdev_type != WMI_VDEV_TYPE_STA ||
596+
!arvif->is_up ||
597+
!arvif->rekey_data.enable_offload)
598+
continue;
599+
600+
/* get rekey info before disable rekey offload */
601+
if (!enable) {
602+
ret = ath11k_wmi_gtk_rekey_getinfo(ar, arvif);
603+
if (ret) {
604+
ath11k_warn(ar->ab, "failed to request rekey info vdev %i, ret %d\n",
605+
arvif->vdev_id, ret);
606+
return ret;
607+
}
608+
}
609+
610+
ret = ath11k_wmi_gtk_rekey_offload(ar, arvif, enable);
611+
612+
if (ret) {
613+
ath11k_warn(ar->ab, "failed to offload gtk reky vdev %i: enable %d, ret %d\n",
614+
arvif->vdev_id, enable, ret);
615+
return ret;
616+
}
617+
}
618+
619+
return 0;
620+
}
621+
585622
static int ath11k_wow_protocol_offload(struct ath11k *ar, bool enable)
586623
{
587624
int ret;
@@ -593,6 +630,13 @@ static int ath11k_wow_protocol_offload(struct ath11k *ar, bool enable)
593630
return ret;
594631
}
595632

633+
ret = ath11k_gtk_rekey_offload(ar, enable);
634+
if (ret) {
635+
ath11k_warn(ar->ab, "failed to offload gtk rekey %d %d\n",
636+
enable, ret);
637+
return ret;
638+
}
639+
596640
return 0;
597641
}
598642

0 commit comments

Comments
 (0)