ath10k: enable gtk offload for the wcn3990 wlan module

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>
This commit is contained in:
Sarada Prasanna Garnayak 2017-11-24 15:27:46 +05:30
parent 9d94fcc769
commit b36f40c0d8
8 changed files with 147 additions and 3 deletions

View 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 {

View 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,

View 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,
@ -1205,6 +1207,23 @@ ath10k_wmi_set_arp_ns_offload(struct ath10k *ar, struct ath10k_vif *arvif)
return ath10k_wmi_cmd_send(ar, skb, cmd_id);
}
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)
{

View file

@ -3014,6 +3014,40 @@ ath10k_wmi_tlv_op_gen_tdls_peer_update(struct ath10k *ar,
return 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)
@ -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,

View 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;

View 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.

View 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) {

View 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)