diff options
-rw-r--r-- | include/net/cfg80211.h | 46 | ||||
-rw-r--r-- | include/net/mac80211.h | 2 | ||||
-rw-r--r-- | include/uapi/linux/nl80211.h | 4 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 14 | ||||
-rw-r--r-- | net/mac80211/ht.c | 4 | ||||
-rw-r--r-- | net/mac80211/ibss.c | 65 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 6 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 57 | ||||
-rw-r--r-- | net/mac80211/mesh.h | 2 | ||||
-rw-r--r-- | net/mac80211/mesh_plink.c | 8 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 35 | ||||
-rw-r--r-- | net/mac80211/rate.c | 8 | ||||
-rw-r--r-- | net/mac80211/scan.c | 9 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 2 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 1 | ||||
-rw-r--r-- | net/mac80211/vht.c | 2 | ||||
-rw-r--r-- | net/wireless/chan.c | 57 | ||||
-rw-r--r-- | net/wireless/core.c | 6 | ||||
-rw-r--r-- | net/wireless/mlme.c | 12 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 277 | ||||
-rw-r--r-- | net/wireless/scan.c | 4 | ||||
-rw-r--r-- | net/wireless/sme.c | 23 | ||||
-rw-r--r-- | net/wireless/sysfs.c | 2 |
23 files changed, 415 insertions, 231 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 6a43c34ce96f..7b0730aeb892 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -188,6 +188,8 @@ struct ieee80211_channel { | |||
188 | * when used with 802.11g (on the 2.4 GHz band); filled by the | 188 | * when used with 802.11g (on the 2.4 GHz band); filled by the |
189 | * core code when registering the wiphy. | 189 | * core code when registering the wiphy. |
190 | * @IEEE80211_RATE_ERP_G: This is an ERP rate in 802.11g mode. | 190 | * @IEEE80211_RATE_ERP_G: This is an ERP rate in 802.11g mode. |
191 | * @IEEE80211_RATE_SUPPORTS_5MHZ: Rate can be used in 5 MHz mode | ||
192 | * @IEEE80211_RATE_SUPPORTS_10MHZ: Rate can be used in 10 MHz mode | ||
191 | */ | 193 | */ |
192 | enum ieee80211_rate_flags { | 194 | enum ieee80211_rate_flags { |
193 | IEEE80211_RATE_SHORT_PREAMBLE = 1<<0, | 195 | IEEE80211_RATE_SHORT_PREAMBLE = 1<<0, |
@@ -195,6 +197,8 @@ enum ieee80211_rate_flags { | |||
195 | IEEE80211_RATE_MANDATORY_B = 1<<2, | 197 | IEEE80211_RATE_MANDATORY_B = 1<<2, |
196 | IEEE80211_RATE_MANDATORY_G = 1<<3, | 198 | IEEE80211_RATE_MANDATORY_G = 1<<3, |
197 | IEEE80211_RATE_ERP_G = 1<<4, | 199 | IEEE80211_RATE_ERP_G = 1<<4, |
200 | IEEE80211_RATE_SUPPORTS_5MHZ = 1<<5, | ||
201 | IEEE80211_RATE_SUPPORTS_10MHZ = 1<<6, | ||
198 | }; | 202 | }; |
199 | 203 | ||
200 | /** | 204 | /** |
@@ -433,6 +437,30 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy, | |||
433 | u32 prohibited_flags); | 437 | u32 prohibited_flags); |
434 | 438 | ||
435 | /** | 439 | /** |
440 | * ieee80211_chandef_rate_flags - returns rate flags for a channel | ||
441 | * | ||
442 | * In some channel types, not all rates may be used - for example CCK | ||
443 | * rates may not be used in 5/10 MHz channels. | ||
444 | * | ||
445 | * @chandef: channel definition for the channel | ||
446 | * | ||
447 | * Returns: rate flags which apply for this channel | ||
448 | */ | ||
449 | static inline enum ieee80211_rate_flags | ||
450 | ieee80211_chandef_rate_flags(struct cfg80211_chan_def *chandef) | ||
451 | { | ||
452 | switch (chandef->width) { | ||
453 | case NL80211_CHAN_WIDTH_5: | ||
454 | return IEEE80211_RATE_SUPPORTS_5MHZ; | ||
455 | case NL80211_CHAN_WIDTH_10: | ||
456 | return IEEE80211_RATE_SUPPORTS_10MHZ; | ||
457 | default: | ||
458 | break; | ||
459 | } | ||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | /** | ||
436 | * enum survey_info_flags - survey information flags | 464 | * enum survey_info_flags - survey information flags |
437 | * | 465 | * |
438 | * @SURVEY_INFO_NOISE_DBM: noise (in dBm) was filled in | 466 | * @SURVEY_INFO_NOISE_DBM: noise (in dBm) was filled in |
@@ -1431,7 +1459,8 @@ const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie); | |||
1431 | * This structure provides information needed to complete IEEE 802.11 | 1459 | * This structure provides information needed to complete IEEE 802.11 |
1432 | * authentication. | 1460 | * authentication. |
1433 | * | 1461 | * |
1434 | * @bss: The BSS to authenticate with. | 1462 | * @bss: The BSS to authenticate with, the callee must obtain a reference |
1463 | * to it if it needs to keep it. | ||
1435 | * @auth_type: Authentication type (algorithm) | 1464 | * @auth_type: Authentication type (algorithm) |
1436 | * @ie: Extra IEs to add to Authentication frame or %NULL | 1465 | * @ie: Extra IEs to add to Authentication frame or %NULL |
1437 | * @ie_len: Length of ie buffer in octets | 1466 | * @ie_len: Length of ie buffer in octets |
@@ -1469,11 +1498,10 @@ enum cfg80211_assoc_req_flags { | |||
1469 | * | 1498 | * |
1470 | * This structure provides information needed to complete IEEE 802.11 | 1499 | * This structure provides information needed to complete IEEE 802.11 |
1471 | * (re)association. | 1500 | * (re)association. |
1472 | * @bss: The BSS to associate with. If the call is successful the driver | 1501 | * @bss: The BSS to associate with. If the call is successful the driver is |
1473 | * is given a reference that it must release, normally via a call to | 1502 | * given a reference that it must give back to cfg80211_send_rx_assoc() |
1474 | * cfg80211_send_rx_assoc(), or, if association timed out, with a | 1503 | * or to cfg80211_assoc_timeout(). To ensure proper refcounting, new |
1475 | * call to cfg80211_put_bss() (in addition to calling | 1504 | * association requests while already associating must be rejected. |
1476 | * cfg80211_send_assoc_timeout()) | ||
1477 | * @ie: Extra IEs to add to (Re)Association Request frame or %NULL | 1505 | * @ie: Extra IEs to add to (Re)Association Request frame or %NULL |
1478 | * @ie_len: Length of ie buffer in octets | 1506 | * @ie_len: Length of ie buffer in octets |
1479 | * @use_mfp: Use management frame protection (IEEE 802.11w) in this association | 1507 | * @use_mfp: Use management frame protection (IEEE 802.11w) in this association |
@@ -2342,6 +2370,7 @@ struct cfg80211_ops { | |||
2342 | * responds to probe-requests in hardware. | 2370 | * responds to probe-requests in hardware. |
2343 | * @WIPHY_FLAG_OFFCHAN_TX: Device supports direct off-channel TX. | 2371 | * @WIPHY_FLAG_OFFCHAN_TX: Device supports direct off-channel TX. |
2344 | * @WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL: Device supports remain-on-channel call. | 2372 | * @WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL: Device supports remain-on-channel call. |
2373 | * @WIPHY_FLAG_SUPPORTS_5_10_MHZ: Device supports 5 MHz and 10 MHz channels. | ||
2345 | */ | 2374 | */ |
2346 | enum wiphy_flags { | 2375 | enum wiphy_flags { |
2347 | WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0), | 2376 | WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0), |
@@ -2365,6 +2394,7 @@ enum wiphy_flags { | |||
2365 | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD = BIT(19), | 2394 | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD = BIT(19), |
2366 | WIPHY_FLAG_OFFCHAN_TX = BIT(20), | 2395 | WIPHY_FLAG_OFFCHAN_TX = BIT(20), |
2367 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL = BIT(21), | 2396 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL = BIT(21), |
2397 | WIPHY_FLAG_SUPPORTS_5_10_MHZ = BIT(22), | ||
2368 | }; | 2398 | }; |
2369 | 2399 | ||
2370 | /** | 2400 | /** |
@@ -3492,11 +3522,11 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, | |||
3492 | /** | 3522 | /** |
3493 | * cfg80211_assoc_timeout - notification of timed out association | 3523 | * cfg80211_assoc_timeout - notification of timed out association |
3494 | * @dev: network device | 3524 | * @dev: network device |
3495 | * @addr: The MAC address of the device with which the association timed out | 3525 | * @bss: The BSS entry with which association timed out. |
3496 | * | 3526 | * |
3497 | * This function may sleep. The caller must hold the corresponding wdev's mutex. | 3527 | * This function may sleep. The caller must hold the corresponding wdev's mutex. |
3498 | */ | 3528 | */ |
3499 | void cfg80211_assoc_timeout(struct net_device *dev, const u8 *addr); | 3529 | void cfg80211_assoc_timeout(struct net_device *dev, struct cfg80211_bss *bss); |
3500 | 3530 | ||
3501 | /** | 3531 | /** |
3502 | * cfg80211_tx_mlme_mgmt - notification of transmitted deauth/disassoc frame | 3532 | * cfg80211_tx_mlme_mgmt - notification of transmitted deauth/disassoc frame |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index a405a7a9775c..5b7a3dadadde 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -305,6 +305,7 @@ enum ieee80211_rssi_event { | |||
305 | * @basic_rates: bitmap of basic rates, each bit stands for an | 305 | * @basic_rates: bitmap of basic rates, each bit stands for an |
306 | * index into the rate table configured by the driver in | 306 | * index into the rate table configured by the driver in |
307 | * the current band. | 307 | * the current band. |
308 | * @beacon_rate: associated AP's beacon TX rate | ||
308 | * @mcast_rate: per-band multicast rate index + 1 (0: disabled) | 309 | * @mcast_rate: per-band multicast rate index + 1 (0: disabled) |
309 | * @bssid: The BSSID for this BSS | 310 | * @bssid: The BSSID for this BSS |
310 | * @enable_beacon: whether beaconing should be enabled or not | 311 | * @enable_beacon: whether beaconing should be enabled or not |
@@ -352,6 +353,7 @@ struct ieee80211_bss_conf { | |||
352 | u32 sync_device_ts; | 353 | u32 sync_device_ts; |
353 | u8 sync_dtim_count; | 354 | u8 sync_dtim_count; |
354 | u32 basic_rates; | 355 | u32 basic_rates; |
356 | struct ieee80211_rate *beacon_rate; | ||
355 | int mcast_rate[IEEE80211_NUM_BANDS]; | 357 | int mcast_rate[IEEE80211_NUM_BANDS]; |
356 | u16 ht_operation_mode; | 358 | u16 ht_operation_mode; |
357 | s32 cqm_rssi_thold; | 359 | s32 cqm_rssi_thold; |
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index ca6facf4df0c..861e5eba3953 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h | |||
@@ -2758,6 +2758,8 @@ enum nl80211_channel_type { | |||
2758 | * and %NL80211_ATTR_CENTER_FREQ2 attributes must be provided as well | 2758 | * and %NL80211_ATTR_CENTER_FREQ2 attributes must be provided as well |
2759 | * @NL80211_CHAN_WIDTH_160: 160 MHz channel, the %NL80211_ATTR_CENTER_FREQ1 | 2759 | * @NL80211_CHAN_WIDTH_160: 160 MHz channel, the %NL80211_ATTR_CENTER_FREQ1 |
2760 | * attribute must be provided as well | 2760 | * attribute must be provided as well |
2761 | * @NL80211_CHAN_WIDTH_5: 5 MHz OFDM channel | ||
2762 | * @NL80211_CHAN_WIDTH_10: 10 MHz OFDM channel | ||
2761 | */ | 2763 | */ |
2762 | enum nl80211_chan_width { | 2764 | enum nl80211_chan_width { |
2763 | NL80211_CHAN_WIDTH_20_NOHT, | 2765 | NL80211_CHAN_WIDTH_20_NOHT, |
@@ -2766,6 +2768,8 @@ enum nl80211_chan_width { | |||
2766 | NL80211_CHAN_WIDTH_80, | 2768 | NL80211_CHAN_WIDTH_80, |
2767 | NL80211_CHAN_WIDTH_80P80, | 2769 | NL80211_CHAN_WIDTH_80P80, |
2768 | NL80211_CHAN_WIDTH_160, | 2770 | NL80211_CHAN_WIDTH_160, |
2771 | NL80211_CHAN_WIDTH_5, | ||
2772 | NL80211_CHAN_WIDTH_10, | ||
2769 | }; | 2773 | }; |
2770 | 2774 | ||
2771 | /** | 2775 | /** |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 082f270b5912..8184d121ff09 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -2827,7 +2827,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
2827 | !rcu_access_pointer(sdata->bss->beacon)) | 2827 | !rcu_access_pointer(sdata->bss->beacon)) |
2828 | need_offchan = true; | 2828 | need_offchan = true; |
2829 | if (!ieee80211_is_action(mgmt->frame_control) || | 2829 | if (!ieee80211_is_action(mgmt->frame_control) || |
2830 | mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) | 2830 | mgmt->u.action.category == WLAN_CATEGORY_PUBLIC || |
2831 | mgmt->u.action.category == WLAN_CATEGORY_SELF_PROTECTED) | ||
2831 | break; | 2832 | break; |
2832 | rcu_read_lock(); | 2833 | rcu_read_lock(); |
2833 | sta = sta_info_get(sdata, mgmt->da); | 2834 | sta = sta_info_get(sdata, mgmt->da); |
@@ -2930,19 +2931,8 @@ static void ieee80211_mgmt_frame_register(struct wiphy *wiphy, | |||
2930 | u16 frame_type, bool reg) | 2931 | u16 frame_type, bool reg) |
2931 | { | 2932 | { |
2932 | struct ieee80211_local *local = wiphy_priv(wiphy); | 2933 | struct ieee80211_local *local = wiphy_priv(wiphy); |
2933 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | ||
2934 | 2934 | ||
2935 | switch (frame_type) { | 2935 | switch (frame_type) { |
2936 | case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH: | ||
2937 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
2938 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
2939 | |||
2940 | if (reg) | ||
2941 | ifibss->auth_frame_registrations++; | ||
2942 | else | ||
2943 | ifibss->auth_frame_registrations--; | ||
2944 | } | ||
2945 | break; | ||
2946 | case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ: | 2936 | case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ: |
2947 | if (reg) | 2937 | if (reg) |
2948 | local->probe_req_reg++; | 2938 | local->probe_req_reg++; |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 75dff338f581..f83534f6a2ee 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -281,13 +281,14 @@ void ieee80211_ba_session_work(struct work_struct *work) | |||
281 | sta, tid, WLAN_BACK_RECIPIENT, | 281 | sta, tid, WLAN_BACK_RECIPIENT, |
282 | WLAN_REASON_UNSPECIFIED, true); | 282 | WLAN_REASON_UNSPECIFIED, true); |
283 | 283 | ||
284 | spin_lock_bh(&sta->lock); | ||
285 | |||
284 | tid_tx = sta->ampdu_mlme.tid_start_tx[tid]; | 286 | tid_tx = sta->ampdu_mlme.tid_start_tx[tid]; |
285 | if (tid_tx) { | 287 | if (tid_tx) { |
286 | /* | 288 | /* |
287 | * Assign it over to the normal tid_tx array | 289 | * Assign it over to the normal tid_tx array |
288 | * where it "goes live". | 290 | * where it "goes live". |
289 | */ | 291 | */ |
290 | spin_lock_bh(&sta->lock); | ||
291 | 292 | ||
292 | sta->ampdu_mlme.tid_start_tx[tid] = NULL; | 293 | sta->ampdu_mlme.tid_start_tx[tid] = NULL; |
293 | /* could there be a race? */ | 294 | /* could there be a race? */ |
@@ -300,6 +301,7 @@ void ieee80211_ba_session_work(struct work_struct *work) | |||
300 | ieee80211_tx_ba_session_handle_start(sta, tid); | 301 | ieee80211_tx_ba_session_handle_start(sta, tid); |
301 | continue; | 302 | continue; |
302 | } | 303 | } |
304 | spin_unlock_bh(&sta->lock); | ||
303 | 305 | ||
304 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); | 306 | tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
305 | if (tid_tx && test_and_clear_bit(HT_AGG_STATE_WANT_STOP, | 307 | if (tid_tx && test_and_clear_bit(HT_AGG_STATE_WANT_STOP, |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index caa4b4f7f6e4..ea7b9c2c7e66 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -81,7 +81,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
81 | 81 | ||
82 | sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; | 82 | sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; |
83 | 83 | ||
84 | cfg80211_chandef_create(&chandef, chan, ifibss->channel_type); | 84 | chandef = ifibss->chandef; |
85 | if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) { | 85 | if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) { |
86 | chandef.width = NL80211_CHAN_WIDTH_20; | 86 | chandef.width = NL80211_CHAN_WIDTH_20; |
87 | chandef.center_freq1 = chan->center_freq; | 87 | chandef.center_freq1 = chan->center_freq; |
@@ -176,6 +176,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
176 | 176 | ||
177 | /* add HT capability and information IEs */ | 177 | /* add HT capability and information IEs */ |
178 | if (chandef.width != NL80211_CHAN_WIDTH_20_NOHT && | 178 | if (chandef.width != NL80211_CHAN_WIDTH_20_NOHT && |
179 | chandef.width != NL80211_CHAN_WIDTH_5 && | ||
180 | chandef.width != NL80211_CHAN_WIDTH_10 && | ||
179 | sband->ht_cap.ht_supported) { | 181 | sband->ht_cap.ht_supported) { |
180 | pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, | 182 | pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, |
181 | sband->ht_cap.cap); | 183 | sband->ht_cap.cap); |
@@ -298,8 +300,7 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
298 | tsf, false); | 300 | tsf, false); |
299 | } | 301 | } |
300 | 302 | ||
301 | static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta, | 303 | static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta) |
302 | bool auth) | ||
303 | __acquires(RCU) | 304 | __acquires(RCU) |
304 | { | 305 | { |
305 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 306 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
@@ -321,20 +322,12 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta, | |||
321 | /* If it fails, maybe we raced another insertion? */ | 322 | /* If it fails, maybe we raced another insertion? */ |
322 | if (sta_info_insert_rcu(sta)) | 323 | if (sta_info_insert_rcu(sta)) |
323 | return sta_info_get(sdata, addr); | 324 | return sta_info_get(sdata, addr); |
324 | if (auth && !sdata->u.ibss.auth_frame_registrations) { | ||
325 | ibss_dbg(sdata, | ||
326 | "TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n", | ||
327 | sdata->vif.addr, addr, sdata->u.ibss.bssid); | ||
328 | ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, 0, NULL, 0, | ||
329 | addr, sdata->u.ibss.bssid, NULL, 0, 0, 0); | ||
330 | } | ||
331 | return sta; | 325 | return sta; |
332 | } | 326 | } |
333 | 327 | ||
334 | static struct sta_info * | 328 | static struct sta_info * |
335 | ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | 329 | ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid, |
336 | const u8 *bssid, const u8 *addr, | 330 | const u8 *addr, u32 supp_rates) |
337 | u32 supp_rates, bool auth) | ||
338 | __acquires(RCU) | 331 | __acquires(RCU) |
339 | { | 332 | { |
340 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 333 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
@@ -385,7 +378,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | |||
385 | sta->sta.supp_rates[band] = supp_rates | | 378 | sta->sta.supp_rates[band] = supp_rates | |
386 | ieee80211_mandatory_rates(sband); | 379 | ieee80211_mandatory_rates(sband); |
387 | 380 | ||
388 | return ieee80211_ibss_finish_sta(sta, auth); | 381 | return ieee80211_ibss_finish_sta(sta); |
389 | } | 382 | } |
390 | 383 | ||
391 | static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata, | 384 | static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata, |
@@ -407,8 +400,6 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, | |||
407 | size_t len) | 400 | size_t len) |
408 | { | 401 | { |
409 | u16 auth_alg, auth_transaction; | 402 | u16 auth_alg, auth_transaction; |
410 | struct sta_info *sta; | ||
411 | u8 deauth_frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; | ||
412 | 403 | ||
413 | sdata_assert_lock(sdata); | 404 | sdata_assert_lock(sdata); |
414 | 405 | ||
@@ -425,22 +416,6 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, | |||
425 | if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) | 416 | if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) |
426 | return; | 417 | return; |
427 | 418 | ||
428 | sta_info_destroy_addr(sdata, mgmt->sa); | ||
429 | sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, 0, false); | ||
430 | rcu_read_unlock(); | ||
431 | |||
432 | /* | ||
433 | * if we have any problem in allocating the new station, we reply with a | ||
434 | * DEAUTH frame to tell the other end that we had a problem | ||
435 | */ | ||
436 | if (!sta) { | ||
437 | ieee80211_send_deauth_disassoc(sdata, sdata->u.ibss.bssid, | ||
438 | IEEE80211_STYPE_DEAUTH, | ||
439 | WLAN_REASON_UNSPECIFIED, true, | ||
440 | deauth_frame_buf); | ||
441 | return; | ||
442 | } | ||
443 | |||
444 | /* | 419 | /* |
445 | * IEEE 802.11 standard does not require authentication in IBSS | 420 | * IEEE 802.11 standard does not require authentication in IBSS |
446 | * networks and most implementations do not seem to use it. | 421 | * networks and most implementations do not seem to use it. |
@@ -506,7 +481,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
506 | } else { | 481 | } else { |
507 | rcu_read_unlock(); | 482 | rcu_read_unlock(); |
508 | sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid, | 483 | sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid, |
509 | mgmt->sa, supp_rates, true); | 484 | mgmt->sa, supp_rates); |
510 | } | 485 | } |
511 | } | 486 | } |
512 | 487 | ||
@@ -514,7 +489,9 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
514 | set_sta_flag(sta, WLAN_STA_WME); | 489 | set_sta_flag(sta, WLAN_STA_WME); |
515 | 490 | ||
516 | if (sta && elems->ht_operation && elems->ht_cap_elem && | 491 | if (sta && elems->ht_operation && elems->ht_cap_elem && |
517 | sdata->u.ibss.channel_type != NL80211_CHAN_NO_HT) { | 492 | sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT && |
493 | sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_5 && | ||
494 | sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_10) { | ||
518 | /* we both use HT */ | 495 | /* we both use HT */ |
519 | struct ieee80211_ht_cap htcap_ie; | 496 | struct ieee80211_ht_cap htcap_ie; |
520 | struct cfg80211_chan_def chandef; | 497 | struct cfg80211_chan_def chandef; |
@@ -529,8 +506,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
529 | * fall back to HT20 if we don't use or use | 506 | * fall back to HT20 if we don't use or use |
530 | * the other extension channel | 507 | * the other extension channel |
531 | */ | 508 | */ |
532 | if (cfg80211_get_chandef_type(&chandef) != | 509 | if (chandef.center_freq1 != |
533 | sdata->u.ibss.channel_type) | 510 | sdata->u.ibss.chandef.center_freq1) |
534 | htcap_ie.cap_info &= | 511 | htcap_ie.cap_info &= |
535 | cpu_to_le16(~IEEE80211_HT_CAP_SUP_WIDTH_20_40); | 512 | cpu_to_le16(~IEEE80211_HT_CAP_SUP_WIDTH_20_40); |
536 | 513 | ||
@@ -569,7 +546,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
569 | 546 | ||
570 | /* different channel */ | 547 | /* different channel */ |
571 | if (sdata->u.ibss.fixed_channel && | 548 | if (sdata->u.ibss.fixed_channel && |
572 | sdata->u.ibss.channel != cbss->channel) | 549 | sdata->u.ibss.chandef.chan != cbss->channel) |
573 | goto put_bss; | 550 | goto put_bss; |
574 | 551 | ||
575 | /* different SSID */ | 552 | /* different SSID */ |
@@ -610,7 +587,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
610 | ieee80211_sta_join_ibss(sdata, bss); | 587 | ieee80211_sta_join_ibss(sdata, bss); |
611 | supp_rates = ieee80211_sta_get_rates(local, elems, band, NULL); | 588 | supp_rates = ieee80211_sta_get_rates(local, elems, band, NULL); |
612 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, | 589 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, |
613 | supp_rates, true); | 590 | supp_rates); |
614 | rcu_read_unlock(); | 591 | rcu_read_unlock(); |
615 | } | 592 | } |
616 | 593 | ||
@@ -759,7 +736,7 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) | |||
759 | sdata->drop_unencrypted = 0; | 736 | sdata->drop_unencrypted = 0; |
760 | 737 | ||
761 | __ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int, | 738 | __ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int, |
762 | ifibss->channel, ifibss->basic_rates, | 739 | ifibss->chandef.chan, ifibss->basic_rates, |
763 | capability, 0, true); | 740 | capability, 0, true); |
764 | } | 741 | } |
765 | 742 | ||
@@ -791,7 +768,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
791 | if (ifibss->fixed_bssid) | 768 | if (ifibss->fixed_bssid) |
792 | bssid = ifibss->bssid; | 769 | bssid = ifibss->bssid; |
793 | if (ifibss->fixed_channel) | 770 | if (ifibss->fixed_channel) |
794 | chan = ifibss->channel; | 771 | chan = ifibss->chandef.chan; |
795 | if (!is_zero_ether_addr(ifibss->bssid)) | 772 | if (!is_zero_ether_addr(ifibss->bssid)) |
796 | bssid = ifibss->bssid; | 773 | bssid = ifibss->bssid; |
797 | cbss = cfg80211_get_bss(local->hw.wiphy, chan, bssid, | 774 | cbss = cfg80211_get_bss(local->hw.wiphy, chan, bssid, |
@@ -982,7 +959,7 @@ void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata) | |||
982 | list_del(&sta->list); | 959 | list_del(&sta->list); |
983 | spin_unlock_bh(&ifibss->incomplete_lock); | 960 | spin_unlock_bh(&ifibss->incomplete_lock); |
984 | 961 | ||
985 | ieee80211_ibss_finish_sta(sta, true); | 962 | ieee80211_ibss_finish_sta(sta); |
986 | rcu_read_unlock(); | 963 | rcu_read_unlock(); |
987 | spin_lock_bh(&ifibss->incomplete_lock); | 964 | spin_lock_bh(&ifibss->incomplete_lock); |
988 | } | 965 | } |
@@ -1058,9 +1035,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
1058 | 1035 | ||
1059 | sdata->vif.bss_conf.beacon_int = params->beacon_interval; | 1036 | sdata->vif.bss_conf.beacon_int = params->beacon_interval; |
1060 | 1037 | ||
1061 | sdata->u.ibss.channel = params->chandef.chan; | 1038 | sdata->u.ibss.chandef = params->chandef; |
1062 | sdata->u.ibss.channel_type = | ||
1063 | cfg80211_get_chandef_type(¶ms->chandef); | ||
1064 | sdata->u.ibss.fixed_channel = params->channel_fixed; | 1039 | sdata->u.ibss.fixed_channel = params->channel_fixed; |
1065 | 1040 | ||
1066 | if (params->ie) { | 1041 | if (params->ie) { |
@@ -1119,7 +1094,7 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | |||
1119 | if (ifibss->privacy) | 1094 | if (ifibss->privacy) |
1120 | capability |= WLAN_CAPABILITY_PRIVACY; | 1095 | capability |= WLAN_CAPABILITY_PRIVACY; |
1121 | 1096 | ||
1122 | cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->channel, | 1097 | cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan, |
1123 | ifibss->bssid, ifibss->ssid, | 1098 | ifibss->bssid, ifibss->ssid, |
1124 | ifibss->ssid_len, WLAN_CAPABILITY_IBSS | | 1099 | ifibss->ssid_len, WLAN_CAPABILITY_IBSS | |
1125 | WLAN_CAPABILITY_PRIVACY, | 1100 | WLAN_CAPABILITY_PRIVACY, |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index f97cd9d9105f..8412a303993a 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -94,6 +94,7 @@ struct ieee80211_bss { | |||
94 | #define IEEE80211_MAX_SUPP_RATES 32 | 94 | #define IEEE80211_MAX_SUPP_RATES 32 |
95 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; | 95 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; |
96 | size_t supp_rates_len; | 96 | size_t supp_rates_len; |
97 | struct ieee80211_rate *beacon_rate; | ||
97 | 98 | ||
98 | /* | 99 | /* |
99 | * During association, we save an ERP value from a probe response so | 100 | * During association, we save an ERP value from a probe response so |
@@ -497,14 +498,12 @@ struct ieee80211_if_ibss { | |||
497 | bool privacy; | 498 | bool privacy; |
498 | 499 | ||
499 | bool control_port; | 500 | bool control_port; |
500 | unsigned int auth_frame_registrations; | ||
501 | 501 | ||
502 | u8 bssid[ETH_ALEN] __aligned(2); | 502 | u8 bssid[ETH_ALEN] __aligned(2); |
503 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | 503 | u8 ssid[IEEE80211_MAX_SSID_LEN]; |
504 | u8 ssid_len, ie_len; | 504 | u8 ssid_len, ie_len; |
505 | u8 *ie; | 505 | u8 *ie; |
506 | struct ieee80211_channel *channel; | 506 | struct cfg80211_chan_def chandef; |
507 | enum nl80211_channel_type channel_type; | ||
508 | 507 | ||
509 | unsigned long ibss_join_req; | 508 | unsigned long ibss_join_req; |
510 | /* probe response/beacon for IBSS */ | 509 | /* probe response/beacon for IBSS */ |
@@ -543,6 +542,7 @@ struct ieee80211_if_mesh { | |||
543 | struct timer_list mesh_path_root_timer; | 542 | struct timer_list mesh_path_root_timer; |
544 | 543 | ||
545 | unsigned long wrkq_flags; | 544 | unsigned long wrkq_flags; |
545 | unsigned long mbss_changed; | ||
546 | 546 | ||
547 | u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; | 547 | u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; |
548 | size_t mesh_id_len; | 548 | size_t mesh_id_len; |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 6c33af482df4..447f41bbe744 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -161,11 +161,8 @@ void mesh_sta_cleanup(struct sta_info *sta) | |||
161 | del_timer_sync(&sta->plink_timer); | 161 | del_timer_sync(&sta->plink_timer); |
162 | } | 162 | } |
163 | 163 | ||
164 | if (changed) { | 164 | if (changed) |
165 | sdata_lock(sdata); | ||
166 | ieee80211_mbss_info_change_notify(sdata, changed); | 165 | ieee80211_mbss_info_change_notify(sdata, changed); |
167 | sdata_unlock(sdata); | ||
168 | } | ||
169 | } | 166 | } |
170 | 167 | ||
171 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) | 168 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) |
@@ -419,7 +416,9 @@ int mesh_add_ht_cap_ie(struct ieee80211_sub_if_data *sdata, | |||
419 | 416 | ||
420 | sband = local->hw.wiphy->bands[band]; | 417 | sband = local->hw.wiphy->bands[band]; |
421 | if (!sband->ht_cap.ht_supported || | 418 | if (!sband->ht_cap.ht_supported || |
422 | sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT) | 419 | sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT || |
420 | sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 || | ||
421 | sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10) | ||
423 | return 0; | 422 | return 0; |
424 | 423 | ||
425 | if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap)) | 424 | if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap)) |
@@ -719,14 +718,18 @@ ieee80211_mesh_rebuild_beacon(struct ieee80211_sub_if_data *sdata) | |||
719 | void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata, | 718 | void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata, |
720 | u32 changed) | 719 | u32 changed) |
721 | { | 720 | { |
722 | if (sdata->vif.bss_conf.enable_beacon && | 721 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
723 | (changed & (BSS_CHANGED_BEACON | | 722 | unsigned long bits = changed; |
724 | BSS_CHANGED_HT | | 723 | u32 bit; |
725 | BSS_CHANGED_BASIC_RATES | | 724 | |
726 | BSS_CHANGED_BEACON_INT))) | 725 | if (!bits) |
727 | if (ieee80211_mesh_rebuild_beacon(sdata)) | 726 | return; |
728 | return; | 727 | |
729 | ieee80211_bss_info_change_notify(sdata, changed); | 728 | /* if we race with running work, worst case this work becomes a noop */ |
729 | for_each_set_bit(bit, &bits, sizeof(changed) * BITS_PER_BYTE) | ||
730 | set_bit(bit, &ifmsh->mbss_changed); | ||
731 | set_bit(MESH_WORK_MBSS_CHANGED, &ifmsh->wrkq_flags); | ||
732 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); | ||
730 | } | 733 | } |
731 | 734 | ||
732 | int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | 735 | int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) |
@@ -799,6 +802,10 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | |||
799 | del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); | 802 | del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); |
800 | del_timer_sync(&sdata->u.mesh.mesh_path_timer); | 803 | del_timer_sync(&sdata->u.mesh.mesh_path_timer); |
801 | 804 | ||
805 | /* clear any mesh work (for next join) we may have accrued */ | ||
806 | ifmsh->wrkq_flags = 0; | ||
807 | ifmsh->mbss_changed = 0; | ||
808 | |||
802 | local->fif_other_bss--; | 809 | local->fif_other_bss--; |
803 | atomic_dec(&local->iff_allmultis); | 810 | atomic_dec(&local->iff_allmultis); |
804 | ieee80211_configure_filter(local); | 811 | ieee80211_configure_filter(local); |
@@ -965,6 +972,28 @@ out: | |||
965 | sdata_unlock(sdata); | 972 | sdata_unlock(sdata); |
966 | } | 973 | } |
967 | 974 | ||
975 | static void mesh_bss_info_changed(struct ieee80211_sub_if_data *sdata) | ||
976 | { | ||
977 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
978 | u32 bit, changed = 0; | ||
979 | |||
980 | for_each_set_bit(bit, &ifmsh->mbss_changed, | ||
981 | sizeof(changed) * BITS_PER_BYTE) { | ||
982 | clear_bit(bit, &ifmsh->mbss_changed); | ||
983 | changed |= BIT(bit); | ||
984 | } | ||
985 | |||
986 | if (sdata->vif.bss_conf.enable_beacon && | ||
987 | (changed & (BSS_CHANGED_BEACON | | ||
988 | BSS_CHANGED_HT | | ||
989 | BSS_CHANGED_BASIC_RATES | | ||
990 | BSS_CHANGED_BEACON_INT))) | ||
991 | if (ieee80211_mesh_rebuild_beacon(sdata)) | ||
992 | return; | ||
993 | |||
994 | ieee80211_bss_info_change_notify(sdata, changed); | ||
995 | } | ||
996 | |||
968 | void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata) | 997 | void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata) |
969 | { | 998 | { |
970 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 999 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
@@ -995,6 +1024,8 @@ void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata) | |||
995 | if (test_and_clear_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags)) | 1024 | if (test_and_clear_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags)) |
996 | mesh_sync_adjust_tbtt(sdata); | 1025 | mesh_sync_adjust_tbtt(sdata); |
997 | 1026 | ||
1027 | if (test_and_clear_bit(MESH_WORK_MBSS_CHANGED, &ifmsh->wrkq_flags)) | ||
1028 | mesh_bss_info_changed(sdata); | ||
998 | out: | 1029 | out: |
999 | sdata_unlock(sdata); | 1030 | sdata_unlock(sdata); |
1000 | } | 1031 | } |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 01a28bca6e9b..2bc7fd2f787d 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -58,6 +58,7 @@ enum mesh_path_flags { | |||
58 | * @MESH_WORK_ROOT: the mesh root station needs to send a frame | 58 | * @MESH_WORK_ROOT: the mesh root station needs to send a frame |
59 | * @MESH_WORK_DRIFT_ADJUST: time to compensate for clock drift relative to other | 59 | * @MESH_WORK_DRIFT_ADJUST: time to compensate for clock drift relative to other |
60 | * mesh nodes | 60 | * mesh nodes |
61 | * @MESH_WORK_MBSS_CHANGED: rebuild beacon and notify driver of BSS changes | ||
61 | */ | 62 | */ |
62 | enum mesh_deferred_task_flags { | 63 | enum mesh_deferred_task_flags { |
63 | MESH_WORK_HOUSEKEEPING, | 64 | MESH_WORK_HOUSEKEEPING, |
@@ -65,6 +66,7 @@ enum mesh_deferred_task_flags { | |||
65 | MESH_WORK_GROW_MPP_TABLE, | 66 | MESH_WORK_GROW_MPP_TABLE, |
66 | MESH_WORK_ROOT, | 67 | MESH_WORK_ROOT, |
67 | MESH_WORK_DRIFT_ADJUST, | 68 | MESH_WORK_DRIFT_ADJUST, |
69 | MESH_WORK_MBSS_CHANGED, | ||
68 | }; | 70 | }; |
69 | 71 | ||
70 | /** | 72 | /** |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 09bebed99416..02c05fa15c20 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -154,8 +154,14 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) | |||
154 | u16 ht_opmode; | 154 | u16 ht_opmode; |
155 | bool non_ht_sta = false, ht20_sta = false; | 155 | bool non_ht_sta = false, ht20_sta = false; |
156 | 156 | ||
157 | if (sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT) | 157 | switch (sdata->vif.bss_conf.chandef.width) { |
158 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
159 | case NL80211_CHAN_WIDTH_5: | ||
160 | case NL80211_CHAN_WIDTH_10: | ||
158 | return 0; | 161 | return 0; |
162 | default: | ||
163 | break; | ||
164 | } | ||
159 | 165 | ||
160 | rcu_read_lock(); | 166 | rcu_read_lock(); |
161 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | 167 | list_for_each_entry_rcu(sta, &local->sta_list, list) { |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 9e49f557fa5c..ae31968d42d3 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -190,6 +190,12 @@ static u32 chandef_downgrade(struct cfg80211_chan_def *c) | |||
190 | c->width = NL80211_CHAN_WIDTH_20_NOHT; | 190 | c->width = NL80211_CHAN_WIDTH_20_NOHT; |
191 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | 191 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; |
192 | break; | 192 | break; |
193 | case NL80211_CHAN_WIDTH_5: | ||
194 | case NL80211_CHAN_WIDTH_10: | ||
195 | WARN_ON_ONCE(1); | ||
196 | /* keep c->width */ | ||
197 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
198 | break; | ||
193 | } | 199 | } |
194 | 200 | ||
195 | WARN_ON_ONCE(!cfg80211_chandef_valid(c)); | 201 | WARN_ON_ONCE(!cfg80211_chandef_valid(c)); |
@@ -1779,8 +1785,10 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
1779 | * probably just won't work at all. | 1785 | * probably just won't work at all. |
1780 | */ | 1786 | */ |
1781 | bss_conf->dtim_period = sdata->u.mgd.dtim_period ?: 1; | 1787 | bss_conf->dtim_period = sdata->u.mgd.dtim_period ?: 1; |
1788 | bss_conf->beacon_rate = bss->beacon_rate; | ||
1782 | bss_info_changed |= BSS_CHANGED_BEACON_INFO; | 1789 | bss_info_changed |= BSS_CHANGED_BEACON_INFO; |
1783 | } else { | 1790 | } else { |
1791 | bss_conf->beacon_rate = NULL; | ||
1784 | bss_conf->dtim_period = 0; | 1792 | bss_conf->dtim_period = 0; |
1785 | } | 1793 | } |
1786 | 1794 | ||
@@ -1903,6 +1911,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1903 | del_timer_sync(&sdata->u.mgd.chswitch_timer); | 1911 | del_timer_sync(&sdata->u.mgd.chswitch_timer); |
1904 | 1912 | ||
1905 | sdata->vif.bss_conf.dtim_period = 0; | 1913 | sdata->vif.bss_conf.dtim_period = 0; |
1914 | sdata->vif.bss_conf.beacon_rate = NULL; | ||
1915 | |||
1906 | ifmgd->have_beacon = false; | 1916 | ifmgd->have_beacon = false; |
1907 | 1917 | ||
1908 | ifmgd->flags = 0; | 1918 | ifmgd->flags = 0; |
@@ -2785,8 +2795,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
2785 | if (!ieee80211_assoc_success(sdata, bss, mgmt, len)) { | 2795 | if (!ieee80211_assoc_success(sdata, bss, mgmt, len)) { |
2786 | /* oops -- internal error -- send timeout for now */ | 2796 | /* oops -- internal error -- send timeout for now */ |
2787 | ieee80211_destroy_assoc_data(sdata, false); | 2797 | ieee80211_destroy_assoc_data(sdata, false); |
2788 | cfg80211_put_bss(sdata->local->hw.wiphy, bss); | 2798 | cfg80211_assoc_timeout(sdata->dev, bss); |
2789 | cfg80211_assoc_timeout(sdata->dev, mgmt->bssid); | ||
2790 | return; | 2799 | return; |
2791 | } | 2800 | } |
2792 | sdata_info(sdata, "associated\n"); | 2801 | sdata_info(sdata, "associated\n"); |
@@ -2827,8 +2836,10 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
2827 | 2836 | ||
2828 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, | 2837 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, |
2829 | channel); | 2838 | channel); |
2830 | if (bss) | 2839 | if (bss) { |
2831 | ieee80211_rx_bss_put(local, bss); | 2840 | ieee80211_rx_bss_put(local, bss); |
2841 | sdata->vif.bss_conf.beacon_rate = bss->beacon_rate; | ||
2842 | } | ||
2832 | 2843 | ||
2833 | if (!sdata->u.mgd.associated || | 2844 | if (!sdata->u.mgd.associated || |
2834 | !ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid)) | 2845 | !ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid)) |
@@ -3501,13 +3512,10 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
3501 | time_after(jiffies, ifmgd->assoc_data->timeout)) { | 3512 | time_after(jiffies, ifmgd->assoc_data->timeout)) { |
3502 | if ((ifmgd->assoc_data->need_beacon && !ifmgd->have_beacon) || | 3513 | if ((ifmgd->assoc_data->need_beacon && !ifmgd->have_beacon) || |
3503 | ieee80211_do_assoc(sdata)) { | 3514 | ieee80211_do_assoc(sdata)) { |
3504 | u8 bssid[ETH_ALEN]; | 3515 | struct cfg80211_bss *bss = ifmgd->assoc_data->bss; |
3505 | |||
3506 | memcpy(bssid, ifmgd->assoc_data->bss->bssid, ETH_ALEN); | ||
3507 | 3516 | ||
3508 | ieee80211_destroy_assoc_data(sdata, false); | 3517 | ieee80211_destroy_assoc_data(sdata, false); |
3509 | 3518 | cfg80211_assoc_timeout(sdata->dev, bss); | |
3510 | cfg80211_assoc_timeout(sdata->dev, bssid); | ||
3511 | } | 3519 | } |
3512 | } else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started) | 3520 | } else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started) |
3513 | run_again(sdata, ifmgd->assoc_data->timeout); | 3521 | run_again(sdata, ifmgd->assoc_data->timeout); |
@@ -3838,6 +3846,12 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, | |||
3838 | */ | 3846 | */ |
3839 | ret = ieee80211_vif_use_channel(sdata, &chandef, | 3847 | ret = ieee80211_vif_use_channel(sdata, &chandef, |
3840 | IEEE80211_CHANCTX_SHARED); | 3848 | IEEE80211_CHANCTX_SHARED); |
3849 | |||
3850 | /* don't downgrade for 5 and 10 MHz channels, though. */ | ||
3851 | if (chandef.width == NL80211_CHAN_WIDTH_5 || | ||
3852 | chandef.width == NL80211_CHAN_WIDTH_10) | ||
3853 | return ret; | ||
3854 | |||
3841 | while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { | 3855 | while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { |
3842 | ifmgd->flags |= chandef_downgrade(&chandef); | 3856 | ifmgd->flags |= chandef_downgrade(&chandef); |
3843 | ret = ieee80211_vif_use_channel(sdata, &chandef, | 3857 | ret = ieee80211_vif_use_channel(sdata, &chandef, |
@@ -4427,8 +4441,11 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata) | |||
4427 | cancel_work_sync(&ifmgd->chswitch_work); | 4441 | cancel_work_sync(&ifmgd->chswitch_work); |
4428 | 4442 | ||
4429 | sdata_lock(sdata); | 4443 | sdata_lock(sdata); |
4430 | if (ifmgd->assoc_data) | 4444 | if (ifmgd->assoc_data) { |
4445 | struct cfg80211_bss *bss = ifmgd->assoc_data->bss; | ||
4431 | ieee80211_destroy_assoc_data(sdata, false); | 4446 | ieee80211_destroy_assoc_data(sdata, false); |
4447 | cfg80211_assoc_timeout(sdata->dev, bss); | ||
4448 | } | ||
4432 | if (ifmgd->auth_data) | 4449 | if (ifmgd->auth_data) |
4433 | ieee80211_destroy_auth_data(sdata, false); | 4450 | ieee80211_destroy_auth_data(sdata, false); |
4434 | del_timer_sync(&ifmgd->timer); | 4451 | del_timer_sync(&ifmgd->timer); |
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index a02bef35b134..30d58d2d13e2 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c | |||
@@ -397,8 +397,14 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate, | |||
397 | return; | 397 | return; |
398 | 398 | ||
399 | /* if HT BSS, and we handle a data frame, also try HT rates */ | 399 | /* if HT BSS, and we handle a data frame, also try HT rates */ |
400 | if (chan_width == NL80211_CHAN_WIDTH_20_NOHT) | 400 | switch (chan_width) { |
401 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
402 | case NL80211_CHAN_WIDTH_5: | ||
403 | case NL80211_CHAN_WIDTH_10: | ||
401 | return; | 404 | return; |
405 | default: | ||
406 | break; | ||
407 | } | ||
402 | 408 | ||
403 | alt_rate.idx = 0; | 409 | alt_rate.idx = 0; |
404 | /* keep protection flags */ | 410 | /* keep protection flags */ |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 99b103921a4b..1b122a79b0d8 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -140,6 +140,15 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | |||
140 | bss->valid_data |= IEEE80211_BSS_VALID_WMM; | 140 | bss->valid_data |= IEEE80211_BSS_VALID_WMM; |
141 | } | 141 | } |
142 | 142 | ||
143 | if (beacon) { | ||
144 | struct ieee80211_supported_band *sband = | ||
145 | local->hw.wiphy->bands[rx_status->band]; | ||
146 | if (!(rx_status->flag & RX_FLAG_HT) && | ||
147 | !(rx_status->flag & RX_FLAG_VHT)) | ||
148 | bss->beacon_rate = | ||
149 | &sband->bitrates[rx_status->rate_idx]; | ||
150 | } | ||
151 | |||
143 | return bss; | 152 | return bss; |
144 | } | 153 | } |
145 | 154 | ||
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index b4297982d34a..aeb967a0aeed 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -149,6 +149,7 @@ static void cleanup_single_sta(struct sta_info *sta) | |||
149 | * directly by station destruction. | 149 | * directly by station destruction. |
150 | */ | 150 | */ |
151 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) { | 151 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) { |
152 | kfree(sta->ampdu_mlme.tid_start_tx[i]); | ||
152 | tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]); | 153 | tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]); |
153 | if (!tid_tx) | 154 | if (!tid_tx) |
154 | continue; | 155 | continue; |
@@ -346,6 +347,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
346 | if (ieee80211_vif_is_mesh(&sdata->vif) && | 347 | if (ieee80211_vif_is_mesh(&sdata->vif) && |
347 | !sdata->u.mesh.user_mpm) | 348 | !sdata->u.mesh.user_mpm) |
348 | init_timer(&sta->plink_timer); | 349 | init_timer(&sta->plink_timer); |
350 | sta->nonpeer_pm = NL80211_MESH_POWER_ACTIVE; | ||
349 | #endif | 351 | #endif |
350 | 352 | ||
351 | memcpy(sta->sta.addr, addr, ETH_ALEN); | 353 | memcpy(sta->sta.addr, addr, ETH_ALEN); |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index bd12fc54266c..4208dbd5861f 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -203,6 +203,7 @@ struct tid_ampdu_rx { | |||
203 | * driver requested to close until the work for it runs | 203 | * driver requested to close until the work for it runs |
204 | * @mtx: mutex to protect all TX data (except non-NULL assignments | 204 | * @mtx: mutex to protect all TX data (except non-NULL assignments |
205 | * to tid_tx[idx], which are protected by the sta spinlock) | 205 | * to tid_tx[idx], which are protected by the sta spinlock) |
206 | * tid_start_tx is also protected by sta->lock. | ||
206 | */ | 207 | */ |
207 | struct sta_ampdu_mlme { | 208 | struct sta_ampdu_mlme { |
208 | struct mutex mtx; | 209 | struct mutex mtx; |
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index 171344d4eb7c..97c289414e32 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c | |||
@@ -396,7 +396,7 @@ void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, | |||
396 | new_bw = ieee80211_sta_cur_vht_bw(sta); | 396 | new_bw = ieee80211_sta_cur_vht_bw(sta); |
397 | if (new_bw != sta->sta.bandwidth) { | 397 | if (new_bw != sta->sta.bandwidth) { |
398 | sta->sta.bandwidth = new_bw; | 398 | sta->sta.bandwidth = new_bw; |
399 | changed |= IEEE80211_RC_NSS_CHANGED; | 399 | changed |= IEEE80211_RC_BW_CHANGED; |
400 | } | 400 | } |
401 | 401 | ||
402 | change: | 402 | change: |
diff --git a/net/wireless/chan.c b/net/wireless/chan.c index fd556ac05fdb..50f6195c8b70 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c | |||
@@ -54,6 +54,8 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef) | |||
54 | control_freq = chandef->chan->center_freq; | 54 | control_freq = chandef->chan->center_freq; |
55 | 55 | ||
56 | switch (chandef->width) { | 56 | switch (chandef->width) { |
57 | case NL80211_CHAN_WIDTH_5: | ||
58 | case NL80211_CHAN_WIDTH_10: | ||
57 | case NL80211_CHAN_WIDTH_20: | 59 | case NL80211_CHAN_WIDTH_20: |
58 | case NL80211_CHAN_WIDTH_20_NOHT: | 60 | case NL80211_CHAN_WIDTH_20_NOHT: |
59 | if (chandef->center_freq1 != control_freq) | 61 | if (chandef->center_freq1 != control_freq) |
@@ -152,6 +154,12 @@ static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c) | |||
152 | int width; | 154 | int width; |
153 | 155 | ||
154 | switch (c->width) { | 156 | switch (c->width) { |
157 | case NL80211_CHAN_WIDTH_5: | ||
158 | width = 5; | ||
159 | break; | ||
160 | case NL80211_CHAN_WIDTH_10: | ||
161 | width = 10; | ||
162 | break; | ||
155 | case NL80211_CHAN_WIDTH_20: | 163 | case NL80211_CHAN_WIDTH_20: |
156 | case NL80211_CHAN_WIDTH_20_NOHT: | 164 | case NL80211_CHAN_WIDTH_20_NOHT: |
157 | width = 20; | 165 | width = 20; |
@@ -194,6 +202,16 @@ cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1, | |||
194 | if (c1->width == c2->width) | 202 | if (c1->width == c2->width) |
195 | return NULL; | 203 | return NULL; |
196 | 204 | ||
205 | /* | ||
206 | * can't be compatible if one of them is 5 or 10 MHz, | ||
207 | * but they don't have the same width. | ||
208 | */ | ||
209 | if (c1->width == NL80211_CHAN_WIDTH_5 || | ||
210 | c1->width == NL80211_CHAN_WIDTH_10 || | ||
211 | c2->width == NL80211_CHAN_WIDTH_5 || | ||
212 | c2->width == NL80211_CHAN_WIDTH_10) | ||
213 | return NULL; | ||
214 | |||
197 | if (c1->width == NL80211_CHAN_WIDTH_20_NOHT || | 215 | if (c1->width == NL80211_CHAN_WIDTH_20_NOHT || |
198 | c1->width == NL80211_CHAN_WIDTH_20) | 216 | c1->width == NL80211_CHAN_WIDTH_20) |
199 | return c2; | 217 | return c2; |
@@ -264,11 +282,17 @@ static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy, | |||
264 | u32 bandwidth) | 282 | u32 bandwidth) |
265 | { | 283 | { |
266 | struct ieee80211_channel *c; | 284 | struct ieee80211_channel *c; |
267 | u32 freq; | 285 | u32 freq, start_freq, end_freq; |
286 | |||
287 | if (bandwidth <= 20) { | ||
288 | start_freq = center_freq; | ||
289 | end_freq = center_freq; | ||
290 | } else { | ||
291 | start_freq = center_freq - bandwidth/2 + 10; | ||
292 | end_freq = center_freq + bandwidth/2 - 10; | ||
293 | } | ||
268 | 294 | ||
269 | for (freq = center_freq - bandwidth/2 + 10; | 295 | for (freq = start_freq; freq <= end_freq; freq += 20) { |
270 | freq <= center_freq + bandwidth/2 - 10; | ||
271 | freq += 20) { | ||
272 | c = ieee80211_get_channel(wiphy, freq); | 296 | c = ieee80211_get_channel(wiphy, freq); |
273 | if (!c) | 297 | if (!c) |
274 | return -EINVAL; | 298 | return -EINVAL; |
@@ -310,11 +334,17 @@ static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, | |||
310 | u32 prohibited_flags) | 334 | u32 prohibited_flags) |
311 | { | 335 | { |
312 | struct ieee80211_channel *c; | 336 | struct ieee80211_channel *c; |
313 | u32 freq; | 337 | u32 freq, start_freq, end_freq; |
338 | |||
339 | if (bandwidth <= 20) { | ||
340 | start_freq = center_freq; | ||
341 | end_freq = center_freq; | ||
342 | } else { | ||
343 | start_freq = center_freq - bandwidth/2 + 10; | ||
344 | end_freq = center_freq + bandwidth/2 - 10; | ||
345 | } | ||
314 | 346 | ||
315 | for (freq = center_freq - bandwidth/2 + 10; | 347 | for (freq = start_freq; freq <= end_freq; freq += 20) { |
316 | freq <= center_freq + bandwidth/2 - 10; | ||
317 | freq += 20) { | ||
318 | c = ieee80211_get_channel(wiphy, freq); | 348 | c = ieee80211_get_channel(wiphy, freq); |
319 | if (!c) | 349 | if (!c) |
320 | return false; | 350 | return false; |
@@ -349,6 +379,12 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy, | |||
349 | control_freq = chandef->chan->center_freq; | 379 | control_freq = chandef->chan->center_freq; |
350 | 380 | ||
351 | switch (chandef->width) { | 381 | switch (chandef->width) { |
382 | case NL80211_CHAN_WIDTH_5: | ||
383 | width = 5; | ||
384 | break; | ||
385 | case NL80211_CHAN_WIDTH_10: | ||
386 | width = 10; | ||
387 | break; | ||
352 | case NL80211_CHAN_WIDTH_20: | 388 | case NL80211_CHAN_WIDTH_20: |
353 | if (!ht_cap->ht_supported) | 389 | if (!ht_cap->ht_supported) |
354 | return false; | 390 | return false; |
@@ -405,6 +441,11 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy, | |||
405 | if (width > 20) | 441 | if (width > 20) |
406 | prohibited_flags |= IEEE80211_CHAN_NO_OFDM; | 442 | prohibited_flags |= IEEE80211_CHAN_NO_OFDM; |
407 | 443 | ||
444 | /* 5 and 10 MHz are only defined for the OFDM PHY */ | ||
445 | if (width < 20) | ||
446 | prohibited_flags |= IEEE80211_CHAN_NO_OFDM; | ||
447 | |||
448 | |||
408 | if (!cfg80211_secondary_chans_ok(wiphy, chandef->center_freq1, | 449 | if (!cfg80211_secondary_chans_ok(wiphy, chandef->center_freq1, |
409 | width, prohibited_flags)) | 450 | width, prohibited_flags)) |
410 | return false; | 451 | return false; |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 4224e7554a76..672459b9483b 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -934,6 +934,12 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
934 | * freed. | 934 | * freed. |
935 | */ | 935 | */ |
936 | cfg80211_process_wdev_events(wdev); | 936 | cfg80211_process_wdev_events(wdev); |
937 | |||
938 | if (WARN_ON(wdev->current_bss)) { | ||
939 | cfg80211_unhold_bss(wdev->current_bss); | ||
940 | cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); | ||
941 | wdev->current_bss = NULL; | ||
942 | } | ||
937 | break; | 943 | break; |
938 | case NETDEV_PRE_UP: | 944 | case NETDEV_PRE_UP: |
939 | if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) | 945 | if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index a61a44bc6cf0..bfac5e186f57 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -38,6 +38,7 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss, | |||
38 | * frame instead of reassoc. | 38 | * frame instead of reassoc. |
39 | */ | 39 | */ |
40 | if (cfg80211_sme_rx_assoc_resp(wdev, status_code)) { | 40 | if (cfg80211_sme_rx_assoc_resp(wdev, status_code)) { |
41 | cfg80211_unhold_bss(bss_from_pub(bss)); | ||
41 | cfg80211_put_bss(wiphy, bss); | 42 | cfg80211_put_bss(wiphy, bss); |
42 | return; | 43 | return; |
43 | } | 44 | } |
@@ -131,16 +132,19 @@ void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr) | |||
131 | } | 132 | } |
132 | EXPORT_SYMBOL(cfg80211_auth_timeout); | 133 | EXPORT_SYMBOL(cfg80211_auth_timeout); |
133 | 134 | ||
134 | void cfg80211_assoc_timeout(struct net_device *dev, const u8 *addr) | 135 | void cfg80211_assoc_timeout(struct net_device *dev, struct cfg80211_bss *bss) |
135 | { | 136 | { |
136 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 137 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
137 | struct wiphy *wiphy = wdev->wiphy; | 138 | struct wiphy *wiphy = wdev->wiphy; |
138 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 139 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
139 | 140 | ||
140 | trace_cfg80211_send_assoc_timeout(dev, addr); | 141 | trace_cfg80211_send_assoc_timeout(dev, bss->bssid); |
141 | 142 | ||
142 | nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL); | 143 | nl80211_send_assoc_timeout(rdev, dev, bss->bssid, GFP_KERNEL); |
143 | cfg80211_sme_assoc_timeout(wdev); | 144 | cfg80211_sme_assoc_timeout(wdev); |
145 | |||
146 | cfg80211_unhold_bss(bss_from_pub(bss)); | ||
147 | cfg80211_put_bss(wiphy, bss); | ||
144 | } | 148 | } |
145 | EXPORT_SYMBOL(cfg80211_assoc_timeout); | 149 | EXPORT_SYMBOL(cfg80211_assoc_timeout); |
146 | 150 | ||
@@ -307,6 +311,8 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
307 | goto out; | 311 | goto out; |
308 | 312 | ||
309 | err = rdev_assoc(rdev, dev, req); | 313 | err = rdev_assoc(rdev, dev, req); |
314 | if (!err) | ||
315 | cfg80211_hold_bss(bss_from_pub(req->bss)); | ||
310 | 316 | ||
311 | out: | 317 | out: |
312 | if (err) | 318 | if (err) |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e4028197b75d..7dc3343427c1 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -1111,10 +1111,16 @@ nl80211_send_mgmt_stypes(struct sk_buff *msg, | |||
1111 | return 0; | 1111 | return 0; |
1112 | } | 1112 | } |
1113 | 1113 | ||
1114 | struct nl80211_dump_wiphy_state { | ||
1115 | s64 filter_wiphy; | ||
1116 | long start; | ||
1117 | long split_start, band_start, chan_start; | ||
1118 | bool split; | ||
1119 | }; | ||
1120 | |||
1114 | static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | 1121 | static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, |
1115 | struct sk_buff *msg, u32 portid, u32 seq, | 1122 | struct sk_buff *msg, u32 portid, u32 seq, |
1116 | int flags, bool split, long *split_start, | 1123 | int flags, struct nl80211_dump_wiphy_state *state) |
1117 | long *band_start, long *chan_start) | ||
1118 | { | 1124 | { |
1119 | void *hdr; | 1125 | void *hdr; |
1120 | struct nlattr *nl_bands, *nl_band; | 1126 | struct nlattr *nl_bands, *nl_band; |
@@ -1125,19 +1131,14 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1125 | int i; | 1131 | int i; |
1126 | const struct ieee80211_txrx_stypes *mgmt_stypes = | 1132 | const struct ieee80211_txrx_stypes *mgmt_stypes = |
1127 | dev->wiphy.mgmt_stypes; | 1133 | dev->wiphy.mgmt_stypes; |
1128 | long start = 0, start_chan = 0, start_band = 0; | ||
1129 | u32 features; | 1134 | u32 features; |
1130 | 1135 | ||
1131 | hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_WIPHY); | 1136 | hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_WIPHY); |
1132 | if (!hdr) | 1137 | if (!hdr) |
1133 | return -ENOBUFS; | 1138 | return -ENOBUFS; |
1134 | 1139 | ||
1135 | /* allow always using the variables */ | 1140 | if (WARN_ON(!state)) |
1136 | if (!split) { | 1141 | return -EINVAL; |
1137 | split_start = &start; | ||
1138 | band_start = &start_band; | ||
1139 | chan_start = &start_chan; | ||
1140 | } | ||
1141 | 1142 | ||
1142 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx) || | 1143 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx) || |
1143 | nla_put_string(msg, NL80211_ATTR_WIPHY_NAME, | 1144 | nla_put_string(msg, NL80211_ATTR_WIPHY_NAME, |
@@ -1146,7 +1147,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1146 | cfg80211_rdev_list_generation)) | 1147 | cfg80211_rdev_list_generation)) |
1147 | goto nla_put_failure; | 1148 | goto nla_put_failure; |
1148 | 1149 | ||
1149 | switch (*split_start) { | 1150 | switch (state->split_start) { |
1150 | case 0: | 1151 | case 0: |
1151 | if (nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, | 1152 | if (nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, |
1152 | dev->wiphy.retry_short) || | 1153 | dev->wiphy.retry_short) || |
@@ -1188,9 +1189,12 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1188 | if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) && | 1189 | if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) && |
1189 | nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP)) | 1190 | nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP)) |
1190 | goto nla_put_failure; | 1191 | goto nla_put_failure; |
1192 | if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) && | ||
1193 | nla_put_flag(msg, WIPHY_FLAG_SUPPORTS_5_10_MHZ)) | ||
1194 | goto nla_put_failure; | ||
1191 | 1195 | ||
1192 | (*split_start)++; | 1196 | state->split_start++; |
1193 | if (split) | 1197 | if (state->split) |
1194 | break; | 1198 | break; |
1195 | case 1: | 1199 | case 1: |
1196 | if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES, | 1200 | if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES, |
@@ -1234,22 +1238,23 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1234 | } | 1238 | } |
1235 | } | 1239 | } |
1236 | 1240 | ||
1237 | (*split_start)++; | 1241 | state->split_start++; |
1238 | if (split) | 1242 | if (state->split) |
1239 | break; | 1243 | break; |
1240 | case 2: | 1244 | case 2: |
1241 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES, | 1245 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES, |
1242 | dev->wiphy.interface_modes)) | 1246 | dev->wiphy.interface_modes)) |
1243 | goto nla_put_failure; | 1247 | goto nla_put_failure; |
1244 | (*split_start)++; | 1248 | state->split_start++; |
1245 | if (split) | 1249 | if (state->split) |
1246 | break; | 1250 | break; |
1247 | case 3: | 1251 | case 3: |
1248 | nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); | 1252 | nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); |
1249 | if (!nl_bands) | 1253 | if (!nl_bands) |
1250 | goto nla_put_failure; | 1254 | goto nla_put_failure; |
1251 | 1255 | ||
1252 | for (band = *band_start; band < IEEE80211_NUM_BANDS; band++) { | 1256 | for (band = state->band_start; |
1257 | band < IEEE80211_NUM_BANDS; band++) { | ||
1253 | struct ieee80211_supported_band *sband; | 1258 | struct ieee80211_supported_band *sband; |
1254 | 1259 | ||
1255 | sband = dev->wiphy.bands[band]; | 1260 | sband = dev->wiphy.bands[band]; |
@@ -1261,12 +1266,12 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1261 | if (!nl_band) | 1266 | if (!nl_band) |
1262 | goto nla_put_failure; | 1267 | goto nla_put_failure; |
1263 | 1268 | ||
1264 | switch (*chan_start) { | 1269 | switch (state->chan_start) { |
1265 | case 0: | 1270 | case 0: |
1266 | if (nl80211_send_band_rateinfo(msg, sband)) | 1271 | if (nl80211_send_band_rateinfo(msg, sband)) |
1267 | goto nla_put_failure; | 1272 | goto nla_put_failure; |
1268 | (*chan_start)++; | 1273 | state->chan_start++; |
1269 | if (split) | 1274 | if (state->split) |
1270 | break; | 1275 | break; |
1271 | default: | 1276 | default: |
1272 | /* add frequencies */ | 1277 | /* add frequencies */ |
@@ -1275,7 +1280,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1275 | if (!nl_freqs) | 1280 | if (!nl_freqs) |
1276 | goto nla_put_failure; | 1281 | goto nla_put_failure; |
1277 | 1282 | ||
1278 | for (i = *chan_start - 1; | 1283 | for (i = state->chan_start - 1; |
1279 | i < sband->n_channels; | 1284 | i < sband->n_channels; |
1280 | i++) { | 1285 | i++) { |
1281 | nl_freq = nla_nest_start(msg, i); | 1286 | nl_freq = nla_nest_start(msg, i); |
@@ -1284,26 +1289,27 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1284 | 1289 | ||
1285 | chan = &sband->channels[i]; | 1290 | chan = &sband->channels[i]; |
1286 | 1291 | ||
1287 | if (nl80211_msg_put_channel(msg, chan, | 1292 | if (nl80211_msg_put_channel( |
1288 | split)) | 1293 | msg, chan, |
1294 | state->split)) | ||
1289 | goto nla_put_failure; | 1295 | goto nla_put_failure; |
1290 | 1296 | ||
1291 | nla_nest_end(msg, nl_freq); | 1297 | nla_nest_end(msg, nl_freq); |
1292 | if (split) | 1298 | if (state->split) |
1293 | break; | 1299 | break; |
1294 | } | 1300 | } |
1295 | if (i < sband->n_channels) | 1301 | if (i < sband->n_channels) |
1296 | *chan_start = i + 2; | 1302 | state->chan_start = i + 2; |
1297 | else | 1303 | else |
1298 | *chan_start = 0; | 1304 | state->chan_start = 0; |
1299 | nla_nest_end(msg, nl_freqs); | 1305 | nla_nest_end(msg, nl_freqs); |
1300 | } | 1306 | } |
1301 | 1307 | ||
1302 | nla_nest_end(msg, nl_band); | 1308 | nla_nest_end(msg, nl_band); |
1303 | 1309 | ||
1304 | if (split) { | 1310 | if (state->split) { |
1305 | /* start again here */ | 1311 | /* start again here */ |
1306 | if (*chan_start) | 1312 | if (state->chan_start) |
1307 | band--; | 1313 | band--; |
1308 | break; | 1314 | break; |
1309 | } | 1315 | } |
@@ -1311,14 +1317,14 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1311 | nla_nest_end(msg, nl_bands); | 1317 | nla_nest_end(msg, nl_bands); |
1312 | 1318 | ||
1313 | if (band < IEEE80211_NUM_BANDS) | 1319 | if (band < IEEE80211_NUM_BANDS) |
1314 | *band_start = band + 1; | 1320 | state->band_start = band + 1; |
1315 | else | 1321 | else |
1316 | *band_start = 0; | 1322 | state->band_start = 0; |
1317 | 1323 | ||
1318 | /* if bands & channels are done, continue outside */ | 1324 | /* if bands & channels are done, continue outside */ |
1319 | if (*band_start == 0 && *chan_start == 0) | 1325 | if (state->band_start == 0 && state->chan_start == 0) |
1320 | (*split_start)++; | 1326 | state->split_start++; |
1321 | if (split) | 1327 | if (state->split) |
1322 | break; | 1328 | break; |
1323 | case 4: | 1329 | case 4: |
1324 | nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS); | 1330 | nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS); |
@@ -1384,7 +1390,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1384 | } | 1390 | } |
1385 | CMD(start_p2p_device, START_P2P_DEVICE); | 1391 | CMD(start_p2p_device, START_P2P_DEVICE); |
1386 | CMD(set_mcast_rate, SET_MCAST_RATE); | 1392 | CMD(set_mcast_rate, SET_MCAST_RATE); |
1387 | if (split) { | 1393 | if (state->split) { |
1388 | CMD(crit_proto_start, CRIT_PROTOCOL_START); | 1394 | CMD(crit_proto_start, CRIT_PROTOCOL_START); |
1389 | CMD(crit_proto_stop, CRIT_PROTOCOL_STOP); | 1395 | CMD(crit_proto_stop, CRIT_PROTOCOL_STOP); |
1390 | } | 1396 | } |
@@ -1408,8 +1414,8 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1408 | } | 1414 | } |
1409 | 1415 | ||
1410 | nla_nest_end(msg, nl_cmds); | 1416 | nla_nest_end(msg, nl_cmds); |
1411 | (*split_start)++; | 1417 | state->split_start++; |
1412 | if (split) | 1418 | if (state->split) |
1413 | break; | 1419 | break; |
1414 | case 5: | 1420 | case 5: |
1415 | if (dev->ops->remain_on_channel && | 1421 | if (dev->ops->remain_on_channel && |
@@ -1425,29 +1431,30 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1425 | 1431 | ||
1426 | if (nl80211_send_mgmt_stypes(msg, mgmt_stypes)) | 1432 | if (nl80211_send_mgmt_stypes(msg, mgmt_stypes)) |
1427 | goto nla_put_failure; | 1433 | goto nla_put_failure; |
1428 | (*split_start)++; | 1434 | state->split_start++; |
1429 | if (split) | 1435 | if (state->split) |
1430 | break; | 1436 | break; |
1431 | case 6: | 1437 | case 6: |
1432 | #ifdef CONFIG_PM | 1438 | #ifdef CONFIG_PM |
1433 | if (nl80211_send_wowlan(msg, dev, split)) | 1439 | if (nl80211_send_wowlan(msg, dev, state->split)) |
1434 | goto nla_put_failure; | 1440 | goto nla_put_failure; |
1435 | (*split_start)++; | 1441 | state->split_start++; |
1436 | if (split) | 1442 | if (state->split) |
1437 | break; | 1443 | break; |
1438 | #else | 1444 | #else |
1439 | (*split_start)++; | 1445 | state->split_start++; |
1440 | #endif | 1446 | #endif |
1441 | case 7: | 1447 | case 7: |
1442 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, | 1448 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, |
1443 | dev->wiphy.software_iftypes)) | 1449 | dev->wiphy.software_iftypes)) |
1444 | goto nla_put_failure; | 1450 | goto nla_put_failure; |
1445 | 1451 | ||
1446 | if (nl80211_put_iface_combinations(&dev->wiphy, msg, split)) | 1452 | if (nl80211_put_iface_combinations(&dev->wiphy, msg, |
1453 | state->split)) | ||
1447 | goto nla_put_failure; | 1454 | goto nla_put_failure; |
1448 | 1455 | ||
1449 | (*split_start)++; | 1456 | state->split_start++; |
1450 | if (split) | 1457 | if (state->split) |
1451 | break; | 1458 | break; |
1452 | case 8: | 1459 | case 8: |
1453 | if ((dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) && | 1460 | if ((dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) && |
@@ -1461,7 +1468,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1461 | * dump is split, otherwise it makes it too big. Therefore | 1468 | * dump is split, otherwise it makes it too big. Therefore |
1462 | * only advertise it in that case. | 1469 | * only advertise it in that case. |
1463 | */ | 1470 | */ |
1464 | if (split) | 1471 | if (state->split) |
1465 | features |= NL80211_FEATURE_ADVERTISE_CHAN_LIMITS; | 1472 | features |= NL80211_FEATURE_ADVERTISE_CHAN_LIMITS; |
1466 | if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS, features)) | 1473 | if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS, features)) |
1467 | goto nla_put_failure; | 1474 | goto nla_put_failure; |
@@ -1488,7 +1495,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1488 | * case we'll continue with more data in the next round, | 1495 | * case we'll continue with more data in the next round, |
1489 | * but break unconditionally so unsplit data stops here. | 1496 | * but break unconditionally so unsplit data stops here. |
1490 | */ | 1497 | */ |
1491 | (*split_start)++; | 1498 | state->split_start++; |
1492 | break; | 1499 | break; |
1493 | case 9: | 1500 | case 9: |
1494 | if (dev->wiphy.extended_capabilities && | 1501 | if (dev->wiphy.extended_capabilities && |
@@ -1507,7 +1514,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1507 | goto nla_put_failure; | 1514 | goto nla_put_failure; |
1508 | 1515 | ||
1509 | /* done */ | 1516 | /* done */ |
1510 | *split_start = 0; | 1517 | state->split_start = 0; |
1511 | break; | 1518 | break; |
1512 | } | 1519 | } |
1513 | return genlmsg_end(msg, hdr); | 1520 | return genlmsg_end(msg, hdr); |
@@ -1517,59 +1524,76 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1517 | return -EMSGSIZE; | 1524 | return -EMSGSIZE; |
1518 | } | 1525 | } |
1519 | 1526 | ||
1527 | static int nl80211_dump_wiphy_parse(struct sk_buff *skb, | ||
1528 | struct netlink_callback *cb, | ||
1529 | struct nl80211_dump_wiphy_state *state) | ||
1530 | { | ||
1531 | struct nlattr **tb = nl80211_fam.attrbuf; | ||
1532 | int ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | ||
1533 | tb, nl80211_fam.maxattr, nl80211_policy); | ||
1534 | /* ignore parse errors for backward compatibility */ | ||
1535 | if (ret) | ||
1536 | return 0; | ||
1537 | |||
1538 | state->split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP]; | ||
1539 | if (tb[NL80211_ATTR_WIPHY]) | ||
1540 | state->filter_wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]); | ||
1541 | if (tb[NL80211_ATTR_WDEV]) | ||
1542 | state->filter_wiphy = nla_get_u64(tb[NL80211_ATTR_WDEV]) >> 32; | ||
1543 | if (tb[NL80211_ATTR_IFINDEX]) { | ||
1544 | struct net_device *netdev; | ||
1545 | struct cfg80211_registered_device *rdev; | ||
1546 | int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); | ||
1547 | |||
1548 | netdev = dev_get_by_index(sock_net(skb->sk), ifidx); | ||
1549 | if (!netdev) | ||
1550 | return -ENODEV; | ||
1551 | if (netdev->ieee80211_ptr) { | ||
1552 | rdev = wiphy_to_dev( | ||
1553 | netdev->ieee80211_ptr->wiphy); | ||
1554 | state->filter_wiphy = rdev->wiphy_idx; | ||
1555 | } | ||
1556 | dev_put(netdev); | ||
1557 | } | ||
1558 | |||
1559 | return 0; | ||
1560 | } | ||
1561 | |||
1520 | static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | 1562 | static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) |
1521 | { | 1563 | { |
1522 | int idx = 0, ret; | 1564 | int idx = 0, ret; |
1523 | int start = cb->args[0]; | 1565 | struct nl80211_dump_wiphy_state *state = (void *)cb->args[0]; |
1524 | struct cfg80211_registered_device *dev; | 1566 | struct cfg80211_registered_device *dev; |
1525 | s64 filter_wiphy = -1; | ||
1526 | bool split = false; | ||
1527 | struct nlattr **tb = nl80211_fam.attrbuf; | ||
1528 | int res; | ||
1529 | 1567 | ||
1530 | rtnl_lock(); | 1568 | rtnl_lock(); |
1531 | res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | 1569 | if (!state) { |
1532 | tb, nl80211_fam.maxattr, nl80211_policy); | 1570 | state = kzalloc(sizeof(*state), GFP_KERNEL); |
1533 | if (res == 0) { | 1571 | if (!state) |
1534 | split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP]; | 1572 | return -ENOMEM; |
1535 | if (tb[NL80211_ATTR_WIPHY]) | 1573 | state->filter_wiphy = -1; |
1536 | filter_wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]); | 1574 | ret = nl80211_dump_wiphy_parse(skb, cb, state); |
1537 | if (tb[NL80211_ATTR_WDEV]) | 1575 | if (ret) { |
1538 | filter_wiphy = nla_get_u64(tb[NL80211_ATTR_WDEV]) >> 32; | 1576 | kfree(state); |
1539 | if (tb[NL80211_ATTR_IFINDEX]) { | 1577 | rtnl_unlock(); |
1540 | struct net_device *netdev; | 1578 | return ret; |
1541 | int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); | ||
1542 | |||
1543 | netdev = dev_get_by_index(sock_net(skb->sk), ifidx); | ||
1544 | if (!netdev) { | ||
1545 | rtnl_unlock(); | ||
1546 | return -ENODEV; | ||
1547 | } | ||
1548 | if (netdev->ieee80211_ptr) { | ||
1549 | dev = wiphy_to_dev( | ||
1550 | netdev->ieee80211_ptr->wiphy); | ||
1551 | filter_wiphy = dev->wiphy_idx; | ||
1552 | } | ||
1553 | dev_put(netdev); | ||
1554 | } | 1579 | } |
1580 | cb->args[0] = (long)state; | ||
1555 | } | 1581 | } |
1556 | 1582 | ||
1557 | list_for_each_entry(dev, &cfg80211_rdev_list, list) { | 1583 | list_for_each_entry(dev, &cfg80211_rdev_list, list) { |
1558 | if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) | 1584 | if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) |
1559 | continue; | 1585 | continue; |
1560 | if (++idx <= start) | 1586 | if (++idx <= state->start) |
1561 | continue; | 1587 | continue; |
1562 | if (filter_wiphy != -1 && dev->wiphy_idx != filter_wiphy) | 1588 | if (state->filter_wiphy != -1 && |
1589 | state->filter_wiphy != dev->wiphy_idx) | ||
1563 | continue; | 1590 | continue; |
1564 | /* attempt to fit multiple wiphy data chunks into the skb */ | 1591 | /* attempt to fit multiple wiphy data chunks into the skb */ |
1565 | do { | 1592 | do { |
1566 | ret = nl80211_send_wiphy(dev, skb, | 1593 | ret = nl80211_send_wiphy(dev, skb, |
1567 | NETLINK_CB(cb->skb).portid, | 1594 | NETLINK_CB(cb->skb).portid, |
1568 | cb->nlh->nlmsg_seq, | 1595 | cb->nlh->nlmsg_seq, |
1569 | NLM_F_MULTI, | 1596 | NLM_F_MULTI, state); |
1570 | split, &cb->args[1], | ||
1571 | &cb->args[2], | ||
1572 | &cb->args[3]); | ||
1573 | if (ret < 0) { | 1597 | if (ret < 0) { |
1574 | /* | 1598 | /* |
1575 | * If sending the wiphy data didn't fit (ENOBUFS | 1599 | * If sending the wiphy data didn't fit (ENOBUFS |
@@ -1594,27 +1618,34 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | |||
1594 | idx--; | 1618 | idx--; |
1595 | break; | 1619 | break; |
1596 | } | 1620 | } |
1597 | } while (cb->args[1] > 0); | 1621 | } while (state->split_start > 0); |
1598 | break; | 1622 | break; |
1599 | } | 1623 | } |
1600 | rtnl_unlock(); | 1624 | rtnl_unlock(); |
1601 | 1625 | ||
1602 | cb->args[0] = idx; | 1626 | state->start = idx; |
1603 | 1627 | ||
1604 | return skb->len; | 1628 | return skb->len; |
1605 | } | 1629 | } |
1606 | 1630 | ||
1631 | static int nl80211_dump_wiphy_done(struct netlink_callback *cb) | ||
1632 | { | ||
1633 | kfree((void *)cb->args[0]); | ||
1634 | return 0; | ||
1635 | } | ||
1636 | |||
1607 | static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) | 1637 | static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) |
1608 | { | 1638 | { |
1609 | struct sk_buff *msg; | 1639 | struct sk_buff *msg; |
1610 | struct cfg80211_registered_device *dev = info->user_ptr[0]; | 1640 | struct cfg80211_registered_device *dev = info->user_ptr[0]; |
1641 | struct nl80211_dump_wiphy_state state = {}; | ||
1611 | 1642 | ||
1612 | msg = nlmsg_new(4096, GFP_KERNEL); | 1643 | msg = nlmsg_new(4096, GFP_KERNEL); |
1613 | if (!msg) | 1644 | if (!msg) |
1614 | return -ENOMEM; | 1645 | return -ENOMEM; |
1615 | 1646 | ||
1616 | if (nl80211_send_wiphy(dev, msg, info->snd_portid, info->snd_seq, 0, | 1647 | if (nl80211_send_wiphy(dev, msg, info->snd_portid, info->snd_seq, 0, |
1617 | false, NULL, NULL, NULL) < 0) { | 1648 | &state) < 0) { |
1618 | nlmsg_free(msg); | 1649 | nlmsg_free(msg); |
1619 | return -ENOBUFS; | 1650 | return -ENOBUFS; |
1620 | } | 1651 | } |
@@ -1731,6 +1762,11 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, | |||
1731 | IEEE80211_CHAN_DISABLED)) | 1762 | IEEE80211_CHAN_DISABLED)) |
1732 | return -EINVAL; | 1763 | return -EINVAL; |
1733 | 1764 | ||
1765 | if ((chandef->width == NL80211_CHAN_WIDTH_5 || | ||
1766 | chandef->width == NL80211_CHAN_WIDTH_10) && | ||
1767 | !(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ)) | ||
1768 | return -EINVAL; | ||
1769 | |||
1734 | return 0; | 1770 | return 0; |
1735 | } | 1771 | } |
1736 | 1772 | ||
@@ -2882,61 +2918,58 @@ static int nl80211_set_mac_acl(struct sk_buff *skb, struct genl_info *info) | |||
2882 | return err; | 2918 | return err; |
2883 | } | 2919 | } |
2884 | 2920 | ||
2885 | static int nl80211_parse_beacon(struct genl_info *info, | 2921 | static int nl80211_parse_beacon(struct nlattr *attrs[], |
2886 | struct cfg80211_beacon_data *bcn) | 2922 | struct cfg80211_beacon_data *bcn) |
2887 | { | 2923 | { |
2888 | bool haveinfo = false; | 2924 | bool haveinfo = false; |
2889 | 2925 | ||
2890 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]) || | 2926 | if (!is_valid_ie_attr(attrs[NL80211_ATTR_BEACON_TAIL]) || |
2891 | !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]) || | 2927 | !is_valid_ie_attr(attrs[NL80211_ATTR_IE]) || |
2892 | !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_PROBE_RESP]) || | 2928 | !is_valid_ie_attr(attrs[NL80211_ATTR_IE_PROBE_RESP]) || |
2893 | !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_ASSOC_RESP])) | 2929 | !is_valid_ie_attr(attrs[NL80211_ATTR_IE_ASSOC_RESP])) |
2894 | return -EINVAL; | 2930 | return -EINVAL; |
2895 | 2931 | ||
2896 | memset(bcn, 0, sizeof(*bcn)); | 2932 | memset(bcn, 0, sizeof(*bcn)); |
2897 | 2933 | ||
2898 | if (info->attrs[NL80211_ATTR_BEACON_HEAD]) { | 2934 | if (attrs[NL80211_ATTR_BEACON_HEAD]) { |
2899 | bcn->head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]); | 2935 | bcn->head = nla_data(attrs[NL80211_ATTR_BEACON_HEAD]); |
2900 | bcn->head_len = nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]); | 2936 | bcn->head_len = nla_len(attrs[NL80211_ATTR_BEACON_HEAD]); |
2901 | if (!bcn->head_len) | 2937 | if (!bcn->head_len) |
2902 | return -EINVAL; | 2938 | return -EINVAL; |
2903 | haveinfo = true; | 2939 | haveinfo = true; |
2904 | } | 2940 | } |
2905 | 2941 | ||
2906 | if (info->attrs[NL80211_ATTR_BEACON_TAIL]) { | 2942 | if (attrs[NL80211_ATTR_BEACON_TAIL]) { |
2907 | bcn->tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]); | 2943 | bcn->tail = nla_data(attrs[NL80211_ATTR_BEACON_TAIL]); |
2908 | bcn->tail_len = | 2944 | bcn->tail_len = nla_len(attrs[NL80211_ATTR_BEACON_TAIL]); |
2909 | nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]); | ||
2910 | haveinfo = true; | 2945 | haveinfo = true; |
2911 | } | 2946 | } |
2912 | 2947 | ||
2913 | if (!haveinfo) | 2948 | if (!haveinfo) |
2914 | return -EINVAL; | 2949 | return -EINVAL; |
2915 | 2950 | ||
2916 | if (info->attrs[NL80211_ATTR_IE]) { | 2951 | if (attrs[NL80211_ATTR_IE]) { |
2917 | bcn->beacon_ies = nla_data(info->attrs[NL80211_ATTR_IE]); | 2952 | bcn->beacon_ies = nla_data(attrs[NL80211_ATTR_IE]); |
2918 | bcn->beacon_ies_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 2953 | bcn->beacon_ies_len = nla_len(attrs[NL80211_ATTR_IE]); |
2919 | } | 2954 | } |
2920 | 2955 | ||
2921 | if (info->attrs[NL80211_ATTR_IE_PROBE_RESP]) { | 2956 | if (attrs[NL80211_ATTR_IE_PROBE_RESP]) { |
2922 | bcn->proberesp_ies = | 2957 | bcn->proberesp_ies = |
2923 | nla_data(info->attrs[NL80211_ATTR_IE_PROBE_RESP]); | 2958 | nla_data(attrs[NL80211_ATTR_IE_PROBE_RESP]); |
2924 | bcn->proberesp_ies_len = | 2959 | bcn->proberesp_ies_len = |
2925 | nla_len(info->attrs[NL80211_ATTR_IE_PROBE_RESP]); | 2960 | nla_len(attrs[NL80211_ATTR_IE_PROBE_RESP]); |
2926 | } | 2961 | } |
2927 | 2962 | ||
2928 | if (info->attrs[NL80211_ATTR_IE_ASSOC_RESP]) { | 2963 | if (attrs[NL80211_ATTR_IE_ASSOC_RESP]) { |
2929 | bcn->assocresp_ies = | 2964 | bcn->assocresp_ies = |
2930 | nla_data(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]); | 2965 | nla_data(attrs[NL80211_ATTR_IE_ASSOC_RESP]); |
2931 | bcn->assocresp_ies_len = | 2966 | bcn->assocresp_ies_len = |
2932 | nla_len(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]); | 2967 | nla_len(attrs[NL80211_ATTR_IE_ASSOC_RESP]); |
2933 | } | 2968 | } |
2934 | 2969 | ||
2935 | if (info->attrs[NL80211_ATTR_PROBE_RESP]) { | 2970 | if (attrs[NL80211_ATTR_PROBE_RESP]) { |
2936 | bcn->probe_resp = | 2971 | bcn->probe_resp = nla_data(attrs[NL80211_ATTR_PROBE_RESP]); |
2937 | nla_data(info->attrs[NL80211_ATTR_PROBE_RESP]); | 2972 | bcn->probe_resp_len = nla_len(attrs[NL80211_ATTR_PROBE_RESP]); |
2938 | bcn->probe_resp_len = | ||
2939 | nla_len(info->attrs[NL80211_ATTR_PROBE_RESP]); | ||
2940 | } | 2973 | } |
2941 | 2974 | ||
2942 | return 0; | 2975 | return 0; |
@@ -3015,7 +3048,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
3015 | !info->attrs[NL80211_ATTR_BEACON_HEAD]) | 3048 | !info->attrs[NL80211_ATTR_BEACON_HEAD]) |
3016 | return -EINVAL; | 3049 | return -EINVAL; |
3017 | 3050 | ||
3018 | err = nl80211_parse_beacon(info, ¶ms.beacon); | 3051 | err = nl80211_parse_beacon(info->attrs, ¶ms.beacon); |
3019 | if (err) | 3052 | if (err) |
3020 | return err; | 3053 | return err; |
3021 | 3054 | ||
@@ -3167,7 +3200,7 @@ static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info) | |||
3167 | if (!wdev->beacon_interval) | 3200 | if (!wdev->beacon_interval) |
3168 | return -EINVAL; | 3201 | return -EINVAL; |
3169 | 3202 | ||
3170 | err = nl80211_parse_beacon(info, ¶ms); | 3203 | err = nl80211_parse_beacon(info->attrs, ¶ms); |
3171 | if (err) | 3204 | if (err) |
3172 | return err; | 3205 | return err; |
3173 | 3206 | ||
@@ -6283,11 +6316,16 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
6283 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef)) | 6316 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef)) |
6284 | return -EINVAL; | 6317 | return -EINVAL; |
6285 | 6318 | ||
6286 | if (ibss.chandef.width > NL80211_CHAN_WIDTH_40) | 6319 | switch (ibss.chandef.width) { |
6287 | return -EINVAL; | 6320 | case NL80211_CHAN_WIDTH_20_NOHT: |
6288 | if (ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT && | 6321 | break; |
6289 | !(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS)) | 6322 | case NL80211_CHAN_WIDTH_20: |
6323 | case NL80211_CHAN_WIDTH_40: | ||
6324 | if (rdev->wiphy.features & NL80211_FEATURE_HT_IBSS) | ||
6325 | break; | ||
6326 | default: | ||
6290 | return -EINVAL; | 6327 | return -EINVAL; |
6328 | } | ||
6291 | 6329 | ||
6292 | ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; | 6330 | ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; |
6293 | ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; | 6331 | ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; |
@@ -8401,6 +8439,7 @@ static struct genl_ops nl80211_ops[] = { | |||
8401 | .cmd = NL80211_CMD_GET_WIPHY, | 8439 | .cmd = NL80211_CMD_GET_WIPHY, |
8402 | .doit = nl80211_get_wiphy, | 8440 | .doit = nl80211_get_wiphy, |
8403 | .dumpit = nl80211_dump_wiphy, | 8441 | .dumpit = nl80211_dump_wiphy, |
8442 | .done = nl80211_dump_wiphy_done, | ||
8404 | .policy = nl80211_policy, | 8443 | .policy = nl80211_policy, |
8405 | /* can be retrieved by unprivileged users */ | 8444 | /* can be retrieved by unprivileged users */ |
8406 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | 8445 | .internal_flags = NL80211_FLAG_NEED_WIPHY | |
@@ -9021,13 +9060,13 @@ static struct genl_multicast_group nl80211_regulatory_mcgrp = { | |||
9021 | void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) | 9060 | void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) |
9022 | { | 9061 | { |
9023 | struct sk_buff *msg; | 9062 | struct sk_buff *msg; |
9063 | struct nl80211_dump_wiphy_state state = {}; | ||
9024 | 9064 | ||
9025 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 9065 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
9026 | if (!msg) | 9066 | if (!msg) |
9027 | return; | 9067 | return; |
9028 | 9068 | ||
9029 | if (nl80211_send_wiphy(rdev, msg, 0, 0, 0, | 9069 | if (nl80211_send_wiphy(rdev, msg, 0, 0, 0, &state) < 0) { |
9030 | false, NULL, NULL, NULL) < 0) { | ||
9031 | nlmsg_free(msg); | 9070 | nlmsg_free(msg); |
9032 | return; | 9071 | return; |
9033 | } | 9072 | } |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index dd01b58fa78c..ae8c186b50d6 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -523,6 +523,7 @@ static int cmp_bss(struct cfg80211_bss *a, | |||
523 | } | 523 | } |
524 | } | 524 | } |
525 | 525 | ||
526 | /* Returned bss is reference counted and must be cleaned up appropriately. */ | ||
526 | struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, | 527 | struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, |
527 | struct ieee80211_channel *channel, | 528 | struct ieee80211_channel *channel, |
528 | const u8 *bssid, | 529 | const u8 *bssid, |
@@ -678,6 +679,7 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *dev, | |||
678 | return true; | 679 | return true; |
679 | } | 680 | } |
680 | 681 | ||
682 | /* Returned bss is reference counted and must be cleaned up appropriately. */ | ||
681 | static struct cfg80211_internal_bss * | 683 | static struct cfg80211_internal_bss * |
682 | cfg80211_bss_update(struct cfg80211_registered_device *dev, | 684 | cfg80211_bss_update(struct cfg80211_registered_device *dev, |
683 | struct cfg80211_internal_bss *tmp) | 685 | struct cfg80211_internal_bss *tmp) |
@@ -866,6 +868,7 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen, | |||
866 | return channel; | 868 | return channel; |
867 | } | 869 | } |
868 | 870 | ||
871 | /* Returned bss is reference counted and must be cleaned up appropriately. */ | ||
869 | struct cfg80211_bss* | 872 | struct cfg80211_bss* |
870 | cfg80211_inform_bss(struct wiphy *wiphy, | 873 | cfg80211_inform_bss(struct wiphy *wiphy, |
871 | struct ieee80211_channel *channel, | 874 | struct ieee80211_channel *channel, |
@@ -923,6 +926,7 @@ cfg80211_inform_bss(struct wiphy *wiphy, | |||
923 | } | 926 | } |
924 | EXPORT_SYMBOL(cfg80211_inform_bss); | 927 | EXPORT_SYMBOL(cfg80211_inform_bss); |
925 | 928 | ||
929 | /* Returned bss is reference counted and must be cleaned up appropriately. */ | ||
926 | struct cfg80211_bss * | 930 | struct cfg80211_bss * |
927 | cfg80211_inform_bss_frame(struct wiphy *wiphy, | 931 | cfg80211_inform_bss_frame(struct wiphy *wiphy, |
928 | struct ieee80211_channel *channel, | 932 | struct ieee80211_channel *channel, |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index ae7e2cbf45cb..1d3cfb1a3f28 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -239,6 +239,7 @@ void cfg80211_conn_work(struct work_struct *work) | |||
239 | rtnl_unlock(); | 239 | rtnl_unlock(); |
240 | } | 240 | } |
241 | 241 | ||
242 | /* Returned bss is reference counted and must be cleaned up appropriately. */ | ||
242 | static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev) | 243 | static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev) |
243 | { | 244 | { |
244 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 245 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
@@ -557,6 +558,7 @@ static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work); | |||
557 | * SME event handling | 558 | * SME event handling |
558 | */ | 559 | */ |
559 | 560 | ||
561 | /* This method must consume bss one way or another */ | ||
560 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | 562 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, |
561 | const u8 *req_ie, size_t req_ie_len, | 563 | const u8 *req_ie, size_t req_ie_len, |
562 | const u8 *resp_ie, size_t resp_ie_len, | 564 | const u8 *resp_ie, size_t resp_ie_len, |
@@ -572,8 +574,10 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
572 | ASSERT_WDEV_LOCK(wdev); | 574 | ASSERT_WDEV_LOCK(wdev); |
573 | 575 | ||
574 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION && | 576 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION && |
575 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) | 577 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) { |
578 | cfg80211_put_bss(wdev->wiphy, bss); | ||
576 | return; | 579 | return; |
580 | } | ||
577 | 581 | ||
578 | nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, | 582 | nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, |
579 | bssid, req_ie, req_ie_len, | 583 | bssid, req_ie, req_ie_len, |
@@ -615,19 +619,24 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
615 | kfree(wdev->connect_keys); | 619 | kfree(wdev->connect_keys); |
616 | wdev->connect_keys = NULL; | 620 | wdev->connect_keys = NULL; |
617 | wdev->ssid_len = 0; | 621 | wdev->ssid_len = 0; |
618 | cfg80211_put_bss(wdev->wiphy, bss); | 622 | if (bss) { |
623 | cfg80211_unhold_bss(bss_from_pub(bss)); | ||
624 | cfg80211_put_bss(wdev->wiphy, bss); | ||
625 | } | ||
619 | return; | 626 | return; |
620 | } | 627 | } |
621 | 628 | ||
622 | if (!bss) | 629 | if (!bss) { |
630 | WARN_ON_ONCE(!wiphy_to_dev(wdev->wiphy)->ops->connect); | ||
623 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, | 631 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, |
624 | wdev->ssid, wdev->ssid_len, | 632 | wdev->ssid, wdev->ssid_len, |
625 | WLAN_CAPABILITY_ESS, | 633 | WLAN_CAPABILITY_ESS, |
626 | WLAN_CAPABILITY_ESS); | 634 | WLAN_CAPABILITY_ESS); |
627 | if (WARN_ON(!bss)) | 635 | if (WARN_ON(!bss)) |
628 | return; | 636 | return; |
637 | cfg80211_hold_bss(bss_from_pub(bss)); | ||
638 | } | ||
629 | 639 | ||
630 | cfg80211_hold_bss(bss_from_pub(bss)); | ||
631 | wdev->current_bss = bss_from_pub(bss); | 640 | wdev->current_bss = bss_from_pub(bss); |
632 | 641 | ||
633 | cfg80211_upload_connect_keys(wdev); | 642 | cfg80211_upload_connect_keys(wdev); |
@@ -691,6 +700,7 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
691 | } | 700 | } |
692 | EXPORT_SYMBOL(cfg80211_connect_result); | 701 | EXPORT_SYMBOL(cfg80211_connect_result); |
693 | 702 | ||
703 | /* Consumes bss object one way or another */ | ||
694 | void __cfg80211_roamed(struct wireless_dev *wdev, | 704 | void __cfg80211_roamed(struct wireless_dev *wdev, |
695 | struct cfg80211_bss *bss, | 705 | struct cfg80211_bss *bss, |
696 | const u8 *req_ie, size_t req_ie_len, | 706 | const u8 *req_ie, size_t req_ie_len, |
@@ -767,6 +777,7 @@ void cfg80211_roamed(struct net_device *dev, | |||
767 | } | 777 | } |
768 | EXPORT_SYMBOL(cfg80211_roamed); | 778 | EXPORT_SYMBOL(cfg80211_roamed); |
769 | 779 | ||
780 | /* Consumes bss object one way or another */ | ||
770 | void cfg80211_roamed_bss(struct net_device *dev, | 781 | void cfg80211_roamed_bss(struct net_device *dev, |
771 | struct cfg80211_bss *bss, const u8 *req_ie, | 782 | struct cfg80211_bss *bss, const u8 *req_ie, |
772 | size_t req_ie_len, const u8 *resp_ie, | 783 | size_t req_ie_len, const u8 *resp_ie, |
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 360a42c6f694..a23253e06358 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c | |||
@@ -83,6 +83,7 @@ static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
83 | return 0; | 83 | return 0; |
84 | } | 84 | } |
85 | 85 | ||
86 | #ifdef CONFIG_PM | ||
86 | static void cfg80211_leave_all(struct cfg80211_registered_device *rdev) | 87 | static void cfg80211_leave_all(struct cfg80211_registered_device *rdev) |
87 | { | 88 | { |
88 | struct wireless_dev *wdev; | 89 | struct wireless_dev *wdev; |
@@ -91,7 +92,6 @@ static void cfg80211_leave_all(struct cfg80211_registered_device *rdev) | |||
91 | cfg80211_leave(rdev, wdev); | 92 | cfg80211_leave(rdev, wdev); |
92 | } | 93 | } |
93 | 94 | ||
94 | #ifdef CONFIG_PM | ||
95 | static int wiphy_suspend(struct device *dev, pm_message_t state) | 95 | static int wiphy_suspend(struct device *dev, pm_message_t state) |
96 | { | 96 | { |
97 | struct cfg80211_registered_device *rdev = dev_to_rdev(dev); | 97 | struct cfg80211_registered_device *rdev = dev_to_rdev(dev); |