aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-11-28 19:25:20 -0500
committerJohannes Berg <johannes.berg@intel.com>2012-11-30 07:42:20 -0500
commit9caf03640279e64d0ba36539b42daa1b43a49486 (patch)
treecb094a4a577f61421d1b402e16f0e68f151d5726
parentb9a9ada14aab17f08c1d9735601f1097cdcfc6de (diff)
cfg80211: fix BSS struct IE access races
When a BSS struct is updated, the IEs are currently overwritten or freed. This can lead to races if some other CPU is accessing the BSS struct and using the IEs concurrently. Fix this by always allocating the IEs in a new struct that holds the data and length and protecting access to this new struct with RCU. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--drivers/net/wireless/libertas/cfg.c9
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c35
-rw-r--r--include/net/cfg80211.h41
-rw-r--r--net/mac80211/mlme.c80
-rw-r--r--net/wireless/core.h2
-rw-r--r--net/wireless/nl80211.c27
-rw-r--r--net/wireless/reg.c2
-rw-r--r--net/wireless/reg.h2
-rw-r--r--net/wireless/scan.c409
-rw-r--r--net/wireless/sme.c13
-rw-r--r--net/wireless/util.c9
-rw-r--r--net/wireless/wext-sme.c8
12 files changed, 353 insertions, 284 deletions
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index ec36868f6fc5..ec6d5d6b452e 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -298,6 +298,7 @@ static int lbs_add_common_rates_tlv(u8 *tlv, struct cfg80211_bss *bss)
298 const u8 *rates_eid, *ext_rates_eid; 298 const u8 *rates_eid, *ext_rates_eid;
299 int n = 0; 299 int n = 0;
300 300
301 rcu_read_lock();
301 rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES); 302 rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
302 ext_rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES); 303 ext_rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
303 304
@@ -325,6 +326,7 @@ static int lbs_add_common_rates_tlv(u8 *tlv, struct cfg80211_bss *bss)
325 *tlv++ = 0x96; 326 *tlv++ = 0x96;
326 n = 4; 327 n = 4;
327 } 328 }
329 rcu_read_unlock();
328 330
329 rate_tlv->header.len = cpu_to_le16(n); 331 rate_tlv->header.len = cpu_to_le16(n);
330 return sizeof(rate_tlv->header) + n; 332 return sizeof(rate_tlv->header) + n;
@@ -1140,11 +1142,13 @@ static int lbs_associate(struct lbs_private *priv,
1140 cmd->capability = cpu_to_le16(bss->capability); 1142 cmd->capability = cpu_to_le16(bss->capability);
1141 1143
1142 /* add SSID TLV */ 1144 /* add SSID TLV */
1145 rcu_read_lock();
1143 ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); 1146 ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID);
1144 if (ssid_eid) 1147 if (ssid_eid)
1145 pos += lbs_add_ssid_tlv(pos, ssid_eid + 2, ssid_eid[1]); 1148 pos += lbs_add_ssid_tlv(pos, ssid_eid + 2, ssid_eid[1]);
1146 else 1149 else
1147 lbs_deb_assoc("no SSID\n"); 1150 lbs_deb_assoc("no SSID\n");
1151 rcu_read_unlock();
1148 1152
1149 /* add DS param TLV */ 1153 /* add DS param TLV */
1150 if (bss->channel) 1154 if (bss->channel)
@@ -1782,7 +1786,7 @@ static int lbs_ibss_join_existing(struct lbs_private *priv,
1782 struct cfg80211_ibss_params *params, 1786 struct cfg80211_ibss_params *params,
1783 struct cfg80211_bss *bss) 1787 struct cfg80211_bss *bss)
1784{ 1788{
1785 const u8 *rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES); 1789 const u8 *rates_eid;
1786 struct cmd_ds_802_11_ad_hoc_join cmd; 1790 struct cmd_ds_802_11_ad_hoc_join cmd;
1787 u8 preamble = RADIO_PREAMBLE_SHORT; 1791 u8 preamble = RADIO_PREAMBLE_SHORT;
1788 int ret = 0; 1792 int ret = 0;
@@ -1841,6 +1845,8 @@ static int lbs_ibss_join_existing(struct lbs_private *priv,
1841 1845
1842 /* set rates to the intersection of our rates and the rates in the 1846 /* set rates to the intersection of our rates and the rates in the
1843 bss */ 1847 bss */
1848 rcu_read_lock();
1849 rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
1844 if (!rates_eid) { 1850 if (!rates_eid) {
1845 lbs_add_rates(cmd.bss.rates); 1851 lbs_add_rates(cmd.bss.rates);
1846 } else { 1852 } else {
@@ -1860,6 +1866,7 @@ static int lbs_ibss_join_existing(struct lbs_private *priv,
1860 } 1866 }
1861 } 1867 }
1862 } 1868 }
1869 rcu_read_unlock();
1863 1870
1864 /* Only v8 and below support setting this */ 1871 /* Only v8 and below support setting this */
1865 if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8) { 1872 if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8) {
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index 24af6ba7d8a1..5d7b83e2dc4d 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -158,12 +158,22 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
158 struct cfg80211_bss *bss, 158 struct cfg80211_bss *bss,
159 struct mwifiex_bssdescriptor *bss_desc) 159 struct mwifiex_bssdescriptor *bss_desc)
160{ 160{
161 int ret; 161 int ret, beacon_ie_len;
162 u8 *beacon_ie; 162 u8 *beacon_ie;
163 struct mwifiex_bss_priv *bss_priv = (void *)bss->priv; 163 struct mwifiex_bss_priv *bss_priv = (void *)bss->priv;
164 const struct cfg80211_bss_ies *ies;
165
166 rcu_read_lock();
167 ies = rcu_dereference(bss->ies);
168 if (WARN_ON(!ies)) {
169 /* should never happen */
170 rcu_read_unlock();
171 return -EINVAL;
172 }
173 beacon_ie = kmemdup(ies->data, ies->len, GFP_ATOMIC);
174 beacon_ie_len = ies->len;
175 rcu_read_unlock();
164 176
165 beacon_ie = kmemdup(bss->information_elements, bss->len_beacon_ies,
166 GFP_KERNEL);
167 if (!beacon_ie) { 177 if (!beacon_ie) {
168 dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n"); 178 dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n");
169 return -ENOMEM; 179 return -ENOMEM;
@@ -172,7 +182,7 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
172 memcpy(bss_desc->mac_address, bss->bssid, ETH_ALEN); 182 memcpy(bss_desc->mac_address, bss->bssid, ETH_ALEN);
173 bss_desc->rssi = bss->signal; 183 bss_desc->rssi = bss->signal;
174 bss_desc->beacon_buf = beacon_ie; 184 bss_desc->beacon_buf = beacon_ie;
175 bss_desc->beacon_buf_size = bss->len_beacon_ies; 185 bss_desc->beacon_buf_size = beacon_ie_len;
176 bss_desc->beacon_period = bss->beacon_interval; 186 bss_desc->beacon_period = bss->beacon_interval;
177 bss_desc->cap_info_bitmap = bss->capability; 187 bss_desc->cap_info_bitmap = bss->capability;
178 bss_desc->bss_band = bss_priv->band; 188 bss_desc->bss_band = bss_priv->band;
@@ -198,18 +208,23 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
198static int mwifiex_process_country_ie(struct mwifiex_private *priv, 208static int mwifiex_process_country_ie(struct mwifiex_private *priv,
199 struct cfg80211_bss *bss) 209 struct cfg80211_bss *bss)
200{ 210{
201 u8 *country_ie, country_ie_len; 211 const u8 *country_ie;
212 u8 country_ie_len;
202 struct mwifiex_802_11d_domain_reg *domain_info = 213 struct mwifiex_802_11d_domain_reg *domain_info =
203 &priv->adapter->domain_reg; 214 &priv->adapter->domain_reg;
204 215
205 country_ie = (u8 *)ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY); 216 rcu_read_lock();
206 217 country_ie = ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY);
207 if (!country_ie) 218 if (!country_ie) {
219 rcu_read_unlock();
208 return 0; 220 return 0;
221 }
209 222
210 country_ie_len = country_ie[1]; 223 country_ie_len = country_ie[1];
211 if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) 224 if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) {
225 rcu_read_unlock();
212 return 0; 226 return 0;
227 }
213 228
214 domain_info->country_code[0] = country_ie[2]; 229 domain_info->country_code[0] = country_ie[2];
215 domain_info->country_code[1] = country_ie[3]; 230 domain_info->country_code[1] = country_ie[3];
@@ -223,6 +238,8 @@ static int mwifiex_process_country_ie(struct mwifiex_private *priv,
223 memcpy((u8 *)domain_info->triplet, 238 memcpy((u8 *)domain_info->triplet,
224 &country_ie[2] + IEEE80211_COUNTRY_STRING_LEN, country_ie_len); 239 &country_ie[2] + IEEE80211_COUNTRY_STRING_LEN, country_ie_len);
225 240
241 rcu_read_unlock();
242
226 if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, 243 if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
227 HostCmd_ACT_GEN_SET, 0, NULL)) { 244 HostCmd_ACT_GEN_SET, 0, NULL)) {
228 wiphy_err(priv->adapter->wiphy, 245 wiphy_err(priv->adapter->wiphy,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 731b48fa238b..8e6a6b73b9c9 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1206,6 +1206,18 @@ enum cfg80211_signal_type {
1206}; 1206};
1207 1207
1208/** 1208/**
1209 * struct cfg80211_bss_ie_data - BSS entry IE data
1210 * @rcu_head: internal use, for freeing
1211 * @len: length of the IEs
1212 * @data: IE data
1213 */
1214struct cfg80211_bss_ies {
1215 struct rcu_head rcu_head;
1216 int len;
1217 u8 data[];
1218};
1219
1220/**
1209 * struct cfg80211_bss - BSS description 1221 * struct cfg80211_bss - BSS description
1210 * 1222 *
1211 * This structure describes a BSS (which may also be a mesh network) 1223 * This structure describes a BSS (which may also be a mesh network)
@@ -1216,36 +1228,34 @@ enum cfg80211_signal_type {
1216 * @tsf: timestamp of last received update 1228 * @tsf: timestamp of last received update
1217 * @beacon_interval: the beacon interval as from the frame 1229 * @beacon_interval: the beacon interval as from the frame
1218 * @capability: the capability field in host byte order 1230 * @capability: the capability field in host byte order
1219 * @information_elements: the information elements (Note that there 1231 * @ies: the information elements (Note that there
1220 * is no guarantee that these are well-formed!); this is a pointer to 1232 * is no guarantee that these are well-formed!); this is a pointer to
1221 * either the beacon_ies or proberesp_ies depending on whether Probe 1233 * either the beacon_ies or proberesp_ies depending on whether Probe
1222 * Response frame has been received 1234 * Response frame has been received
1223 * @len_information_elements: total length of the information elements
1224 * @beacon_ies: the information elements from the last Beacon frame 1235 * @beacon_ies: the information elements from the last Beacon frame
1225 * @len_beacon_ies: total length of the beacon_ies
1226 * @proberesp_ies: the information elements from the last Probe Response frame 1236 * @proberesp_ies: the information elements from the last Probe Response frame
1227 * @len_proberesp_ies: total length of the proberesp_ies
1228 * @signal: signal strength value (type depends on the wiphy's signal_type) 1237 * @signal: signal strength value (type depends on the wiphy's signal_type)
1229 * @free_priv: function pointer to free private data 1238 * @free_priv: function pointer to free private data
1230 * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes 1239 * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes
1231 */ 1240 */
1232struct cfg80211_bss { 1241struct cfg80211_bss {
1242 u64 tsf;
1243
1233 struct ieee80211_channel *channel; 1244 struct ieee80211_channel *channel;
1234 1245
1235 u8 bssid[ETH_ALEN]; 1246 const struct cfg80211_bss_ies __rcu *ies;
1236 u64 tsf; 1247 const struct cfg80211_bss_ies __rcu *beacon_ies;
1248 const struct cfg80211_bss_ies __rcu *proberesp_ies;
1249
1250 void (*free_priv)(struct cfg80211_bss *bss);
1251
1252 s32 signal;
1253
1237 u16 beacon_interval; 1254 u16 beacon_interval;
1238 u16 capability; 1255 u16 capability;
1239 u8 *information_elements;
1240 size_t len_information_elements;
1241 u8 *beacon_ies;
1242 size_t len_beacon_ies;
1243 u8 *proberesp_ies;
1244 size_t len_proberesp_ies;
1245 1256
1246 s32 signal; 1257 u8 bssid[ETH_ALEN];
1247 1258
1248 void (*free_priv)(struct cfg80211_bss *bss);
1249 u8 priv[0] __attribute__((__aligned__(sizeof(void *)))); 1259 u8 priv[0] __attribute__((__aligned__(sizeof(void *))));
1250}; 1260};
1251 1261
@@ -1253,6 +1263,9 @@ struct cfg80211_bss {
1253 * ieee80211_bss_get_ie - find IE with given ID 1263 * ieee80211_bss_get_ie - find IE with given ID
1254 * @bss: the bss to search 1264 * @bss: the bss to search
1255 * @ie: the IE ID 1265 * @ie: the IE ID
1266 *
1267 * Note that the return value is an RCU-protected pointer, so
1268 * rcu_read_lock() must be held when calling this function.
1256 * Returns %NULL if not found. 1269 * Returns %NULL if not found.
1257 */ 1270 */
1258const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie); 1271const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 35d8cffc973a..481d5035b397 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1382,19 +1382,26 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
1382 sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE; 1382 sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE;
1383 1383
1384 if (sdata->vif.p2p) { 1384 if (sdata->vif.p2p) {
1385 u8 noa[2]; 1385 const struct cfg80211_bss_ies *ies;
1386 int ret;
1387 1386
1388 ret = cfg80211_get_p2p_attr(cbss->information_elements, 1387 rcu_read_lock();
1389 cbss->len_information_elements, 1388 ies = rcu_dereference(cbss->ies);
1390 IEEE80211_P2P_ATTR_ABSENCE_NOTICE, 1389 if (ies) {
1391 noa, sizeof(noa)); 1390 u8 noa[2];
1392 if (ret >= 2) { 1391 int ret;
1393 bss_conf->p2p_oppps = noa[1] & 0x80; 1392
1394 bss_conf->p2p_ctwindow = noa[1] & 0x7f; 1393 ret = cfg80211_get_p2p_attr(
1395 bss_info_changed |= BSS_CHANGED_P2P_PS; 1394 ies->data, ies->len,
1396 sdata->u.mgd.p2p_noa_index = noa[0]; 1395 IEEE80211_P2P_ATTR_ABSENCE_NOTICE,
1396 noa, sizeof(noa));
1397 if (ret >= 2) {
1398 bss_conf->p2p_oppps = noa[1] & 0x80;
1399 bss_conf->p2p_ctwindow = noa[1] & 0x7f;
1400 bss_info_changed |= BSS_CHANGED_P2P_PS;
1401 sdata->u.mgd.p2p_noa_index = noa[0];
1402 }
1397 } 1403 }
1404 rcu_read_unlock();
1398 } 1405 }
1399 1406
1400 /* just to be sure */ 1407 /* just to be sure */
@@ -1659,6 +1666,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
1659 } else { 1666 } else {
1660 int ssid_len; 1667 int ssid_len;
1661 1668
1669 rcu_read_lock();
1662 ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); 1670 ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID);
1663 if (WARN_ON_ONCE(ssid == NULL)) 1671 if (WARN_ON_ONCE(ssid == NULL))
1664 ssid_len = 0; 1672 ssid_len = 0;
@@ -1668,6 +1676,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
1668 ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL, 1676 ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL,
1669 0, (u32) -1, true, false, 1677 0, (u32) -1, true, false,
1670 ifmgd->associated->channel, false); 1678 ifmgd->associated->channel, false);
1679 rcu_read_unlock();
1671 } 1680 }
1672 1681
1673 ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); 1682 ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms);
@@ -1763,6 +1772,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,
1763 else 1772 else
1764 return NULL; 1773 return NULL;
1765 1774
1775 rcu_read_lock();
1766 ssid = ieee80211_bss_get_ie(cbss, WLAN_EID_SSID); 1776 ssid = ieee80211_bss_get_ie(cbss, WLAN_EID_SSID);
1767 if (WARN_ON_ONCE(ssid == NULL)) 1777 if (WARN_ON_ONCE(ssid == NULL))
1768 ssid_len = 0; 1778 ssid_len = 0;
@@ -1773,6 +1783,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,
1773 (u32) -1, cbss->channel, 1783 (u32) -1, cbss->channel,
1774 ssid + 2, ssid_len, 1784 ssid + 2, ssid_len,
1775 NULL, 0, true); 1785 NULL, 0, true);
1786 rcu_read_unlock();
1776 1787
1777 return skb; 1788 return skb;
1778} 1789}
@@ -2858,9 +2869,12 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
2858 auth_data->bss->bssid, auth_data->tries, 2869 auth_data->bss->bssid, auth_data->tries,
2859 IEEE80211_AUTH_MAX_TRIES); 2870 IEEE80211_AUTH_MAX_TRIES);
2860 2871
2872 rcu_read_lock();
2861 ssidie = ieee80211_bss_get_ie(auth_data->bss, WLAN_EID_SSID); 2873 ssidie = ieee80211_bss_get_ie(auth_data->bss, WLAN_EID_SSID);
2862 if (!ssidie) 2874 if (!ssidie) {
2875 rcu_read_unlock();
2863 return -EINVAL; 2876 return -EINVAL;
2877 }
2864 /* 2878 /*
2865 * Direct probe is sent to broadcast address as some APs 2879 * Direct probe is sent to broadcast address as some APs
2866 * will not answer to direct packet in unassociated state. 2880 * will not answer to direct packet in unassociated state.
@@ -2868,6 +2882,7 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
2868 ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1], 2882 ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1],
2869 NULL, 0, (u32) -1, true, false, 2883 NULL, 0, (u32) -1, true, false,
2870 auth_data->bss->channel, false); 2884 auth_data->bss->channel, false);
2885 rcu_read_unlock();
2871 } 2886 }
2872 2887
2873 auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; 2888 auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
@@ -3404,9 +3419,7 @@ static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata,
3404 if (ifmgd->flags & IEEE80211_STA_DISABLE_HT) 3419 if (ifmgd->flags & IEEE80211_STA_DISABLE_HT)
3405 return chains; 3420 return chains;
3406 3421
3407 ht_cap_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, 3422 ht_cap_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_CAPABILITY);
3408 cbss->information_elements,
3409 cbss->len_information_elements);
3410 if (ht_cap_ie && ht_cap_ie[1] >= sizeof(*ht_cap)) { 3423 if (ht_cap_ie && ht_cap_ie[1] >= sizeof(*ht_cap)) {
3411 ht_cap = (void *)(ht_cap_ie + 2); 3424 ht_cap = (void *)(ht_cap_ie + 2);
3412 chains = ieee80211_mcs_to_chains(&ht_cap->mcs); 3425 chains = ieee80211_mcs_to_chains(&ht_cap->mcs);
@@ -3419,9 +3432,7 @@ static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata,
3419 if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT) 3432 if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT)
3420 return chains; 3433 return chains;
3421 3434
3422 vht_cap_ie = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, 3435 vht_cap_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_VHT_CAPABILITY);
3423 cbss->information_elements,
3424 cbss->len_information_elements);
3425 if (vht_cap_ie && vht_cap_ie[1] >= sizeof(*vht_cap)) { 3436 if (vht_cap_ie && vht_cap_ie[1] >= sizeof(*vht_cap)) {
3426 u8 nss; 3437 u8 nss;
3427 u16 tx_mcs_map; 3438 u16 tx_mcs_map;
@@ -3457,13 +3468,13 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
3457 IEEE80211_STA_DISABLE_80P80MHZ | 3468 IEEE80211_STA_DISABLE_80P80MHZ |
3458 IEEE80211_STA_DISABLE_160MHZ); 3469 IEEE80211_STA_DISABLE_160MHZ);
3459 3470
3471 rcu_read_lock();
3472
3460 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && 3473 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) &&
3461 sband->ht_cap.ht_supported) { 3474 sband->ht_cap.ht_supported) {
3462 const u8 *ht_oper_ie; 3475 const u8 *ht_oper_ie;
3463 3476
3464 ht_oper_ie = cfg80211_find_ie(WLAN_EID_HT_OPERATION, 3477 ht_oper_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_OPERATION);
3465 cbss->information_elements,
3466 cbss->len_information_elements);
3467 if (ht_oper_ie && ht_oper_ie[1] >= sizeof(*ht_oper)) 3478 if (ht_oper_ie && ht_oper_ie[1] >= sizeof(*ht_oper))
3468 ht_oper = (void *)(ht_oper_ie + 2); 3479 ht_oper = (void *)(ht_oper_ie + 2);
3469 } 3480 }
@@ -3472,9 +3483,8 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
3472 sband->vht_cap.vht_supported) { 3483 sband->vht_cap.vht_supported) {
3473 const u8 *vht_oper_ie; 3484 const u8 *vht_oper_ie;
3474 3485
3475 vht_oper_ie = cfg80211_find_ie(WLAN_EID_VHT_OPERATION, 3486 vht_oper_ie = ieee80211_bss_get_ie(cbss,
3476 cbss->information_elements, 3487 WLAN_EID_VHT_OPERATION);
3477 cbss->len_information_elements);
3478 if (vht_oper_ie && vht_oper_ie[1] >= sizeof(*vht_oper)) 3488 if (vht_oper_ie && vht_oper_ie[1] >= sizeof(*vht_oper))
3479 vht_oper = (void *)(vht_oper_ie + 2); 3489 vht_oper = (void *)(vht_oper_ie + 2);
3480 if (vht_oper && !ht_oper) { 3490 if (vht_oper && !ht_oper) {
@@ -3494,6 +3504,8 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
3494 sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss), 3504 sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss),
3495 local->rx_chains); 3505 local->rx_chains);
3496 3506
3507 rcu_read_unlock();
3508
3497 /* will change later if needed */ 3509 /* will change later if needed */
3498 sdata->smps_mode = IEEE80211_SMPS_OFF; 3510 sdata->smps_mode = IEEE80211_SMPS_OFF;
3499 3511
@@ -3734,14 +3746,21 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
3734 const u8 *ssidie, *ht_ie; 3746 const u8 *ssidie, *ht_ie;
3735 int i, err; 3747 int i, err;
3736 3748
3737 ssidie = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
3738 if (!ssidie)
3739 return -EINVAL;
3740
3741 assoc_data = kzalloc(sizeof(*assoc_data) + req->ie_len, GFP_KERNEL); 3749 assoc_data = kzalloc(sizeof(*assoc_data) + req->ie_len, GFP_KERNEL);
3742 if (!assoc_data) 3750 if (!assoc_data)
3743 return -ENOMEM; 3751 return -ENOMEM;
3744 3752
3753 rcu_read_lock();
3754 ssidie = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
3755 if (!ssidie) {
3756 rcu_read_unlock();
3757 kfree(assoc_data);
3758 return -EINVAL;
3759 }
3760 memcpy(assoc_data->ssid, ssidie + 2, ssidie[1]);
3761 assoc_data->ssid_len = ssidie[1];
3762 rcu_read_unlock();
3763
3745 mutex_lock(&ifmgd->mtx); 3764 mutex_lock(&ifmgd->mtx);
3746 3765
3747 if (ifmgd->associated) 3766 if (ifmgd->associated)
@@ -3836,12 +3855,14 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
3836 assoc_data->supp_rates = bss->supp_rates; 3855 assoc_data->supp_rates = bss->supp_rates;
3837 assoc_data->supp_rates_len = bss->supp_rates_len; 3856 assoc_data->supp_rates_len = bss->supp_rates_len;
3838 3857
3858 rcu_read_lock();
3839 ht_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_OPERATION); 3859 ht_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_OPERATION);
3840 if (ht_ie && ht_ie[1] >= sizeof(struct ieee80211_ht_operation)) 3860 if (ht_ie && ht_ie[1] >= sizeof(struct ieee80211_ht_operation))
3841 assoc_data->ap_ht_param = 3861 assoc_data->ap_ht_param =
3842 ((struct ieee80211_ht_operation *)(ht_ie + 2))->ht_param; 3862 ((struct ieee80211_ht_operation *)(ht_ie + 2))->ht_param;
3843 else 3863 else
3844 ifmgd->flags |= IEEE80211_STA_DISABLE_HT; 3864 ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
3865 rcu_read_unlock();
3845 3866
3846 if (bss->wmm_used && bss->uapsd_supported && 3867 if (bss->wmm_used && bss->uapsd_supported &&
3847 (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) { 3868 (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) {
@@ -3852,9 +3873,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
3852 ifmgd->flags &= ~IEEE80211_STA_UAPSD_ENABLED; 3873 ifmgd->flags &= ~IEEE80211_STA_UAPSD_ENABLED;
3853 } 3874 }
3854 3875
3855 memcpy(assoc_data->ssid, ssidie + 2, ssidie[1]);
3856 assoc_data->ssid_len = ssidie[1];
3857
3858 if (req->prev_bssid) 3876 if (req->prev_bssid)
3859 memcpy(assoc_data->prev_bssid, req->prev_bssid, ETH_ALEN); 3877 memcpy(assoc_data->prev_bssid, req->prev_bssid, ETH_ALEN);
3860 3878
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 6183a0d25b8b..3563097169cb 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -138,8 +138,6 @@ struct cfg80211_internal_bss {
138 unsigned long ts; 138 unsigned long ts;
139 struct kref ref; 139 struct kref ref;
140 atomic_t hold; 140 atomic_t hold;
141 bool beacon_ies_allocated;
142 bool proberesp_ies_allocated;
143 141
144 /* must be last because of priv member */ 142 /* must be last because of priv member */
145 struct cfg80211_bss pub; 143 struct cfg80211_bss pub;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 4a719770eaaf..f45706adaf34 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -4808,6 +4808,7 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
4808 struct cfg80211_internal_bss *intbss) 4808 struct cfg80211_internal_bss *intbss)
4809{ 4809{
4810 struct cfg80211_bss *res = &intbss->pub; 4810 struct cfg80211_bss *res = &intbss->pub;
4811 const struct cfg80211_bss_ies *ies;
4811 void *hdr; 4812 void *hdr;
4812 struct nlattr *bss; 4813 struct nlattr *bss;
4813 4814
@@ -4828,16 +4829,24 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
4828 if (!bss) 4829 if (!bss)
4829 goto nla_put_failure; 4830 goto nla_put_failure;
4830 if ((!is_zero_ether_addr(res->bssid) && 4831 if ((!is_zero_ether_addr(res->bssid) &&
4831 nla_put(msg, NL80211_BSS_BSSID, ETH_ALEN, res->bssid)) || 4832 nla_put(msg, NL80211_BSS_BSSID, ETH_ALEN, res->bssid)))
4832 (res->information_elements && res->len_information_elements &&
4833 nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS,
4834 res->len_information_elements,
4835 res->information_elements)) ||
4836 (res->beacon_ies && res->len_beacon_ies &&
4837 res->beacon_ies != res->information_elements &&
4838 nla_put(msg, NL80211_BSS_BEACON_IES,
4839 res->len_beacon_ies, res->beacon_ies)))
4840 goto nla_put_failure; 4833 goto nla_put_failure;
4834
4835 rcu_read_lock();
4836 ies = rcu_dereference(res->ies);
4837 if (ies && ies->len && nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS,
4838 ies->len, ies->data)) {
4839 rcu_read_unlock();
4840 goto nla_put_failure;
4841 }
4842 ies = rcu_dereference(res->beacon_ies);
4843 if (ies && ies->len && nla_put(msg, NL80211_BSS_BEACON_IES,
4844 ies->len, ies->data)) {
4845 rcu_read_unlock();
4846 goto nla_put_failure;
4847 }
4848 rcu_read_unlock();
4849
4841 if (res->tsf && 4850 if (res->tsf &&
4842 nla_put_u64(msg, NL80211_BSS_TSF, res->tsf)) 4851 nla_put_u64(msg, NL80211_BSS_TSF, res->tsf))
4843 goto nla_put_failure; 4852 goto nla_put_failure;
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index bcc7d7ee5a51..b6c7ea6d98f8 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1797,7 +1797,7 @@ EXPORT_SYMBOL(regulatory_hint);
1797 */ 1797 */
1798void regulatory_hint_11d(struct wiphy *wiphy, 1798void regulatory_hint_11d(struct wiphy *wiphy,
1799 enum ieee80211_band band, 1799 enum ieee80211_band band,
1800 u8 *country_ie, 1800 const u8 *country_ie,
1801 u8 country_ie_len) 1801 u8 country_ie_len)
1802{ 1802{
1803 char alpha2[2]; 1803 char alpha2[2];
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index f023c8a31c60..4c0a32ffd530 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -81,7 +81,7 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy,
81 */ 81 */
82void regulatory_hint_11d(struct wiphy *wiphy, 82void regulatory_hint_11d(struct wiphy *wiphy,
83 enum ieee80211_band band, 83 enum ieee80211_band band,
84 u8 *country_ie, 84 const u8 *country_ie,
85 u8 country_ie_len); 85 u8 country_ie_len);
86 86
87/** 87/**
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 834e0d153fbe..01592d7d4789 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -23,6 +23,7 @@
23 23
24static void bss_release(struct kref *ref) 24static void bss_release(struct kref *ref)
25{ 25{
26 struct cfg80211_bss_ies *ies;
26 struct cfg80211_internal_bss *bss; 27 struct cfg80211_internal_bss *bss;
27 28
28 bss = container_of(ref, struct cfg80211_internal_bss, ref); 29 bss = container_of(ref, struct cfg80211_internal_bss, ref);
@@ -33,10 +34,12 @@ static void bss_release(struct kref *ref)
33 if (bss->pub.free_priv) 34 if (bss->pub.free_priv)
34 bss->pub.free_priv(&bss->pub); 35 bss->pub.free_priv(&bss->pub);
35 36
36 if (bss->beacon_ies_allocated) 37 ies = (void *)rcu_access_pointer(bss->pub.beacon_ies);
37 kfree(bss->pub.beacon_ies); 38 if (ies)
38 if (bss->proberesp_ies_allocated) 39 kfree_rcu(ies, rcu_head);
39 kfree(bss->pub.proberesp_ies); 40 ies = (void *)rcu_access_pointer(bss->pub.proberesp_ies);
41 if (ies)
42 kfree_rcu(ies, rcu_head);
40 43
41 kfree(bss); 44 kfree(bss);
42} 45}
@@ -288,7 +291,7 @@ const u8 *cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type,
288} 291}
289EXPORT_SYMBOL(cfg80211_find_vendor_ie); 292EXPORT_SYMBOL(cfg80211_find_vendor_ie);
290 293
291static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2) 294static int cmp_ies(u8 num, const u8 *ies1, int len1, const u8 *ies2, int len2)
292{ 295{
293 const u8 *ie1 = cfg80211_find_ie(num, ies1, len1); 296 const u8 *ie1 = cfg80211_find_ie(num, ies1, len1);
294 const u8 *ie2 = cfg80211_find_ie(num, ies2, len2); 297 const u8 *ie2 = cfg80211_find_ie(num, ies2, len2);
@@ -311,6 +314,7 @@ static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2)
311static bool is_bss(struct cfg80211_bss *a, const u8 *bssid, 314static bool is_bss(struct cfg80211_bss *a, const u8 *bssid,
312 const u8 *ssid, size_t ssid_len) 315 const u8 *ssid, size_t ssid_len)
313{ 316{
317 const struct cfg80211_bss_ies *ies;
314 const u8 *ssidie; 318 const u8 *ssidie;
315 319
316 if (bssid && !ether_addr_equal(a->bssid, bssid)) 320 if (bssid && !ether_addr_equal(a->bssid, bssid))
@@ -319,9 +323,10 @@ static bool is_bss(struct cfg80211_bss *a, const u8 *bssid,
319 if (!ssid) 323 if (!ssid)
320 return true; 324 return true;
321 325
322 ssidie = cfg80211_find_ie(WLAN_EID_SSID, 326 ies = rcu_access_pointer(a->ies);
323 a->information_elements, 327 if (!ies)
324 a->len_information_elements); 328 return false;
329 ssidie = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len);
325 if (!ssidie) 330 if (!ssidie)
326 return false; 331 return false;
327 if (ssidie[1] != ssid_len) 332 if (ssidie[1] != ssid_len)
@@ -331,20 +336,21 @@ static bool is_bss(struct cfg80211_bss *a, const u8 *bssid,
331 336
332static bool is_mesh_bss(struct cfg80211_bss *a) 337static bool is_mesh_bss(struct cfg80211_bss *a)
333{ 338{
339 const struct cfg80211_bss_ies *ies;
334 const u8 *ie; 340 const u8 *ie;
335 341
336 if (!WLAN_CAPABILITY_IS_STA_BSS(a->capability)) 342 if (!WLAN_CAPABILITY_IS_STA_BSS(a->capability))
337 return false; 343 return false;
338 344
339 ie = cfg80211_find_ie(WLAN_EID_MESH_ID, 345 ies = rcu_access_pointer(a->ies);
340 a->information_elements, 346 if (!ies)
341 a->len_information_elements); 347 return false;
348
349 ie = cfg80211_find_ie(WLAN_EID_MESH_ID, ies->data, ies->len);
342 if (!ie) 350 if (!ie)
343 return false; 351 return false;
344 352
345 ie = cfg80211_find_ie(WLAN_EID_MESH_CONFIG, 353 ie = cfg80211_find_ie(WLAN_EID_MESH_CONFIG, ies->data, ies->len);
346 a->information_elements,
347 a->len_information_elements);
348 if (!ie) 354 if (!ie)
349 return false; 355 return false;
350 356
@@ -355,14 +361,17 @@ static bool is_mesh(struct cfg80211_bss *a,
355 const u8 *meshid, size_t meshidlen, 361 const u8 *meshid, size_t meshidlen,
356 const u8 *meshcfg) 362 const u8 *meshcfg)
357{ 363{
364 const struct cfg80211_bss_ies *ies;
358 const u8 *ie; 365 const u8 *ie;
359 366
360 if (!WLAN_CAPABILITY_IS_STA_BSS(a->capability)) 367 if (!WLAN_CAPABILITY_IS_STA_BSS(a->capability))
361 return false; 368 return false;
362 369
363 ie = cfg80211_find_ie(WLAN_EID_MESH_ID, 370 ies = rcu_access_pointer(a->ies);
364 a->information_elements, 371 if (!ies)
365 a->len_information_elements); 372 return false;
373
374 ie = cfg80211_find_ie(WLAN_EID_MESH_ID, ies->data, ies->len);
366 if (!ie) 375 if (!ie)
367 return false; 376 return false;
368 if (ie[1] != meshidlen) 377 if (ie[1] != meshidlen)
@@ -370,9 +379,7 @@ static bool is_mesh(struct cfg80211_bss *a,
370 if (memcmp(ie + 2, meshid, meshidlen)) 379 if (memcmp(ie + 2, meshid, meshidlen))
371 return false; 380 return false;
372 381
373 ie = cfg80211_find_ie(WLAN_EID_MESH_CONFIG, 382 ie = cfg80211_find_ie(WLAN_EID_MESH_CONFIG, ies->data, ies->len);
374 a->information_elements,
375 a->len_information_elements);
376 if (!ie) 383 if (!ie)
377 return false; 384 return false;
378 if (ie[1] != sizeof(struct ieee80211_meshconf_ie)) 385 if (ie[1] != sizeof(struct ieee80211_meshconf_ie))
@@ -389,24 +396,28 @@ static bool is_mesh(struct cfg80211_bss *a,
389 396
390static int cmp_bss_core(struct cfg80211_bss *a, struct cfg80211_bss *b) 397static int cmp_bss_core(struct cfg80211_bss *a, struct cfg80211_bss *b)
391{ 398{
399 const struct cfg80211_bss_ies *a_ies, *b_ies;
392 int r; 400 int r;
393 401
394 if (a->channel != b->channel) 402 if (a->channel != b->channel)
395 return b->channel->center_freq - a->channel->center_freq; 403 return b->channel->center_freq - a->channel->center_freq;
396 404
397 if (is_mesh_bss(a) && is_mesh_bss(b)) { 405 if (is_mesh_bss(a) && is_mesh_bss(b)) {
406 a_ies = rcu_access_pointer(a->ies);
407 if (!a_ies)
408 return -1;
409 b_ies = rcu_access_pointer(b->ies);
410 if (!b_ies)
411 return 1;
412
398 r = cmp_ies(WLAN_EID_MESH_ID, 413 r = cmp_ies(WLAN_EID_MESH_ID,
399 a->information_elements, 414 a_ies->data, a_ies->len,
400 a->len_information_elements, 415 b_ies->data, b_ies->len);
401 b->information_elements,
402 b->len_information_elements);
403 if (r) 416 if (r)
404 return r; 417 return r;
405 return cmp_ies(WLAN_EID_MESH_CONFIG, 418 return cmp_ies(WLAN_EID_MESH_CONFIG,
406 a->information_elements, 419 a_ies->data, a_ies->len,
407 a->len_information_elements, 420 b_ies->data, b_ies->len);
408 b->information_elements,
409 b->len_information_elements);
410 } 421 }
411 422
412 /* 423 /*
@@ -419,21 +430,28 @@ static int cmp_bss_core(struct cfg80211_bss *a, struct cfg80211_bss *b)
419static int cmp_bss(struct cfg80211_bss *a, 430static int cmp_bss(struct cfg80211_bss *a,
420 struct cfg80211_bss *b) 431 struct cfg80211_bss *b)
421{ 432{
433 const struct cfg80211_bss_ies *a_ies, *b_ies;
422 int r; 434 int r;
423 435
424 r = cmp_bss_core(a, b); 436 r = cmp_bss_core(a, b);
425 if (r) 437 if (r)
426 return r; 438 return r;
427 439
440 a_ies = rcu_access_pointer(a->ies);
441 if (!a_ies)
442 return -1;
443 b_ies = rcu_access_pointer(b->ies);
444 if (!b_ies)
445 return 1;
446
428 return cmp_ies(WLAN_EID_SSID, 447 return cmp_ies(WLAN_EID_SSID,
429 a->information_elements, 448 a_ies->data, a_ies->len,
430 a->len_information_elements, 449 b_ies->data, b_ies->len);
431 b->information_elements,
432 b->len_information_elements);
433} 450}
434 451
435static int cmp_hidden_bss(struct cfg80211_bss *a, struct cfg80211_bss *b) 452static int cmp_hidden_bss(struct cfg80211_bss *a, struct cfg80211_bss *b)
436{ 453{
454 const struct cfg80211_bss_ies *a_ies, *b_ies;
437 const u8 *ie1; 455 const u8 *ie1;
438 const u8 *ie2; 456 const u8 *ie2;
439 int i; 457 int i;
@@ -443,12 +461,15 @@ static int cmp_hidden_bss(struct cfg80211_bss *a, struct cfg80211_bss *b)
443 if (r) 461 if (r)
444 return r; 462 return r;
445 463
446 ie1 = cfg80211_find_ie(WLAN_EID_SSID, 464 a_ies = rcu_access_pointer(a->ies);
447 a->information_elements, 465 if (!a_ies)
448 a->len_information_elements); 466 return -1;
449 ie2 = cfg80211_find_ie(WLAN_EID_SSID, 467 b_ies = rcu_access_pointer(b->ies);
450 b->information_elements, 468 if (!b_ies)
451 b->len_information_elements); 469 return 1;
470
471 ie1 = cfg80211_find_ie(WLAN_EID_SSID, a_ies->data, a_ies->len);
472 ie2 = cfg80211_find_ie(WLAN_EID_SSID, b_ies->data, b_ies->len);
452 473
453 /* 474 /*
454 * Key comparator must use same algorithm in any rb-tree 475 * Key comparator must use same algorithm in any rb-tree
@@ -633,126 +654,84 @@ static void
633copy_hidden_ies(struct cfg80211_internal_bss *res, 654copy_hidden_ies(struct cfg80211_internal_bss *res,
634 struct cfg80211_internal_bss *hidden) 655 struct cfg80211_internal_bss *hidden)
635{ 656{
636 if (unlikely(res->pub.beacon_ies)) 657 const struct cfg80211_bss_ies *ies;
637 return; 658
638 if (WARN_ON(!hidden->pub.beacon_ies)) 659 if (rcu_access_pointer(res->pub.beacon_ies))
639 return; 660 return;
640 661
641 res->pub.beacon_ies = kmalloc(hidden->pub.len_beacon_ies, GFP_ATOMIC); 662 ies = rcu_access_pointer(hidden->pub.beacon_ies);
642 if (unlikely(!res->pub.beacon_ies)) 663 if (WARN_ON(!ies))
643 return; 664 return;
644 665
645 res->beacon_ies_allocated = true; 666 ies = kmemdup(ies, sizeof(*ies) + ies->len, GFP_ATOMIC);
646 res->pub.len_beacon_ies = hidden->pub.len_beacon_ies; 667 if (unlikely(!ies))
647 memcpy(res->pub.beacon_ies, hidden->pub.beacon_ies, 668 return;
648 res->pub.len_beacon_ies); 669 rcu_assign_pointer(res->pub.beacon_ies, ies);
649} 670}
650 671
651static struct cfg80211_internal_bss * 672static struct cfg80211_internal_bss *
652cfg80211_bss_update(struct cfg80211_registered_device *dev, 673cfg80211_bss_update(struct cfg80211_registered_device *dev,
653 struct cfg80211_internal_bss *res) 674 struct cfg80211_internal_bss *tmp)
654{ 675{
655 struct cfg80211_internal_bss *found = NULL; 676 struct cfg80211_internal_bss *found = NULL;
656 677
657 /* 678 if (WARN_ON(!tmp->pub.channel))
658 * The reference to "res" is donated to this function.
659 */
660
661 if (WARN_ON(!res->pub.channel)) {
662 kref_put(&res->ref, bss_release);
663 return NULL; 679 return NULL;
664 }
665 680
666 res->ts = jiffies; 681 tmp->ts = jiffies;
667 682
668 spin_lock_bh(&dev->bss_lock); 683 spin_lock_bh(&dev->bss_lock);
669 684
670 found = rb_find_bss(dev, res); 685 if (WARN_ON(!rcu_access_pointer(tmp->pub.ies))) {
686 spin_unlock_bh(&dev->bss_lock);
687 return NULL;
688 }
689
690 found = rb_find_bss(dev, tmp);
671 691
672 if (found) { 692 if (found) {
673 found->pub.beacon_interval = res->pub.beacon_interval; 693 found->pub.beacon_interval = tmp->pub.beacon_interval;
674 found->pub.tsf = res->pub.tsf; 694 found->pub.tsf = tmp->pub.tsf;
675 found->pub.signal = res->pub.signal; 695 found->pub.signal = tmp->pub.signal;
676 found->pub.capability = res->pub.capability; 696 found->pub.capability = tmp->pub.capability;
677 found->ts = res->ts; 697 found->ts = tmp->ts;
678 698
679 /* Update IEs */ 699 /* Update IEs */
680 if (res->pub.proberesp_ies) { 700 if (rcu_access_pointer(tmp->pub.proberesp_ies)) {
681 size_t used = dev->wiphy.bss_priv_size + sizeof(*res); 701 const struct cfg80211_bss_ies *old;
682 size_t ielen = res->pub.len_proberesp_ies; 702
683 703 old = rcu_access_pointer(found->pub.proberesp_ies);
684 if (found->pub.proberesp_ies &&
685 !found->proberesp_ies_allocated &&
686 ksize(found) >= used + ielen) {
687 memcpy(found->pub.proberesp_ies,
688 res->pub.proberesp_ies, ielen);
689 found->pub.len_proberesp_ies = ielen;
690 } else {
691 u8 *ies = found->pub.proberesp_ies;
692
693 if (found->proberesp_ies_allocated)
694 ies = krealloc(ies, ielen, GFP_ATOMIC);
695 else
696 ies = kmalloc(ielen, GFP_ATOMIC);
697
698 if (ies) {
699 memcpy(ies, res->pub.proberesp_ies,
700 ielen);
701 found->proberesp_ies_allocated = true;
702 found->pub.proberesp_ies = ies;
703 found->pub.len_proberesp_ies = ielen;
704 }
705 }
706 704
705 rcu_assign_pointer(found->pub.proberesp_ies,
706 tmp->pub.proberesp_ies);
707 /* Override possible earlier Beacon frame IEs */ 707 /* Override possible earlier Beacon frame IEs */
708 found->pub.information_elements = 708 rcu_assign_pointer(found->pub.ies,
709 found->pub.proberesp_ies; 709 tmp->pub.proberesp_ies);
710 found->pub.len_information_elements = 710 if (old)
711 found->pub.len_proberesp_ies; 711 kfree_rcu((struct cfg80211_bss_ies *)old,
712 } 712 rcu_head);
713 } else if (rcu_access_pointer(tmp->pub.beacon_ies)) {
714 const struct cfg80211_bss_ies *old, *ies;
713 715
714 if (res->pub.beacon_ies) { 716 old = rcu_access_pointer(found->pub.beacon_ies);
715 size_t used = dev->wiphy.bss_priv_size + sizeof(*res); 717 ies = rcu_access_pointer(found->pub.ies);
716 size_t ielen = res->pub.len_beacon_ies; 718
717 bool information_elements_is_beacon_ies = 719 rcu_assign_pointer(found->pub.beacon_ies,
718 (found->pub.information_elements == 720 tmp->pub.beacon_ies);
719 found->pub.beacon_ies);
720
721 if (found->pub.beacon_ies &&
722 !found->beacon_ies_allocated &&
723 ksize(found) >= used + ielen) {
724 memcpy(found->pub.beacon_ies,
725 res->pub.beacon_ies, ielen);
726 found->pub.len_beacon_ies = ielen;
727 } else {
728 u8 *ies = found->pub.beacon_ies;
729
730 if (found->beacon_ies_allocated)
731 ies = krealloc(ies, ielen, GFP_ATOMIC);
732 else
733 ies = kmalloc(ielen, GFP_ATOMIC);
734
735 if (ies) {
736 memcpy(ies, res->pub.beacon_ies,
737 ielen);
738 found->beacon_ies_allocated = true;
739 found->pub.beacon_ies = ies;
740 found->pub.len_beacon_ies = ielen;
741 }
742 }
743 721
744 /* Override IEs if they were from a beacon before */ 722 /* Override IEs if they were from a beacon before */
745 if (information_elements_is_beacon_ies) { 723 if (old == ies)
746 found->pub.information_elements = 724 rcu_assign_pointer(found->pub.ies,
747 found->pub.beacon_ies; 725 tmp->pub.beacon_ies);
748 found->pub.len_information_elements =
749 found->pub.len_beacon_ies;
750 }
751 }
752 726
753 kref_put(&res->ref, bss_release); 727 if (old)
728 kfree_rcu((struct cfg80211_bss_ies *)old,
729 rcu_head);
730 }
754 } else { 731 } else {
732 struct cfg80211_internal_bss *new;
755 struct cfg80211_internal_bss *hidden; 733 struct cfg80211_internal_bss *hidden;
734 struct cfg80211_bss_ies *ies;
756 735
757 /* First check if the beacon is a probe response from 736 /* First check if the beacon is a probe response from
758 * a hidden bss. If so, copy beacon ies (with nullified 737 * a hidden bss. If so, copy beacon ies (with nullified
@@ -763,14 +742,32 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
763 /* TODO: The code is not trying to update existing probe 742 /* TODO: The code is not trying to update existing probe
764 * response bss entries when beacon ies are 743 * response bss entries when beacon ies are
765 * getting changed. */ 744 * getting changed. */
766 hidden = rb_find_hidden_bss(dev, res); 745 hidden = rb_find_hidden_bss(dev, tmp);
767 if (hidden) 746 if (hidden)
768 copy_hidden_ies(res, hidden); 747 copy_hidden_ies(tmp, hidden);
769 748
770 /* this "consumes" the reference */ 749 /*
771 list_add_tail(&res->list, &dev->bss_list); 750 * create a copy -- the "res" variable that is passed in
772 rb_insert_bss(dev, res); 751 * is allocated on the stack since it's not needed in the
773 found = res; 752 * more common case of an update
753 */
754 new = kzalloc(sizeof(*new) + dev->wiphy.bss_priv_size,
755 GFP_ATOMIC);
756 if (!new) {
757 ies = (void *)rcu_dereference(tmp->pub.beacon_ies);
758 if (ies)
759 kfree_rcu(ies, rcu_head);
760 ies = (void *)rcu_dereference(tmp->pub.proberesp_ies);
761 if (ies)
762 kfree_rcu(ies, rcu_head);
763 spin_unlock_bh(&dev->bss_lock);
764 return NULL;
765 }
766 memcpy(new, tmp, sizeof(*new));
767 kref_init(&new->ref);
768 list_add_tail(&new->list, &dev->bss_list);
769 rb_insert_bss(dev, new);
770 found = new;
774 } 771 }
775 772
776 dev->bss_generation++; 773 dev->bss_generation++;
@@ -819,14 +816,12 @@ cfg80211_inform_bss(struct wiphy *wiphy,
819 u16 beacon_interval, const u8 *ie, size_t ielen, 816 u16 beacon_interval, const u8 *ie, size_t ielen,
820 s32 signal, gfp_t gfp) 817 s32 signal, gfp_t gfp)
821{ 818{
822 struct cfg80211_internal_bss *res; 819 struct cfg80211_bss_ies *ies;
823 size_t privsz; 820 struct cfg80211_internal_bss tmp = {}, *res;
824 821
825 if (WARN_ON(!wiphy)) 822 if (WARN_ON(!wiphy))
826 return NULL; 823 return NULL;
827 824
828 privsz = wiphy->bss_priv_size;
829
830 if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC && 825 if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC &&
831 (signal < 0 || signal > 100))) 826 (signal < 0 || signal > 100)))
832 return NULL; 827 return NULL;
@@ -835,36 +830,33 @@ cfg80211_inform_bss(struct wiphy *wiphy,
835 if (!channel) 830 if (!channel)
836 return NULL; 831 return NULL;
837 832
838 res = kzalloc(sizeof(*res) + privsz + ielen, gfp); 833 memcpy(tmp.pub.bssid, bssid, ETH_ALEN);
839 if (!res) 834 tmp.pub.channel = channel;
840 return NULL; 835 tmp.pub.signal = signal;
841 836 tmp.pub.tsf = tsf;
842 memcpy(res->pub.bssid, bssid, ETH_ALEN); 837 tmp.pub.beacon_interval = beacon_interval;
843 res->pub.channel = channel; 838 tmp.pub.capability = capability;
844 res->pub.signal = signal;
845 res->pub.tsf = tsf;
846 res->pub.beacon_interval = beacon_interval;
847 res->pub.capability = capability;
848 /* 839 /*
849 * Since we do not know here whether the IEs are from a Beacon or Probe 840 * Since we do not know here whether the IEs are from a Beacon or Probe
850 * Response frame, we need to pick one of the options and only use it 841 * Response frame, we need to pick one of the options and only use it
851 * with the driver that does not provide the full Beacon/Probe Response 842 * with the driver that does not provide the full Beacon/Probe Response
852 * frame. Use Beacon frame pointer to avoid indicating that this should 843 * frame. Use Beacon frame pointer to avoid indicating that this should
853 * override the information_elements pointer should we have received an 844 * override the iies pointer should we have received an earlier
854 * earlier indication of Probe Response data. 845 * indication of Probe Response data.
855 * 846 *
856 * The initial buffer for the IEs is allocated with the BSS entry and 847 * The initial buffer for the IEs is allocated with the BSS entry and
857 * is located after the private area. 848 * is located after the private area.
858 */ 849 */
859 res->pub.beacon_ies = (u8 *)res + sizeof(*res) + privsz; 850 ies = kmalloc(sizeof(*ies) + ielen, gfp);
860 memcpy(res->pub.beacon_ies, ie, ielen); 851 if (!ies)
861 res->pub.len_beacon_ies = ielen; 852 return NULL;
862 res->pub.information_elements = res->pub.beacon_ies; 853 ies->len = ielen;
863 res->pub.len_information_elements = res->pub.len_beacon_ies; 854 memcpy(ies->data, ie, ielen);
864 855
865 kref_init(&res->ref); 856 rcu_assign_pointer(tmp.pub.beacon_ies, ies);
857 rcu_assign_pointer(tmp.pub.ies, ies);
866 858
867 res = cfg80211_bss_update(wiphy_to_dev(wiphy), res); 859 res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp);
868 if (!res) 860 if (!res)
869 return NULL; 861 return NULL;
870 862
@@ -883,10 +875,10 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
883 struct ieee80211_mgmt *mgmt, size_t len, 875 struct ieee80211_mgmt *mgmt, size_t len,
884 s32 signal, gfp_t gfp) 876 s32 signal, gfp_t gfp)
885{ 877{
886 struct cfg80211_internal_bss *res; 878 struct cfg80211_internal_bss tmp = {}, *res;
879 struct cfg80211_bss_ies *ies;
887 size_t ielen = len - offsetof(struct ieee80211_mgmt, 880 size_t ielen = len - offsetof(struct ieee80211_mgmt,
888 u.probe_resp.variable); 881 u.probe_resp.variable);
889 size_t privsz;
890 882
891 BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) != 883 BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) !=
892 offsetof(struct ieee80211_mgmt, u.beacon.variable)); 884 offsetof(struct ieee80211_mgmt, u.beacon.variable));
@@ -906,45 +898,31 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
906 if (WARN_ON(len < offsetof(struct ieee80211_mgmt, u.probe_resp.variable))) 898 if (WARN_ON(len < offsetof(struct ieee80211_mgmt, u.probe_resp.variable)))
907 return NULL; 899 return NULL;
908 900
909 privsz = wiphy->bss_priv_size;
910
911 channel = cfg80211_get_bss_channel(wiphy, mgmt->u.beacon.variable, 901 channel = cfg80211_get_bss_channel(wiphy, mgmt->u.beacon.variable,
912 ielen, channel); 902 ielen, channel);
913 if (!channel) 903 if (!channel)
914 return NULL; 904 return NULL;
915 905
916 res = kzalloc(sizeof(*res) + privsz + ielen, gfp); 906 ies = kmalloc(sizeof(*ies) + ielen, gfp);
917 if (!res) 907 if (!ies)
918 return NULL; 908 return NULL;
909 ies->len = ielen;
910 memcpy(ies->data, mgmt->u.probe_resp.variable, ielen);
919 911
920 memcpy(res->pub.bssid, mgmt->bssid, ETH_ALEN); 912 if (ieee80211_is_probe_resp(mgmt->frame_control))
921 res->pub.channel = channel; 913 rcu_assign_pointer(tmp.pub.proberesp_ies, ies);
922 res->pub.signal = signal; 914 else
923 res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); 915 rcu_assign_pointer(tmp.pub.beacon_ies, ies);
924 res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); 916 rcu_assign_pointer(tmp.pub.ies, ies);
925 res->pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); 917
926 /* 918 memcpy(tmp.pub.bssid, mgmt->bssid, ETH_ALEN);
927 * The initial buffer for the IEs is allocated with the BSS entry and 919 tmp.pub.channel = channel;
928 * is located after the private area. 920 tmp.pub.signal = signal;
929 */ 921 tmp.pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
930 if (ieee80211_is_probe_resp(mgmt->frame_control)) { 922 tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
931 res->pub.proberesp_ies = (u8 *) res + sizeof(*res) + privsz; 923 tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
932 memcpy(res->pub.proberesp_ies, mgmt->u.probe_resp.variable, 924
933 ielen); 925 res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp);
934 res->pub.len_proberesp_ies = ielen;
935 res->pub.information_elements = res->pub.proberesp_ies;
936 res->pub.len_information_elements = res->pub.len_proberesp_ies;
937 } else {
938 res->pub.beacon_ies = (u8 *) res + sizeof(*res) + privsz;
939 memcpy(res->pub.beacon_ies, mgmt->u.beacon.variable, ielen);
940 res->pub.len_beacon_ies = ielen;
941 res->pub.information_elements = res->pub.beacon_ies;
942 res->pub.len_information_elements = res->pub.len_beacon_ies;
943 }
944
945 kref_init(&res->ref);
946
947 res = cfg80211_bss_update(wiphy_to_dev(wiphy), res);
948 if (!res) 926 if (!res)
949 return NULL; 927 return NULL;
950 928
@@ -1136,22 +1114,21 @@ int cfg80211_wext_siwscan(struct net_device *dev,
1136EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan); 1114EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan);
1137 1115
1138static void ieee80211_scan_add_ies(struct iw_request_info *info, 1116static void ieee80211_scan_add_ies(struct iw_request_info *info,
1139 struct cfg80211_bss *bss, 1117 const struct cfg80211_bss_ies *ies,
1140 char **current_ev, char *end_buf) 1118 char **current_ev, char *end_buf)
1141{ 1119{
1142 u8 *pos, *end, *next; 1120 const u8 *pos, *end, *next;
1143 struct iw_event iwe; 1121 struct iw_event iwe;
1144 1122
1145 if (!bss->information_elements || 1123 if (!ies)
1146 !bss->len_information_elements)
1147 return; 1124 return;
1148 1125
1149 /* 1126 /*
1150 * If needed, fragment the IEs buffer (at IE boundaries) into short 1127 * If needed, fragment the IEs buffer (at IE boundaries) into short
1151 * enough fragments to fit into IW_GENERIC_IE_MAX octet messages. 1128 * enough fragments to fit into IW_GENERIC_IE_MAX octet messages.
1152 */ 1129 */
1153 pos = bss->information_elements; 1130 pos = ies->data;
1154 end = pos + bss->len_information_elements; 1131 end = pos + ies->len;
1155 1132
1156 while (end - pos > IW_GENERIC_IE_MAX) { 1133 while (end - pos > IW_GENERIC_IE_MAX) {
1157 next = pos + 2 + pos[1]; 1134 next = pos + 2 + pos[1];
@@ -1162,7 +1139,8 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info,
1162 iwe.cmd = IWEVGENIE; 1139 iwe.cmd = IWEVGENIE;
1163 iwe.u.data.length = next - pos; 1140 iwe.u.data.length = next - pos;
1164 *current_ev = iwe_stream_add_point(info, *current_ev, 1141 *current_ev = iwe_stream_add_point(info, *current_ev,
1165 end_buf, &iwe, pos); 1142 end_buf, &iwe,
1143 (void *)pos);
1166 1144
1167 pos = next; 1145 pos = next;
1168 } 1146 }
@@ -1172,7 +1150,8 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info,
1172 iwe.cmd = IWEVGENIE; 1150 iwe.cmd = IWEVGENIE;
1173 iwe.u.data.length = end - pos; 1151 iwe.u.data.length = end - pos;
1174 *current_ev = iwe_stream_add_point(info, *current_ev, 1152 *current_ev = iwe_stream_add_point(info, *current_ev,
1175 end_buf, &iwe, pos); 1153 end_buf, &iwe,
1154 (void *)pos);
1176 } 1155 }
1177} 1156}
1178 1157
@@ -1191,10 +1170,11 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1191 struct cfg80211_internal_bss *bss, char *current_ev, 1170 struct cfg80211_internal_bss *bss, char *current_ev,
1192 char *end_buf) 1171 char *end_buf)
1193{ 1172{
1173 const struct cfg80211_bss_ies *ies;
1194 struct iw_event iwe; 1174 struct iw_event iwe;
1175 const u8 *ie;
1195 u8 *buf, *cfg, *p; 1176 u8 *buf, *cfg, *p;
1196 u8 *ie = bss->pub.information_elements; 1177 int rem, i, sig;
1197 int rem = bss->pub.len_information_elements, i, sig;
1198 bool ismesh = false; 1178 bool ismesh = false;
1199 1179
1200 memset(&iwe, 0, sizeof(iwe)); 1180 memset(&iwe, 0, sizeof(iwe));
@@ -1259,7 +1239,17 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1259 current_ev = iwe_stream_add_point(info, current_ev, end_buf, 1239 current_ev = iwe_stream_add_point(info, current_ev, end_buf,
1260 &iwe, ""); 1240 &iwe, "");
1261 1241
1262 while (rem >= 2) { 1242 rcu_read_lock();
1243 ies = rcu_dereference(bss->pub.ies);
1244 if (ies) {
1245 rem = ies->len;
1246 ie = ies->data;
1247 } else {
1248 rem = 0;
1249 ie = NULL;
1250 }
1251
1252 while (ies && rem >= 2) {
1263 /* invalid data */ 1253 /* invalid data */
1264 if (ie[1] > rem - 2) 1254 if (ie[1] > rem - 2)
1265 break; 1255 break;
@@ -1271,7 +1261,7 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1271 iwe.u.data.length = ie[1]; 1261 iwe.u.data.length = ie[1];
1272 iwe.u.data.flags = 1; 1262 iwe.u.data.flags = 1;
1273 current_ev = iwe_stream_add_point(info, current_ev, end_buf, 1263 current_ev = iwe_stream_add_point(info, current_ev, end_buf,
1274 &iwe, ie + 2); 1264 &iwe, (u8 *)ie + 2);
1275 break; 1265 break;
1276 case WLAN_EID_MESH_ID: 1266 case WLAN_EID_MESH_ID:
1277 memset(&iwe, 0, sizeof(iwe)); 1267 memset(&iwe, 0, sizeof(iwe));
@@ -1279,7 +1269,7 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1279 iwe.u.data.length = ie[1]; 1269 iwe.u.data.length = ie[1];
1280 iwe.u.data.flags = 1; 1270 iwe.u.data.flags = 1;
1281 current_ev = iwe_stream_add_point(info, current_ev, end_buf, 1271 current_ev = iwe_stream_add_point(info, current_ev, end_buf,
1282 &iwe, ie + 2); 1272 &iwe, (u8 *)ie + 2);
1283 break; 1273 break;
1284 case WLAN_EID_MESH_CONFIG: 1274 case WLAN_EID_MESH_CONFIG:
1285 ismesh = true; 1275 ismesh = true;
@@ -1288,7 +1278,7 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1288 buf = kmalloc(50, GFP_ATOMIC); 1278 buf = kmalloc(50, GFP_ATOMIC);
1289 if (!buf) 1279 if (!buf)
1290 break; 1280 break;
1291 cfg = ie + 2; 1281 cfg = (u8 *)ie + 2;
1292 memset(&iwe, 0, sizeof(iwe)); 1282 memset(&iwe, 0, sizeof(iwe));
1293 iwe.cmd = IWEVCUSTOM; 1283 iwe.cmd = IWEVCUSTOM;
1294 sprintf(buf, "Mesh Network Path Selection Protocol ID: " 1284 sprintf(buf, "Mesh Network Path Selection Protocol ID: "
@@ -1386,7 +1376,8 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1386 kfree(buf); 1376 kfree(buf);
1387 } 1377 }
1388 1378
1389 ieee80211_scan_add_ies(info, &bss->pub, &current_ev, end_buf); 1379 ieee80211_scan_add_ies(info, ies, &current_ev, end_buf);
1380 rcu_read_unlock();
1390 1381
1391 return current_ev; 1382 return current_ev;
1392} 1383}
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index c7490027237d..f2431e41a373 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -417,7 +417,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
417 struct cfg80211_bss *bss) 417 struct cfg80211_bss *bss)
418{ 418{
419 struct wireless_dev *wdev = dev->ieee80211_ptr; 419 struct wireless_dev *wdev = dev->ieee80211_ptr;
420 u8 *country_ie; 420 const u8 *country_ie;
421#ifdef CONFIG_CFG80211_WEXT 421#ifdef CONFIG_CFG80211_WEXT
422 union iwreq_data wrqu; 422 union iwreq_data wrqu;
423#endif 423#endif
@@ -501,7 +501,15 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
501 wdev->sme_state = CFG80211_SME_CONNECTED; 501 wdev->sme_state = CFG80211_SME_CONNECTED;
502 cfg80211_upload_connect_keys(wdev); 502 cfg80211_upload_connect_keys(wdev);
503 503
504 country_ie = (u8 *) ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY); 504 rcu_read_lock();
505 country_ie = ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY);
506 if (!country_ie) {
507 rcu_read_unlock();
508 return;
509 }
510
511 country_ie = kmemdup(country_ie, 2 + country_ie[1], GFP_ATOMIC);
512 rcu_read_unlock();
505 513
506 if (!country_ie) 514 if (!country_ie)
507 return; 515 return;
@@ -515,6 +523,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
515 bss->channel->band, 523 bss->channel->band,
516 country_ie + 2, 524 country_ie + 2,
517 country_ie[1]); 525 country_ie[1]);
526 kfree(country_ie);
518} 527}
519 528
520void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, 529void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 3cce6e486219..16d76a807c2f 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -688,10 +688,13 @@ EXPORT_SYMBOL(cfg80211_classify8021d);
688 688
689const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie) 689const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie)
690{ 690{
691 if (bss->information_elements == NULL) 691 const struct cfg80211_bss_ies *ies;
692
693 ies = rcu_dereference(bss->ies);
694 if (!ies)
692 return NULL; 695 return NULL;
693 return cfg80211_find_ie(ie, bss->information_elements, 696
694 bss->len_information_elements); 697 return cfg80211_find_ie(ie, ies->data, ies->len);
695} 698}
696EXPORT_SYMBOL(ieee80211_bss_get_ie); 699EXPORT_SYMBOL(ieee80211_bss_get_ie);
697 700
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
index 873af63187c0..fb9622f6d99c 100644
--- a/net/wireless/wext-sme.c
+++ b/net/wireless/wext-sme.c
@@ -242,13 +242,17 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev,
242 242
243 wdev_lock(wdev); 243 wdev_lock(wdev);
244 if (wdev->current_bss) { 244 if (wdev->current_bss) {
245 const u8 *ie = ieee80211_bss_get_ie(&wdev->current_bss->pub, 245 const u8 *ie;
246 WLAN_EID_SSID); 246
247 rcu_read_lock();
248 ie = ieee80211_bss_get_ie(&wdev->current_bss->pub,
249 WLAN_EID_SSID);
247 if (ie) { 250 if (ie) {
248 data->flags = 1; 251 data->flags = 1;
249 data->length = ie[1]; 252 data->length = ie[1];
250 memcpy(ssid, ie + 2, data->length); 253 memcpy(ssid, ie + 2, data->length);
251 } 254 }
255 rcu_read_unlock();
252 } else if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) { 256 } else if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) {
253 data->flags = 1; 257 data->flags = 1;
254 data->length = wdev->wext.connect.ssid_len; 258 data->length = wdev->wext.connect.ssid_len;