struct cfg80211_bitrate_mask bitrate_mask;
struct wmi_ns_arp_offload_req arp_offload;
struct wmi_ns_arp_offload_req ns_offload;
+ struct wmi_gtk_rekey_data gtk_rekey_data;
};
struct ath10k_vif_iter {
.suspend = ath10k_wow_op_suspend,
.resume = ath10k_wow_op_resume,
.set_wakeup = ath10k_wow_op_set_wakeup,
+ .set_rekey_data = ath10k_wow_op_set_rekey_data,
#endif
#ifdef CONFIG_MAC80211_DEBUGFS
.sta_add_debugfs = ath10k_sta_add_debugfs,
const struct wmi_sta_keepalive_arg *arg);
struct sk_buff *(*gen_set_arp_ns_offload)(struct ath10k *ar,
struct ath10k_vif *arvif);
+ struct sk_buff *(*gen_gtk_offload)(struct ath10k *ar,
+ struct ath10k_vif *arvif);
struct sk_buff *(*gen_wow_enable)(struct ath10k *ar);
struct sk_buff *(*gen_wow_add_wakeup_event)(struct ath10k *ar, u32 vdev_id,
enum wmi_wow_wakeup_event event,
}
static inline int
+ath10k_wmi_gtk_offload(struct ath10k *ar, struct ath10k_vif *arvif)
+{
+ struct sk_buff *skb;
+ u32 cmd_id;
+
+ if (!ar->wmi.ops->gen_gtk_offload)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_gtk_offload(ar, arvif);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ cmd_id = ar->wmi.cmd->gtk_offload_cmdid;
+ return ath10k_wmi_cmd_send(ar, skb, cmd_id);
+}
+
+static inline int
ath10k_wmi_wow_enable(struct ath10k *ar)
{
struct sk_buff *skb;
}
static struct sk_buff *
+ath10k_wmi_op_gen_gtk_offload(struct ath10k *ar, struct ath10k_vif *arvif)
+{
+ struct wmi_tlv_gtk_offload_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ struct wmi_gtk_rekey_data *rekey_data = &arvif->gtk_rekey_data;
+ int len;
+
+ len = sizeof(*cmd) + sizeof(*tlv);
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (void *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_GTK_OFFLOAD_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ if (rekey_data->enable_offload) {
+ cmd->vdev_id = __cpu_to_le32(arvif->vdev_id);
+ cmd->flags |= __cpu_to_le32(WMI_GTK_OFFLOAD_ENABLE_OPCODE);
+ memcpy(cmd->kek, rekey_data->kek, NL80211_KEK_LEN);
+ memcpy(cmd->kck, rekey_data->kck, NL80211_KCK_LEN);
+ cmd->replay_ctr = __cpu_to_le64(rekey_data->replay_ctr);
+ } else {
+ cmd->vdev_id = __cpu_to_le32(arvif->vdev_id);
+ cmd->flags |= __cpu_to_le32(WMI_GTK_OFFLOAD_DISABLE_OPCODE);
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi GTK offload for vdev: %d\n", arvif->vdev_id);
+ return skb;
+}
+
+static struct sk_buff *
ath10k_wmi_tlv_op_gen_set_arp_ns_offload(struct ath10k *ar,
struct ath10k_vif *arvif)
{
.gen_vdev_sta_uapsd = ath10k_wmi_tlv_op_gen_vdev_sta_uapsd,
.gen_sta_keepalive = ath10k_wmi_tlv_op_gen_sta_keepalive,
.gen_set_arp_ns_offload = ath10k_wmi_tlv_op_gen_set_arp_ns_offload,
+ .gen_gtk_offload = ath10k_wmi_op_gen_gtk_offload,
.gen_wow_enable = ath10k_wmi_tlv_op_gen_wow_enable,
.gen_wow_add_wakeup_event = ath10k_wmi_tlv_op_gen_wow_add_wakeup_event,
.gen_wow_host_wakeup_ind = ath10k_wmi_tlv_gen_wow_host_wakeup_ind,
__le32 num_ns_ext_tuples;
} __packed;
+struct wmi_tlv_gtk_offload_cmd {
+ __le32 vdev_id;
+ __le32 flags;
+ u8 kek[NL80211_KEK_LEN];
+ u8 kck[NL80211_KCK_LEN];
+ __le64 replay_ctr;
+} __packed;
+
struct wmi_tlv_wow_host_wakeup_ind {
__le32 reserved;
} __packed;
struct wmi_mac_addr target_mac;
} __packed;
+/* GTK offload data structure */
+#define WMI_GTK_OFFLOAD_ENABLE_OPCODE BIT(24)
+#define WMI_GTK_OFFLOAD_DISABLE_OPCODE BIT(25)
+#define WMI_GTK_OFFLOAD_ENABLE 1
+#define WMI_GTK_OFFLOAD_DISABLE 0
+
+struct wmi_gtk_rekey_data {
+ bool valid;
+ bool enable_offload;
+ u8 kck[NL80211_KCK_LEN];
+ u8 kek[NL80211_KEK_LEN];
+ __le64 replay_ctr;
+} __packed;
+
struct wmi_start_scan_tlvs {
/* TLV parameters. These includes channel list, ssid list, bssid list,
* extra ies.
return 0;
}
+void ath10k_wow_op_set_rekey_data(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct cfg80211_gtk_rekey_data *data)
+{
+ struct ath10k *ar = hw->priv;
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+
+ mutex_lock(&ar->conf_mutex);
+ memcpy(&arvif->gtk_rekey_data.kek, data->kek, NL80211_KEK_LEN);
+ memcpy(&arvif->gtk_rekey_data.kck, data->kck, NL80211_KCK_LEN);
+ arvif->gtk_rekey_data.replay_ctr =
+ __cpu_to_le64(*(__le64 *)data->replay_ctr);
+ arvif->gtk_rekey_data.valid = true;
+ mutex_unlock(&ar->conf_mutex);
+}
+
+static int ath10k_wow_config_gtk_offload(struct ath10k *ar, bool gtk_offload)
+{
+ struct ath10k_vif *arvif;
+ struct ieee80211_bss_conf *bss;
+ struct wmi_gtk_rekey_data *rekey_data;
+ int ret;
+
+ list_for_each_entry(arvif, &ar->arvifs, list) {
+ if (arvif->vdev_type != WMI_VDEV_TYPE_STA)
+ continue;
+
+ bss = &arvif->vif->bss_conf;
+ if (!arvif->is_up || !bss->assoc)
+ continue;
+
+ rekey_data = &arvif->gtk_rekey_data;
+ if (!rekey_data->valid)
+ continue;
+
+ if (gtk_offload)
+ rekey_data->enable_offload = WMI_GTK_OFFLOAD_ENABLE;
+ else
+ rekey_data->enable_offload = WMI_GTK_OFFLOAD_DISABLE;
+ ret = ath10k_wmi_gtk_offload(ar, arvif);
+ if (ret) {
+ ath10k_err(ar, "GTK offload failed for vdev_id: %d\n",
+ arvif->vdev_id);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
int ath10k_wow_op_suspend(struct ieee80211_hw *hw,
struct cfg80211_wowlan *wowlan)
{
goto exit;
}
+ ret = ath10k_wow_config_gtk_offload(ar, true);
+ if (ret) {
+ ath10k_warn(ar, "failed to enable GTK offload: %d\n", ret);
+ goto exit;
+ }
+
ret = ath10k_wow_enable_ns_arp_offload(ar, true);
if (ret) {
ath10k_warn(ar, "failed to enable ARP-NS offload: %d\n", ret);
- goto exit;
+ goto disable_gtk_offload;
}
ret = ath10k_wow_cleanup(ar);
disable_ns_arp_offload:
ath10k_wow_enable_ns_arp_offload(ar, false);
+disable_gtk_offload:
+ ath10k_wow_config_gtk_offload(ar, false);
exit:
mutex_unlock(&ar->conf_mutex);
return ret ? 1 : 0;
}
ret = ath10k_wow_enable_ns_arp_offload(ar, false);
- if (ret)
+ if (ret) {
ath10k_warn(ar, "failed to disable ARP-NS offload: %d\n", ret);
+ goto exit;
+ }
+
+ ret = ath10k_wow_config_gtk_offload(ar, false);
+ if (ret)
+ ath10k_warn(ar, "failed to disable GTK offload: %d\n", ret);
exit:
if (ret) {
struct cfg80211_wowlan *wowlan);
int ath10k_wow_op_resume(struct ieee80211_hw *hw);
void ath10k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled);
-
+void ath10k_wow_op_set_rekey_data(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct cfg80211_gtk_rekey_data *data);
#else
static inline int ath10k_wow_init(struct ath10k *ar)