cfg80211: send extended capabilities IE in connect
If the connect request from userspace didn't include an extended capabilities IE, create one using the driver capabilities. This fixes VHT associations, since those need to set the operating mode notification capability. Reviewed-by: Gregory Greenman <gregory.greenman@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
29464ccc78
commit
46b9d18014
|
@ -42,7 +42,7 @@ struct cfg80211_conn {
|
|||
CFG80211_CONN_CONNECTED,
|
||||
} state;
|
||||
u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
|
||||
u8 *ie;
|
||||
const u8 *ie;
|
||||
size_t ie_len;
|
||||
bool auto_auth, prev_bssid_valid;
|
||||
};
|
||||
|
@ -423,6 +423,62 @@ void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev)
|
|||
schedule_work(&rdev->conn_work);
|
||||
}
|
||||
|
||||
static int cfg80211_sme_get_conn_ies(struct wireless_dev *wdev,
|
||||
const u8 *ies, size_t ies_len,
|
||||
const u8 **out_ies, size_t *out_ies_len)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
|
||||
u8 *buf;
|
||||
size_t offs;
|
||||
|
||||
if (!rdev->wiphy.extended_capabilities_len ||
|
||||
(ies && cfg80211_find_ie(WLAN_EID_EXT_CAPABILITY, ies, ies_len))) {
|
||||
*out_ies = kmemdup(ies, ies_len, GFP_KERNEL);
|
||||
if (!*out_ies)
|
||||
return -ENOMEM;
|
||||
*out_ies_len = ies_len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
buf = kmalloc(ies_len + rdev->wiphy.extended_capabilities_len + 2,
|
||||
GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
if (ies_len) {
|
||||
static const u8 before_extcapa[] = {
|
||||
/* not listing IEs expected to be created by driver */
|
||||
WLAN_EID_RSN,
|
||||
WLAN_EID_QOS_CAPA,
|
||||
WLAN_EID_RRM_ENABLED_CAPABILITIES,
|
||||
WLAN_EID_MOBILITY_DOMAIN,
|
||||
WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
|
||||
WLAN_EID_BSS_COEX_2040,
|
||||
};
|
||||
|
||||
offs = ieee80211_ie_split(ies, ies_len, before_extcapa,
|
||||
ARRAY_SIZE(before_extcapa), 0);
|
||||
memcpy(buf, ies, offs);
|
||||
/* leave a whole for extended capabilities IE */
|
||||
memcpy(buf + offs + rdev->wiphy.extended_capabilities_len + 2,
|
||||
ies + offs, ies_len - offs);
|
||||
} else {
|
||||
offs = 0;
|
||||
}
|
||||
|
||||
/* place extended capabilities IE (with only driver capabilities) */
|
||||
buf[offs] = WLAN_EID_EXT_CAPABILITY;
|
||||
buf[offs + 1] = rdev->wiphy.extended_capabilities_len;
|
||||
memcpy(buf + offs + 2,
|
||||
rdev->wiphy.extended_capabilities,
|
||||
rdev->wiphy.extended_capabilities_len);
|
||||
|
||||
*out_ies = buf;
|
||||
*out_ies_len = ies_len + rdev->wiphy.extended_capabilities_len + 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cfg80211_sme_connect(struct wireless_dev *wdev,
|
||||
struct cfg80211_connect_params *connect,
|
||||
const u8 *prev_bssid)
|
||||
|
@ -453,16 +509,14 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev,
|
|||
memcpy(wdev->conn->bssid, connect->bssid, ETH_ALEN);
|
||||
}
|
||||
|
||||
if (connect->ie) {
|
||||
wdev->conn->ie = kmemdup(connect->ie, connect->ie_len,
|
||||
GFP_KERNEL);
|
||||
wdev->conn->params.ie = wdev->conn->ie;
|
||||
if (!wdev->conn->ie) {
|
||||
kfree(wdev->conn);
|
||||
wdev->conn = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (cfg80211_sme_get_conn_ies(wdev, connect->ie, connect->ie_len,
|
||||
&wdev->conn->ie,
|
||||
&wdev->conn->params.ie_len)) {
|
||||
kfree(wdev->conn);
|
||||
wdev->conn = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
wdev->conn->params.ie = wdev->conn->ie;
|
||||
|
||||
if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) {
|
||||
wdev->conn->auto_auth = true;
|
||||
|
|
Loading…
Reference in New Issue