diff options
-rw-r--r-- | drivers/net/wireless/libertas/cfg.c | 9 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/sta_ioctl.c | 35 | ||||
-rw-r--r-- | include/net/cfg80211.h | 41 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 80 | ||||
-rw-r--r-- | net/wireless/core.h | 2 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 27 | ||||
-rw-r--r-- | net/wireless/reg.c | 2 | ||||
-rw-r--r-- | net/wireless/reg.h | 2 | ||||
-rw-r--r-- | net/wireless/scan.c | 409 | ||||
-rw-r--r-- | net/wireless/sme.c | 13 | ||||
-rw-r--r-- | net/wireless/util.c | 9 | ||||
-rw-r--r-- | net/wireless/wext-sme.c | 8 |
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, | |||
198 | static int mwifiex_process_country_ie(struct mwifiex_private *priv, | 208 | static 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 | */ | ||
1214 | struct 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 | */ |
1232 | struct cfg80211_bss { | 1241 | struct 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 | */ |
1258 | const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie); | 1271 | const 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 | */ |
1798 | void regulatory_hint_11d(struct wiphy *wiphy, | 1798 | void 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 | */ |
82 | void regulatory_hint_11d(struct wiphy *wiphy, | 82 | void 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 | ||
24 | static void bss_release(struct kref *ref) | 24 | static 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 | } |
289 | EXPORT_SYMBOL(cfg80211_find_vendor_ie); | 292 | EXPORT_SYMBOL(cfg80211_find_vendor_ie); |
290 | 293 | ||
291 | static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2) | 294 | static 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) | |||
311 | static bool is_bss(struct cfg80211_bss *a, const u8 *bssid, | 314 | static 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 | ||
332 | static bool is_mesh_bss(struct cfg80211_bss *a) | 337 | static 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 | ||
390 | static int cmp_bss_core(struct cfg80211_bss *a, struct cfg80211_bss *b) | 397 | static 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) | |||
419 | static int cmp_bss(struct cfg80211_bss *a, | 430 | static 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 | ||
435 | static int cmp_hidden_bss(struct cfg80211_bss *a, struct cfg80211_bss *b) | 452 | static 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 | |||
633 | copy_hidden_ies(struct cfg80211_internal_bss *res, | 654 | copy_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 | ||
651 | static struct cfg80211_internal_bss * | 672 | static struct cfg80211_internal_bss * |
652 | cfg80211_bss_update(struct cfg80211_registered_device *dev, | 673 | cfg80211_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, | |||
1136 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan); | 1114 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan); |
1137 | 1115 | ||
1138 | static void ieee80211_scan_add_ies(struct iw_request_info *info, | 1116 | static 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, ¤t_ev, end_buf); | 1379 | ieee80211_scan_add_ies(info, ies, ¤t_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 | ||
520 | void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | 529 | void 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 | ||
689 | const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie) | 689 | const 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 | } |
696 | EXPORT_SYMBOL(ieee80211_bss_get_ie); | 699 | EXPORT_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; |