diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index b64b2a35756072d53d665cec633e05e850039399..89e29ead254fabd55c5bc5c6d7c1bece1b35c683 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -61,7 +61,8 @@ static void ath6kl_add_new_sta(struct ath6kl *ar, u8 *mac, u16 aid, u8 *wpaie, sta = &ar->sta_list[free_slot]; memcpy(sta->mac, mac, ETH_ALEN); - memcpy(sta->wpa_ie, wpaie, ielen); + if (ielen <= ATH6KL_MAX_IE) + memcpy(sta->wpa_ie, wpaie, ielen); sta->aid = aid; sta->keymgmt = keymgmt; sta->ucipher = ucipher; @@ -429,9 +430,11 @@ static void ath6kl_install_static_wep_keys(struct ath6kl *ar) static void ath6kl_connect_ap_mode(struct ath6kl *ar, u16 channel, u8 *bssid, u16 listen_int, u16 beacon_int, - u8 assoc_resp_len, u8 *assoc_info) + u8 assoc_req_len, u8 *assoc_info) { struct net_device *dev = ar->net_dev; + u8 *ies = NULL, *wpa_ie = NULL, *pos; + size_t ies_len = 0; struct station_info sinfo; struct ath6kl_req_key *ik; enum crypto_type keyType = NONE_CRYPT; @@ -473,7 +476,43 @@ static void ath6kl_connect_ap_mode(struct ath6kl *ar, u16 channel, u8 *bssid, ath6kl_dbg(ATH6KL_DBG_TRC, "new station %pM aid=%d\n", bssid, channel); - ath6kl_add_new_sta(ar, bssid, channel, assoc_info, assoc_resp_len, + if (assoc_req_len > sizeof(struct ieee80211_hdr_3addr)) { + struct ieee80211_mgmt *mgmt = + (struct ieee80211_mgmt *) assoc_info; + if (ieee80211_is_assoc_req(mgmt->frame_control) && + assoc_req_len >= sizeof(struct ieee80211_hdr_3addr) + + sizeof(mgmt->u.assoc_req)) { + ies = mgmt->u.assoc_req.variable; + ies_len = assoc_info + assoc_req_len - ies; + } else if (ieee80211_is_reassoc_req(mgmt->frame_control) && + assoc_req_len >= sizeof(struct ieee80211_hdr_3addr) + + sizeof(mgmt->u.reassoc_req)) { + ies = mgmt->u.reassoc_req.variable; + ies_len = assoc_info + assoc_req_len - ies; + } + } + + pos = ies; + while (pos && pos + 1 < ies + ies_len) { + if (pos + 2 + pos[1] > ies + ies_len) + break; + if (pos[0] == WLAN_EID_RSN) + wpa_ie = pos; /* RSN IE */ + else if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && + pos[1] >= 4 && + pos[2] == 0x00 && pos[3] == 0x50 && pos[4] == 0xf2) { + if (pos[5] == 0x01) + wpa_ie = pos; /* WPA IE */ + else if (pos[5] == 0x04) { + wpa_ie = pos; /* WPS IE */ + break; /* overrides WPA/RSN IE */ + } + } + pos += 2 + pos[1]; + } + + ath6kl_add_new_sta(ar, bssid, channel, wpa_ie, + wpa_ie ? 2 + wpa_ie[1] : 0, listen_int & 0xFF, beacon_int, (listen_int >> 8) & 0xFF); @@ -481,9 +520,11 @@ static void ath6kl_connect_ap_mode(struct ath6kl *ar, u16 channel, u8 *bssid, memset(&sinfo, 0, sizeof(sinfo)); /* TODO: sinfo.generation */ - /* TODO: need to deliver (Re)AssocReq IEs somehow.. change in - * cfg80211 needed, e.g., by adding those into sinfo - */ + + sinfo.assoc_req_ies = ies; + sinfo.assoc_req_ies_len = ies_len; + sinfo.filled |= STATION_INFO_ASSOC_REQ_IES; + cfg80211_new_sta(ar->net_dev, bssid, &sinfo, GFP_KERNEL); netif_wake_queue(ar->net_dev); @@ -895,8 +936,8 @@ void ath6kl_connect_event(struct ath6kl *ar, u16 channel, u8 *bssid, if (ar->nw_type == AP_NETWORK) { ath6kl_connect_ap_mode(ar, channel, bssid, listen_int, - beacon_int, assoc_resp_len, - assoc_info); + beacon_int, assoc_req_len, + assoc_info + beacon_ie_len); return; }