diff options
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/cfg.c | 30 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 32 | ||||
-rw-r--r-- | net/mac80211/ibss.c | 74 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 21 | ||||
-rw-r--r-- | net/mac80211/iface.c | 49 | ||||
-rw-r--r-- | net/mac80211/key.c | 60 | ||||
-rw-r--r-- | net/mac80211/key.h | 3 | ||||
-rw-r--r-- | net/mac80211/main.c | 8 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 5 | ||||
-rw-r--r-- | net/mac80211/mesh_sync.c | 9 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 2 | ||||
-rw-r--r-- | net/mac80211/pm.c | 3 | ||||
-rw-r--r-- | net/mac80211/rx.c | 33 | ||||
-rw-r--r-- | net/mac80211/scan.c | 80 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 118 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 30 | ||||
-rw-r--r-- | net/mac80211/trace.h | 58 | ||||
-rw-r--r-- | net/mac80211/tx.c | 12 | ||||
-rw-r--r-- | net/mac80211/util.c | 34 |
19 files changed, 306 insertions, 355 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index f80e8c4c6bcd..ac185286842d 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -301,9 +301,10 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
301 | if (!sta) | 301 | if (!sta) |
302 | goto out; | 302 | goto out; |
303 | 303 | ||
304 | if (pairwise) | 304 | if (pairwise && key_idx < NUM_DEFAULT_KEYS) |
305 | key = rcu_dereference(sta->ptk[key_idx]); | 305 | key = rcu_dereference(sta->ptk[key_idx]); |
306 | else if (key_idx < NUM_DEFAULT_KEYS) | 306 | else if (!pairwise && |
307 | key_idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) | ||
307 | key = rcu_dereference(sta->gtk[key_idx]); | 308 | key = rcu_dereference(sta->gtk[key_idx]); |
308 | } else | 309 | } else |
309 | key = rcu_dereference(sdata->keys[key_idx]); | 310 | key = rcu_dereference(sdata->keys[key_idx]); |
@@ -873,8 +874,8 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
873 | return 0; | 874 | return 0; |
874 | } | 875 | } |
875 | 876 | ||
876 | int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, | 877 | static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, |
877 | struct cfg80211_beacon_data *params) | 878 | struct cfg80211_beacon_data *params) |
878 | { | 879 | { |
879 | struct beacon_data *new, *old; | 880 | struct beacon_data *new, *old; |
880 | int new_head_len, new_tail_len; | 881 | int new_head_len, new_tail_len; |
@@ -1097,17 +1098,8 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
1097 | if (old_probe_resp) | 1098 | if (old_probe_resp) |
1098 | kfree_rcu(old_probe_resp, rcu_head); | 1099 | kfree_rcu(old_probe_resp, rcu_head); |
1099 | 1100 | ||
1100 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | 1101 | __sta_info_flush(sdata, true); |
1101 | sta_info_flush_defer(vlan); | 1102 | ieee80211_free_keys(sdata, true); |
1102 | sta_info_flush_defer(sdata); | ||
1103 | synchronize_net(); | ||
1104 | rcu_barrier(); | ||
1105 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) { | ||
1106 | sta_info_flush_cleanup(vlan); | ||
1107 | ieee80211_free_keys(vlan); | ||
1108 | } | ||
1109 | sta_info_flush_cleanup(sdata); | ||
1110 | ieee80211_free_keys(sdata); | ||
1111 | 1103 | ||
1112 | sdata->vif.bss_conf.enable_beacon = false; | 1104 | sdata->vif.bss_conf.enable_beacon = false; |
1113 | sdata->vif.bss_conf.ssid_len = 0; | 1105 | sdata->vif.bss_conf.ssid_len = 0; |
@@ -2587,8 +2579,8 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, | |||
2587 | int j; | 2579 | int j; |
2588 | 2580 | ||
2589 | sdata->rc_rateidx_mask[i] = mask->control[i].legacy; | 2581 | sdata->rc_rateidx_mask[i] = mask->control[i].legacy; |
2590 | memcpy(sdata->rc_rateidx_mcs_mask[i], mask->control[i].mcs, | 2582 | memcpy(sdata->rc_rateidx_mcs_mask[i], mask->control[i].ht_mcs, |
2591 | sizeof(mask->control[i].mcs)); | 2583 | sizeof(mask->control[i].ht_mcs)); |
2592 | 2584 | ||
2593 | sdata->rc_has_mcs_mask[i] = false; | 2585 | sdata->rc_has_mcs_mask[i] = false; |
2594 | if (!sband) | 2586 | if (!sband) |
@@ -3047,8 +3039,8 @@ unlock: | |||
3047 | sdata_unlock(sdata); | 3039 | sdata_unlock(sdata); |
3048 | } | 3040 | } |
3049 | 3041 | ||
3050 | static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | 3042 | int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, |
3051 | struct cfg80211_csa_settings *params) | 3043 | struct cfg80211_csa_settings *params) |
3052 | { | 3044 | { |
3053 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 3045 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
3054 | struct ieee80211_local *local = sdata->local; | 3046 | struct ieee80211_local *local = sdata->local; |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 5d03c47c0a4c..ef8b385eff04 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -242,22 +242,6 @@ static inline u64 drv_prepare_multicast(struct ieee80211_local *local, | |||
242 | return ret; | 242 | return ret; |
243 | } | 243 | } |
244 | 244 | ||
245 | static inline void drv_set_multicast_list(struct ieee80211_local *local, | ||
246 | struct ieee80211_sub_if_data *sdata, | ||
247 | struct netdev_hw_addr_list *mc_list) | ||
248 | { | ||
249 | bool allmulti = sdata->flags & IEEE80211_SDATA_ALLMULTI; | ||
250 | |||
251 | trace_drv_set_multicast_list(local, sdata, mc_list->count); | ||
252 | |||
253 | check_sdata_in_driver(sdata); | ||
254 | |||
255 | if (local->ops->set_multicast_list) | ||
256 | local->ops->set_multicast_list(&local->hw, &sdata->vif, | ||
257 | allmulti, mc_list); | ||
258 | trace_drv_return_void(local); | ||
259 | } | ||
260 | |||
261 | static inline void drv_configure_filter(struct ieee80211_local *local, | 245 | static inline void drv_configure_filter(struct ieee80211_local *local, |
262 | unsigned int changed_flags, | 246 | unsigned int changed_flags, |
263 | unsigned int *total_flags, | 247 | unsigned int *total_flags, |
@@ -550,6 +534,22 @@ static inline void drv_sta_remove_debugfs(struct ieee80211_local *local, | |||
550 | } | 534 | } |
551 | #endif | 535 | #endif |
552 | 536 | ||
537 | static inline void drv_sta_pre_rcu_remove(struct ieee80211_local *local, | ||
538 | struct ieee80211_sub_if_data *sdata, | ||
539 | struct sta_info *sta) | ||
540 | { | ||
541 | might_sleep(); | ||
542 | |||
543 | sdata = get_bss_sdata(sdata); | ||
544 | check_sdata_in_driver(sdata); | ||
545 | |||
546 | trace_drv_sta_pre_rcu_remove(local, sdata, &sta->sta); | ||
547 | if (local->ops->sta_pre_rcu_remove) | ||
548 | local->ops->sta_pre_rcu_remove(&local->hw, &sdata->vif, | ||
549 | &sta->sta); | ||
550 | trace_drv_return_void(local); | ||
551 | } | ||
552 | |||
553 | static inline __must_check | 553 | static inline __must_check |
554 | int drv_sta_state(struct ieee80211_local *local, | 554 | int drv_sta_state(struct ieee80211_local *local, |
555 | struct ieee80211_sub_if_data *sdata, | 555 | struct ieee80211_sub_if_data *sdata, |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 2eda7b13124a..d6ba841437b6 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -522,7 +522,7 @@ int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata, | |||
522 | if (csa_settings) | 522 | if (csa_settings) |
523 | ieee80211_send_action_csa(sdata, csa_settings); | 523 | ieee80211_send_action_csa(sdata, csa_settings); |
524 | 524 | ||
525 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | 525 | return BSS_CHANGED_BEACON; |
526 | out: | 526 | out: |
527 | return ret; | 527 | return ret; |
528 | } | 528 | } |
@@ -534,7 +534,8 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata) | |||
534 | int err; | 534 | int err; |
535 | u16 capability; | 535 | u16 capability; |
536 | 536 | ||
537 | sdata_lock(sdata); | 537 | sdata_assert_lock(sdata); |
538 | |||
538 | /* update cfg80211 bss information with the new channel */ | 539 | /* update cfg80211 bss information with the new channel */ |
539 | if (!is_zero_ether_addr(ifibss->bssid)) { | 540 | if (!is_zero_ether_addr(ifibss->bssid)) { |
540 | capability = WLAN_CAPABILITY_IBSS; | 541 | capability = WLAN_CAPABILITY_IBSS; |
@@ -559,10 +560,12 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata) | |||
559 | 560 | ||
560 | /* generate the beacon */ | 561 | /* generate the beacon */ |
561 | err = ieee80211_ibss_csa_beacon(sdata, NULL); | 562 | err = ieee80211_ibss_csa_beacon(sdata, NULL); |
562 | sdata_unlock(sdata); | ||
563 | if (err < 0) | 563 | if (err < 0) |
564 | return err; | 564 | return err; |
565 | 565 | ||
566 | if (err) | ||
567 | ieee80211_bss_info_change_notify(sdata, err); | ||
568 | |||
566 | return 0; | 569 | return 0; |
567 | } | 570 | } |
568 | 571 | ||
@@ -753,12 +756,16 @@ static void ieee80211_csa_connection_drop_work(struct work_struct *work) | |||
753 | container_of(work, struct ieee80211_sub_if_data, | 756 | container_of(work, struct ieee80211_sub_if_data, |
754 | u.ibss.csa_connection_drop_work); | 757 | u.ibss.csa_connection_drop_work); |
755 | 758 | ||
759 | sdata_lock(sdata); | ||
760 | |||
756 | ieee80211_ibss_disconnect(sdata); | 761 | ieee80211_ibss_disconnect(sdata); |
757 | synchronize_rcu(); | 762 | synchronize_rcu(); |
758 | skb_queue_purge(&sdata->skb_queue); | 763 | skb_queue_purge(&sdata->skb_queue); |
759 | 764 | ||
760 | /* trigger a scan to find another IBSS network to join */ | 765 | /* trigger a scan to find another IBSS network to join */ |
761 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); | 766 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
767 | |||
768 | sdata_unlock(sdata); | ||
762 | } | 769 | } |
763 | 770 | ||
764 | static void ieee80211_ibss_csa_mark_radar(struct ieee80211_sub_if_data *sdata) | 771 | static void ieee80211_ibss_csa_mark_radar(struct ieee80211_sub_if_data *sdata) |
@@ -784,18 +791,10 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
784 | struct cfg80211_csa_settings params; | 791 | struct cfg80211_csa_settings params; |
785 | struct ieee80211_csa_ie csa_ie; | 792 | struct ieee80211_csa_ie csa_ie; |
786 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 793 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
787 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
788 | struct ieee80211_chanctx *chanctx; | ||
789 | enum nl80211_channel_type ch_type; | 794 | enum nl80211_channel_type ch_type; |
790 | int err, num_chanctx; | 795 | int err; |
791 | u32 sta_flags; | 796 | u32 sta_flags; |
792 | 797 | ||
793 | if (sdata->vif.csa_active) | ||
794 | return true; | ||
795 | |||
796 | if (!sdata->vif.bss_conf.ibss_joined) | ||
797 | return false; | ||
798 | |||
799 | sta_flags = IEEE80211_STA_DISABLE_VHT; | 798 | sta_flags = IEEE80211_STA_DISABLE_VHT; |
800 | switch (ifibss->chandef.width) { | 799 | switch (ifibss->chandef.width) { |
801 | case NL80211_CHAN_WIDTH_5: | 800 | case NL80211_CHAN_WIDTH_5: |
@@ -830,9 +829,6 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
830 | params.count = csa_ie.count; | 829 | params.count = csa_ie.count; |
831 | params.chandef = csa_ie.chandef; | 830 | params.chandef = csa_ie.chandef; |
832 | 831 | ||
833 | if (ifibss->chandef.chan->band != params.chandef.chan->band) | ||
834 | goto disconnect; | ||
835 | |||
836 | switch (ifibss->chandef.width) { | 832 | switch (ifibss->chandef.width) { |
837 | case NL80211_CHAN_WIDTH_20_NOHT: | 833 | case NL80211_CHAN_WIDTH_20_NOHT: |
838 | case NL80211_CHAN_WIDTH_20: | 834 | case NL80211_CHAN_WIDTH_20: |
@@ -888,28 +884,12 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
888 | params.radar_required = true; | 884 | params.radar_required = true; |
889 | } | 885 | } |
890 | 886 | ||
891 | rcu_read_lock(); | 887 | if (cfg80211_chandef_identical(¶ms.chandef, |
892 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 888 | &sdata->vif.bss_conf.chandef)) { |
893 | if (!chanctx_conf) { | 889 | ibss_dbg(sdata, |
894 | rcu_read_unlock(); | 890 | "received csa with an identical chandef, ignoring\n"); |
895 | goto disconnect; | 891 | return true; |
896 | } | ||
897 | |||
898 | /* don't handle for multi-VIF cases */ | ||
899 | chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf); | ||
900 | if (chanctx->refcount > 1) { | ||
901 | rcu_read_unlock(); | ||
902 | goto disconnect; | ||
903 | } | ||
904 | num_chanctx = 0; | ||
905 | list_for_each_entry_rcu(chanctx, &sdata->local->chanctx_list, list) | ||
906 | num_chanctx++; | ||
907 | |||
908 | if (num_chanctx > 1) { | ||
909 | rcu_read_unlock(); | ||
910 | goto disconnect; | ||
911 | } | 892 | } |
912 | rcu_read_unlock(); | ||
913 | 893 | ||
914 | /* all checks done, now perform the channel switch. */ | 894 | /* all checks done, now perform the channel switch. */ |
915 | ibss_dbg(sdata, | 895 | ibss_dbg(sdata, |
@@ -918,19 +898,9 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
918 | 898 | ||
919 | params.block_tx = !!csa_ie.mode; | 899 | params.block_tx = !!csa_ie.mode; |
920 | 900 | ||
921 | ieee80211_ibss_csa_beacon(sdata, ¶ms); | 901 | if (ieee80211_channel_switch(sdata->local->hw.wiphy, sdata->dev, |
922 | sdata->csa_radar_required = params.radar_required; | 902 | ¶ms)) |
923 | 903 | goto disconnect; | |
924 | if (params.block_tx) | ||
925 | ieee80211_stop_queues_by_reason(&sdata->local->hw, | ||
926 | IEEE80211_MAX_QUEUE_MAP, | ||
927 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
928 | |||
929 | sdata->csa_chandef = params.chandef; | ||
930 | sdata->vif.csa_active = true; | ||
931 | |||
932 | ieee80211_bss_info_change_notify(sdata, err); | ||
933 | drv_channel_switch_beacon(sdata, ¶ms.chandef); | ||
934 | 904 | ||
935 | ieee80211_ibss_csa_mark_radar(sdata); | 905 | ieee80211_ibss_csa_mark_radar(sdata); |
936 | 906 | ||
@@ -966,7 +936,8 @@ ieee80211_rx_mgmt_spectrum_mgmt(struct ieee80211_sub_if_data *sdata, | |||
966 | if (len < required_len) | 936 | if (len < required_len) |
967 | return; | 937 | return; |
968 | 938 | ||
969 | ieee80211_ibss_process_chanswitch(sdata, elems, false); | 939 | if (!sdata->vif.csa_active) |
940 | ieee80211_ibss_process_chanswitch(sdata, elems, false); | ||
970 | } | 941 | } |
971 | 942 | ||
972 | static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata, | 943 | static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata, |
@@ -1147,7 +1118,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1147 | goto put_bss; | 1118 | goto put_bss; |
1148 | 1119 | ||
1149 | /* process channel switch */ | 1120 | /* process channel switch */ |
1150 | if (ieee80211_ibss_process_chanswitch(sdata, elems, true)) | 1121 | if (sdata->vif.csa_active || |
1122 | ieee80211_ibss_process_chanswitch(sdata, elems, true)) | ||
1151 | goto put_bss; | 1123 | goto put_bss; |
1152 | 1124 | ||
1153 | /* same BSSID */ | 1125 | /* same BSSID */ |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ed5bf8b4b5c2..fb5dbcb79a12 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -232,6 +232,7 @@ struct ieee80211_rx_data { | |||
232 | struct beacon_data { | 232 | struct beacon_data { |
233 | u8 *head, *tail; | 233 | u8 *head, *tail; |
234 | int head_len, tail_len; | 234 | int head_len, tail_len; |
235 | struct ieee80211_meshconf_ie *meshconf; | ||
235 | struct rcu_head rcu_head; | 236 | struct rcu_head rcu_head; |
236 | }; | 237 | }; |
237 | 238 | ||
@@ -540,7 +541,10 @@ struct ieee80211_mesh_sync_ops { | |||
540 | struct ieee80211_mgmt *mgmt, | 541 | struct ieee80211_mgmt *mgmt, |
541 | struct ieee802_11_elems *elems, | 542 | struct ieee802_11_elems *elems, |
542 | struct ieee80211_rx_status *rx_status); | 543 | struct ieee80211_rx_status *rx_status); |
543 | void (*adjust_tbtt)(struct ieee80211_sub_if_data *sdata); | 544 | |
545 | /* should be called with beacon_data under RCU read lock */ | ||
546 | void (*adjust_tbtt)(struct ieee80211_sub_if_data *sdata, | ||
547 | struct beacon_data *beacon); | ||
544 | /* add other framework functions here */ | 548 | /* add other framework functions here */ |
545 | }; | 549 | }; |
546 | 550 | ||
@@ -614,6 +618,9 @@ struct ieee80211_if_mesh { | |||
614 | bool chsw_init; | 618 | bool chsw_init; |
615 | u8 chsw_ttl; | 619 | u8 chsw_ttl; |
616 | u16 pre_value; | 620 | u16 pre_value; |
621 | |||
622 | /* offset from skb->data while building IE */ | ||
623 | int meshconf_offset; | ||
617 | }; | 624 | }; |
618 | 625 | ||
619 | #ifdef CONFIG_MAC80211_MESH | 626 | #ifdef CONFIG_MAC80211_MESH |
@@ -776,10 +783,6 @@ struct ieee80211_sub_if_data { | |||
776 | u32 mntr_flags; | 783 | u32 mntr_flags; |
777 | } u; | 784 | } u; |
778 | 785 | ||
779 | spinlock_t cleanup_stations_lock; | ||
780 | struct list_head cleanup_stations; | ||
781 | struct work_struct cleanup_stations_wk; | ||
782 | |||
783 | #ifdef CONFIG_MAC80211_DEBUGFS | 786 | #ifdef CONFIG_MAC80211_DEBUGFS |
784 | struct { | 787 | struct { |
785 | struct dentry *subdir_stations; | 788 | struct dentry *subdir_stations; |
@@ -1117,6 +1120,7 @@ struct ieee80211_local { | |||
1117 | 1120 | ||
1118 | struct work_struct sched_scan_stopped_work; | 1121 | struct work_struct sched_scan_stopped_work; |
1119 | struct ieee80211_sub_if_data __rcu *sched_scan_sdata; | 1122 | struct ieee80211_sub_if_data __rcu *sched_scan_sdata; |
1123 | struct cfg80211_sched_scan_request *sched_scan_req; | ||
1120 | 1124 | ||
1121 | unsigned long leave_oper_channel_time; | 1125 | unsigned long leave_oper_channel_time; |
1122 | enum mac80211_scan_state next_scan_state; | 1126 | enum mac80211_scan_state next_scan_state; |
@@ -1425,6 +1429,9 @@ void ieee80211_rx_bss_put(struct ieee80211_local *local, | |||
1425 | struct ieee80211_bss *bss); | 1429 | struct ieee80211_bss *bss); |
1426 | 1430 | ||
1427 | /* scheduled scan handling */ | 1431 | /* scheduled scan handling */ |
1432 | int | ||
1433 | __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | ||
1434 | struct cfg80211_sched_scan_request *req); | ||
1428 | int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | 1435 | int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, |
1429 | struct cfg80211_sched_scan_request *req); | 1436 | struct cfg80211_sched_scan_request *req); |
1430 | int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata); | 1437 | int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata); |
@@ -1443,6 +1450,8 @@ void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc); | |||
1443 | 1450 | ||
1444 | /* channel switch handling */ | 1451 | /* channel switch handling */ |
1445 | void ieee80211_csa_finalize_work(struct work_struct *work); | 1452 | void ieee80211_csa_finalize_work(struct work_struct *work); |
1453 | int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | ||
1454 | struct cfg80211_csa_settings *params); | ||
1446 | 1455 | ||
1447 | /* interface handling */ | 1456 | /* interface handling */ |
1448 | int ieee80211_iface_init(void); | 1457 | int ieee80211_iface_init(void); |
@@ -1465,8 +1474,6 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local); | |||
1465 | 1474 | ||
1466 | bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata); | 1475 | bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata); |
1467 | void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata); | 1476 | void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata); |
1468 | int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, | ||
1469 | struct cfg80211_beacon_data *params); | ||
1470 | 1477 | ||
1471 | static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) | 1478 | static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) |
1472 | { | 1479 | { |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index a4f98123d0bf..d624ed49a7d9 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -786,10 +786,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
786 | * This is relevant only in WDS mode, in all other modes we've | 786 | * This is relevant only in WDS mode, in all other modes we've |
787 | * already removed all stations when disconnecting or similar, | 787 | * already removed all stations when disconnecting or similar, |
788 | * so warn otherwise. | 788 | * so warn otherwise. |
789 | * | ||
790 | * We call sta_info_flush_cleanup() later, to combine RCU waits. | ||
791 | */ | 789 | */ |
792 | flushed = sta_info_flush_defer(sdata); | 790 | flushed = sta_info_flush(sdata); |
793 | WARN_ON_ONCE((sdata->vif.type != NL80211_IFTYPE_WDS && flushed > 0) || | 791 | WARN_ON_ONCE((sdata->vif.type != NL80211_IFTYPE_WDS && flushed > 0) || |
794 | (sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1)); | 792 | (sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1)); |
795 | 793 | ||
@@ -891,23 +889,15 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
891 | cancel_work_sync(&sdata->work); | 889 | cancel_work_sync(&sdata->work); |
892 | /* | 890 | /* |
893 | * When we get here, the interface is marked down. | 891 | * When we get here, the interface is marked down. |
892 | * Free the remaining keys, if there are any | ||
893 | * (shouldn't be, except maybe in WDS mode?) | ||
894 | * | 894 | * |
895 | * sta_info_flush_cleanup() requires rcu_barrier() | 895 | * Force the key freeing to always synchronize_net() |
896 | * first to wait for the station call_rcu() calls | 896 | * to wait for the RX path in case it is using this |
897 | * to complete, and we also need synchronize_rcu() | 897 | * interface enqueuing frames * at this very time on |
898 | * to wait for the RX path in case it is using the | ||
899 | * interface and enqueuing frames at this very time on | ||
900 | * another CPU. | 898 | * another CPU. |
901 | */ | 899 | */ |
902 | synchronize_rcu(); | 900 | ieee80211_free_keys(sdata, true); |
903 | rcu_barrier(); | ||
904 | sta_info_flush_cleanup(sdata); | ||
905 | |||
906 | /* | ||
907 | * Free all remaining keys, there shouldn't be any, | ||
908 | * except maybe in WDS mode? | ||
909 | */ | ||
910 | ieee80211_free_keys(sdata); | ||
911 | 901 | ||
912 | /* fall through */ | 902 | /* fall through */ |
913 | case NL80211_IFTYPE_AP: | 903 | case NL80211_IFTYPE_AP: |
@@ -1018,17 +1008,6 @@ static void ieee80211_set_multicast_list(struct net_device *dev) | |||
1018 | atomic_dec(&local->iff_promiscs); | 1008 | atomic_dec(&local->iff_promiscs); |
1019 | sdata->flags ^= IEEE80211_SDATA_PROMISC; | 1009 | sdata->flags ^= IEEE80211_SDATA_PROMISC; |
1020 | } | 1010 | } |
1021 | |||
1022 | /* | ||
1023 | * TODO: If somebody needs this on AP interfaces, | ||
1024 | * it can be enabled easily but multicast | ||
1025 | * addresses from VLANs need to be synced. | ||
1026 | */ | ||
1027 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR && | ||
1028 | sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | ||
1029 | sdata->vif.type != NL80211_IFTYPE_AP) | ||
1030 | drv_set_multicast_list(local, sdata, &dev->mc); | ||
1031 | |||
1032 | spin_lock_bh(&local->filter_lock); | 1011 | spin_lock_bh(&local->filter_lock); |
1033 | __hw_addr_sync(&local->mc_list, &dev->mc, dev->addr_len); | 1012 | __hw_addr_sync(&local->mc_list, &dev->mc, dev->addr_len); |
1034 | spin_unlock_bh(&local->filter_lock); | 1013 | spin_unlock_bh(&local->filter_lock); |
@@ -1044,7 +1023,7 @@ static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata) | |||
1044 | int i; | 1023 | int i; |
1045 | 1024 | ||
1046 | /* free extra data */ | 1025 | /* free extra data */ |
1047 | ieee80211_free_keys(sdata); | 1026 | ieee80211_free_keys(sdata, false); |
1048 | 1027 | ||
1049 | ieee80211_debugfs_remove_netdev(sdata); | 1028 | ieee80211_debugfs_remove_netdev(sdata); |
1050 | 1029 | ||
@@ -1578,15 +1557,6 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, | |||
1578 | mutex_unlock(&local->iflist_mtx); | 1557 | mutex_unlock(&local->iflist_mtx); |
1579 | } | 1558 | } |
1580 | 1559 | ||
1581 | static void ieee80211_cleanup_sdata_stas_wk(struct work_struct *wk) | ||
1582 | { | ||
1583 | struct ieee80211_sub_if_data *sdata; | ||
1584 | |||
1585 | sdata = container_of(wk, struct ieee80211_sub_if_data, cleanup_stations_wk); | ||
1586 | |||
1587 | ieee80211_cleanup_sdata_stas(sdata); | ||
1588 | } | ||
1589 | |||
1590 | int ieee80211_if_add(struct ieee80211_local *local, const char *name, | 1560 | int ieee80211_if_add(struct ieee80211_local *local, const char *name, |
1591 | struct wireless_dev **new_wdev, enum nl80211_iftype type, | 1561 | struct wireless_dev **new_wdev, enum nl80211_iftype type, |
1592 | struct vif_params *params) | 1562 | struct vif_params *params) |
@@ -1659,9 +1629,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
1659 | 1629 | ||
1660 | INIT_LIST_HEAD(&sdata->key_list); | 1630 | INIT_LIST_HEAD(&sdata->key_list); |
1661 | 1631 | ||
1662 | spin_lock_init(&sdata->cleanup_stations_lock); | ||
1663 | INIT_LIST_HEAD(&sdata->cleanup_stations); | ||
1664 | INIT_WORK(&sdata->cleanup_stations_wk, ieee80211_cleanup_sdata_stas_wk); | ||
1665 | INIT_DELAYED_WORK(&sdata->dfs_cac_timer_work, | 1632 | INIT_DELAYED_WORK(&sdata->dfs_cac_timer_work, |
1666 | ieee80211_dfs_cac_timer_work); | 1633 | ieee80211_dfs_cac_timer_work); |
1667 | INIT_DELAYED_WORK(&sdata->dec_tailroom_needed_wk, | 1634 | INIT_DELAYED_WORK(&sdata->dec_tailroom_needed_wk, |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index e568d98167d0..6ff65a1ebaa9 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -589,14 +589,10 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw, | |||
589 | } | 589 | } |
590 | EXPORT_SYMBOL(ieee80211_iter_keys); | 590 | EXPORT_SYMBOL(ieee80211_iter_keys); |
591 | 591 | ||
592 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) | 592 | static void ieee80211_free_keys_iface(struct ieee80211_sub_if_data *sdata, |
593 | struct list_head *keys) | ||
593 | { | 594 | { |
594 | struct ieee80211_key *key, *tmp; | 595 | struct ieee80211_key *key, *tmp; |
595 | LIST_HEAD(keys); | ||
596 | |||
597 | cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk); | ||
598 | |||
599 | mutex_lock(&sdata->local->key_mtx); | ||
600 | 596 | ||
601 | sdata->crypto_tx_tailroom_needed_cnt -= | 597 | sdata->crypto_tx_tailroom_needed_cnt -= |
602 | sdata->crypto_tx_tailroom_pending_dec; | 598 | sdata->crypto_tx_tailroom_pending_dec; |
@@ -608,28 +604,51 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) | |||
608 | ieee80211_key_replace(key->sdata, key->sta, | 604 | ieee80211_key_replace(key->sdata, key->sta, |
609 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, | 605 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, |
610 | key, NULL); | 606 | key, NULL); |
611 | list_add_tail(&key->list, &keys); | 607 | list_add_tail(&key->list, keys); |
612 | } | 608 | } |
613 | 609 | ||
614 | ieee80211_debugfs_key_update_default(sdata); | 610 | ieee80211_debugfs_key_update_default(sdata); |
611 | } | ||
615 | 612 | ||
616 | if (!list_empty(&keys)) { | 613 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata, |
617 | synchronize_net(); | 614 | bool force_synchronize) |
618 | list_for_each_entry_safe(key, tmp, &keys, list) | 615 | { |
619 | __ieee80211_key_destroy(key, false); | 616 | struct ieee80211_local *local = sdata->local; |
617 | struct ieee80211_sub_if_data *vlan; | ||
618 | struct ieee80211_key *key, *tmp; | ||
619 | LIST_HEAD(keys); | ||
620 | |||
621 | cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk); | ||
622 | |||
623 | mutex_lock(&local->key_mtx); | ||
624 | |||
625 | ieee80211_free_keys_iface(sdata, &keys); | ||
626 | |||
627 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | ||
628 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | ||
629 | ieee80211_free_keys_iface(vlan, &keys); | ||
620 | } | 630 | } |
621 | 631 | ||
632 | if (!list_empty(&keys) || force_synchronize) | ||
633 | synchronize_net(); | ||
634 | list_for_each_entry_safe(key, tmp, &keys, list) | ||
635 | __ieee80211_key_destroy(key, false); | ||
636 | |||
622 | WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt || | 637 | WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt || |
623 | sdata->crypto_tx_tailroom_pending_dec); | 638 | sdata->crypto_tx_tailroom_pending_dec); |
639 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | ||
640 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | ||
641 | WARN_ON_ONCE(vlan->crypto_tx_tailroom_needed_cnt || | ||
642 | vlan->crypto_tx_tailroom_pending_dec); | ||
643 | } | ||
624 | 644 | ||
625 | mutex_unlock(&sdata->local->key_mtx); | 645 | mutex_unlock(&local->key_mtx); |
626 | } | 646 | } |
627 | 647 | ||
628 | void ieee80211_free_sta_keys(struct ieee80211_local *local, | 648 | void ieee80211_free_sta_keys(struct ieee80211_local *local, |
629 | struct sta_info *sta) | 649 | struct sta_info *sta) |
630 | { | 650 | { |
631 | struct ieee80211_key *key, *tmp; | 651 | struct ieee80211_key *key; |
632 | LIST_HEAD(keys); | ||
633 | int i; | 652 | int i; |
634 | 653 | ||
635 | mutex_lock(&local->key_mtx); | 654 | mutex_lock(&local->key_mtx); |
@@ -640,7 +659,7 @@ void ieee80211_free_sta_keys(struct ieee80211_local *local, | |||
640 | ieee80211_key_replace(key->sdata, key->sta, | 659 | ieee80211_key_replace(key->sdata, key->sta, |
641 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, | 660 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, |
642 | key, NULL); | 661 | key, NULL); |
643 | list_add(&key->list, &keys); | 662 | __ieee80211_key_destroy(key, true); |
644 | } | 663 | } |
645 | 664 | ||
646 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) { | 665 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) { |
@@ -650,17 +669,8 @@ void ieee80211_free_sta_keys(struct ieee80211_local *local, | |||
650 | ieee80211_key_replace(key->sdata, key->sta, | 669 | ieee80211_key_replace(key->sdata, key->sta, |
651 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, | 670 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, |
652 | key, NULL); | 671 | key, NULL); |
653 | list_add(&key->list, &keys); | ||
654 | } | ||
655 | |||
656 | /* | ||
657 | * NB: the station code relies on this being | ||
658 | * done even if there aren't any keys | ||
659 | */ | ||
660 | synchronize_net(); | ||
661 | |||
662 | list_for_each_entry_safe(key, tmp, &keys, list) | ||
663 | __ieee80211_key_destroy(key, true); | 672 | __ieee80211_key_destroy(key, true); |
673 | } | ||
664 | 674 | ||
665 | mutex_unlock(&local->key_mtx); | 675 | mutex_unlock(&local->key_mtx); |
666 | } | 676 | } |
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 0aebb889caba..19db68663d75 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -136,7 +136,8 @@ void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, | |||
136 | bool uni, bool multi); | 136 | bool uni, bool multi); |
137 | void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, | 137 | void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, |
138 | int idx); | 138 | int idx); |
139 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); | 139 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata, |
140 | bool force_synchronize); | ||
140 | void ieee80211_free_sta_keys(struct ieee80211_local *local, | 141 | void ieee80211_free_sta_keys(struct ieee80211_local *local, |
141 | struct sta_info *sta); | 142 | struct sta_info *sta); |
142 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); | 143 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index fa34cd2344b9..2bd5b552b2f6 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -250,12 +250,8 @@ static void ieee80211_restart_work(struct work_struct *work) | |||
250 | /* wait for scan work complete */ | 250 | /* wait for scan work complete */ |
251 | flush_workqueue(local->workqueue); | 251 | flush_workqueue(local->workqueue); |
252 | 252 | ||
253 | mutex_lock(&local->mtx); | 253 | WARN(test_bit(SCAN_HW_SCANNING, &local->scanning), |
254 | WARN(test_bit(SCAN_HW_SCANNING, &local->scanning) || | 254 | "%s called with hardware scan in progress\n", __func__); |
255 | rcu_dereference_protected(local->sched_scan_sdata, | ||
256 | lockdep_is_held(&local->mtx)), | ||
257 | "%s called with hardware scan in progress\n", __func__); | ||
258 | mutex_unlock(&local->mtx); | ||
259 | 255 | ||
260 | rtnl_lock(); | 256 | rtnl_lock(); |
261 | ieee80211_scan_cancel(local); | 257 | ieee80211_scan_cancel(local); |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 89df62b2b689..5a74b249ba35 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -259,6 +259,9 @@ int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata, | |||
259 | *pos++ = WLAN_EID_MESH_CONFIG; | 259 | *pos++ = WLAN_EID_MESH_CONFIG; |
260 | *pos++ = meshconf_len; | 260 | *pos++ = meshconf_len; |
261 | 261 | ||
262 | /* save a pointer for quick updates in pre-tbtt */ | ||
263 | ifmsh->meshconf_offset = pos - skb->data; | ||
264 | |||
262 | /* Active path selection protocol ID */ | 265 | /* Active path selection protocol ID */ |
263 | *pos++ = ifmsh->mesh_pp_id; | 266 | *pos++ = ifmsh->mesh_pp_id; |
264 | /* Active path selection metric ID */ | 267 | /* Active path selection metric ID */ |
@@ -723,6 +726,8 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) | |||
723 | 726 | ||
724 | bcn->tail_len = skb->len; | 727 | bcn->tail_len = skb->len; |
725 | memcpy(bcn->tail, skb->data, bcn->tail_len); | 728 | memcpy(bcn->tail, skb->data, bcn->tail_len); |
729 | bcn->meshconf = (struct ieee80211_meshconf_ie *) | ||
730 | (bcn->tail + ifmsh->meshconf_offset); | ||
726 | 731 | ||
727 | dev_kfree_skb(skb); | 732 | dev_kfree_skb(skb); |
728 | rcu_assign_pointer(ifmsh->beacon, bcn); | 733 | rcu_assign_pointer(ifmsh->beacon, bcn); |
diff --git a/net/mac80211/mesh_sync.c b/net/mac80211/mesh_sync.c index d1cf2d553499..2bc5dc25d5ad 100644 --- a/net/mac80211/mesh_sync.c +++ b/net/mac80211/mesh_sync.c | |||
@@ -164,12 +164,15 @@ no_sync: | |||
164 | rcu_read_unlock(); | 164 | rcu_read_unlock(); |
165 | } | 165 | } |
166 | 166 | ||
167 | static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata) | 167 | static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata, |
168 | struct beacon_data *beacon) | ||
168 | { | 169 | { |
169 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 170 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
171 | u8 cap; | ||
170 | 172 | ||
171 | WARN_ON(ifmsh->mesh_sp_id != IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET); | 173 | WARN_ON(ifmsh->mesh_sp_id != IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET); |
172 | BUG_ON(!rcu_read_lock_held()); | 174 | BUG_ON(!rcu_read_lock_held()); |
175 | cap = beacon->meshconf->meshconf_cap; | ||
173 | 176 | ||
174 | spin_lock_bh(&ifmsh->sync_offset_lock); | 177 | spin_lock_bh(&ifmsh->sync_offset_lock); |
175 | 178 | ||
@@ -194,6 +197,10 @@ static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata) | |||
194 | ifmsh->adjusting_tbtt = false; | 197 | ifmsh->adjusting_tbtt = false; |
195 | } | 198 | } |
196 | spin_unlock_bh(&ifmsh->sync_offset_lock); | 199 | spin_unlock_bh(&ifmsh->sync_offset_lock); |
200 | |||
201 | beacon->meshconf->meshconf_cap = ifmsh->adjusting_tbtt ? | ||
202 | IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING | cap : | ||
203 | ~IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING & cap; | ||
197 | } | 204 | } |
198 | 205 | ||
199 | static const struct sync_method sync_methods[] = { | 206 | static const struct sync_method sync_methods[] = { |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 900ead344f5b..9c2c7ee2cc30 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -1698,7 +1698,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1698 | memset(ifmgd->bssid, 0, ETH_ALEN); | 1698 | memset(ifmgd->bssid, 0, ETH_ALEN); |
1699 | 1699 | ||
1700 | /* remove AP and TDLS peers */ | 1700 | /* remove AP and TDLS peers */ |
1701 | sta_info_flush_defer(sdata); | 1701 | sta_info_flush(sdata); |
1702 | 1702 | ||
1703 | /* finally reset all BSS / config parameters */ | 1703 | /* finally reset all BSS / config parameters */ |
1704 | changed |= ieee80211_reset_erp_info(sdata); | 1704 | changed |= ieee80211_reset_erp_info(sdata); |
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 340126204343..af64fb8e8add 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -37,9 +37,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
37 | IEEE80211_MAX_QUEUE_MAP, | 37 | IEEE80211_MAX_QUEUE_MAP, |
38 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 38 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); |
39 | 39 | ||
40 | /* flush out all packets and station cleanup call_rcu()s */ | 40 | /* flush out all packets */ |
41 | synchronize_net(); | 41 | synchronize_net(); |
42 | rcu_barrier(); | ||
43 | 42 | ||
44 | ieee80211_flush_queues(local, NULL); | 43 | ieee80211_flush_queues(local, NULL); |
45 | 44 | ||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 2dfa75522733..5a2afe9583a8 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1963,20 +1963,17 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) | |||
1963 | } | 1963 | } |
1964 | } | 1964 | } |
1965 | 1965 | ||
1966 | if (skb) { | ||
1967 | int align __maybe_unused; | ||
1968 | |||
1969 | #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS | 1966 | #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS |
1970 | /* | 1967 | if (skb) { |
1971 | * 'align' will only take the values 0 or 2 here | 1968 | /* 'align' will only take the values 0 or 2 here since all |
1972 | * since all frames are required to be aligned | 1969 | * frames are required to be aligned to 2-byte boundaries |
1973 | * to 2-byte boundaries when being passed to | 1970 | * when being passed to mac80211; the code here works just |
1974 | * mac80211; the code here works just as well if | 1971 | * as well if that isn't true, but mac80211 assumes it can |
1975 | * that isn't true, but mac80211 assumes it can | 1972 | * access fields as 2-byte aligned (e.g. for ether_addr_equal) |
1976 | * access fields as 2-byte aligned (e.g. for | ||
1977 | * compare_ether_addr) | ||
1978 | */ | 1973 | */ |
1979 | align = ((unsigned long)(skb->data + sizeof(struct ethhdr))) & 3; | 1974 | int align; |
1975 | |||
1976 | align = (unsigned long)(skb->data + sizeof(struct ethhdr)) & 3; | ||
1980 | if (align) { | 1977 | if (align) { |
1981 | if (WARN_ON(skb_headroom(skb) < 3)) { | 1978 | if (WARN_ON(skb_headroom(skb) < 3)) { |
1982 | dev_kfree_skb(skb); | 1979 | dev_kfree_skb(skb); |
@@ -1989,14 +1986,14 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) | |||
1989 | skb_set_tail_pointer(skb, len); | 1986 | skb_set_tail_pointer(skb, len); |
1990 | } | 1987 | } |
1991 | } | 1988 | } |
1989 | } | ||
1992 | #endif | 1990 | #endif |
1993 | 1991 | ||
1994 | if (skb) { | 1992 | if (skb) { |
1995 | /* deliver to local stack */ | 1993 | /* deliver to local stack */ |
1996 | skb->protocol = eth_type_trans(skb, dev); | 1994 | skb->protocol = eth_type_trans(skb, dev); |
1997 | memset(skb->cb, 0, sizeof(skb->cb)); | 1995 | memset(skb->cb, 0, sizeof(skb->cb)); |
1998 | netif_receive_skb(skb); | 1996 | netif_receive_skb(skb); |
1999 | } | ||
2000 | } | 1997 | } |
2001 | 1998 | ||
2002 | if (xmit_skb) { | 1999 | if (xmit_skb) { |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 4d73c46df862..88c81616f8f7 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -271,10 +271,11 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) | |||
271 | return true; | 271 | return true; |
272 | } | 272 | } |
273 | 273 | ||
274 | static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, | 274 | static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) |
275 | bool was_hw_scan) | ||
276 | { | 275 | { |
277 | struct ieee80211_local *local = hw_to_local(hw); | 276 | struct ieee80211_local *local = hw_to_local(hw); |
277 | bool hw_scan = local->ops->hw_scan; | ||
278 | bool was_scanning = local->scanning; | ||
278 | 279 | ||
279 | lockdep_assert_held(&local->mtx); | 280 | lockdep_assert_held(&local->mtx); |
280 | 281 | ||
@@ -290,7 +291,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, | |||
290 | if (WARN_ON(!local->scan_req)) | 291 | if (WARN_ON(!local->scan_req)) |
291 | return; | 292 | return; |
292 | 293 | ||
293 | if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { | 294 | if (hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { |
294 | int rc; | 295 | int rc; |
295 | 296 | ||
296 | rc = drv_hw_scan(local, | 297 | rc = drv_hw_scan(local, |
@@ -316,7 +317,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, | |||
316 | /* Set power back to normal operating levels. */ | 317 | /* Set power back to normal operating levels. */ |
317 | ieee80211_hw_config(local, 0); | 318 | ieee80211_hw_config(local, 0); |
318 | 319 | ||
319 | if (!was_hw_scan) { | 320 | if (!hw_scan) { |
320 | ieee80211_configure_filter(local); | 321 | ieee80211_configure_filter(local); |
321 | drv_sw_scan_complete(local); | 322 | drv_sw_scan_complete(local); |
322 | ieee80211_offchannel_return(local); | 323 | ieee80211_offchannel_return(local); |
@@ -327,7 +328,8 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, | |||
327 | ieee80211_mlme_notify_scan_completed(local); | 328 | ieee80211_mlme_notify_scan_completed(local); |
328 | ieee80211_ibss_notify_scan_completed(local); | 329 | ieee80211_ibss_notify_scan_completed(local); |
329 | ieee80211_mesh_notify_scan_completed(local); | 330 | ieee80211_mesh_notify_scan_completed(local); |
330 | ieee80211_start_next_roc(local); | 331 | if (was_scanning) |
332 | ieee80211_start_next_roc(local); | ||
331 | } | 333 | } |
332 | 334 | ||
333 | void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | 335 | void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) |
@@ -747,7 +749,7 @@ void ieee80211_scan_work(struct work_struct *work) | |||
747 | container_of(work, struct ieee80211_local, scan_work.work); | 749 | container_of(work, struct ieee80211_local, scan_work.work); |
748 | struct ieee80211_sub_if_data *sdata; | 750 | struct ieee80211_sub_if_data *sdata; |
749 | unsigned long next_delay = 0; | 751 | unsigned long next_delay = 0; |
750 | bool aborted, hw_scan; | 752 | bool aborted; |
751 | 753 | ||
752 | mutex_lock(&local->mtx); | 754 | mutex_lock(&local->mtx); |
753 | 755 | ||
@@ -786,14 +788,6 @@ void ieee80211_scan_work(struct work_struct *work) | |||
786 | } | 788 | } |
787 | 789 | ||
788 | /* | 790 | /* |
789 | * Avoid re-scheduling when the sdata is going away. | ||
790 | */ | ||
791 | if (!ieee80211_sdata_running(sdata)) { | ||
792 | aborted = true; | ||
793 | goto out_complete; | ||
794 | } | ||
795 | |||
796 | /* | ||
797 | * as long as no delay is required advance immediately | 791 | * as long as no delay is required advance immediately |
798 | * without scheduling a new work | 792 | * without scheduling a new work |
799 | */ | 793 | */ |
@@ -834,8 +828,7 @@ void ieee80211_scan_work(struct work_struct *work) | |||
834 | goto out; | 828 | goto out; |
835 | 829 | ||
836 | out_complete: | 830 | out_complete: |
837 | hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning); | 831 | __ieee80211_scan_completed(&local->hw, aborted); |
838 | __ieee80211_scan_completed(&local->hw, aborted, hw_scan); | ||
839 | out: | 832 | out: |
840 | mutex_unlock(&local->mtx); | 833 | mutex_unlock(&local->mtx); |
841 | } | 834 | } |
@@ -973,13 +966,13 @@ void ieee80211_scan_cancel(struct ieee80211_local *local) | |||
973 | */ | 966 | */ |
974 | cancel_delayed_work(&local->scan_work); | 967 | cancel_delayed_work(&local->scan_work); |
975 | /* and clean up */ | 968 | /* and clean up */ |
976 | __ieee80211_scan_completed(&local->hw, true, false); | 969 | __ieee80211_scan_completed(&local->hw, true); |
977 | out: | 970 | out: |
978 | mutex_unlock(&local->mtx); | 971 | mutex_unlock(&local->mtx); |
979 | } | 972 | } |
980 | 973 | ||
981 | int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | 974 | int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, |
982 | struct cfg80211_sched_scan_request *req) | 975 | struct cfg80211_sched_scan_request *req) |
983 | { | 976 | { |
984 | struct ieee80211_local *local = sdata->local; | 977 | struct ieee80211_local *local = sdata->local; |
985 | struct ieee80211_sched_scan_ies sched_scan_ies = {}; | 978 | struct ieee80211_sched_scan_ies sched_scan_ies = {}; |
@@ -989,17 +982,10 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | |||
989 | iebufsz = 2 + IEEE80211_MAX_SSID_LEN + | 982 | iebufsz = 2 + IEEE80211_MAX_SSID_LEN + |
990 | local->scan_ies_len + req->ie_len; | 983 | local->scan_ies_len + req->ie_len; |
991 | 984 | ||
992 | mutex_lock(&local->mtx); | 985 | lockdep_assert_held(&local->mtx); |
993 | |||
994 | if (rcu_access_pointer(local->sched_scan_sdata)) { | ||
995 | ret = -EBUSY; | ||
996 | goto out; | ||
997 | } | ||
998 | 986 | ||
999 | if (!local->ops->sched_scan_start) { | 987 | if (!local->ops->sched_scan_start) |
1000 | ret = -ENOTSUPP; | 988 | return -ENOTSUPP; |
1001 | goto out; | ||
1002 | } | ||
1003 | 989 | ||
1004 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | 990 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { |
1005 | if (!local->hw.wiphy->bands[i]) | 991 | if (!local->hw.wiphy->bands[i]) |
@@ -1020,13 +1006,39 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | |||
1020 | } | 1006 | } |
1021 | 1007 | ||
1022 | ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); | 1008 | ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); |
1023 | if (ret == 0) | 1009 | if (ret == 0) { |
1024 | rcu_assign_pointer(local->sched_scan_sdata, sdata); | 1010 | rcu_assign_pointer(local->sched_scan_sdata, sdata); |
1011 | local->sched_scan_req = req; | ||
1012 | } | ||
1025 | 1013 | ||
1026 | out_free: | 1014 | out_free: |
1027 | while (i > 0) | 1015 | while (i > 0) |
1028 | kfree(sched_scan_ies.ie[--i]); | 1016 | kfree(sched_scan_ies.ie[--i]); |
1029 | out: | 1017 | |
1018 | if (ret) { | ||
1019 | /* Clean in case of failure after HW restart or upon resume. */ | ||
1020 | rcu_assign_pointer(local->sched_scan_sdata, NULL); | ||
1021 | local->sched_scan_req = NULL; | ||
1022 | } | ||
1023 | |||
1024 | return ret; | ||
1025 | } | ||
1026 | |||
1027 | int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | ||
1028 | struct cfg80211_sched_scan_request *req) | ||
1029 | { | ||
1030 | struct ieee80211_local *local = sdata->local; | ||
1031 | int ret; | ||
1032 | |||
1033 | mutex_lock(&local->mtx); | ||
1034 | |||
1035 | if (rcu_access_pointer(local->sched_scan_sdata)) { | ||
1036 | mutex_unlock(&local->mtx); | ||
1037 | return -EBUSY; | ||
1038 | } | ||
1039 | |||
1040 | ret = __ieee80211_request_sched_scan_start(sdata, req); | ||
1041 | |||
1030 | mutex_unlock(&local->mtx); | 1042 | mutex_unlock(&local->mtx); |
1031 | return ret; | 1043 | return ret; |
1032 | } | 1044 | } |
@@ -1043,6 +1055,9 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata) | |||
1043 | goto out; | 1055 | goto out; |
1044 | } | 1056 | } |
1045 | 1057 | ||
1058 | /* We don't want to restart sched scan anymore. */ | ||
1059 | local->sched_scan_req = NULL; | ||
1060 | |||
1046 | if (rcu_access_pointer(local->sched_scan_sdata)) | 1061 | if (rcu_access_pointer(local->sched_scan_sdata)) |
1047 | drv_sched_scan_stop(local, sdata); | 1062 | drv_sched_scan_stop(local, sdata); |
1048 | 1063 | ||
@@ -1077,6 +1092,9 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work) | |||
1077 | 1092 | ||
1078 | rcu_assign_pointer(local->sched_scan_sdata, NULL); | 1093 | rcu_assign_pointer(local->sched_scan_sdata, NULL); |
1079 | 1094 | ||
1095 | /* If sched scan was aborted by the driver. */ | ||
1096 | local->sched_scan_req = NULL; | ||
1097 | |||
1080 | mutex_unlock(&local->mtx); | 1098 | mutex_unlock(&local->mtx); |
1081 | 1099 | ||
1082 | cfg80211_sched_scan_stopped(local->hw.wiphy); | 1100 | cfg80211_sched_scan_stopped(local->hw.wiphy); |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 8ed97f76c3cf..4576ba0ff221 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -99,23 +99,6 @@ static void cleanup_single_sta(struct sta_info *sta) | |||
99 | struct ieee80211_local *local = sdata->local; | 99 | struct ieee80211_local *local = sdata->local; |
100 | struct ps_data *ps; | 100 | struct ps_data *ps; |
101 | 101 | ||
102 | /* | ||
103 | * At this point, when being called as call_rcu callback, | ||
104 | * neither mac80211 nor the driver can reference this | ||
105 | * sta struct any more except by still existing timers | ||
106 | * associated with this station that we clean up below. | ||
107 | * | ||
108 | * Note though that this still uses the sdata and even | ||
109 | * calls the driver in AP and mesh mode, so interfaces | ||
110 | * of those types mush use call sta_info_flush_cleanup() | ||
111 | * (typically via sta_info_flush()) before deconfiguring | ||
112 | * the driver. | ||
113 | * | ||
114 | * In station mode, nothing happens here so it doesn't | ||
115 | * have to (and doesn't) do that, this is intentional to | ||
116 | * speed up roaming. | ||
117 | */ | ||
118 | |||
119 | if (test_sta_flag(sta, WLAN_STA_PS_STA)) { | 102 | if (test_sta_flag(sta, WLAN_STA_PS_STA)) { |
120 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP || | 103 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP || |
121 | sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 104 | sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
@@ -160,37 +143,6 @@ static void cleanup_single_sta(struct sta_info *sta) | |||
160 | sta_info_free(local, sta); | 143 | sta_info_free(local, sta); |
161 | } | 144 | } |
162 | 145 | ||
163 | void ieee80211_cleanup_sdata_stas(struct ieee80211_sub_if_data *sdata) | ||
164 | { | ||
165 | struct sta_info *sta; | ||
166 | |||
167 | spin_lock_bh(&sdata->cleanup_stations_lock); | ||
168 | while (!list_empty(&sdata->cleanup_stations)) { | ||
169 | sta = list_first_entry(&sdata->cleanup_stations, | ||
170 | struct sta_info, list); | ||
171 | list_del(&sta->list); | ||
172 | spin_unlock_bh(&sdata->cleanup_stations_lock); | ||
173 | |||
174 | cleanup_single_sta(sta); | ||
175 | |||
176 | spin_lock_bh(&sdata->cleanup_stations_lock); | ||
177 | } | ||
178 | |||
179 | spin_unlock_bh(&sdata->cleanup_stations_lock); | ||
180 | } | ||
181 | |||
182 | static void free_sta_rcu(struct rcu_head *h) | ||
183 | { | ||
184 | struct sta_info *sta = container_of(h, struct sta_info, rcu_head); | ||
185 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
186 | |||
187 | spin_lock(&sdata->cleanup_stations_lock); | ||
188 | list_add_tail(&sta->list, &sdata->cleanup_stations); | ||
189 | spin_unlock(&sdata->cleanup_stations_lock); | ||
190 | |||
191 | ieee80211_queue_work(&sdata->local->hw, &sdata->cleanup_stations_wk); | ||
192 | } | ||
193 | |||
194 | /* protected by RCU */ | 146 | /* protected by RCU */ |
195 | struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, | 147 | struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, |
196 | const u8 *addr) | 148 | const u8 *addr) |
@@ -842,7 +794,7 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, | |||
842 | return have_buffered; | 794 | return have_buffered; |
843 | } | 795 | } |
844 | 796 | ||
845 | int __must_check __sta_info_destroy(struct sta_info *sta) | 797 | static int __must_check __sta_info_destroy_part1(struct sta_info *sta) |
846 | { | 798 | { |
847 | struct ieee80211_local *local; | 799 | struct ieee80211_local *local; |
848 | struct ieee80211_sub_if_data *sdata; | 800 | struct ieee80211_sub_if_data *sdata; |
@@ -868,12 +820,35 @@ int __must_check __sta_info_destroy(struct sta_info *sta) | |||
868 | ieee80211_sta_tear_down_BA_sessions(sta, AGG_STOP_DESTROY_STA); | 820 | ieee80211_sta_tear_down_BA_sessions(sta, AGG_STOP_DESTROY_STA); |
869 | 821 | ||
870 | ret = sta_info_hash_del(local, sta); | 822 | ret = sta_info_hash_del(local, sta); |
871 | if (ret) | 823 | if (WARN_ON(ret)) |
872 | return ret; | 824 | return ret; |
873 | 825 | ||
874 | list_del_rcu(&sta->list); | 826 | list_del_rcu(&sta->list); |
875 | 827 | ||
876 | /* this always calls synchronize_net() */ | 828 | drv_sta_pre_rcu_remove(local, sta->sdata, sta); |
829 | |||
830 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && | ||
831 | rcu_access_pointer(sdata->u.vlan.sta) == sta) | ||
832 | RCU_INIT_POINTER(sdata->u.vlan.sta, NULL); | ||
833 | |||
834 | return 0; | ||
835 | } | ||
836 | |||
837 | static void __sta_info_destroy_part2(struct sta_info *sta) | ||
838 | { | ||
839 | struct ieee80211_local *local = sta->local; | ||
840 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
841 | int ret; | ||
842 | |||
843 | /* | ||
844 | * NOTE: This assumes at least synchronize_net() was done | ||
845 | * after _part1 and before _part2! | ||
846 | */ | ||
847 | |||
848 | might_sleep(); | ||
849 | lockdep_assert_held(&local->sta_mtx); | ||
850 | |||
851 | /* now keys can no longer be reached */ | ||
877 | ieee80211_free_sta_keys(local, sta); | 852 | ieee80211_free_sta_keys(local, sta); |
878 | 853 | ||
879 | sta->dead = true; | 854 | sta->dead = true; |
@@ -881,9 +856,6 @@ int __must_check __sta_info_destroy(struct sta_info *sta) | |||
881 | local->num_sta--; | 856 | local->num_sta--; |
882 | local->sta_generation++; | 857 | local->sta_generation++; |
883 | 858 | ||
884 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
885 | RCU_INIT_POINTER(sdata->u.vlan.sta, NULL); | ||
886 | |||
887 | while (sta->sta_state > IEEE80211_STA_NONE) { | 859 | while (sta->sta_state > IEEE80211_STA_NONE) { |
888 | ret = sta_info_move_state(sta, sta->sta_state - 1); | 860 | ret = sta_info_move_state(sta, sta->sta_state - 1); |
889 | if (ret) { | 861 | if (ret) { |
@@ -906,7 +878,19 @@ int __must_check __sta_info_destroy(struct sta_info *sta) | |||
906 | ieee80211_sta_debugfs_remove(sta); | 878 | ieee80211_sta_debugfs_remove(sta); |
907 | ieee80211_recalc_min_chandef(sdata); | 879 | ieee80211_recalc_min_chandef(sdata); |
908 | 880 | ||
909 | call_rcu(&sta->rcu_head, free_sta_rcu); | 881 | cleanup_single_sta(sta); |
882 | } | ||
883 | |||
884 | int __must_check __sta_info_destroy(struct sta_info *sta) | ||
885 | { | ||
886 | int err = __sta_info_destroy_part1(sta); | ||
887 | |||
888 | if (err) | ||
889 | return err; | ||
890 | |||
891 | synchronize_net(); | ||
892 | |||
893 | __sta_info_destroy_part2(sta); | ||
910 | 894 | ||
911 | return 0; | 895 | return 0; |
912 | } | 896 | } |
@@ -976,32 +960,38 @@ void sta_info_stop(struct ieee80211_local *local) | |||
976 | } | 960 | } |
977 | 961 | ||
978 | 962 | ||
979 | int sta_info_flush_defer(struct ieee80211_sub_if_data *sdata) | 963 | int __sta_info_flush(struct ieee80211_sub_if_data *sdata, bool vlans) |
980 | { | 964 | { |
981 | struct ieee80211_local *local = sdata->local; | 965 | struct ieee80211_local *local = sdata->local; |
982 | struct sta_info *sta, *tmp; | 966 | struct sta_info *sta, *tmp; |
967 | LIST_HEAD(free_list); | ||
983 | int ret = 0; | 968 | int ret = 0; |
984 | 969 | ||
985 | might_sleep(); | 970 | might_sleep(); |
986 | 971 | ||
972 | WARN_ON(vlans && sdata->vif.type != NL80211_IFTYPE_AP); | ||
973 | WARN_ON(vlans && !sdata->bss); | ||
974 | |||
987 | mutex_lock(&local->sta_mtx); | 975 | mutex_lock(&local->sta_mtx); |
988 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { | 976 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { |
989 | if (sdata == sta->sdata) { | 977 | if (sdata == sta->sdata || |
990 | WARN_ON(__sta_info_destroy(sta)); | 978 | (vlans && sdata->bss == sta->sdata->bss)) { |
979 | if (!WARN_ON(__sta_info_destroy_part1(sta))) | ||
980 | list_add(&sta->free_list, &free_list); | ||
991 | ret++; | 981 | ret++; |
992 | } | 982 | } |
993 | } | 983 | } |
984 | |||
985 | if (!list_empty(&free_list)) { | ||
986 | synchronize_net(); | ||
987 | list_for_each_entry_safe(sta, tmp, &free_list, free_list) | ||
988 | __sta_info_destroy_part2(sta); | ||
989 | } | ||
994 | mutex_unlock(&local->sta_mtx); | 990 | mutex_unlock(&local->sta_mtx); |
995 | 991 | ||
996 | return ret; | 992 | return ret; |
997 | } | 993 | } |
998 | 994 | ||
999 | void sta_info_flush_cleanup(struct ieee80211_sub_if_data *sdata) | ||
1000 | { | ||
1001 | ieee80211_cleanup_sdata_stas(sdata); | ||
1002 | cancel_work_sync(&sdata->cleanup_stations_wk); | ||
1003 | } | ||
1004 | |||
1005 | void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, | 995 | void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, |
1006 | unsigned long exp_time) | 996 | unsigned long exp_time) |
1007 | { | 997 | { |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 0218caf5c14a..d77ff7090630 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -247,6 +247,7 @@ struct ieee80211_tx_latency_stat { | |||
247 | * mac80211 is communicating with. | 247 | * mac80211 is communicating with. |
248 | * | 248 | * |
249 | * @list: global linked list entry | 249 | * @list: global linked list entry |
250 | * @free_list: list entry for keeping track of stations to free | ||
250 | * @hnext: hash table linked list pointer | 251 | * @hnext: hash table linked list pointer |
251 | * @local: pointer to the global information | 252 | * @local: pointer to the global information |
252 | * @sdata: virtual interface this station belongs to | 253 | * @sdata: virtual interface this station belongs to |
@@ -329,7 +330,7 @@ struct ieee80211_tx_latency_stat { | |||
329 | */ | 330 | */ |
330 | struct sta_info { | 331 | struct sta_info { |
331 | /* General information, mostly static */ | 332 | /* General information, mostly static */ |
332 | struct list_head list; | 333 | struct list_head list, free_list; |
333 | struct rcu_head rcu_head; | 334 | struct rcu_head rcu_head; |
334 | struct sta_info __rcu *hnext; | 335 | struct sta_info __rcu *hnext; |
335 | struct ieee80211_local *local; | 336 | struct ieee80211_local *local; |
@@ -605,21 +606,6 @@ void sta_info_recalc_tim(struct sta_info *sta); | |||
605 | 606 | ||
606 | void sta_info_init(struct ieee80211_local *local); | 607 | void sta_info_init(struct ieee80211_local *local); |
607 | void sta_info_stop(struct ieee80211_local *local); | 608 | void sta_info_stop(struct ieee80211_local *local); |
608 | int sta_info_flush_defer(struct ieee80211_sub_if_data *sdata); | ||
609 | |||
610 | /** | ||
611 | * sta_info_flush_cleanup - flush the sta_info cleanup queue | ||
612 | * @sdata: the interface | ||
613 | * | ||
614 | * Flushes the sta_info cleanup queue for a given interface; | ||
615 | * this is necessary before the interface is removed or, for | ||
616 | * AP/mesh interfaces, before it is deconfigured. | ||
617 | * | ||
618 | * Note an rcu_barrier() must precede the function, after all | ||
619 | * stations have been flushed/removed to ensure the call_rcu() | ||
620 | * calls that add stations to the cleanup queue have completed. | ||
621 | */ | ||
622 | void sta_info_flush_cleanup(struct ieee80211_sub_if_data *sdata); | ||
623 | 609 | ||
624 | /** | 610 | /** |
625 | * sta_info_flush - flush matching STA entries from the STA table | 611 | * sta_info_flush - flush matching STA entries from the STA table |
@@ -627,15 +613,13 @@ void sta_info_flush_cleanup(struct ieee80211_sub_if_data *sdata); | |||
627 | * Returns the number of removed STA entries. | 613 | * Returns the number of removed STA entries. |
628 | * | 614 | * |
629 | * @sdata: sdata to remove all stations from | 615 | * @sdata: sdata to remove all stations from |
616 | * @vlans: if the given interface is an AP interface, also flush VLANs | ||
630 | */ | 617 | */ |
618 | int __sta_info_flush(struct ieee80211_sub_if_data *sdata, bool vlans); | ||
619 | |||
631 | static inline int sta_info_flush(struct ieee80211_sub_if_data *sdata) | 620 | static inline int sta_info_flush(struct ieee80211_sub_if_data *sdata) |
632 | { | 621 | { |
633 | int ret = sta_info_flush_defer(sdata); | 622 | return __sta_info_flush(sdata, false); |
634 | |||
635 | rcu_barrier(); | ||
636 | sta_info_flush_cleanup(sdata); | ||
637 | |||
638 | return ret; | ||
639 | } | 623 | } |
640 | 624 | ||
641 | void sta_set_rate_info_tx(struct sta_info *sta, | 625 | void sta_set_rate_info_tx(struct sta_info *sta, |
@@ -651,6 +635,4 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta); | |||
651 | void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta); | 635 | void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta); |
652 | void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta); | 636 | void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta); |
653 | 637 | ||
654 | void ieee80211_cleanup_sdata_stas(struct ieee80211_sub_if_data *sdata); | ||
655 | |||
656 | #endif /* STA_INFO_H */ | 638 | #endif /* STA_INFO_H */ |
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index e9ccf22f6dd9..3a669d7ec7ad 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
@@ -443,30 +443,6 @@ TRACE_EVENT(drv_prepare_multicast, | |||
443 | ) | 443 | ) |
444 | ); | 444 | ); |
445 | 445 | ||
446 | TRACE_EVENT(drv_set_multicast_list, | ||
447 | TP_PROTO(struct ieee80211_local *local, | ||
448 | struct ieee80211_sub_if_data *sdata, int mc_count), | ||
449 | |||
450 | TP_ARGS(local, sdata, mc_count), | ||
451 | |||
452 | TP_STRUCT__entry( | ||
453 | LOCAL_ENTRY | ||
454 | __field(bool, allmulti) | ||
455 | __field(int, mc_count) | ||
456 | ), | ||
457 | |||
458 | TP_fast_assign( | ||
459 | LOCAL_ASSIGN; | ||
460 | __entry->allmulti = sdata->flags & IEEE80211_SDATA_ALLMULTI; | ||
461 | __entry->mc_count = mc_count; | ||
462 | ), | ||
463 | |||
464 | TP_printk( | ||
465 | LOCAL_PR_FMT " configure mc filter, count=%d, allmulti=%d", | ||
466 | LOCAL_PR_ARG, __entry->mc_count, __entry->allmulti | ||
467 | ) | ||
468 | ); | ||
469 | |||
470 | TRACE_EVENT(drv_configure_filter, | 446 | TRACE_EVENT(drv_configure_filter, |
471 | TP_PROTO(struct ieee80211_local *local, | 447 | TP_PROTO(struct ieee80211_local *local, |
472 | unsigned int changed_flags, | 448 | unsigned int changed_flags, |
@@ -790,7 +766,7 @@ TRACE_EVENT(drv_sta_rc_update, | |||
790 | ) | 766 | ) |
791 | ); | 767 | ); |
792 | 768 | ||
793 | TRACE_EVENT(drv_sta_add, | 769 | DECLARE_EVENT_CLASS(sta_event, |
794 | TP_PROTO(struct ieee80211_local *local, | 770 | TP_PROTO(struct ieee80211_local *local, |
795 | struct ieee80211_sub_if_data *sdata, | 771 | struct ieee80211_sub_if_data *sdata, |
796 | struct ieee80211_sta *sta), | 772 | struct ieee80211_sta *sta), |
@@ -815,29 +791,25 @@ TRACE_EVENT(drv_sta_add, | |||
815 | ) | 791 | ) |
816 | ); | 792 | ); |
817 | 793 | ||
818 | TRACE_EVENT(drv_sta_remove, | 794 | DEFINE_EVENT(sta_event, drv_sta_add, |
819 | TP_PROTO(struct ieee80211_local *local, | 795 | TP_PROTO(struct ieee80211_local *local, |
820 | struct ieee80211_sub_if_data *sdata, | 796 | struct ieee80211_sub_if_data *sdata, |
821 | struct ieee80211_sta *sta), | 797 | struct ieee80211_sta *sta), |
798 | TP_ARGS(local, sdata, sta) | ||
799 | ); | ||
822 | 800 | ||
823 | TP_ARGS(local, sdata, sta), | 801 | DEFINE_EVENT(sta_event, drv_sta_remove, |
824 | 802 | TP_PROTO(struct ieee80211_local *local, | |
825 | TP_STRUCT__entry( | 803 | struct ieee80211_sub_if_data *sdata, |
826 | LOCAL_ENTRY | 804 | struct ieee80211_sta *sta), |
827 | VIF_ENTRY | 805 | TP_ARGS(local, sdata, sta) |
828 | STA_ENTRY | 806 | ); |
829 | ), | ||
830 | |||
831 | TP_fast_assign( | ||
832 | LOCAL_ASSIGN; | ||
833 | VIF_ASSIGN; | ||
834 | STA_ASSIGN; | ||
835 | ), | ||
836 | 807 | ||
837 | TP_printk( | 808 | DEFINE_EVENT(sta_event, drv_sta_pre_rcu_remove, |
838 | LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT, | 809 | TP_PROTO(struct ieee80211_local *local, |
839 | LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG | 810 | struct ieee80211_sub_if_data *sdata, |
840 | ) | 811 | struct ieee80211_sta *sta), |
812 | TP_ARGS(local, sdata, sta) | ||
841 | ); | 813 | ); |
842 | 814 | ||
843 | TRACE_EVENT(drv_conf_tx, | 815 | TRACE_EVENT(drv_conf_tx, |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 6d59e21cdb9f..2f0e176e7989 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -2549,7 +2549,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2549 | */ | 2549 | */ |
2550 | skb = dev_alloc_skb(local->tx_headroom + | 2550 | skb = dev_alloc_skb(local->tx_headroom + |
2551 | beacon->head_len + | 2551 | beacon->head_len + |
2552 | beacon->tail_len + 256); | 2552 | beacon->tail_len + 256 + |
2553 | local->hw.extra_beacon_tailroom); | ||
2553 | if (!skb) | 2554 | if (!skb) |
2554 | goto out; | 2555 | goto out; |
2555 | 2556 | ||
@@ -2581,7 +2582,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2581 | ieee80211_update_csa(sdata, presp); | 2582 | ieee80211_update_csa(sdata, presp); |
2582 | 2583 | ||
2583 | 2584 | ||
2584 | skb = dev_alloc_skb(local->tx_headroom + presp->head_len); | 2585 | skb = dev_alloc_skb(local->tx_headroom + presp->head_len + |
2586 | local->hw.extra_beacon_tailroom); | ||
2585 | if (!skb) | 2587 | if (!skb) |
2586 | goto out; | 2588 | goto out; |
2587 | skb_reserve(skb, local->tx_headroom); | 2589 | skb_reserve(skb, local->tx_headroom); |
@@ -2602,13 +2604,13 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2602 | ieee80211_update_csa(sdata, bcn); | 2604 | ieee80211_update_csa(sdata, bcn); |
2603 | 2605 | ||
2604 | if (ifmsh->sync_ops) | 2606 | if (ifmsh->sync_ops) |
2605 | ifmsh->sync_ops->adjust_tbtt( | 2607 | ifmsh->sync_ops->adjust_tbtt(sdata, bcn); |
2606 | sdata); | ||
2607 | 2608 | ||
2608 | skb = dev_alloc_skb(local->tx_headroom + | 2609 | skb = dev_alloc_skb(local->tx_headroom + |
2609 | bcn->head_len + | 2610 | bcn->head_len + |
2610 | 256 + /* TIM IE */ | 2611 | 256 + /* TIM IE */ |
2611 | bcn->tail_len); | 2612 | bcn->tail_len + |
2613 | local->hw.extra_beacon_tailroom); | ||
2612 | if (!skb) | 2614 | if (!skb) |
2613 | goto out; | 2615 | goto out; |
2614 | skb_reserve(skb, local->tx_headroom); | 2616 | skb_reserve(skb, local->tx_headroom); |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 875e172c001c..591b46b72462 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -642,6 +642,17 @@ void ieee80211_iterate_active_interfaces_rtnl( | |||
642 | } | 642 | } |
643 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl); | 643 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl); |
644 | 644 | ||
645 | struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev) | ||
646 | { | ||
647 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | ||
648 | |||
649 | if (!ieee80211_sdata_running(sdata) || | ||
650 | !(sdata->flags & IEEE80211_SDATA_IN_DRIVER)) | ||
651 | return NULL; | ||
652 | return &sdata->vif; | ||
653 | } | ||
654 | EXPORT_SYMBOL_GPL(wdev_to_ieee80211_vif); | ||
655 | |||
645 | /* | 656 | /* |
646 | * Nothing should have been stuffed into the workqueue during | 657 | * Nothing should have been stuffed into the workqueue during |
647 | * the suspend->resume cycle. If this WARN is seen then there | 658 | * the suspend->resume cycle. If this WARN is seen then there |
@@ -1451,6 +1462,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1451 | struct sta_info *sta; | 1462 | struct sta_info *sta; |
1452 | int res, i; | 1463 | int res, i; |
1453 | bool reconfig_due_to_wowlan = false; | 1464 | bool reconfig_due_to_wowlan = false; |
1465 | struct ieee80211_sub_if_data *sched_scan_sdata; | ||
1466 | bool sched_scan_stopped = false; | ||
1454 | 1467 | ||
1455 | #ifdef CONFIG_PM | 1468 | #ifdef CONFIG_PM |
1456 | if (local->suspended) | 1469 | if (local->suspended) |
@@ -1754,6 +1767,27 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1754 | #else | 1767 | #else |
1755 | WARN_ON(1); | 1768 | WARN_ON(1); |
1756 | #endif | 1769 | #endif |
1770 | |||
1771 | /* | ||
1772 | * Reconfigure sched scan if it was interrupted by FW restart or | ||
1773 | * suspend. | ||
1774 | */ | ||
1775 | mutex_lock(&local->mtx); | ||
1776 | sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata, | ||
1777 | lockdep_is_held(&local->mtx)); | ||
1778 | if (sched_scan_sdata && local->sched_scan_req) | ||
1779 | /* | ||
1780 | * Sched scan stopped, but we don't want to report it. Instead, | ||
1781 | * we're trying to reschedule. | ||
1782 | */ | ||
1783 | if (__ieee80211_request_sched_scan_start(sched_scan_sdata, | ||
1784 | local->sched_scan_req)) | ||
1785 | sched_scan_stopped = true; | ||
1786 | mutex_unlock(&local->mtx); | ||
1787 | |||
1788 | if (sched_scan_stopped) | ||
1789 | cfg80211_sched_scan_stopped(local->hw.wiphy); | ||
1790 | |||
1757 | return 0; | 1791 | return 0; |
1758 | } | 1792 | } |
1759 | 1793 | ||