Commit d97c121b authored by Vasanthakumar Thiagarajan's avatar Vasanthakumar Thiagarajan Committed by Kalle Valo

ath6kl: Fix 4-way handshake failure in AP and P2P GO mode

RSN capability field of RSN IE which is generated (which is what really
advertised in beacon/probe response) differs from the one generated in
wpa_supplicant. This inconsistency in rsn IE results in 4-way handshake
failure. To fix this, configure rsn capability used in wpa_supplicant
in firmware using a new wmi command, WMI_SET_IE_CMDID. There is a bit
(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE) in fw_capabilities to advertise
this support to driver.
Signed-off-by: default avatarSubramania Sharma <sharmat@qca.qualcomm.com>
Signed-off-by: default avatarVasanthakumar Thiagarajan <vthiagar@qca.qualcomm.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent df90b369
...@@ -2548,6 +2548,52 @@ static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev, ...@@ -2548,6 +2548,52 @@ static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
return 0; return 0;
} }
static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon,
u8 *rsn_capab)
{
const u8 *rsn_ie;
size_t rsn_ie_len;
u16 cnt;
if (!beacon->tail)
return -EINVAL;
rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, beacon->tail, beacon->tail_len);
if (!rsn_ie)
return -EINVAL;
rsn_ie_len = *(rsn_ie + 1);
/* skip element id and length */
rsn_ie += 2;
/* skip version, group cipher */
if (rsn_ie_len < 6)
return -EINVAL;
rsn_ie += 6;
rsn_ie_len -= 6;
/* skip pairwise cipher suite */
if (rsn_ie_len < 2)
return -EINVAL;
cnt = *((u16 *) rsn_ie);
rsn_ie += (2 + cnt * 4);
rsn_ie_len -= (2 + cnt * 4);
/* skip akm suite */
if (rsn_ie_len < 2)
return -EINVAL;
cnt = *((u16 *) rsn_ie);
rsn_ie += (2 + cnt * 4);
rsn_ie_len -= (2 + cnt * 4);
if (rsn_ie_len < 2)
return -EINVAL;
memcpy(rsn_capab, rsn_ie, 2);
return 0;
}
static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_ap_settings *info) struct cfg80211_ap_settings *info)
{ {
...@@ -2560,6 +2606,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, ...@@ -2560,6 +2606,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
struct wmi_connect_cmd p; struct wmi_connect_cmd p;
int res; int res;
int i, ret; int i, ret;
u16 rsn_capab = 0;
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__); ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__);
...@@ -2700,6 +2747,23 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, ...@@ -2700,6 +2747,23 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
vif->next_ch_type != NL80211_CHAN_NO_HT)) vif->next_ch_type != NL80211_CHAN_NO_HT))
return -EIO; return -EIO;
/*
* Get the PTKSA replay counter in the RSN IE. Supplicant
* will use the RSN IE in M3 message and firmware has to
* advertise the same in beacon/probe response. Send
* the complete RSN IE capability field to firmware
*/
if (!ath6kl_get_rsn_capab(&info->beacon, (u8 *) &rsn_capab) &&
test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE,
ar->fw_capabilities)) {
res = ath6kl_wmi_set_ie_cmd(ar->wmi, vif->fw_vif_idx,
WLAN_EID_RSN, WMI_RSN_IE_CAPB,
(const u8 *) &rsn_capab,
sizeof(rsn_capab));
if (res < 0)
return res;
}
res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p); res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p);
if (res < 0) if (res < 0)
return res; return res;
......
...@@ -97,6 +97,9 @@ enum ath6kl_fw_capability { ...@@ -97,6 +97,9 @@ enum ath6kl_fw_capability {
*/ */
ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT, ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT,
/* Firmware has support to override rsn cap of rsn ie */
ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE,
/* this needs to be last */ /* this needs to be last */
ATH6KL_FW_CAPABILITY_MAX, ATH6KL_FW_CAPABILITY_MAX,
}; };
......
...@@ -3221,6 +3221,29 @@ int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type, ...@@ -3221,6 +3221,29 @@ int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type,
NO_SYNC_WMIFLAG); NO_SYNC_WMIFLAG);
} }
int ath6kl_wmi_set_ie_cmd(struct wmi *wmi, u8 if_idx, u8 ie_id, u8 ie_field,
const u8 *ie_info, u8 ie_len)
{
struct sk_buff *skb;
struct wmi_set_ie_cmd *p;
skb = ath6kl_wmi_get_new_buf(sizeof(*p) + ie_len);
if (!skb)
return -ENOMEM;
ath6kl_dbg(ATH6KL_DBG_WMI, "set_ie_cmd: ie_id=%u ie_ie_field=%u ie_len=%u\n",
ie_id, ie_field, ie_len);
p = (struct wmi_set_ie_cmd *) skb->data;
p->ie_id = ie_id;
p->ie_field = ie_field;
p->ie_len = ie_len;
if (ie_info && ie_len > 0)
memcpy(p->ie_info, ie_info, ie_len);
return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_IE_CMDID,
NO_SYNC_WMIFLAG);
}
int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable) int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable)
{ {
struct sk_buff *skb; struct sk_buff *skb;
......
...@@ -426,6 +426,7 @@ enum wmi_cmd_id { ...@@ -426,6 +426,7 @@ enum wmi_cmd_id {
WMI_SET_FRAMERATES_CMDID, WMI_SET_FRAMERATES_CMDID,
WMI_SET_AP_PS_CMDID, WMI_SET_AP_PS_CMDID,
WMI_SET_QOS_SUPP_CMDID, WMI_SET_QOS_SUPP_CMDID,
WMI_SET_IE_CMDID,
/* WMI_THIN_RESERVED_... mark the start and end /* WMI_THIN_RESERVED_... mark the start and end
* values for WMI_THIN_RESERVED command IDs. These * values for WMI_THIN_RESERVED command IDs. These
...@@ -632,6 +633,11 @@ enum wmi_mgmt_frame_type { ...@@ -632,6 +633,11 @@ enum wmi_mgmt_frame_type {
WMI_NUM_MGMT_FRAME WMI_NUM_MGMT_FRAME
}; };
enum wmi_ie_field_type {
WMI_RSN_IE_CAPB = 0x1,
WMI_IE_FULL = 0xFF, /* indicats full IE */
};
/* WMI_CONNECT_CMDID */ /* WMI_CONNECT_CMDID */
enum network_type { enum network_type {
INFRA_NETWORK = 0x01, INFRA_NETWORK = 0x01,
...@@ -1926,6 +1932,14 @@ struct wmi_set_appie_cmd { ...@@ -1926,6 +1932,14 @@ struct wmi_set_appie_cmd {
u8 ie_info[0]; u8 ie_info[0];
} __packed; } __packed;
struct wmi_set_ie_cmd {
u8 ie_id;
u8 ie_field; /* enum wmi_ie_field_type */
u8 ie_len;
u8 reserved;
u8 ie_info[0];
} __packed;
/* Notify the WSC registration status to the target */ /* Notify the WSC registration status to the target */
#define WSC_REG_ACTIVE 1 #define WSC_REG_ACTIVE 1
#define WSC_REG_INACTIVE 0 #define WSC_REG_INACTIVE 0
...@@ -2536,6 +2550,9 @@ int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 if_idx, ...@@ -2536,6 +2550,9 @@ int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 if_idx,
int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type, int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type,
const u8 *ie, u8 ie_len); const u8 *ie, u8 ie_len);
int ath6kl_wmi_set_ie_cmd(struct wmi *wmi, u8 if_idx, u8 ie_id, u8 ie_field,
const u8 *ie_info, u8 ie_len);
/* P2P */ /* P2P */
int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable); int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable);
......
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