aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;