diff options
author | Vasanthakumar Thiagarajan <vthiagar@qca.qualcomm.com> | 2012-04-09 11:21:20 -0400 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2012-04-09 11:33:07 -0400 |
commit | d97c121bb23d32ef631c553d2656f8ccf8349507 (patch) | |
tree | 5ed670bed75b13c29a41fca6eeef255e46f6d569 | |
parent | df90b36940019a879d08bc5e8a20daa0c9fe0122 (diff) |
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: Subramania Sharma <sharmat@qca.qualcomm.com>
Signed-off-by: Vasanthakumar Thiagarajan <vthiagar@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/cfg80211.c | 64 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/core.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/wmi.c | 23 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/wmi.h | 17 |
4 files changed, 107 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 900993017d09..86d388f57708 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c | |||
@@ -2548,6 +2548,52 @@ static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev, | |||
2548 | return 0; | 2548 | return 0; |
2549 | } | 2549 | } |
2550 | 2550 | ||
2551 | static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon, | ||
2552 | u8 *rsn_capab) | ||
2553 | { | ||
2554 | const u8 *rsn_ie; | ||
2555 | size_t rsn_ie_len; | ||
2556 | u16 cnt; | ||
2557 | |||
2558 | if (!beacon->tail) | ||
2559 | return -EINVAL; | ||
2560 | |||
2561 | rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, beacon->tail, beacon->tail_len); | ||
2562 | if (!rsn_ie) | ||
2563 | return -EINVAL; | ||
2564 | |||
2565 | rsn_ie_len = *(rsn_ie + 1); | ||
2566 | /* skip element id and length */ | ||
2567 | rsn_ie += 2; | ||
2568 | |||
2569 | /* skip version, group cipher */ | ||
2570 | if (rsn_ie_len < 6) | ||
2571 | return -EINVAL; | ||
2572 | rsn_ie += 6; | ||
2573 | rsn_ie_len -= 6; | ||
2574 | |||
2575 | /* skip pairwise cipher suite */ | ||
2576 | if (rsn_ie_len < 2) | ||
2577 | return -EINVAL; | ||
2578 | cnt = *((u16 *) rsn_ie); | ||
2579 | rsn_ie += (2 + cnt * 4); | ||
2580 | rsn_ie_len -= (2 + cnt * 4); | ||
2581 | |||
2582 | /* skip akm suite */ | ||
2583 | if (rsn_ie_len < 2) | ||
2584 | return -EINVAL; | ||
2585 | cnt = *((u16 *) rsn_ie); | ||
2586 | rsn_ie += (2 + cnt * 4); | ||
2587 | rsn_ie_len -= (2 + cnt * 4); | ||
2588 | |||
2589 | if (rsn_ie_len < 2) | ||
2590 | return -EINVAL; | ||
2591 | |||
2592 | memcpy(rsn_capab, rsn_ie, 2); | ||
2593 | |||
2594 | return 0; | ||
2595 | } | ||
2596 | |||
2551 | static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, | 2597 | static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, |
2552 | struct cfg80211_ap_settings *info) | 2598 | struct cfg80211_ap_settings *info) |
2553 | { | 2599 | { |
@@ -2560,6 +2606,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
2560 | struct wmi_connect_cmd p; | 2606 | struct wmi_connect_cmd p; |
2561 | int res; | 2607 | int res; |
2562 | int i, ret; | 2608 | int i, ret; |
2609 | u16 rsn_capab = 0; | ||
2563 | 2610 | ||
2564 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__); | 2611 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__); |
2565 | 2612 | ||
@@ -2700,6 +2747,23 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
2700 | vif->next_ch_type != NL80211_CHAN_NO_HT)) | 2747 | vif->next_ch_type != NL80211_CHAN_NO_HT)) |
2701 | return -EIO; | 2748 | return -EIO; |
2702 | 2749 | ||
2750 | /* | ||
2751 | * Get the PTKSA replay counter in the RSN IE. Supplicant | ||
2752 | * will use the RSN IE in M3 message and firmware has to | ||
2753 | * advertise the same in beacon/probe response. Send | ||
2754 | * the complete RSN IE capability field to firmware | ||
2755 | */ | ||
2756 | if (!ath6kl_get_rsn_capab(&info->beacon, (u8 *) &rsn_capab) && | ||
2757 | test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE, | ||
2758 | ar->fw_capabilities)) { | ||
2759 | res = ath6kl_wmi_set_ie_cmd(ar->wmi, vif->fw_vif_idx, | ||
2760 | WLAN_EID_RSN, WMI_RSN_IE_CAPB, | ||
2761 | (const u8 *) &rsn_capab, | ||
2762 | sizeof(rsn_capab)); | ||
2763 | if (res < 0) | ||
2764 | return res; | ||
2765 | } | ||
2766 | |||
2703 | res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p); | 2767 | res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p); |
2704 | if (res < 0) | 2768 | if (res < 0) |
2705 | return res; | 2769 | return res; |
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 8e7e9480a786..9d67964a51dd 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h | |||
@@ -97,6 +97,9 @@ enum ath6kl_fw_capability { | |||
97 | */ | 97 | */ |
98 | ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT, | 98 | ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT, |
99 | 99 | ||
100 | /* Firmware has support to override rsn cap of rsn ie */ | ||
101 | ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE, | ||
102 | |||
100 | /* this needs to be last */ | 103 | /* this needs to be last */ |
101 | ATH6KL_FW_CAPABILITY_MAX, | 104 | ATH6KL_FW_CAPABILITY_MAX, |
102 | }; | 105 | }; |
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index efd707e69255..7c8a9977faf5 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c | |||
@@ -3221,6 +3221,29 @@ int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type, | |||
3221 | NO_SYNC_WMIFLAG); | 3221 | NO_SYNC_WMIFLAG); |
3222 | } | 3222 | } |
3223 | 3223 | ||
3224 | int ath6kl_wmi_set_ie_cmd(struct wmi *wmi, u8 if_idx, u8 ie_id, u8 ie_field, | ||
3225 | const u8 *ie_info, u8 ie_len) | ||
3226 | { | ||
3227 | struct sk_buff *skb; | ||
3228 | struct wmi_set_ie_cmd *p; | ||
3229 | |||
3230 | skb = ath6kl_wmi_get_new_buf(sizeof(*p) + ie_len); | ||
3231 | if (!skb) | ||
3232 | return -ENOMEM; | ||
3233 | |||
3234 | ath6kl_dbg(ATH6KL_DBG_WMI, "set_ie_cmd: ie_id=%u ie_ie_field=%u ie_len=%u\n", | ||
3235 | ie_id, ie_field, ie_len); | ||
3236 | p = (struct wmi_set_ie_cmd *) skb->data; | ||
3237 | p->ie_id = ie_id; | ||
3238 | p->ie_field = ie_field; | ||
3239 | p->ie_len = ie_len; | ||
3240 | if (ie_info && ie_len > 0) | ||
3241 | memcpy(p->ie_info, ie_info, ie_len); | ||
3242 | |||
3243 | return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_IE_CMDID, | ||
3244 | NO_SYNC_WMIFLAG); | ||
3245 | } | ||
3246 | |||
3224 | int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable) | 3247 | int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable) |
3225 | { | 3248 | { |
3226 | struct sk_buff *skb; | 3249 | struct sk_buff *skb; |
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index ee45d1022532..d3d2ab5c1689 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h | |||
@@ -426,6 +426,7 @@ enum wmi_cmd_id { | |||
426 | WMI_SET_FRAMERATES_CMDID, | 426 | WMI_SET_FRAMERATES_CMDID, |
427 | WMI_SET_AP_PS_CMDID, | 427 | WMI_SET_AP_PS_CMDID, |
428 | WMI_SET_QOS_SUPP_CMDID, | 428 | WMI_SET_QOS_SUPP_CMDID, |
429 | WMI_SET_IE_CMDID, | ||
429 | 430 | ||
430 | /* WMI_THIN_RESERVED_... mark the start and end | 431 | /* WMI_THIN_RESERVED_... mark the start and end |
431 | * values for WMI_THIN_RESERVED command IDs. These | 432 | * values for WMI_THIN_RESERVED command IDs. These |
@@ -632,6 +633,11 @@ enum wmi_mgmt_frame_type { | |||
632 | WMI_NUM_MGMT_FRAME | 633 | WMI_NUM_MGMT_FRAME |
633 | }; | 634 | }; |
634 | 635 | ||
636 | enum wmi_ie_field_type { | ||
637 | WMI_RSN_IE_CAPB = 0x1, | ||
638 | WMI_IE_FULL = 0xFF, /* indicats full IE */ | ||
639 | }; | ||
640 | |||
635 | /* WMI_CONNECT_CMDID */ | 641 | /* WMI_CONNECT_CMDID */ |
636 | enum network_type { | 642 | enum network_type { |
637 | INFRA_NETWORK = 0x01, | 643 | INFRA_NETWORK = 0x01, |
@@ -1926,6 +1932,14 @@ struct wmi_set_appie_cmd { | |||
1926 | u8 ie_info[0]; | 1932 | u8 ie_info[0]; |
1927 | } __packed; | 1933 | } __packed; |
1928 | 1934 | ||
1935 | struct wmi_set_ie_cmd { | ||
1936 | u8 ie_id; | ||
1937 | u8 ie_field; /* enum wmi_ie_field_type */ | ||
1938 | u8 ie_len; | ||
1939 | u8 reserved; | ||
1940 | u8 ie_info[0]; | ||
1941 | } __packed; | ||
1942 | |||
1929 | /* Notify the WSC registration status to the target */ | 1943 | /* Notify the WSC registration status to the target */ |
1930 | #define WSC_REG_ACTIVE 1 | 1944 | #define WSC_REG_ACTIVE 1 |
1931 | #define WSC_REG_INACTIVE 0 | 1945 | #define WSC_REG_INACTIVE 0 |
@@ -2536,6 +2550,9 @@ int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 if_idx, | |||
2536 | int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type, | 2550 | int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type, |
2537 | const u8 *ie, u8 ie_len); | 2551 | const u8 *ie, u8 ie_len); |
2538 | 2552 | ||
2553 | int ath6kl_wmi_set_ie_cmd(struct wmi *wmi, u8 if_idx, u8 ie_id, u8 ie_field, | ||
2554 | const u8 *ie_info, u8 ie_len); | ||
2555 | |||
2539 | /* P2P */ | 2556 | /* P2P */ |
2540 | int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable); | 2557 | int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable); |
2541 | 2558 | ||