aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
authorJohn W. Linville <linville@tuxdriver.com>2012-12-06 14:58:41 -0500
committerJohn W. Linville <linville@tuxdriver.com>2012-12-06 14:58:41 -0500
commit403e16731ffddc097eae89f53f9a7b0f0c9769c4 (patch)
tree228d17985ad8ea22a7763457bf9641eb44781568 /net/wireless
parent55cb0797fa779e36f62876a8aa44cbf3984e8d59 (diff)
parentda29d2a5780d80857773d7776b7603a449b0b6e0 (diff)
Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Conflicts: drivers/net/wireless/mwifiex/sta_ioctl.c net/mac80211/scan.c
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/chan.c92
-rw-r--r--net/wireless/core.h8
-rw-r--r--net/wireless/mesh.c3
-rw-r--r--net/wireless/nl80211.c155
-rw-r--r--net/wireless/reg.c2
-rw-r--r--net/wireless/reg.h2
-rw-r--r--net/wireless/scan.c452
-rw-r--r--net/wireless/sme.c13
-rw-r--r--net/wireless/util.c9
-rw-r--r--net/wireless/wext-sme.c8
10 files changed, 398 insertions, 346 deletions
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index bf2dfd54ff3b..b5f69831e318 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -44,7 +44,7 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
44} 44}
45EXPORT_SYMBOL(cfg80211_chandef_create); 45EXPORT_SYMBOL(cfg80211_chandef_create);
46 46
47bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef) 47bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
48{ 48{
49 u32 control_freq; 49 u32 control_freq;
50 50
@@ -105,6 +105,7 @@ bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef)
105 105
106 return true; 106 return true;
107} 107}
108EXPORT_SYMBOL(cfg80211_chandef_valid);
108 109
109static void chandef_primary_freqs(const struct cfg80211_chan_def *c, 110static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
110 int *pri40, int *pri80) 111 int *pri40, int *pri80)
@@ -187,9 +188,9 @@ cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
187} 188}
188EXPORT_SYMBOL(cfg80211_chandef_compatible); 189EXPORT_SYMBOL(cfg80211_chandef_compatible);
189 190
190bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, 191static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
191 u32 center_freq, u32 bandwidth, 192 u32 center_freq, u32 bandwidth,
192 u32 prohibited_flags) 193 u32 prohibited_flags)
193{ 194{
194 struct ieee80211_channel *c; 195 struct ieee80211_channel *c;
195 u32 freq; 196 u32 freq;
@@ -205,55 +206,88 @@ bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
205 return true; 206 return true;
206} 207}
207 208
208static bool cfg80211_check_beacon_chans(struct wiphy *wiphy, 209bool cfg80211_chandef_usable(struct wiphy *wiphy,
209 u32 center_freq, u32 bw) 210 const struct cfg80211_chan_def *chandef,
211 u32 prohibited_flags)
210{ 212{
211 return cfg80211_secondary_chans_ok(wiphy, center_freq, bw, 213 struct ieee80211_sta_ht_cap *ht_cap;
212 IEEE80211_CHAN_DISABLED | 214 struct ieee80211_sta_vht_cap *vht_cap;
213 IEEE80211_CHAN_PASSIVE_SCAN | 215 u32 width, control_freq;
214 IEEE80211_CHAN_NO_IBSS |
215 IEEE80211_CHAN_RADAR);
216}
217 216
218bool cfg80211_reg_can_beacon(struct wiphy *wiphy, 217 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
219 struct cfg80211_chan_def *chandef) 218 return false;
220{
221 u32 width;
222 bool res;
223 219
224 trace_cfg80211_reg_can_beacon(wiphy, chandef); 220 ht_cap = &wiphy->bands[chandef->chan->band]->ht_cap;
221 vht_cap = &wiphy->bands[chandef->chan->band]->vht_cap;
225 222
226 if (WARN_ON(!cfg80211_chan_def_valid(chandef))) { 223 control_freq = chandef->chan->center_freq;
227 trace_cfg80211_return_bool(false);
228 return false;
229 }
230 224
231 switch (chandef->width) { 225 switch (chandef->width) {
232 case NL80211_CHAN_WIDTH_20_NOHT:
233 case NL80211_CHAN_WIDTH_20: 226 case NL80211_CHAN_WIDTH_20:
227 if (!ht_cap->ht_supported)
228 return false;
229 case NL80211_CHAN_WIDTH_20_NOHT:
234 width = 20; 230 width = 20;
235 break; 231 break;
236 case NL80211_CHAN_WIDTH_40: 232 case NL80211_CHAN_WIDTH_40:
237 width = 40; 233 width = 40;
234 if (!ht_cap->ht_supported)
235 return false;
236 if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
237 ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)
238 return false;
239 if (chandef->center_freq1 < control_freq &&
240 chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
241 return false;
242 if (chandef->center_freq1 > control_freq &&
243 chandef->chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
244 return false;
238 break; 245 break;
239 case NL80211_CHAN_WIDTH_80:
240 case NL80211_CHAN_WIDTH_80P80: 246 case NL80211_CHAN_WIDTH_80P80:
247 if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))
248 return false;
249 case NL80211_CHAN_WIDTH_80:
250 if (!vht_cap->vht_supported)
251 return false;
241 width = 80; 252 width = 80;
242 break; 253 break;
243 case NL80211_CHAN_WIDTH_160: 254 case NL80211_CHAN_WIDTH_160:
255 if (!vht_cap->vht_supported)
256 return false;
257 if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ))
258 return false;
244 width = 160; 259 width = 160;
245 break; 260 break;
246 default: 261 default:
247 WARN_ON_ONCE(1); 262 WARN_ON_ONCE(1);
248 trace_cfg80211_return_bool(false);
249 return false; 263 return false;
250 } 264 }
251 265
252 res = cfg80211_check_beacon_chans(wiphy, chandef->center_freq1, width); 266 /* TODO: missing regulatory check on 80/160 bandwidth */
267
268 if (!cfg80211_secondary_chans_ok(wiphy, chandef->center_freq1,
269 width, prohibited_flags))
270 return false;
271
272 if (!chandef->center_freq2)
273 return true;
274 return cfg80211_secondary_chans_ok(wiphy, chandef->center_freq2,
275 width, prohibited_flags);
276}
277EXPORT_SYMBOL(cfg80211_chandef_usable);
278
279bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
280 struct cfg80211_chan_def *chandef)
281{
282 bool res;
283
284 trace_cfg80211_reg_can_beacon(wiphy, chandef);
253 285
254 if (res && chandef->center_freq2) 286 res = cfg80211_chandef_usable(wiphy, chandef,
255 res = cfg80211_check_beacon_chans(wiphy, chandef->center_freq2, 287 IEEE80211_CHAN_DISABLED |
256 width); 288 IEEE80211_CHAN_PASSIVE_SCAN |
289 IEEE80211_CHAN_NO_IBSS |
290 IEEE80211_CHAN_RADAR);
257 291
258 trace_cfg80211_return_bool(res); 292 trace_cfg80211_return_bool(res);
259 return res; 293 return res;
diff --git a/net/wireless/core.h b/net/wireless/core.h
index a0c8decf6a47..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;
@@ -483,12 +481,6 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
483void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, 481void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
484 enum nl80211_iftype iftype, int num); 482 enum nl80211_iftype iftype, int num);
485 483
486bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef);
487
488bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
489 u32 center_freq, u32 bandwidth,
490 u32 prohibited_flags);
491
492#define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 484#define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10
493 485
494#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS 486#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 3ee5a7282283..f9d6ce5cfabb 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -146,7 +146,8 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
146 if (!setup->chandef.chan) 146 if (!setup->chandef.chan)
147 return -EINVAL; 147 return -EINVAL;
148 148
149 setup->chandef.width = NL80211_CHAN_WIDTH_20_NOHT;; 149 setup->chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
150 setup->chandef.center_freq1 = setup->chandef.chan->center_freq;
150 } 151 }
151 152
152 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef)) 153 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef))
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d038fa45ecd1..f45706adaf34 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -363,6 +363,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
363 [NL80211_ATTR_SAE_DATA] = { .type = NLA_BINARY, }, 363 [NL80211_ATTR_SAE_DATA] = { .type = NLA_BINARY, },
364 [NL80211_ATTR_VHT_CAPABILITY] = { .len = NL80211_VHT_CAPABILITY_LEN }, 364 [NL80211_ATTR_VHT_CAPABILITY] = { .len = NL80211_VHT_CAPABILITY_LEN },
365 [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 }, 365 [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
366 [NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 },
367 [NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 },
366}; 368};
367 369
368/* policy for the key attributes */ 370/* policy for the key attributes */
@@ -1369,9 +1371,7 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
1369 struct genl_info *info, 1371 struct genl_info *info,
1370 struct cfg80211_chan_def *chandef) 1372 struct cfg80211_chan_def *chandef)
1371{ 1373{
1372 struct ieee80211_sta_ht_cap *ht_cap; 1374 u32 control_freq;
1373 struct ieee80211_sta_vht_cap *vht_cap;
1374 u32 control_freq, width;
1375 1375
1376 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) 1376 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
1377 return -EINVAL; 1377 return -EINVAL;
@@ -1417,67 +1417,13 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
1417 info->attrs[NL80211_ATTR_CENTER_FREQ2]); 1417 info->attrs[NL80211_ATTR_CENTER_FREQ2]);
1418 } 1418 }
1419 1419
1420 ht_cap = &rdev->wiphy.bands[chandef->chan->band]->ht_cap; 1420 if (!cfg80211_chandef_valid(chandef))
1421 vht_cap = &rdev->wiphy.bands[chandef->chan->band]->vht_cap;
1422
1423 if (!cfg80211_chan_def_valid(chandef))
1424 return -EINVAL; 1421 return -EINVAL;
1425 1422
1426 switch (chandef->width) { 1423 if (!cfg80211_chandef_usable(&rdev->wiphy, chandef,
1427 case NL80211_CHAN_WIDTH_20: 1424 IEEE80211_CHAN_DISABLED))
1428 if (!ht_cap->ht_supported)
1429 return -EINVAL;
1430 case NL80211_CHAN_WIDTH_20_NOHT:
1431 width = 20;
1432 break;
1433 case NL80211_CHAN_WIDTH_40:
1434 width = 40;
1435 /* quick early regulatory check */
1436 if (chandef->center_freq1 < control_freq &&
1437 chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
1438 return -EINVAL;
1439 if (chandef->center_freq1 > control_freq &&
1440 chandef->chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
1441 return -EINVAL;
1442 if (!ht_cap->ht_supported)
1443 return -EINVAL;
1444 if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
1445 ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)
1446 return -EINVAL;
1447 break;
1448 case NL80211_CHAN_WIDTH_80:
1449 width = 80;
1450 if (!vht_cap->vht_supported)
1451 return -EINVAL;
1452 break;
1453 case NL80211_CHAN_WIDTH_80P80:
1454 width = 80;
1455 if (!vht_cap->vht_supported)
1456 return -EINVAL;
1457 if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))
1458 return -EINVAL;
1459 break;
1460 case NL80211_CHAN_WIDTH_160:
1461 width = 160;
1462 if (!vht_cap->vht_supported)
1463 return -EINVAL;
1464 if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ))
1465 return -EINVAL;
1466 break;
1467 default:
1468 return -EINVAL;
1469 }
1470
1471 if (!cfg80211_secondary_chans_ok(&rdev->wiphy, chandef->center_freq1,
1472 width, IEEE80211_CHAN_DISABLED))
1473 return -EINVAL;
1474 if (chandef->center_freq2 &&
1475 !cfg80211_secondary_chans_ok(&rdev->wiphy, chandef->center_freq2,
1476 width, IEEE80211_CHAN_DISABLED))
1477 return -EINVAL; 1425 return -EINVAL;
1478 1426
1479 /* TODO: missing regulatory check on bandwidth */
1480
1481 return 0; 1427 return 0;
1482} 1428}
1483 1429
@@ -1841,7 +1787,7 @@ static inline u64 wdev_id(struct wireless_dev *wdev)
1841static int nl80211_send_chandef(struct sk_buff *msg, 1787static int nl80211_send_chandef(struct sk_buff *msg,
1842 struct cfg80211_chan_def *chandef) 1788 struct cfg80211_chan_def *chandef)
1843{ 1789{
1844 WARN_ON(!cfg80211_chan_def_valid(chandef)); 1790 WARN_ON(!cfg80211_chandef_valid(chandef));
1845 1791
1846 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, 1792 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
1847 chandef->chan->center_freq)) 1793 chandef->chan->center_freq))
@@ -2732,6 +2678,32 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
2732 info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]); 2678 info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]);
2733 } 2679 }
2734 2680
2681 if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) {
2682 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
2683 return -EINVAL;
2684 params.p2p_ctwindow =
2685 nla_get_u8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]);
2686 if (params.p2p_ctwindow > 127)
2687 return -EINVAL;
2688 if (params.p2p_ctwindow != 0 &&
2689 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN))
2690 return -EINVAL;
2691 }
2692
2693 if (info->attrs[NL80211_ATTR_P2P_OPPPS]) {
2694 u8 tmp;
2695
2696 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
2697 return -EINVAL;
2698 tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]);
2699 if (tmp > 1)
2700 return -EINVAL;
2701 params.p2p_opp_ps = tmp;
2702 if (params.p2p_opp_ps != 0 &&
2703 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS))
2704 return -EINVAL;
2705 }
2706
2735 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { 2707 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
2736 err = nl80211_parse_chandef(rdev, info, &params.chandef); 2708 err = nl80211_parse_chandef(rdev, info, &params.chandef);
2737 if (err) 2709 if (err)
@@ -3698,6 +3670,8 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
3698 params.use_short_slot_time = -1; 3670 params.use_short_slot_time = -1;
3699 params.ap_isolate = -1; 3671 params.ap_isolate = -1;
3700 params.ht_opmode = -1; 3672 params.ht_opmode = -1;
3673 params.p2p_ctwindow = -1;
3674 params.p2p_opp_ps = -1;
3701 3675
3702 if (info->attrs[NL80211_ATTR_BSS_CTS_PROT]) 3676 if (info->attrs[NL80211_ATTR_BSS_CTS_PROT])
3703 params.use_cts_prot = 3677 params.use_cts_prot =
@@ -3720,6 +3694,32 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
3720 params.ht_opmode = 3694 params.ht_opmode =
3721 nla_get_u16(info->attrs[NL80211_ATTR_BSS_HT_OPMODE]); 3695 nla_get_u16(info->attrs[NL80211_ATTR_BSS_HT_OPMODE]);
3722 3696
3697 if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) {
3698 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
3699 return -EINVAL;
3700 params.p2p_ctwindow =
3701 nla_get_s8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]);
3702 if (params.p2p_ctwindow < 0)
3703 return -EINVAL;
3704 if (params.p2p_ctwindow != 0 &&
3705 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN))
3706 return -EINVAL;
3707 }
3708
3709 if (info->attrs[NL80211_ATTR_P2P_OPPPS]) {
3710 u8 tmp;
3711
3712 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
3713 return -EINVAL;
3714 tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]);
3715 if (tmp > 1)
3716 return -EINVAL;
3717 params.p2p_opp_ps = tmp;
3718 if (params.p2p_opp_ps &&
3719 !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS))
3720 return -EINVAL;
3721 }
3722
3723 if (!rdev->ops->change_bss) 3723 if (!rdev->ops->change_bss)
3724 return -EOPNOTSUPP; 3724 return -EOPNOTSUPP;
3725 3725
@@ -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 goto nla_put_failure;
4833 nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS, 4834
4834 res->len_information_elements, 4835 rcu_read_lock();
4835 res->information_elements)) || 4836 ies = rcu_dereference(res->ies);
4836 (res->beacon_ies && res->len_beacon_ies && 4837 if (ies && ies->len && nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS,
4837 res->beacon_ies != res->information_elements && 4838 ies->len, ies->data)) {
4838 nla_put(msg, NL80211_BSS_BEACON_IES, 4839 rcu_read_unlock();
4839 res->len_beacon_ies, res->beacon_ies))) 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();
4840 goto nla_put_failure; 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;
@@ -5502,6 +5511,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
5502 return -EINVAL; 5511 return -EINVAL;
5503 if (ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT && 5512 if (ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
5504 !(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS)) 5513 !(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
5514 return -EINVAL;
5505 5515
5506 ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; 5516 ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
5507 ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; 5517 ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
@@ -6529,14 +6539,13 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = {
6529}; 6539};
6530 6540
6531static int nl80211_set_cqm_txe(struct genl_info *info, 6541static int nl80211_set_cqm_txe(struct genl_info *info,
6532 u32 rate, u32 pkts, u32 intvl) 6542 u32 rate, u32 pkts, u32 intvl)
6533{ 6543{
6534 struct cfg80211_registered_device *rdev = info->user_ptr[0]; 6544 struct cfg80211_registered_device *rdev = info->user_ptr[0];
6535 struct wireless_dev *wdev; 6545 struct wireless_dev *wdev;
6536 struct net_device *dev = info->user_ptr[1]; 6546 struct net_device *dev = info->user_ptr[1];
6537 6547
6538 if ((rate < 0 || rate > 100) || 6548 if (rate > 100 || intvl > NL80211_CQM_TXE_MAX_INTVL)
6539 (intvl < 0 || intvl > NL80211_CQM_TXE_MAX_INTVL))
6540 return -EINVAL; 6549 return -EINVAL;
6541 6550
6542 wdev = dev->ieee80211_ptr; 6551 wdev = dev->ieee80211_ptr;
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index b75756b05af7..6e5308998e30 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1796,7 +1796,7 @@ EXPORT_SYMBOL(regulatory_hint);
1796 */ 1796 */
1797void regulatory_hint_11d(struct wiphy *wiphy, 1797void regulatory_hint_11d(struct wiphy *wiphy,
1798 enum ieee80211_band band, 1798 enum ieee80211_band band,
1799 u8 *country_ie, 1799 const u8 *country_ie,
1800 u8 country_ie_len) 1800 u8 country_ie_len)
1801{ 1801{
1802 char alpha2[2]; 1802 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 9596015975d2..01592d7d4789 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -23,18 +23,23 @@
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);
30
31 if (WARN_ON(atomic_read(&bss->hold)))
32 return;
33
29 if (bss->pub.free_priv) 34 if (bss->pub.free_priv)
30 bss->pub.free_priv(&bss->pub); 35 bss->pub.free_priv(&bss->pub);
31 36
32 if (bss->beacon_ies_allocated) 37 ies = (void *)rcu_access_pointer(bss->pub.beacon_ies);
33 kfree(bss->pub.beacon_ies); 38 if (ies)
34 if (bss->proberesp_ies_allocated) 39 kfree_rcu(ies, rcu_head);
35 kfree(bss->pub.proberesp_ies); 40 ies = (void *)rcu_access_pointer(bss->pub.proberesp_ies);
36 41 if (ies)
37 BUG_ON(atomic_read(&bss->hold)); 42 kfree_rcu(ies, rcu_head);
38 43
39 kfree(bss); 44 kfree(bss);
40} 45}
@@ -236,9 +241,8 @@ void cfg80211_bss_age(struct cfg80211_registered_device *dev,
236 struct cfg80211_internal_bss *bss; 241 struct cfg80211_internal_bss *bss;
237 unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC); 242 unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC);
238 243
239 list_for_each_entry(bss, &dev->bss_list, list) { 244 list_for_each_entry(bss, &dev->bss_list, list)
240 bss->ts -= age_jiffies; 245 bss->ts -= age_jiffies;
241 }
242} 246}
243 247
244void cfg80211_bss_expire(struct cfg80211_registered_device *dev) 248void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
@@ -287,7 +291,7 @@ const u8 *cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type,
287} 291}
288EXPORT_SYMBOL(cfg80211_find_vendor_ie); 292EXPORT_SYMBOL(cfg80211_find_vendor_ie);
289 293
290static 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)
291{ 295{
292 const u8 *ie1 = cfg80211_find_ie(num, ies1, len1); 296 const u8 *ie1 = cfg80211_find_ie(num, ies1, len1);
293 const u8 *ie2 = cfg80211_find_ie(num, ies2, len2); 297 const u8 *ie2 = cfg80211_find_ie(num, ies2, len2);
@@ -307,10 +311,10 @@ static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2)
307 return memcmp(ie1 + 2, ie2 + 2, ie1[1]); 311 return memcmp(ie1 + 2, ie2 + 2, ie1[1]);
308} 312}
309 313
310static bool is_bss(struct cfg80211_bss *a, 314static bool is_bss(struct cfg80211_bss *a, const u8 *bssid,
311 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,
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,
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))
@@ -384,30 +391,33 @@ static bool is_mesh(struct cfg80211_bss *a,
384 * part in the same mesh. 391 * part in the same mesh.
385 */ 392 */
386 return memcmp(ie + 2, meshcfg, 393 return memcmp(ie + 2, meshcfg,
387 sizeof(struct ieee80211_meshconf_ie) - 2) == 0; 394 sizeof(struct ieee80211_meshconf_ie) - 2) == 0;
388} 395}
389 396
390static int cmp_bss_core(struct cfg80211_bss *a, 397static int cmp_bss_core(struct cfg80211_bss *a, struct cfg80211_bss *b)
391 struct cfg80211_bss *b)
392{ 398{
399 const struct cfg80211_bss_ies *a_ies, *b_ies;
393 int r; 400 int r;
394 401
395 if (a->channel != b->channel) 402 if (a->channel != b->channel)
396 return b->channel->center_freq - a->channel->center_freq; 403 return b->channel->center_freq - a->channel->center_freq;
397 404
398 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
399 r = cmp_ies(WLAN_EID_MESH_ID, 413 r = cmp_ies(WLAN_EID_MESH_ID,
400 a->information_elements, 414 a_ies->data, a_ies->len,
401 a->len_information_elements, 415 b_ies->data, b_ies->len);
402 b->information_elements,
403 b->len_information_elements);
404 if (r) 416 if (r)
405 return r; 417 return r;
406 return cmp_ies(WLAN_EID_MESH_CONFIG, 418 return cmp_ies(WLAN_EID_MESH_CONFIG,
407 a->information_elements, 419 a_ies->data, a_ies->len,
408 a->len_information_elements, 420 b_ies->data, b_ies->len);
409 b->information_elements,
410 b->len_information_elements);
411 } 421 }
412 422
413 /* 423 /*
@@ -420,22 +430,28 @@ static int cmp_bss_core(struct cfg80211_bss *a,
420static int cmp_bss(struct cfg80211_bss *a, 430static int cmp_bss(struct cfg80211_bss *a,
421 struct cfg80211_bss *b) 431 struct cfg80211_bss *b)
422{ 432{
433 const struct cfg80211_bss_ies *a_ies, *b_ies;
423 int r; 434 int r;
424 435
425 r = cmp_bss_core(a, b); 436 r = cmp_bss_core(a, b);
426 if (r) 437 if (r)
427 return r; 438 return r;
428 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
429 return cmp_ies(WLAN_EID_SSID, 447 return cmp_ies(WLAN_EID_SSID,
430 a->information_elements, 448 a_ies->data, a_ies->len,
431 a->len_information_elements, 449 b_ies->data, b_ies->len);
432 b->information_elements,
433 b->len_information_elements);
434} 450}
435 451
436static int cmp_hidden_bss(struct cfg80211_bss *a, 452static int cmp_hidden_bss(struct cfg80211_bss *a, struct cfg80211_bss *b)
437 struct cfg80211_bss *b)
438{ 453{
454 const struct cfg80211_bss_ies *a_ies, *b_ies;
439 const u8 *ie1; 455 const u8 *ie1;
440 const u8 *ie2; 456 const u8 *ie2;
441 int i; 457 int i;
@@ -445,17 +461,26 @@ static int cmp_hidden_bss(struct cfg80211_bss *a,
445 if (r) 461 if (r)
446 return r; 462 return r;
447 463
448 ie1 = cfg80211_find_ie(WLAN_EID_SSID, 464 a_ies = rcu_access_pointer(a->ies);
449 a->information_elements, 465 if (!a_ies)
450 a->len_information_elements); 466 return -1;
451 ie2 = cfg80211_find_ie(WLAN_EID_SSID, 467 b_ies = rcu_access_pointer(b->ies);
452 b->information_elements, 468 if (!b_ies)
453 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);
454 473
455 /* Key comparator must use same algorithm in any rb-tree 474 /*
475 * Key comparator must use same algorithm in any rb-tree
456 * search function (order is important), otherwise ordering 476 * search function (order is important), otherwise ordering
457 * of items in the tree is broken and search gives incorrect 477 * of items in the tree is broken and search gives incorrect
458 * results. This code uses same order as cmp_ies() does. */ 478 * results. This code uses same order as cmp_ies() does.
479 *
480 * Note that due to the differring behaviour with hidden SSIDs
481 * this function only works when "b" is the tree element and
482 * "a" is the key we're looking for.
483 */
459 484
460 /* sort missing IE before (left of) present IE */ 485 /* sort missing IE before (left of) present IE */
461 if (!ie1) 486 if (!ie1)
@@ -471,10 +496,14 @@ static int cmp_hidden_bss(struct cfg80211_bss *a,
471 if (ie1[1] != ie2[1]) 496 if (ie1[1] != ie2[1])
472 return ie2[1] - ie1[1]; 497 return ie2[1] - ie1[1];
473 498
474 /* zeroed SSID ie is another indication of a hidden bss */ 499 /*
500 * zeroed SSID ie is another indication of a hidden bss;
501 * if it isn't zeroed just return the regular sort value
502 * to find the next candidate
503 */
475 for (i = 0; i < ie2[1]; i++) 504 for (i = 0; i < ie2[1]; i++)
476 if (ie2[i + 2]) 505 if (ie2[i + 2])
477 return -1; 506 return memcmp(ie1 + 2, ie2 + 2, ie1[1]);
478 507
479 return 0; 508 return 0;
480} 509}
@@ -600,7 +629,7 @@ rb_find_bss(struct cfg80211_registered_device *dev,
600 629
601static struct cfg80211_internal_bss * 630static struct cfg80211_internal_bss *
602rb_find_hidden_bss(struct cfg80211_registered_device *dev, 631rb_find_hidden_bss(struct cfg80211_registered_device *dev,
603 struct cfg80211_internal_bss *res) 632 struct cfg80211_internal_bss *res)
604{ 633{
605 struct rb_node *n = dev->bss_tree.rb_node; 634 struct rb_node *n = dev->bss_tree.rb_node;
606 struct cfg80211_internal_bss *bss; 635 struct cfg80211_internal_bss *bss;
@@ -623,127 +652,86 @@ rb_find_hidden_bss(struct cfg80211_registered_device *dev,
623 652
624static void 653static void
625copy_hidden_ies(struct cfg80211_internal_bss *res, 654copy_hidden_ies(struct cfg80211_internal_bss *res,
626 struct cfg80211_internal_bss *hidden) 655 struct cfg80211_internal_bss *hidden)
627{ 656{
628 if (unlikely(res->pub.beacon_ies)) 657 const struct cfg80211_bss_ies *ies;
629 return; 658
630 if (WARN_ON(!hidden->pub.beacon_ies)) 659 if (rcu_access_pointer(res->pub.beacon_ies))
631 return; 660 return;
632 661
633 res->pub.beacon_ies = kmalloc(hidden->pub.len_beacon_ies, GFP_ATOMIC); 662 ies = rcu_access_pointer(hidden->pub.beacon_ies);
634 if (unlikely(!res->pub.beacon_ies)) 663 if (WARN_ON(!ies))
635 return; 664 return;
636 665
637 res->beacon_ies_allocated = true; 666 ies = kmemdup(ies, sizeof(*ies) + ies->len, GFP_ATOMIC);
638 res->pub.len_beacon_ies = hidden->pub.len_beacon_ies; 667 if (unlikely(!ies))
639 memcpy(res->pub.beacon_ies, hidden->pub.beacon_ies, 668 return;
640 res->pub.len_beacon_ies); 669 rcu_assign_pointer(res->pub.beacon_ies, ies);
641} 670}
642 671
643static struct cfg80211_internal_bss * 672static struct cfg80211_internal_bss *
644cfg80211_bss_update(struct cfg80211_registered_device *dev, 673cfg80211_bss_update(struct cfg80211_registered_device *dev,
645 struct cfg80211_internal_bss *res) 674 struct cfg80211_internal_bss *tmp)
646{ 675{
647 struct cfg80211_internal_bss *found = NULL; 676 struct cfg80211_internal_bss *found = NULL;
648 677
649 /* 678 if (WARN_ON(!tmp->pub.channel))
650 * The reference to "res" is donated to this function.
651 */
652
653 if (WARN_ON(!res->pub.channel)) {
654 kref_put(&res->ref, bss_release);
655 return NULL; 679 return NULL;
656 }
657 680
658 res->ts = jiffies; 681 tmp->ts = jiffies;
659 682
660 spin_lock_bh(&dev->bss_lock); 683 spin_lock_bh(&dev->bss_lock);
661 684
662 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);
663 691
664 if (found) { 692 if (found) {
665 found->pub.beacon_interval = res->pub.beacon_interval; 693 found->pub.beacon_interval = tmp->pub.beacon_interval;
666 found->pub.tsf = res->pub.tsf; 694 found->pub.tsf = tmp->pub.tsf;
667 found->pub.signal = res->pub.signal; 695 found->pub.signal = tmp->pub.signal;
668 found->pub.capability = res->pub.capability; 696 found->pub.capability = tmp->pub.capability;
669 found->ts = res->ts; 697 found->ts = tmp->ts;
670 698
671 /* Update IEs */ 699 /* Update IEs */
672 if (res->pub.proberesp_ies) { 700 if (rcu_access_pointer(tmp->pub.proberesp_ies)) {
673 size_t used = dev->wiphy.bss_priv_size + sizeof(*res); 701 const struct cfg80211_bss_ies *old;
674 size_t ielen = res->pub.len_proberesp_ies;
675
676 if (found->pub.proberesp_ies &&
677 !found->proberesp_ies_allocated &&
678 ksize(found) >= used + ielen) {
679 memcpy(found->pub.proberesp_ies,
680 res->pub.proberesp_ies, ielen);
681 found->pub.len_proberesp_ies = ielen;
682 } else {
683 u8 *ies = found->pub.proberesp_ies;
684
685 if (found->proberesp_ies_allocated)
686 ies = krealloc(ies, ielen, GFP_ATOMIC);
687 else
688 ies = kmalloc(ielen, GFP_ATOMIC);
689
690 if (ies) {
691 memcpy(ies, res->pub.proberesp_ies,
692 ielen);
693 found->proberesp_ies_allocated = true;
694 found->pub.proberesp_ies = ies;
695 found->pub.len_proberesp_ies = ielen;
696 }
697 }
698 702
703 old = rcu_access_pointer(found->pub.proberesp_ies);
704
705 rcu_assign_pointer(found->pub.proberesp_ies,
706 tmp->pub.proberesp_ies);
699 /* Override possible earlier Beacon frame IEs */ 707 /* Override possible earlier Beacon frame IEs */
700 found->pub.information_elements = 708 rcu_assign_pointer(found->pub.ies,
701 found->pub.proberesp_ies; 709 tmp->pub.proberesp_ies);
702 found->pub.len_information_elements = 710 if (old)
703 found->pub.len_proberesp_ies; 711 kfree_rcu((struct cfg80211_bss_ies *)old,
704 } 712 rcu_head);
705 if (res->pub.beacon_ies) { 713 } else if (rcu_access_pointer(tmp->pub.beacon_ies)) {
706 size_t used = dev->wiphy.bss_priv_size + sizeof(*res); 714 const struct cfg80211_bss_ies *old, *ies;
707 size_t ielen = res->pub.len_beacon_ies; 715
708 bool information_elements_is_beacon_ies = 716 old = rcu_access_pointer(found->pub.beacon_ies);
709 (found->pub.information_elements == 717 ies = rcu_access_pointer(found->pub.ies);
710 found->pub.beacon_ies); 718
711 719 rcu_assign_pointer(found->pub.beacon_ies,
712 if (found->pub.beacon_ies && 720 tmp->pub.beacon_ies);
713 !found->beacon_ies_allocated &&
714 ksize(found) >= used + ielen) {
715 memcpy(found->pub.beacon_ies,
716 res->pub.beacon_ies, ielen);
717 found->pub.len_beacon_ies = ielen;
718 } else {
719 u8 *ies = found->pub.beacon_ies;
720
721 if (found->beacon_ies_allocated)
722 ies = krealloc(ies, ielen, GFP_ATOMIC);
723 else
724 ies = kmalloc(ielen, GFP_ATOMIC);
725
726 if (ies) {
727 memcpy(ies, res->pub.beacon_ies,
728 ielen);
729 found->beacon_ies_allocated = true;
730 found->pub.beacon_ies = ies;
731 found->pub.len_beacon_ies = ielen;
732 }
733 }
734 721
735 /* Override IEs if they were from a beacon before */ 722 /* Override IEs if they were from a beacon before */
736 if (information_elements_is_beacon_ies) { 723 if (old == ies)
737 found->pub.information_elements = 724 rcu_assign_pointer(found->pub.ies,
738 found->pub.beacon_ies; 725 tmp->pub.beacon_ies);
739 found->pub.len_information_elements =
740 found->pub.len_beacon_ies;
741 }
742 }
743 726
744 kref_put(&res->ref, bss_release); 727 if (old)
728 kfree_rcu((struct cfg80211_bss_ies *)old,
729 rcu_head);
730 }
745 } else { 731 } else {
732 struct cfg80211_internal_bss *new;
746 struct cfg80211_internal_bss *hidden; 733 struct cfg80211_internal_bss *hidden;
734 struct cfg80211_bss_ies *ies;
747 735
748 /* First check if the beacon is a probe response from 736 /* First check if the beacon is a probe response from
749 * a hidden bss. If so, copy beacon ies (with nullified 737 * a hidden bss. If so, copy beacon ies (with nullified
@@ -754,14 +742,32 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
754 /* TODO: The code is not trying to update existing probe 742 /* TODO: The code is not trying to update existing probe
755 * response bss entries when beacon ies are 743 * response bss entries when beacon ies are
756 * getting changed. */ 744 * getting changed. */
757 hidden = rb_find_hidden_bss(dev, res); 745 hidden = rb_find_hidden_bss(dev, tmp);
758 if (hidden) 746 if (hidden)
759 copy_hidden_ies(res, hidden); 747 copy_hidden_ies(tmp, hidden);
760 748
761 /* this "consumes" the reference */ 749 /*
762 list_add_tail(&res->list, &dev->bss_list); 750 * create a copy -- the "res" variable that is passed in
763 rb_insert_bss(dev, res); 751 * is allocated on the stack since it's not needed in the
764 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;
765 } 771 }
766 772
767 dev->bss_generation++; 773 dev->bss_generation++;
@@ -810,14 +816,12 @@ cfg80211_inform_bss(struct wiphy *wiphy,
810 u16 beacon_interval, const u8 *ie, size_t ielen, 816 u16 beacon_interval, const u8 *ie, size_t ielen,
811 s32 signal, gfp_t gfp) 817 s32 signal, gfp_t gfp)
812{ 818{
813 struct cfg80211_internal_bss *res; 819 struct cfg80211_bss_ies *ies;
814 size_t privsz; 820 struct cfg80211_internal_bss tmp = {}, *res;
815 821
816 if (WARN_ON(!wiphy)) 822 if (WARN_ON(!wiphy))
817 return NULL; 823 return NULL;
818 824
819 privsz = wiphy->bss_priv_size;
820
821 if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC && 825 if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC &&
822 (signal < 0 || signal > 100))) 826 (signal < 0 || signal > 100)))
823 return NULL; 827 return NULL;
@@ -826,36 +830,33 @@ cfg80211_inform_bss(struct wiphy *wiphy,
826 if (!channel) 830 if (!channel)
827 return NULL; 831 return NULL;
828 832
829 res = kzalloc(sizeof(*res) + privsz + ielen, gfp); 833 memcpy(tmp.pub.bssid, bssid, ETH_ALEN);
830 if (!res) 834 tmp.pub.channel = channel;
831 return NULL; 835 tmp.pub.signal = signal;
832 836 tmp.pub.tsf = tsf;
833 memcpy(res->pub.bssid, bssid, ETH_ALEN); 837 tmp.pub.beacon_interval = beacon_interval;
834 res->pub.channel = channel; 838 tmp.pub.capability = capability;
835 res->pub.signal = signal;
836 res->pub.tsf = tsf;
837 res->pub.beacon_interval = beacon_interval;
838 res->pub.capability = capability;
839 /* 839 /*
840 * 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
841 * 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
842 * 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
843 * frame. Use Beacon frame pointer to avoid indicating that this should 843 * frame. Use Beacon frame pointer to avoid indicating that this should
844 * override the information_elements pointer should we have received an 844 * override the iies pointer should we have received an earlier
845 * earlier indication of Probe Response data. 845 * indication of Probe Response data.
846 * 846 *
847 * 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
848 * is located after the private area. 848 * is located after the private area.
849 */ 849 */
850 res->pub.beacon_ies = (u8 *)res + sizeof(*res) + privsz; 850 ies = kmalloc(sizeof(*ies) + ielen, gfp);
851 memcpy(res->pub.beacon_ies, ie, ielen); 851 if (!ies)
852 res->pub.len_beacon_ies = ielen; 852 return NULL;
853 res->pub.information_elements = res->pub.beacon_ies; 853 ies->len = ielen;
854 res->pub.len_information_elements = res->pub.len_beacon_ies; 854 memcpy(ies->data, ie, ielen);
855 855
856 kref_init(&res->ref); 856 rcu_assign_pointer(tmp.pub.beacon_ies, ies);
857 rcu_assign_pointer(tmp.pub.ies, ies);
857 858
858 res = cfg80211_bss_update(wiphy_to_dev(wiphy), res); 859 res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp);
859 if (!res) 860 if (!res)
860 return NULL; 861 return NULL;
861 862
@@ -874,10 +875,10 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
874 struct ieee80211_mgmt *mgmt, size_t len, 875 struct ieee80211_mgmt *mgmt, size_t len,
875 s32 signal, gfp_t gfp) 876 s32 signal, gfp_t gfp)
876{ 877{
877 struct cfg80211_internal_bss *res; 878 struct cfg80211_internal_bss tmp = {}, *res;
879 struct cfg80211_bss_ies *ies;
878 size_t ielen = len - offsetof(struct ieee80211_mgmt, 880 size_t ielen = len - offsetof(struct ieee80211_mgmt,
879 u.probe_resp.variable); 881 u.probe_resp.variable);
880 size_t privsz;
881 882
882 BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) != 883 BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) !=
883 offsetof(struct ieee80211_mgmt, u.beacon.variable)); 884 offsetof(struct ieee80211_mgmt, u.beacon.variable));
@@ -897,45 +898,31 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
897 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)))
898 return NULL; 899 return NULL;
899 900
900 privsz = wiphy->bss_priv_size;
901
902 channel = cfg80211_get_bss_channel(wiphy, mgmt->u.beacon.variable, 901 channel = cfg80211_get_bss_channel(wiphy, mgmt->u.beacon.variable,
903 ielen, channel); 902 ielen, channel);
904 if (!channel) 903 if (!channel)
905 return NULL; 904 return NULL;
906 905
907 res = kzalloc(sizeof(*res) + privsz + ielen, gfp); 906 ies = kmalloc(sizeof(*ies) + ielen, gfp);
908 if (!res) 907 if (!ies)
909 return NULL; 908 return NULL;
909 ies->len = ielen;
910 memcpy(ies->data, mgmt->u.probe_resp.variable, ielen);
910 911
911 memcpy(res->pub.bssid, mgmt->bssid, ETH_ALEN); 912 if (ieee80211_is_probe_resp(mgmt->frame_control))
912 res->pub.channel = channel; 913 rcu_assign_pointer(tmp.pub.proberesp_ies, ies);
913 res->pub.signal = signal; 914 else
914 res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); 915 rcu_assign_pointer(tmp.pub.beacon_ies, ies);
915 res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); 916 rcu_assign_pointer(tmp.pub.ies, ies);
916 res->pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); 917
917 /* 918 memcpy(tmp.pub.bssid, mgmt->bssid, ETH_ALEN);
918 * The initial buffer for the IEs is allocated with the BSS entry and 919 tmp.pub.channel = channel;
919 * is located after the private area. 920 tmp.pub.signal = signal;
920 */ 921 tmp.pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
921 if (ieee80211_is_probe_resp(mgmt->frame_control)) { 922 tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
922 res->pub.proberesp_ies = (u8 *) res + sizeof(*res) + privsz; 923 tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
923 memcpy(res->pub.proberesp_ies, mgmt->u.probe_resp.variable, 924
924 ielen); 925 res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp);
925 res->pub.len_proberesp_ies = ielen;
926 res->pub.information_elements = res->pub.proberesp_ies;
927 res->pub.len_information_elements = res->pub.len_proberesp_ies;
928 } else {
929 res->pub.beacon_ies = (u8 *) res + sizeof(*res) + privsz;
930 memcpy(res->pub.beacon_ies, mgmt->u.beacon.variable, ielen);
931 res->pub.len_beacon_ies = ielen;
932 res->pub.information_elements = res->pub.beacon_ies;
933 res->pub.len_information_elements = res->pub.len_beacon_ies;
934 }
935
936 kref_init(&res->ref);
937
938 res = cfg80211_bss_update(wiphy_to_dev(wiphy), res);
939 if (!res) 926 if (!res)
940 return NULL; 927 return NULL;
941 928
@@ -1127,22 +1114,21 @@ int cfg80211_wext_siwscan(struct net_device *dev,
1127EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan); 1114EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan);
1128 1115
1129static void ieee80211_scan_add_ies(struct iw_request_info *info, 1116static void ieee80211_scan_add_ies(struct iw_request_info *info,
1130 struct cfg80211_bss *bss, 1117 const struct cfg80211_bss_ies *ies,
1131 char **current_ev, char *end_buf) 1118 char **current_ev, char *end_buf)
1132{ 1119{
1133 u8 *pos, *end, *next; 1120 const u8 *pos, *end, *next;
1134 struct iw_event iwe; 1121 struct iw_event iwe;
1135 1122
1136 if (!bss->information_elements || 1123 if (!ies)
1137 !bss->len_information_elements)
1138 return; 1124 return;
1139 1125
1140 /* 1126 /*
1141 * If needed, fragment the IEs buffer (at IE boundaries) into short 1127 * If needed, fragment the IEs buffer (at IE boundaries) into short
1142 * enough fragments to fit into IW_GENERIC_IE_MAX octet messages. 1128 * enough fragments to fit into IW_GENERIC_IE_MAX octet messages.
1143 */ 1129 */
1144 pos = bss->information_elements; 1130 pos = ies->data;
1145 end = pos + bss->len_information_elements; 1131 end = pos + ies->len;
1146 1132
1147 while (end - pos > IW_GENERIC_IE_MAX) { 1133 while (end - pos > IW_GENERIC_IE_MAX) {
1148 next = pos + 2 + pos[1]; 1134 next = pos + 2 + pos[1];
@@ -1153,7 +1139,8 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info,
1153 iwe.cmd = IWEVGENIE; 1139 iwe.cmd = IWEVGENIE;
1154 iwe.u.data.length = next - pos; 1140 iwe.u.data.length = next - pos;
1155 *current_ev = iwe_stream_add_point(info, *current_ev, 1141 *current_ev = iwe_stream_add_point(info, *current_ev,
1156 end_buf, &iwe, pos); 1142 end_buf, &iwe,
1143 (void *)pos);
1157 1144
1158 pos = next; 1145 pos = next;
1159 } 1146 }
@@ -1163,7 +1150,8 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info,
1163 iwe.cmd = IWEVGENIE; 1150 iwe.cmd = IWEVGENIE;
1164 iwe.u.data.length = end - pos; 1151 iwe.u.data.length = end - pos;
1165 *current_ev = iwe_stream_add_point(info, *current_ev, 1152 *current_ev = iwe_stream_add_point(info, *current_ev,
1166 end_buf, &iwe, pos); 1153 end_buf, &iwe,
1154 (void *)pos);
1167 } 1155 }
1168} 1156}
1169 1157
@@ -1182,10 +1170,11 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1182 struct cfg80211_internal_bss *bss, char *current_ev, 1170 struct cfg80211_internal_bss *bss, char *current_ev,
1183 char *end_buf) 1171 char *end_buf)
1184{ 1172{
1173 const struct cfg80211_bss_ies *ies;
1185 struct iw_event iwe; 1174 struct iw_event iwe;
1175 const u8 *ie;
1186 u8 *buf, *cfg, *p; 1176 u8 *buf, *cfg, *p;
1187 u8 *ie = bss->pub.information_elements; 1177 int rem, i, sig;
1188 int rem = bss->pub.len_information_elements, i, sig;
1189 bool ismesh = false; 1178 bool ismesh = false;
1190 1179
1191 memset(&iwe, 0, sizeof(iwe)); 1180 memset(&iwe, 0, sizeof(iwe));
@@ -1250,7 +1239,17 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1250 current_ev = iwe_stream_add_point(info, current_ev, end_buf, 1239 current_ev = iwe_stream_add_point(info, current_ev, end_buf,
1251 &iwe, ""); 1240 &iwe, "");
1252 1241
1253 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) {
1254 /* invalid data */ 1253 /* invalid data */
1255 if (ie[1] > rem - 2) 1254 if (ie[1] > rem - 2)
1256 break; 1255 break;
@@ -1262,7 +1261,7 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1262 iwe.u.data.length = ie[1]; 1261 iwe.u.data.length = ie[1];
1263 iwe.u.data.flags = 1; 1262 iwe.u.data.flags = 1;
1264 current_ev = iwe_stream_add_point(info, current_ev, end_buf, 1263 current_ev = iwe_stream_add_point(info, current_ev, end_buf,
1265 &iwe, ie + 2); 1264 &iwe, (u8 *)ie + 2);
1266 break; 1265 break;
1267 case WLAN_EID_MESH_ID: 1266 case WLAN_EID_MESH_ID:
1268 memset(&iwe, 0, sizeof(iwe)); 1267 memset(&iwe, 0, sizeof(iwe));
@@ -1270,7 +1269,7 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1270 iwe.u.data.length = ie[1]; 1269 iwe.u.data.length = ie[1];
1271 iwe.u.data.flags = 1; 1270 iwe.u.data.flags = 1;
1272 current_ev = iwe_stream_add_point(info, current_ev, end_buf, 1271 current_ev = iwe_stream_add_point(info, current_ev, end_buf,
1273 &iwe, ie + 2); 1272 &iwe, (u8 *)ie + 2);
1274 break; 1273 break;
1275 case WLAN_EID_MESH_CONFIG: 1274 case WLAN_EID_MESH_CONFIG:
1276 ismesh = true; 1275 ismesh = true;
@@ -1279,7 +1278,7 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1279 buf = kmalloc(50, GFP_ATOMIC); 1278 buf = kmalloc(50, GFP_ATOMIC);
1280 if (!buf) 1279 if (!buf)
1281 break; 1280 break;
1282 cfg = ie + 2; 1281 cfg = (u8 *)ie + 2;
1283 memset(&iwe, 0, sizeof(iwe)); 1282 memset(&iwe, 0, sizeof(iwe));
1284 iwe.cmd = IWEVCUSTOM; 1283 iwe.cmd = IWEVCUSTOM;
1285 sprintf(buf, "Mesh Network Path Selection Protocol ID: " 1284 sprintf(buf, "Mesh Network Path Selection Protocol ID: "
@@ -1377,7 +1376,8 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1377 kfree(buf); 1376 kfree(buf);
1378 } 1377 }
1379 1378
1380 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();
1381 1381
1382 return current_ev; 1382 return current_ev;
1383} 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;