OSDN Git Service

ath10k: enable gtk offload for the wcn3990 wlan module
authorSarada Prasanna Garnayak <sgarna@codeaurora.org>
Fri, 24 Nov 2017 09:57:46 +0000 (15:27 +0530)
committerSarada Prasanna Garnayak <sgarna@codeaurora.org>
Tue, 5 Dec 2017 10:10:00 +0000 (15:40 +0530)
Register ops to store the gtk rekey data from the wlan
utility(wpa_supplicant) and configure the GTK offload
during wow suspend.

If the wlan module in suspend state with wowlan mode
this feature adds support to prevent the device to wakeup
from sleep state on gtk rekey failure in wlan firmware.

CRs-Fixed: 2150959
Change-Id: I968acfe65bd082d37c855f89d4460a09c055ffd8
Signed-off-by: Sarada Prasanna Garnayak <sgarna@codeaurora.org>
drivers/net/wireless/ath/ath10k/core.h
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath10k/wmi-ops.h
drivers/net/wireless/ath/ath10k/wmi-tlv.c
drivers/net/wireless/ath/ath10k/wmi-tlv.h
drivers/net/wireless/ath/ath10k/wmi.h
drivers/net/wireless/ath/ath10k/wow.c
drivers/net/wireless/ath/ath10k/wow.h

index f194d43..2ef2e1e 100644 (file)
@@ -433,6 +433,7 @@ struct ath10k_vif {
        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 {
index 9fcc286..16a5c5f 100644 (file)
@@ -7583,6 +7583,7 @@ static const struct ieee80211_ops ath10k_ops = {
        .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,
index dcb0da5..cf738ef 100644 (file)
@@ -162,6 +162,8 @@ struct wmi_ops {
                                             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,
@@ -1206,6 +1208,23 @@ ath10k_wmi_set_arp_ns_offload(struct ath10k *ar, struct ath10k_vif *arvif)
 }
 
 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;
index ad27abc..5ce4fdf 100644 (file)
@@ -3015,6 +3015,40 @@ ath10k_wmi_tlv_op_gen_tdls_peer_update(struct ath10k *ar,
 }
 
 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)
 {
@@ -3778,6 +3812,7 @@ static const struct wmi_ops wmi_tlv_ops = {
        .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,
index 39951d2..18327da 100644 (file)
@@ -1567,6 +1567,14 @@ struct wmi_tlv_arp_ns_offload_cmd {
        __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;
index 44c237e..2694b6a 100644 (file)
@@ -2933,6 +2933,20 @@ struct wmi_arp_offload {
        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.
index 429fcce..6bbcf8b 100644 (file)
@@ -320,6 +320,56 @@ static int ath10k_config_wow_listen_interval(struct ath10k *ar)
        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)
 {
@@ -334,10 +384,16 @@ int ath10k_wow_op_suspend(struct ieee80211_hw *hw,
                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);
@@ -384,6 +440,8 @@ cleanup:
 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;
@@ -427,8 +485,14 @@ int ath10k_wow_op_resume(struct ieee80211_hw *hw)
        }
 
        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) {
index 9745b9d..ce79908 100644 (file)
@@ -29,7 +29,9 @@ int ath10k_wow_op_suspend(struct ieee80211_hw *hw,
                          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)