diff options
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/ap.c | 62 | ||||
-rw-r--r-- | net/wireless/core.c | 141 | ||||
-rw-r--r-- | net/wireless/core.h | 28 | ||||
-rw-r--r-- | net/wireless/mesh.c | 15 | ||||
-rw-r--r-- | net/wireless/mlme.c | 235 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 2188 | ||||
-rw-r--r-- | net/wireless/nl80211.h | 68 | ||||
-rw-r--r-- | net/wireless/rdev-ops.h | 44 | ||||
-rw-r--r-- | net/wireless/reg.c | 8 | ||||
-rw-r--r-- | net/wireless/scan.c | 24 | ||||
-rw-r--r-- | net/wireless/sme.c | 36 | ||||
-rw-r--r-- | net/wireless/sysfs.c | 25 | ||||
-rw-r--r-- | net/wireless/trace.h | 86 | ||||
-rw-r--r-- | net/wireless/util.c | 30 | ||||
-rw-r--r-- | net/wireless/wext-sme.c | 6 |
15 files changed, 1833 insertions, 1163 deletions
diff --git a/net/wireless/ap.c b/net/wireless/ap.c index a4a14e8f55cc..324e8d851dc4 100644 --- a/net/wireless/ap.c +++ b/net/wireless/ap.c | |||
@@ -46,65 +46,3 @@ int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | |||
46 | 46 | ||
47 | return err; | 47 | return err; |
48 | } | 48 | } |
49 | |||
50 | void cfg80211_ch_switch_notify(struct net_device *dev, | ||
51 | struct cfg80211_chan_def *chandef) | ||
52 | { | ||
53 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
54 | struct wiphy *wiphy = wdev->wiphy; | ||
55 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
56 | |||
57 | trace_cfg80211_ch_switch_notify(dev, chandef); | ||
58 | |||
59 | wdev_lock(wdev); | ||
60 | |||
61 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && | ||
62 | wdev->iftype != NL80211_IFTYPE_P2P_GO)) | ||
63 | goto out; | ||
64 | |||
65 | wdev->channel = chandef->chan; | ||
66 | nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL); | ||
67 | out: | ||
68 | wdev_unlock(wdev); | ||
69 | return; | ||
70 | } | ||
71 | EXPORT_SYMBOL(cfg80211_ch_switch_notify); | ||
72 | |||
73 | bool cfg80211_rx_spurious_frame(struct net_device *dev, | ||
74 | const u8 *addr, gfp_t gfp) | ||
75 | { | ||
76 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
77 | bool ret; | ||
78 | |||
79 | trace_cfg80211_rx_spurious_frame(dev, addr); | ||
80 | |||
81 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && | ||
82 | wdev->iftype != NL80211_IFTYPE_P2P_GO)) { | ||
83 | trace_cfg80211_return_bool(false); | ||
84 | return false; | ||
85 | } | ||
86 | ret = nl80211_unexpected_frame(dev, addr, gfp); | ||
87 | trace_cfg80211_return_bool(ret); | ||
88 | return ret; | ||
89 | } | ||
90 | EXPORT_SYMBOL(cfg80211_rx_spurious_frame); | ||
91 | |||
92 | bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev, | ||
93 | const u8 *addr, gfp_t gfp) | ||
94 | { | ||
95 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
96 | bool ret; | ||
97 | |||
98 | trace_cfg80211_rx_unexpected_4addr_frame(dev, addr); | ||
99 | |||
100 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && | ||
101 | wdev->iftype != NL80211_IFTYPE_P2P_GO && | ||
102 | wdev->iftype != NL80211_IFTYPE_AP_VLAN)) { | ||
103 | trace_cfg80211_return_bool(false); | ||
104 | return false; | ||
105 | } | ||
106 | ret = nl80211_unexpected_4addr_frame(dev, addr, gfp); | ||
107 | trace_cfg80211_return_bool(ret); | ||
108 | return ret; | ||
109 | } | ||
110 | EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame); | ||
diff --git a/net/wireless/core.c b/net/wireless/core.c index ea4155fe9733..84c9ad7e1dca 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -212,6 +212,39 @@ static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data) | |||
212 | rdev_rfkill_poll(rdev); | 212 | rdev_rfkill_poll(rdev); |
213 | } | 213 | } |
214 | 214 | ||
215 | void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, | ||
216 | struct wireless_dev *wdev) | ||
217 | { | ||
218 | lockdep_assert_held(&rdev->devlist_mtx); | ||
219 | lockdep_assert_held(&rdev->sched_scan_mtx); | ||
220 | |||
221 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)) | ||
222 | return; | ||
223 | |||
224 | if (!wdev->p2p_started) | ||
225 | return; | ||
226 | |||
227 | rdev_stop_p2p_device(rdev, wdev); | ||
228 | wdev->p2p_started = false; | ||
229 | |||
230 | rdev->opencount--; | ||
231 | |||
232 | if (rdev->scan_req && rdev->scan_req->wdev == wdev) { | ||
233 | bool busy = work_busy(&rdev->scan_done_wk); | ||
234 | |||
235 | /* | ||
236 | * If the work isn't pending or running (in which case it would | ||
237 | * be waiting for the lock we hold) the driver didn't properly | ||
238 | * cancel the scan when the interface was removed. In this case | ||
239 | * warn and leak the scan request object to not crash later. | ||
240 | */ | ||
241 | WARN_ON(!busy); | ||
242 | |||
243 | rdev->scan_req->aborted = true; | ||
244 | ___cfg80211_scan_done(rdev, !busy); | ||
245 | } | ||
246 | } | ||
247 | |||
215 | static int cfg80211_rfkill_set_block(void *data, bool blocked) | 248 | static int cfg80211_rfkill_set_block(void *data, bool blocked) |
216 | { | 249 | { |
217 | struct cfg80211_registered_device *rdev = data; | 250 | struct cfg80211_registered_device *rdev = data; |
@@ -221,7 +254,8 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked) | |||
221 | return 0; | 254 | return 0; |
222 | 255 | ||
223 | rtnl_lock(); | 256 | rtnl_lock(); |
224 | mutex_lock(&rdev->devlist_mtx); | 257 | |
258 | /* read-only iteration need not hold the devlist_mtx */ | ||
225 | 259 | ||
226 | list_for_each_entry(wdev, &rdev->wdev_list, list) { | 260 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
227 | if (wdev->netdev) { | 261 | if (wdev->netdev) { |
@@ -231,18 +265,18 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked) | |||
231 | /* otherwise, check iftype */ | 265 | /* otherwise, check iftype */ |
232 | switch (wdev->iftype) { | 266 | switch (wdev->iftype) { |
233 | case NL80211_IFTYPE_P2P_DEVICE: | 267 | case NL80211_IFTYPE_P2P_DEVICE: |
234 | if (!wdev->p2p_started) | 268 | /* but this requires it */ |
235 | break; | 269 | mutex_lock(&rdev->devlist_mtx); |
236 | rdev_stop_p2p_device(rdev, wdev); | 270 | mutex_lock(&rdev->sched_scan_mtx); |
237 | wdev->p2p_started = false; | 271 | cfg80211_stop_p2p_device(rdev, wdev); |
238 | rdev->opencount--; | 272 | mutex_unlock(&rdev->sched_scan_mtx); |
273 | mutex_unlock(&rdev->devlist_mtx); | ||
239 | break; | 274 | break; |
240 | default: | 275 | default: |
241 | break; | 276 | break; |
242 | } | 277 | } |
243 | } | 278 | } |
244 | 279 | ||
245 | mutex_unlock(&rdev->devlist_mtx); | ||
246 | rtnl_unlock(); | 280 | rtnl_unlock(); |
247 | 281 | ||
248 | return 0; | 282 | return 0; |
@@ -745,17 +779,13 @@ static void wdev_cleanup_work(struct work_struct *work) | |||
745 | wdev = container_of(work, struct wireless_dev, cleanup_work); | 779 | wdev = container_of(work, struct wireless_dev, cleanup_work); |
746 | rdev = wiphy_to_dev(wdev->wiphy); | 780 | rdev = wiphy_to_dev(wdev->wiphy); |
747 | 781 | ||
748 | cfg80211_lock_rdev(rdev); | 782 | mutex_lock(&rdev->sched_scan_mtx); |
749 | 783 | ||
750 | if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) { | 784 | if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) { |
751 | rdev->scan_req->aborted = true; | 785 | rdev->scan_req->aborted = true; |
752 | ___cfg80211_scan_done(rdev, true); | 786 | ___cfg80211_scan_done(rdev, true); |
753 | } | 787 | } |
754 | 788 | ||
755 | cfg80211_unlock_rdev(rdev); | ||
756 | |||
757 | mutex_lock(&rdev->sched_scan_mtx); | ||
758 | |||
759 | if (WARN_ON(rdev->sched_scan_req && | 789 | if (WARN_ON(rdev->sched_scan_req && |
760 | rdev->sched_scan_req->dev == wdev->netdev)) { | 790 | rdev->sched_scan_req->dev == wdev->netdev)) { |
761 | __cfg80211_stop_sched_scan(rdev, false); | 791 | __cfg80211_stop_sched_scan(rdev, false); |
@@ -781,21 +811,19 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev) | |||
781 | return; | 811 | return; |
782 | 812 | ||
783 | mutex_lock(&rdev->devlist_mtx); | 813 | mutex_lock(&rdev->devlist_mtx); |
814 | mutex_lock(&rdev->sched_scan_mtx); | ||
784 | list_del_rcu(&wdev->list); | 815 | list_del_rcu(&wdev->list); |
785 | rdev->devlist_generation++; | 816 | rdev->devlist_generation++; |
786 | 817 | ||
787 | switch (wdev->iftype) { | 818 | switch (wdev->iftype) { |
788 | case NL80211_IFTYPE_P2P_DEVICE: | 819 | case NL80211_IFTYPE_P2P_DEVICE: |
789 | if (!wdev->p2p_started) | 820 | cfg80211_stop_p2p_device(rdev, wdev); |
790 | break; | ||
791 | rdev_stop_p2p_device(rdev, wdev); | ||
792 | wdev->p2p_started = false; | ||
793 | rdev->opencount--; | ||
794 | break; | 821 | break; |
795 | default: | 822 | default: |
796 | WARN_ON_ONCE(1); | 823 | WARN_ON_ONCE(1); |
797 | break; | 824 | break; |
798 | } | 825 | } |
826 | mutex_unlock(&rdev->sched_scan_mtx); | ||
799 | mutex_unlock(&rdev->devlist_mtx); | 827 | mutex_unlock(&rdev->devlist_mtx); |
800 | } | 828 | } |
801 | EXPORT_SYMBOL(cfg80211_unregister_wdev); | 829 | EXPORT_SYMBOL(cfg80211_unregister_wdev); |
@@ -814,6 +842,46 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | |||
814 | rdev->num_running_monitor_ifaces += num; | 842 | rdev->num_running_monitor_ifaces += num; |
815 | } | 843 | } |
816 | 844 | ||
845 | void cfg80211_leave(struct cfg80211_registered_device *rdev, | ||
846 | struct wireless_dev *wdev) | ||
847 | { | ||
848 | struct net_device *dev = wdev->netdev; | ||
849 | |||
850 | switch (wdev->iftype) { | ||
851 | case NL80211_IFTYPE_ADHOC: | ||
852 | cfg80211_leave_ibss(rdev, dev, true); | ||
853 | break; | ||
854 | case NL80211_IFTYPE_P2P_CLIENT: | ||
855 | case NL80211_IFTYPE_STATION: | ||
856 | mutex_lock(&rdev->sched_scan_mtx); | ||
857 | __cfg80211_stop_sched_scan(rdev, false); | ||
858 | mutex_unlock(&rdev->sched_scan_mtx); | ||
859 | |||
860 | wdev_lock(wdev); | ||
861 | #ifdef CONFIG_CFG80211_WEXT | ||
862 | kfree(wdev->wext.ie); | ||
863 | wdev->wext.ie = NULL; | ||
864 | wdev->wext.ie_len = 0; | ||
865 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; | ||
866 | #endif | ||
867 | __cfg80211_disconnect(rdev, dev, | ||
868 | WLAN_REASON_DEAUTH_LEAVING, true); | ||
869 | cfg80211_mlme_down(rdev, dev); | ||
870 | wdev_unlock(wdev); | ||
871 | break; | ||
872 | case NL80211_IFTYPE_MESH_POINT: | ||
873 | cfg80211_leave_mesh(rdev, dev); | ||
874 | break; | ||
875 | case NL80211_IFTYPE_AP: | ||
876 | cfg80211_stop_ap(rdev, dev); | ||
877 | break; | ||
878 | default: | ||
879 | break; | ||
880 | } | ||
881 | |||
882 | wdev->beacon_interval = 0; | ||
883 | } | ||
884 | |||
817 | static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | 885 | static int cfg80211_netdev_notifier_call(struct notifier_block *nb, |
818 | unsigned long state, | 886 | unsigned long state, |
819 | void *ndev) | 887 | void *ndev) |
@@ -882,38 +950,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
882 | dev->priv_flags |= IFF_DONT_BRIDGE; | 950 | dev->priv_flags |= IFF_DONT_BRIDGE; |
883 | break; | 951 | break; |
884 | case NETDEV_GOING_DOWN: | 952 | case NETDEV_GOING_DOWN: |
885 | switch (wdev->iftype) { | 953 | cfg80211_leave(rdev, wdev); |
886 | case NL80211_IFTYPE_ADHOC: | ||
887 | cfg80211_leave_ibss(rdev, dev, true); | ||
888 | break; | ||
889 | case NL80211_IFTYPE_P2P_CLIENT: | ||
890 | case NL80211_IFTYPE_STATION: | ||
891 | mutex_lock(&rdev->sched_scan_mtx); | ||
892 | __cfg80211_stop_sched_scan(rdev, false); | ||
893 | mutex_unlock(&rdev->sched_scan_mtx); | ||
894 | |||
895 | wdev_lock(wdev); | ||
896 | #ifdef CONFIG_CFG80211_WEXT | ||
897 | kfree(wdev->wext.ie); | ||
898 | wdev->wext.ie = NULL; | ||
899 | wdev->wext.ie_len = 0; | ||
900 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; | ||
901 | #endif | ||
902 | __cfg80211_disconnect(rdev, dev, | ||
903 | WLAN_REASON_DEAUTH_LEAVING, true); | ||
904 | cfg80211_mlme_down(rdev, dev); | ||
905 | wdev_unlock(wdev); | ||
906 | break; | ||
907 | case NL80211_IFTYPE_MESH_POINT: | ||
908 | cfg80211_leave_mesh(rdev, dev); | ||
909 | break; | ||
910 | case NL80211_IFTYPE_AP: | ||
911 | cfg80211_stop_ap(rdev, dev); | ||
912 | break; | ||
913 | default: | ||
914 | break; | ||
915 | } | ||
916 | wdev->beacon_interval = 0; | ||
917 | break; | 954 | break; |
918 | case NETDEV_DOWN: | 955 | case NETDEV_DOWN: |
919 | cfg80211_update_iface_num(rdev, wdev->iftype, -1); | 956 | cfg80211_update_iface_num(rdev, wdev->iftype, -1); |
@@ -936,6 +973,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
936 | cfg80211_update_iface_num(rdev, wdev->iftype, 1); | 973 | cfg80211_update_iface_num(rdev, wdev->iftype, 1); |
937 | cfg80211_lock_rdev(rdev); | 974 | cfg80211_lock_rdev(rdev); |
938 | mutex_lock(&rdev->devlist_mtx); | 975 | mutex_lock(&rdev->devlist_mtx); |
976 | mutex_lock(&rdev->sched_scan_mtx); | ||
939 | wdev_lock(wdev); | 977 | wdev_lock(wdev); |
940 | switch (wdev->iftype) { | 978 | switch (wdev->iftype) { |
941 | #ifdef CONFIG_CFG80211_WEXT | 979 | #ifdef CONFIG_CFG80211_WEXT |
@@ -967,6 +1005,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
967 | break; | 1005 | break; |
968 | } | 1006 | } |
969 | wdev_unlock(wdev); | 1007 | wdev_unlock(wdev); |
1008 | mutex_unlock(&rdev->sched_scan_mtx); | ||
970 | rdev->opencount++; | 1009 | rdev->opencount++; |
971 | mutex_unlock(&rdev->devlist_mtx); | 1010 | mutex_unlock(&rdev->devlist_mtx); |
972 | cfg80211_unlock_rdev(rdev); | 1011 | cfg80211_unlock_rdev(rdev); |
@@ -1087,8 +1126,10 @@ static int __init cfg80211_init(void) | |||
1087 | goto out_fail_reg; | 1126 | goto out_fail_reg; |
1088 | 1127 | ||
1089 | cfg80211_wq = create_singlethread_workqueue("cfg80211"); | 1128 | cfg80211_wq = create_singlethread_workqueue("cfg80211"); |
1090 | if (!cfg80211_wq) | 1129 | if (!cfg80211_wq) { |
1130 | err = -ENOMEM; | ||
1091 | goto out_fail_wq; | 1131 | goto out_fail_wq; |
1132 | } | ||
1092 | 1133 | ||
1093 | return 0; | 1134 | return 0; |
1094 | 1135 | ||
diff --git a/net/wireless/core.h b/net/wireless/core.h index 3aec0e429d8a..fd35dae547c4 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -88,6 +88,9 @@ struct cfg80211_registered_device { | |||
88 | 88 | ||
89 | struct delayed_work dfs_update_channels_wk; | 89 | struct delayed_work dfs_update_channels_wk; |
90 | 90 | ||
91 | /* netlink port which started critical protocol (0 means not started) */ | ||
92 | u32 crit_proto_nlportid; | ||
93 | |||
91 | /* must be last because of the way we do wiphy_priv(), | 94 | /* must be last because of the way we do wiphy_priv(), |
92 | * and it should at least be aligned to NETDEV_ALIGN */ | 95 | * and it should at least be aligned to NETDEV_ALIGN */ |
93 | struct wiphy wiphy __aligned(NETDEV_ALIGN); | 96 | struct wiphy wiphy __aligned(NETDEV_ALIGN); |
@@ -330,20 +333,15 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | |||
330 | int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | 333 | int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, |
331 | struct net_device *dev, | 334 | struct net_device *dev, |
332 | struct ieee80211_channel *chan, | 335 | struct ieee80211_channel *chan, |
333 | const u8 *bssid, const u8 *prev_bssid, | 336 | const u8 *bssid, |
334 | const u8 *ssid, int ssid_len, | 337 | const u8 *ssid, int ssid_len, |
335 | const u8 *ie, int ie_len, bool use_mfp, | 338 | struct cfg80211_assoc_request *req); |
336 | struct cfg80211_crypto_settings *crypt, | ||
337 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, | ||
338 | struct ieee80211_ht_cap *ht_capa_mask); | ||
339 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | 339 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, |
340 | struct net_device *dev, struct ieee80211_channel *chan, | 340 | struct net_device *dev, |
341 | const u8 *bssid, const u8 *prev_bssid, | 341 | struct ieee80211_channel *chan, |
342 | const u8 *bssid, | ||
342 | const u8 *ssid, int ssid_len, | 343 | const u8 *ssid, int ssid_len, |
343 | const u8 *ie, int ie_len, bool use_mfp, | 344 | struct cfg80211_assoc_request *req); |
344 | struct cfg80211_crypto_settings *crypt, | ||
345 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, | ||
346 | struct ieee80211_ht_cap *ht_capa_mask); | ||
347 | int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, | 345 | int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, |
348 | struct net_device *dev, const u8 *bssid, | 346 | struct net_device *dev, const u8 *bssid, |
349 | const u8 *ie, int ie_len, u16 reason, | 347 | const u8 *ie, int ie_len, u16 reason, |
@@ -375,6 +373,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | |||
375 | bool no_cck, bool dont_wait_for_ack, u64 *cookie); | 373 | bool no_cck, bool dont_wait_for_ack, u64 *cookie); |
376 | void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, | 374 | void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, |
377 | const struct ieee80211_ht_cap *ht_capa_mask); | 375 | const struct ieee80211_ht_cap *ht_capa_mask); |
376 | void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa, | ||
377 | const struct ieee80211_vht_cap *vht_capa_mask); | ||
378 | 378 | ||
379 | /* SME */ | 379 | /* SME */ |
380 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | 380 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, |
@@ -503,6 +503,12 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | |||
503 | void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | 503 | void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, |
504 | enum nl80211_iftype iftype, int num); | 504 | enum nl80211_iftype iftype, int num); |
505 | 505 | ||
506 | void cfg80211_leave(struct cfg80211_registered_device *rdev, | ||
507 | struct wireless_dev *wdev); | ||
508 | |||
509 | void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, | ||
510 | struct wireless_dev *wdev); | ||
511 | |||
506 | #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 | 512 | #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 |
507 | 513 | ||
508 | #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS | 514 | #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS |
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 55957a284f6c..0bb93f3061a4 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c | |||
@@ -85,6 +85,7 @@ const struct mesh_setup default_mesh_setup = { | |||
85 | .ie = NULL, | 85 | .ie = NULL, |
86 | .ie_len = 0, | 86 | .ie_len = 0, |
87 | .is_secure = false, | 87 | .is_secure = false, |
88 | .user_mpm = false, | ||
88 | .beacon_interval = MESH_DEFAULT_BEACON_INTERVAL, | 89 | .beacon_interval = MESH_DEFAULT_BEACON_INTERVAL, |
89 | .dtim_period = MESH_DEFAULT_DTIM_PERIOD, | 90 | .dtim_period = MESH_DEFAULT_DTIM_PERIOD, |
90 | }; | 91 | }; |
@@ -233,20 +234,6 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, | |||
233 | return 0; | 234 | return 0; |
234 | } | 235 | } |
235 | 236 | ||
236 | void cfg80211_notify_new_peer_candidate(struct net_device *dev, | ||
237 | const u8 *macaddr, const u8* ie, u8 ie_len, gfp_t gfp) | ||
238 | { | ||
239 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
240 | |||
241 | trace_cfg80211_notify_new_peer_candidate(dev, macaddr); | ||
242 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT)) | ||
243 | return; | ||
244 | |||
245 | nl80211_send_new_peer_candidate(wiphy_to_dev(wdev->wiphy), dev, | ||
246 | macaddr, ie, ie_len, gfp); | ||
247 | } | ||
248 | EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate); | ||
249 | |||
250 | static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | 237 | static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, |
251 | struct net_device *dev) | 238 | struct net_device *dev) |
252 | { | 239 | { |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index caddca35d686..0c7b7dd855f6 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -187,30 +187,6 @@ void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len) | |||
187 | } | 187 | } |
188 | EXPORT_SYMBOL(cfg80211_send_disassoc); | 188 | EXPORT_SYMBOL(cfg80211_send_disassoc); |
189 | 189 | ||
190 | void cfg80211_send_unprot_deauth(struct net_device *dev, const u8 *buf, | ||
191 | size_t len) | ||
192 | { | ||
193 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
194 | struct wiphy *wiphy = wdev->wiphy; | ||
195 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
196 | |||
197 | trace_cfg80211_send_unprot_deauth(dev); | ||
198 | nl80211_send_unprot_deauth(rdev, dev, buf, len, GFP_ATOMIC); | ||
199 | } | ||
200 | EXPORT_SYMBOL(cfg80211_send_unprot_deauth); | ||
201 | |||
202 | void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf, | ||
203 | size_t len) | ||
204 | { | ||
205 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
206 | struct wiphy *wiphy = wdev->wiphy; | ||
207 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
208 | |||
209 | trace_cfg80211_send_unprot_disassoc(dev); | ||
210 | nl80211_send_unprot_disassoc(rdev, dev, buf, len, GFP_ATOMIC); | ||
211 | } | ||
212 | EXPORT_SYMBOL(cfg80211_send_unprot_disassoc); | ||
213 | |||
214 | void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) | 190 | void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) |
215 | { | 191 | { |
216 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 192 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
@@ -367,27 +343,38 @@ void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, | |||
367 | p1[i] &= p2[i]; | 343 | p1[i] &= p2[i]; |
368 | } | 344 | } |
369 | 345 | ||
346 | /* Do a logical ht_capa &= ht_capa_mask. */ | ||
347 | void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa, | ||
348 | const struct ieee80211_vht_cap *vht_capa_mask) | ||
349 | { | ||
350 | int i; | ||
351 | u8 *p1, *p2; | ||
352 | if (!vht_capa_mask) { | ||
353 | memset(vht_capa, 0, sizeof(*vht_capa)); | ||
354 | return; | ||
355 | } | ||
356 | |||
357 | p1 = (u8*)(vht_capa); | ||
358 | p2 = (u8*)(vht_capa_mask); | ||
359 | for (i = 0; i < sizeof(*vht_capa); i++) | ||
360 | p1[i] &= p2[i]; | ||
361 | } | ||
362 | |||
370 | int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | 363 | int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, |
371 | struct net_device *dev, | 364 | struct net_device *dev, |
372 | struct ieee80211_channel *chan, | 365 | struct ieee80211_channel *chan, |
373 | const u8 *bssid, const u8 *prev_bssid, | 366 | const u8 *bssid, |
374 | const u8 *ssid, int ssid_len, | 367 | const u8 *ssid, int ssid_len, |
375 | const u8 *ie, int ie_len, bool use_mfp, | 368 | struct cfg80211_assoc_request *req) |
376 | struct cfg80211_crypto_settings *crypt, | ||
377 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, | ||
378 | struct ieee80211_ht_cap *ht_capa_mask) | ||
379 | { | 369 | { |
380 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 370 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
381 | struct cfg80211_assoc_request req; | ||
382 | int err; | 371 | int err; |
383 | bool was_connected = false; | 372 | bool was_connected = false; |
384 | 373 | ||
385 | ASSERT_WDEV_LOCK(wdev); | 374 | ASSERT_WDEV_LOCK(wdev); |
386 | 375 | ||
387 | memset(&req, 0, sizeof(req)); | 376 | if (wdev->current_bss && req->prev_bssid && |
388 | 377 | ether_addr_equal(wdev->current_bss->pub.bssid, req->prev_bssid)) { | |
389 | if (wdev->current_bss && prev_bssid && | ||
390 | ether_addr_equal(wdev->current_bss->pub.bssid, prev_bssid)) { | ||
391 | /* | 378 | /* |
392 | * Trying to reassociate: Allow this to proceed and let the old | 379 | * Trying to reassociate: Allow this to proceed and let the old |
393 | * association to be dropped when the new one is completed. | 380 | * association to be dropped when the new one is completed. |
@@ -399,40 +386,30 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
399 | } else if (wdev->current_bss) | 386 | } else if (wdev->current_bss) |
400 | return -EALREADY; | 387 | return -EALREADY; |
401 | 388 | ||
402 | req.ie = ie; | 389 | cfg80211_oper_and_ht_capa(&req->ht_capa_mask, |
403 | req.ie_len = ie_len; | ||
404 | memcpy(&req.crypto, crypt, sizeof(req.crypto)); | ||
405 | req.use_mfp = use_mfp; | ||
406 | req.prev_bssid = prev_bssid; | ||
407 | req.flags = assoc_flags; | ||
408 | if (ht_capa) | ||
409 | memcpy(&req.ht_capa, ht_capa, sizeof(req.ht_capa)); | ||
410 | if (ht_capa_mask) | ||
411 | memcpy(&req.ht_capa_mask, ht_capa_mask, | ||
412 | sizeof(req.ht_capa_mask)); | ||
413 | cfg80211_oper_and_ht_capa(&req.ht_capa_mask, | ||
414 | rdev->wiphy.ht_capa_mod_mask); | 390 | rdev->wiphy.ht_capa_mod_mask); |
391 | cfg80211_oper_and_vht_capa(&req->vht_capa_mask, | ||
392 | rdev->wiphy.vht_capa_mod_mask); | ||
415 | 393 | ||
416 | req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, | 394 | req->bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, |
417 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); | 395 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); |
418 | if (!req.bss) { | 396 | if (!req->bss) { |
419 | if (was_connected) | 397 | if (was_connected) |
420 | wdev->sme_state = CFG80211_SME_CONNECTED; | 398 | wdev->sme_state = CFG80211_SME_CONNECTED; |
421 | return -ENOENT; | 399 | return -ENOENT; |
422 | } | 400 | } |
423 | 401 | ||
424 | err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel, | 402 | err = cfg80211_can_use_chan(rdev, wdev, chan, CHAN_MODE_SHARED); |
425 | CHAN_MODE_SHARED); | ||
426 | if (err) | 403 | if (err) |
427 | goto out; | 404 | goto out; |
428 | 405 | ||
429 | err = rdev_assoc(rdev, dev, &req); | 406 | err = rdev_assoc(rdev, dev, req); |
430 | 407 | ||
431 | out: | 408 | out: |
432 | if (err) { | 409 | if (err) { |
433 | if (was_connected) | 410 | if (was_connected) |
434 | wdev->sme_state = CFG80211_SME_CONNECTED; | 411 | wdev->sme_state = CFG80211_SME_CONNECTED; |
435 | cfg80211_put_bss(&rdev->wiphy, req.bss); | 412 | cfg80211_put_bss(&rdev->wiphy, req->bss); |
436 | } | 413 | } |
437 | 414 | ||
438 | return err; | 415 | return err; |
@@ -441,21 +418,17 @@ out: | |||
441 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | 418 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, |
442 | struct net_device *dev, | 419 | struct net_device *dev, |
443 | struct ieee80211_channel *chan, | 420 | struct ieee80211_channel *chan, |
444 | const u8 *bssid, const u8 *prev_bssid, | 421 | const u8 *bssid, |
445 | const u8 *ssid, int ssid_len, | 422 | const u8 *ssid, int ssid_len, |
446 | const u8 *ie, int ie_len, bool use_mfp, | 423 | struct cfg80211_assoc_request *req) |
447 | struct cfg80211_crypto_settings *crypt, | ||
448 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, | ||
449 | struct ieee80211_ht_cap *ht_capa_mask) | ||
450 | { | 424 | { |
451 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 425 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
452 | int err; | 426 | int err; |
453 | 427 | ||
454 | mutex_lock(&rdev->devlist_mtx); | 428 | mutex_lock(&rdev->devlist_mtx); |
455 | wdev_lock(wdev); | 429 | wdev_lock(wdev); |
456 | err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, | 430 | err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, |
457 | ssid, ssid_len, ie, ie_len, use_mfp, crypt, | 431 | ssid, ssid_len, req); |
458 | assoc_flags, ht_capa, ht_capa_mask); | ||
459 | wdev_unlock(wdev); | 432 | wdev_unlock(wdev); |
460 | mutex_unlock(&rdev->devlist_mtx); | 433 | mutex_unlock(&rdev->devlist_mtx); |
461 | 434 | ||
@@ -577,62 +550,6 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | |||
577 | } | 550 | } |
578 | } | 551 | } |
579 | 552 | ||
580 | void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie, | ||
581 | struct ieee80211_channel *chan, | ||
582 | unsigned int duration, gfp_t gfp) | ||
583 | { | ||
584 | struct wiphy *wiphy = wdev->wiphy; | ||
585 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
586 | |||
587 | trace_cfg80211_ready_on_channel(wdev, cookie, chan, duration); | ||
588 | nl80211_send_remain_on_channel(rdev, wdev, cookie, chan, duration, gfp); | ||
589 | } | ||
590 | EXPORT_SYMBOL(cfg80211_ready_on_channel); | ||
591 | |||
592 | void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie, | ||
593 | struct ieee80211_channel *chan, | ||
594 | gfp_t gfp) | ||
595 | { | ||
596 | struct wiphy *wiphy = wdev->wiphy; | ||
597 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
598 | |||
599 | trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan); | ||
600 | nl80211_send_remain_on_channel_cancel(rdev, wdev, cookie, chan, gfp); | ||
601 | } | ||
602 | EXPORT_SYMBOL(cfg80211_remain_on_channel_expired); | ||
603 | |||
604 | void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, | ||
605 | struct station_info *sinfo, gfp_t gfp) | ||
606 | { | ||
607 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
608 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
609 | |||
610 | trace_cfg80211_new_sta(dev, mac_addr, sinfo); | ||
611 | nl80211_send_sta_event(rdev, dev, mac_addr, sinfo, gfp); | ||
612 | } | ||
613 | EXPORT_SYMBOL(cfg80211_new_sta); | ||
614 | |||
615 | void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp) | ||
616 | { | ||
617 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
618 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
619 | |||
620 | trace_cfg80211_del_sta(dev, mac_addr); | ||
621 | nl80211_send_sta_del_event(rdev, dev, mac_addr, gfp); | ||
622 | } | ||
623 | EXPORT_SYMBOL(cfg80211_del_sta); | ||
624 | |||
625 | void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, | ||
626 | enum nl80211_connect_failed_reason reason, | ||
627 | gfp_t gfp) | ||
628 | { | ||
629 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
630 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
631 | |||
632 | nl80211_send_conn_failed_event(rdev, dev, mac_addr, reason, gfp); | ||
633 | } | ||
634 | EXPORT_SYMBOL(cfg80211_conn_failed); | ||
635 | |||
636 | struct cfg80211_mgmt_registration { | 553 | struct cfg80211_mgmt_registration { |
637 | struct list_head list; | 554 | struct list_head list; |
638 | 555 | ||
@@ -731,6 +648,11 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid) | |||
731 | 648 | ||
732 | spin_unlock_bh(&wdev->mgmt_registrations_lock); | 649 | spin_unlock_bh(&wdev->mgmt_registrations_lock); |
733 | 650 | ||
651 | if (nlportid && rdev->crit_proto_nlportid == nlportid) { | ||
652 | rdev->crit_proto_nlportid = 0; | ||
653 | rdev_crit_proto_stop(rdev, wdev); | ||
654 | } | ||
655 | |||
734 | if (nlportid == wdev->ap_unexpected_nlportid) | 656 | if (nlportid == wdev->ap_unexpected_nlportid) |
735 | wdev->ap_unexpected_nlportid = 0; | 657 | wdev->ap_unexpected_nlportid = 0; |
736 | } | 658 | } |
@@ -909,85 +831,6 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm, | |||
909 | } | 831 | } |
910 | EXPORT_SYMBOL(cfg80211_rx_mgmt); | 832 | EXPORT_SYMBOL(cfg80211_rx_mgmt); |
911 | 833 | ||
912 | void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, | ||
913 | const u8 *buf, size_t len, bool ack, gfp_t gfp) | ||
914 | { | ||
915 | struct wiphy *wiphy = wdev->wiphy; | ||
916 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
917 | |||
918 | trace_cfg80211_mgmt_tx_status(wdev, cookie, ack); | ||
919 | |||
920 | /* Indicate TX status of the Action frame to user space */ | ||
921 | nl80211_send_mgmt_tx_status(rdev, wdev, cookie, buf, len, ack, gfp); | ||
922 | } | ||
923 | EXPORT_SYMBOL(cfg80211_mgmt_tx_status); | ||
924 | |||
925 | void cfg80211_cqm_rssi_notify(struct net_device *dev, | ||
926 | enum nl80211_cqm_rssi_threshold_event rssi_event, | ||
927 | gfp_t gfp) | ||
928 | { | ||
929 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
930 | struct wiphy *wiphy = wdev->wiphy; | ||
931 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
932 | |||
933 | trace_cfg80211_cqm_rssi_notify(dev, rssi_event); | ||
934 | |||
935 | /* Indicate roaming trigger event to user space */ | ||
936 | nl80211_send_cqm_rssi_notify(rdev, dev, rssi_event, gfp); | ||
937 | } | ||
938 | EXPORT_SYMBOL(cfg80211_cqm_rssi_notify); | ||
939 | |||
940 | void cfg80211_cqm_pktloss_notify(struct net_device *dev, | ||
941 | const u8 *peer, u32 num_packets, gfp_t gfp) | ||
942 | { | ||
943 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
944 | struct wiphy *wiphy = wdev->wiphy; | ||
945 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
946 | |||
947 | trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets); | ||
948 | |||
949 | /* Indicate roaming trigger event to user space */ | ||
950 | nl80211_send_cqm_pktloss_notify(rdev, dev, peer, num_packets, gfp); | ||
951 | } | ||
952 | EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify); | ||
953 | |||
954 | void cfg80211_cqm_txe_notify(struct net_device *dev, | ||
955 | const u8 *peer, u32 num_packets, | ||
956 | u32 rate, u32 intvl, gfp_t gfp) | ||
957 | { | ||
958 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
959 | struct wiphy *wiphy = wdev->wiphy; | ||
960 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
961 | |||
962 | nl80211_send_cqm_txe_notify(rdev, dev, peer, num_packets, | ||
963 | rate, intvl, gfp); | ||
964 | } | ||
965 | EXPORT_SYMBOL(cfg80211_cqm_txe_notify); | ||
966 | |||
967 | void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid, | ||
968 | const u8 *replay_ctr, gfp_t gfp) | ||
969 | { | ||
970 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
971 | struct wiphy *wiphy = wdev->wiphy; | ||
972 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
973 | |||
974 | trace_cfg80211_gtk_rekey_notify(dev, bssid); | ||
975 | nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp); | ||
976 | } | ||
977 | EXPORT_SYMBOL(cfg80211_gtk_rekey_notify); | ||
978 | |||
979 | void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index, | ||
980 | const u8 *bssid, bool preauth, gfp_t gfp) | ||
981 | { | ||
982 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
983 | struct wiphy *wiphy = wdev->wiphy; | ||
984 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
985 | |||
986 | trace_cfg80211_pmksa_candidate_notify(dev, index, bssid, preauth); | ||
987 | nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp); | ||
988 | } | ||
989 | EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify); | ||
990 | |||
991 | void cfg80211_dfs_channels_update_work(struct work_struct *work) | 834 | void cfg80211_dfs_channels_update_work(struct work_struct *work) |
992 | { | 835 | { |
993 | struct delayed_work *delayed_work; | 836 | struct delayed_work *delayed_work; |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index d44ab216c0ec..afa283841e8c 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -370,6 +370,14 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
370 | [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED }, | 370 | [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED }, |
371 | [NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 }, | 371 | [NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 }, |
372 | [NL80211_ATTR_STA_EXT_CAPABILITY] = { .type = NLA_BINARY, }, | 372 | [NL80211_ATTR_STA_EXT_CAPABILITY] = { .type = NLA_BINARY, }, |
373 | [NL80211_ATTR_SPLIT_WIPHY_DUMP] = { .type = NLA_FLAG, }, | ||
374 | [NL80211_ATTR_DISABLE_VHT] = { .type = NLA_FLAG }, | ||
375 | [NL80211_ATTR_VHT_CAPABILITY_MASK] = { | ||
376 | .len = NL80211_VHT_CAPABILITY_LEN, | ||
377 | }, | ||
378 | [NL80211_ATTR_MDID] = { .type = NLA_U16 }, | ||
379 | [NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY, | ||
380 | .len = IEEE80211_MAX_DATA_LEN }, | ||
373 | }; | 381 | }; |
374 | 382 | ||
375 | /* policy for the key attributes */ | 383 | /* policy for the key attributes */ |
@@ -439,62 +447,69 @@ nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = { | |||
439 | [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 }, | 447 | [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 }, |
440 | }; | 448 | }; |
441 | 449 | ||
442 | /* ifidx get helper */ | 450 | static int nl80211_prepare_wdev_dump(struct sk_buff *skb, |
443 | static int nl80211_get_ifidx(struct netlink_callback *cb) | 451 | struct netlink_callback *cb, |
452 | struct cfg80211_registered_device **rdev, | ||
453 | struct wireless_dev **wdev) | ||
444 | { | 454 | { |
445 | int res; | 455 | int err; |
446 | |||
447 | res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | ||
448 | nl80211_fam.attrbuf, nl80211_fam.maxattr, | ||
449 | nl80211_policy); | ||
450 | if (res) | ||
451 | return res; | ||
452 | |||
453 | if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]) | ||
454 | return -EINVAL; | ||
455 | 456 | ||
456 | res = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]); | 457 | rtnl_lock(); |
457 | if (!res) | 458 | mutex_lock(&cfg80211_mutex); |
458 | return -EINVAL; | ||
459 | return res; | ||
460 | } | ||
461 | 459 | ||
462 | static int nl80211_prepare_netdev_dump(struct sk_buff *skb, | 460 | if (!cb->args[0]) { |
463 | struct netlink_callback *cb, | 461 | err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, |
464 | struct cfg80211_registered_device **rdev, | 462 | nl80211_fam.attrbuf, nl80211_fam.maxattr, |
465 | struct net_device **dev) | 463 | nl80211_policy); |
466 | { | 464 | if (err) |
467 | int ifidx = cb->args[0]; | 465 | goto out_unlock; |
468 | int err; | ||
469 | 466 | ||
470 | if (!ifidx) | 467 | *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk), |
471 | ifidx = nl80211_get_ifidx(cb); | 468 | nl80211_fam.attrbuf); |
472 | if (ifidx < 0) | 469 | if (IS_ERR(*wdev)) { |
473 | return ifidx; | 470 | err = PTR_ERR(*wdev); |
471 | goto out_unlock; | ||
472 | } | ||
473 | *rdev = wiphy_to_dev((*wdev)->wiphy); | ||
474 | cb->args[0] = (*rdev)->wiphy_idx; | ||
475 | cb->args[1] = (*wdev)->identifier; | ||
476 | } else { | ||
477 | struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0]); | ||
478 | struct wireless_dev *tmp; | ||
474 | 479 | ||
475 | cb->args[0] = ifidx; | 480 | if (!wiphy) { |
481 | err = -ENODEV; | ||
482 | goto out_unlock; | ||
483 | } | ||
484 | *rdev = wiphy_to_dev(wiphy); | ||
485 | *wdev = NULL; | ||
476 | 486 | ||
477 | rtnl_lock(); | 487 | mutex_lock(&(*rdev)->devlist_mtx); |
488 | list_for_each_entry(tmp, &(*rdev)->wdev_list, list) { | ||
489 | if (tmp->identifier == cb->args[1]) { | ||
490 | *wdev = tmp; | ||
491 | break; | ||
492 | } | ||
493 | } | ||
494 | mutex_unlock(&(*rdev)->devlist_mtx); | ||
478 | 495 | ||
479 | *dev = __dev_get_by_index(sock_net(skb->sk), ifidx); | 496 | if (!*wdev) { |
480 | if (!*dev) { | 497 | err = -ENODEV; |
481 | err = -ENODEV; | 498 | goto out_unlock; |
482 | goto out_rtnl; | 499 | } |
483 | } | 500 | } |
484 | 501 | ||
485 | *rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | 502 | cfg80211_lock_rdev(*rdev); |
486 | if (IS_ERR(*rdev)) { | ||
487 | err = PTR_ERR(*rdev); | ||
488 | goto out_rtnl; | ||
489 | } | ||
490 | 503 | ||
504 | mutex_unlock(&cfg80211_mutex); | ||
491 | return 0; | 505 | return 0; |
492 | out_rtnl: | 506 | out_unlock: |
507 | mutex_unlock(&cfg80211_mutex); | ||
493 | rtnl_unlock(); | 508 | rtnl_unlock(); |
494 | return err; | 509 | return err; |
495 | } | 510 | } |
496 | 511 | ||
497 | static void nl80211_finish_netdev_dump(struct cfg80211_registered_device *rdev) | 512 | static void nl80211_finish_wdev_dump(struct cfg80211_registered_device *rdev) |
498 | { | 513 | { |
499 | cfg80211_unlock_rdev(rdev); | 514 | cfg80211_unlock_rdev(rdev); |
500 | rtnl_unlock(); | 515 | rtnl_unlock(); |
@@ -539,7 +554,8 @@ static inline void *nl80211hdr_put(struct sk_buff *skb, u32 portid, u32 seq, | |||
539 | } | 554 | } |
540 | 555 | ||
541 | static int nl80211_msg_put_channel(struct sk_buff *msg, | 556 | static int nl80211_msg_put_channel(struct sk_buff *msg, |
542 | struct ieee80211_channel *chan) | 557 | struct ieee80211_channel *chan, |
558 | bool large) | ||
543 | { | 559 | { |
544 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_FREQ, | 560 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_FREQ, |
545 | chan->center_freq)) | 561 | chan->center_freq)) |
@@ -554,9 +570,37 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, | |||
554 | if ((chan->flags & IEEE80211_CHAN_NO_IBSS) && | 570 | if ((chan->flags & IEEE80211_CHAN_NO_IBSS) && |
555 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS)) | 571 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS)) |
556 | goto nla_put_failure; | 572 | goto nla_put_failure; |
557 | if ((chan->flags & IEEE80211_CHAN_RADAR) && | 573 | if (chan->flags & IEEE80211_CHAN_RADAR) { |
558 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR)) | 574 | if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR)) |
559 | goto nla_put_failure; | 575 | goto nla_put_failure; |
576 | if (large) { | ||
577 | u32 time; | ||
578 | |||
579 | time = elapsed_jiffies_msecs(chan->dfs_state_entered); | ||
580 | |||
581 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_STATE, | ||
582 | chan->dfs_state)) | ||
583 | goto nla_put_failure; | ||
584 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME, | ||
585 | time)) | ||
586 | goto nla_put_failure; | ||
587 | } | ||
588 | } | ||
589 | |||
590 | if (large) { | ||
591 | if ((chan->flags & IEEE80211_CHAN_NO_HT40MINUS) && | ||
592 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_MINUS)) | ||
593 | goto nla_put_failure; | ||
594 | if ((chan->flags & IEEE80211_CHAN_NO_HT40PLUS) && | ||
595 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_PLUS)) | ||
596 | goto nla_put_failure; | ||
597 | if ((chan->flags & IEEE80211_CHAN_NO_80MHZ) && | ||
598 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_80MHZ)) | ||
599 | goto nla_put_failure; | ||
600 | if ((chan->flags & IEEE80211_CHAN_NO_160MHZ) && | ||
601 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_160MHZ)) | ||
602 | goto nla_put_failure; | ||
603 | } | ||
560 | 604 | ||
561 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, | 605 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, |
562 | DBM_TO_MBM(chan->max_power))) | 606 | DBM_TO_MBM(chan->max_power))) |
@@ -832,7 +876,8 @@ nla_put_failure: | |||
832 | } | 876 | } |
833 | 877 | ||
834 | static int nl80211_put_iface_combinations(struct wiphy *wiphy, | 878 | static int nl80211_put_iface_combinations(struct wiphy *wiphy, |
835 | struct sk_buff *msg) | 879 | struct sk_buff *msg, |
880 | bool large) | ||
836 | { | 881 | { |
837 | struct nlattr *nl_combis; | 882 | struct nlattr *nl_combis; |
838 | int i, j; | 883 | int i, j; |
@@ -881,6 +926,10 @@ static int nl80211_put_iface_combinations(struct wiphy *wiphy, | |||
881 | nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM, | 926 | nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM, |
882 | c->max_interfaces)) | 927 | c->max_interfaces)) |
883 | goto nla_put_failure; | 928 | goto nla_put_failure; |
929 | if (large && | ||
930 | nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS, | ||
931 | c->radar_detect_widths)) | ||
932 | goto nla_put_failure; | ||
884 | 933 | ||
885 | nla_nest_end(msg, nl_combi); | 934 | nla_nest_end(msg, nl_combi); |
886 | } | 935 | } |
@@ -892,412 +941,615 @@ nla_put_failure: | |||
892 | return -ENOBUFS; | 941 | return -ENOBUFS; |
893 | } | 942 | } |
894 | 943 | ||
895 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flags, | 944 | #ifdef CONFIG_PM |
896 | struct cfg80211_registered_device *dev) | 945 | static int nl80211_send_wowlan_tcp_caps(struct cfg80211_registered_device *rdev, |
946 | struct sk_buff *msg) | ||
897 | { | 947 | { |
898 | void *hdr; | 948 | const struct wiphy_wowlan_tcp_support *tcp = rdev->wiphy.wowlan.tcp; |
899 | struct nlattr *nl_bands, *nl_band; | 949 | struct nlattr *nl_tcp; |
900 | struct nlattr *nl_freqs, *nl_freq; | ||
901 | struct nlattr *nl_rates, *nl_rate; | ||
902 | struct nlattr *nl_cmds; | ||
903 | enum ieee80211_band band; | ||
904 | struct ieee80211_channel *chan; | ||
905 | struct ieee80211_rate *rate; | ||
906 | int i; | ||
907 | const struct ieee80211_txrx_stypes *mgmt_stypes = | ||
908 | dev->wiphy.mgmt_stypes; | ||
909 | 950 | ||
910 | hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_WIPHY); | 951 | if (!tcp) |
911 | if (!hdr) | 952 | return 0; |
912 | return -1; | ||
913 | 953 | ||
914 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx) || | 954 | nl_tcp = nla_nest_start(msg, NL80211_WOWLAN_TRIG_TCP_CONNECTION); |
915 | nla_put_string(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)) || | 955 | if (!nl_tcp) |
916 | nla_put_u32(msg, NL80211_ATTR_GENERATION, | 956 | return -ENOBUFS; |
917 | cfg80211_rdev_list_generation) || | ||
918 | nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, | ||
919 | dev->wiphy.retry_short) || | ||
920 | nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, | ||
921 | dev->wiphy.retry_long) || | ||
922 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, | ||
923 | dev->wiphy.frag_threshold) || | ||
924 | nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, | ||
925 | dev->wiphy.rts_threshold) || | ||
926 | nla_put_u8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, | ||
927 | dev->wiphy.coverage_class) || | ||
928 | nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, | ||
929 | dev->wiphy.max_scan_ssids) || | ||
930 | nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS, | ||
931 | dev->wiphy.max_sched_scan_ssids) || | ||
932 | nla_put_u16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, | ||
933 | dev->wiphy.max_scan_ie_len) || | ||
934 | nla_put_u16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN, | ||
935 | dev->wiphy.max_sched_scan_ie_len) || | ||
936 | nla_put_u8(msg, NL80211_ATTR_MAX_MATCH_SETS, | ||
937 | dev->wiphy.max_match_sets)) | ||
938 | goto nla_put_failure; | ||
939 | 957 | ||
940 | if ((dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) && | 958 | if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD, |
941 | nla_put_flag(msg, NL80211_ATTR_SUPPORT_IBSS_RSN)) | 959 | tcp->data_payload_max)) |
942 | goto nla_put_failure; | 960 | return -ENOBUFS; |
943 | if ((dev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) && | ||
944 | nla_put_flag(msg, NL80211_ATTR_SUPPORT_MESH_AUTH)) | ||
945 | goto nla_put_failure; | ||
946 | if ((dev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) && | ||
947 | nla_put_flag(msg, NL80211_ATTR_SUPPORT_AP_UAPSD)) | ||
948 | goto nla_put_failure; | ||
949 | if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) && | ||
950 | nla_put_flag(msg, NL80211_ATTR_ROAM_SUPPORT)) | ||
951 | goto nla_put_failure; | ||
952 | if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) && | ||
953 | nla_put_flag(msg, NL80211_ATTR_TDLS_SUPPORT)) | ||
954 | goto nla_put_failure; | ||
955 | if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) && | ||
956 | nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP)) | ||
957 | goto nla_put_failure; | ||
958 | 961 | ||
959 | if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES, | 962 | if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD, |
960 | sizeof(u32) * dev->wiphy.n_cipher_suites, | 963 | tcp->data_payload_max)) |
961 | dev->wiphy.cipher_suites)) | 964 | return -ENOBUFS; |
962 | goto nla_put_failure; | ||
963 | 965 | ||
964 | if (nla_put_u8(msg, NL80211_ATTR_MAX_NUM_PMKIDS, | 966 | if (tcp->seq && nla_put_flag(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ)) |
965 | dev->wiphy.max_num_pmkids)) | 967 | return -ENOBUFS; |
966 | goto nla_put_failure; | ||
967 | 968 | ||
968 | if ((dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) && | 969 | if (tcp->tok && nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN, |
969 | nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE)) | 970 | sizeof(*tcp->tok), tcp->tok)) |
970 | goto nla_put_failure; | 971 | return -ENOBUFS; |
971 | 972 | ||
972 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX, | 973 | if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL, |
973 | dev->wiphy.available_antennas_tx) || | 974 | tcp->data_interval_max)) |
974 | nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX, | 975 | return -ENOBUFS; |
975 | dev->wiphy.available_antennas_rx)) | ||
976 | goto nla_put_failure; | ||
977 | 976 | ||
978 | if ((dev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) && | 977 | if (nla_put_u32(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD, |
979 | nla_put_u32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD, | 978 | tcp->wake_payload_max)) |
980 | dev->wiphy.probe_resp_offload)) | 979 | return -ENOBUFS; |
981 | goto nla_put_failure; | ||
982 | 980 | ||
983 | if ((dev->wiphy.available_antennas_tx || | 981 | nla_nest_end(msg, nl_tcp); |
984 | dev->wiphy.available_antennas_rx) && dev->ops->get_antenna) { | 982 | return 0; |
985 | u32 tx_ant = 0, rx_ant = 0; | 983 | } |
986 | int res; | 984 | |
987 | res = rdev_get_antenna(dev, &tx_ant, &rx_ant); | 985 | static int nl80211_send_wowlan(struct sk_buff *msg, |
988 | if (!res) { | 986 | struct cfg80211_registered_device *dev, |
989 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX, | 987 | bool large) |
990 | tx_ant) || | 988 | { |
991 | nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_RX, | 989 | struct nlattr *nl_wowlan; |
992 | rx_ant)) | 990 | |
993 | goto nla_put_failure; | 991 | if (!dev->wiphy.wowlan.flags && !dev->wiphy.wowlan.n_patterns) |
994 | } | 992 | return 0; |
993 | |||
994 | nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED); | ||
995 | if (!nl_wowlan) | ||
996 | return -ENOBUFS; | ||
997 | |||
998 | if (((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_ANY) && | ||
999 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) || | ||
1000 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_DISCONNECT) && | ||
1001 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) || | ||
1002 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT) && | ||
1003 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) || | ||
1004 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) && | ||
1005 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) || | ||
1006 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && | ||
1007 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) || | ||
1008 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) && | ||
1009 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) || | ||
1010 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) && | ||
1011 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) || | ||
1012 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_RFKILL_RELEASE) && | ||
1013 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) | ||
1014 | return -ENOBUFS; | ||
1015 | |||
1016 | if (dev->wiphy.wowlan.n_patterns) { | ||
1017 | struct nl80211_wowlan_pattern_support pat = { | ||
1018 | .max_patterns = dev->wiphy.wowlan.n_patterns, | ||
1019 | .min_pattern_len = dev->wiphy.wowlan.pattern_min_len, | ||
1020 | .max_pattern_len = dev->wiphy.wowlan.pattern_max_len, | ||
1021 | .max_pkt_offset = dev->wiphy.wowlan.max_pkt_offset, | ||
1022 | }; | ||
1023 | |||
1024 | if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN, | ||
1025 | sizeof(pat), &pat)) | ||
1026 | return -ENOBUFS; | ||
995 | } | 1027 | } |
996 | 1028 | ||
997 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES, | 1029 | if (large && nl80211_send_wowlan_tcp_caps(dev, msg)) |
998 | dev->wiphy.interface_modes)) | 1030 | return -ENOBUFS; |
999 | goto nla_put_failure; | ||
1000 | 1031 | ||
1001 | nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); | 1032 | nla_nest_end(msg, nl_wowlan); |
1002 | if (!nl_bands) | ||
1003 | goto nla_put_failure; | ||
1004 | 1033 | ||
1005 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 1034 | return 0; |
1006 | if (!dev->wiphy.bands[band]) | 1035 | } |
1007 | continue; | 1036 | #endif |
1008 | 1037 | ||
1009 | nl_band = nla_nest_start(msg, band); | 1038 | static int nl80211_send_band_rateinfo(struct sk_buff *msg, |
1010 | if (!nl_band) | 1039 | struct ieee80211_supported_band *sband) |
1011 | goto nla_put_failure; | 1040 | { |
1041 | struct nlattr *nl_rates, *nl_rate; | ||
1042 | struct ieee80211_rate *rate; | ||
1043 | int i; | ||
1012 | 1044 | ||
1013 | /* add HT info */ | 1045 | /* add HT info */ |
1014 | if (dev->wiphy.bands[band]->ht_cap.ht_supported && | 1046 | if (sband->ht_cap.ht_supported && |
1015 | (nla_put(msg, NL80211_BAND_ATTR_HT_MCS_SET, | 1047 | (nla_put(msg, NL80211_BAND_ATTR_HT_MCS_SET, |
1016 | sizeof(dev->wiphy.bands[band]->ht_cap.mcs), | 1048 | sizeof(sband->ht_cap.mcs), |
1017 | &dev->wiphy.bands[band]->ht_cap.mcs) || | 1049 | &sband->ht_cap.mcs) || |
1018 | nla_put_u16(msg, NL80211_BAND_ATTR_HT_CAPA, | 1050 | nla_put_u16(msg, NL80211_BAND_ATTR_HT_CAPA, |
1019 | dev->wiphy.bands[band]->ht_cap.cap) || | 1051 | sband->ht_cap.cap) || |
1020 | nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR, | 1052 | nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR, |
1021 | dev->wiphy.bands[band]->ht_cap.ampdu_factor) || | 1053 | sband->ht_cap.ampdu_factor) || |
1022 | nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY, | 1054 | nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY, |
1023 | dev->wiphy.bands[band]->ht_cap.ampdu_density))) | 1055 | sband->ht_cap.ampdu_density))) |
1024 | goto nla_put_failure; | 1056 | return -ENOBUFS; |
1025 | 1057 | ||
1026 | /* add VHT info */ | 1058 | /* add VHT info */ |
1027 | if (dev->wiphy.bands[band]->vht_cap.vht_supported && | 1059 | if (sband->vht_cap.vht_supported && |
1028 | (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET, | 1060 | (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET, |
1029 | sizeof(dev->wiphy.bands[band]->vht_cap.vht_mcs), | 1061 | sizeof(sband->vht_cap.vht_mcs), |
1030 | &dev->wiphy.bands[band]->vht_cap.vht_mcs) || | 1062 | &sband->vht_cap.vht_mcs) || |
1031 | nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA, | 1063 | nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA, |
1032 | dev->wiphy.bands[band]->vht_cap.cap))) | 1064 | sband->vht_cap.cap))) |
1033 | goto nla_put_failure; | 1065 | return -ENOBUFS; |
1034 | 1066 | ||
1035 | /* add frequencies */ | 1067 | /* add bitrates */ |
1036 | nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); | 1068 | nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES); |
1037 | if (!nl_freqs) | 1069 | if (!nl_rates) |
1038 | goto nla_put_failure; | 1070 | return -ENOBUFS; |
1039 | 1071 | ||
1040 | for (i = 0; i < dev->wiphy.bands[band]->n_channels; i++) { | 1072 | for (i = 0; i < sband->n_bitrates; i++) { |
1041 | nl_freq = nla_nest_start(msg, i); | 1073 | nl_rate = nla_nest_start(msg, i); |
1042 | if (!nl_freq) | 1074 | if (!nl_rate) |
1043 | goto nla_put_failure; | 1075 | return -ENOBUFS; |
1044 | 1076 | ||
1045 | chan = &dev->wiphy.bands[band]->channels[i]; | 1077 | rate = &sband->bitrates[i]; |
1078 | if (nla_put_u32(msg, NL80211_BITRATE_ATTR_RATE, | ||
1079 | rate->bitrate)) | ||
1080 | return -ENOBUFS; | ||
1081 | if ((rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) && | ||
1082 | nla_put_flag(msg, | ||
1083 | NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE)) | ||
1084 | return -ENOBUFS; | ||
1046 | 1085 | ||
1047 | if (nl80211_msg_put_channel(msg, chan)) | 1086 | nla_nest_end(msg, nl_rate); |
1048 | goto nla_put_failure; | 1087 | } |
1049 | 1088 | ||
1050 | nla_nest_end(msg, nl_freq); | 1089 | nla_nest_end(msg, nl_rates); |
1051 | } | ||
1052 | 1090 | ||
1053 | nla_nest_end(msg, nl_freqs); | 1091 | return 0; |
1092 | } | ||
1054 | 1093 | ||
1055 | /* add bitrates */ | 1094 | static int |
1056 | nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES); | 1095 | nl80211_send_mgmt_stypes(struct sk_buff *msg, |
1057 | if (!nl_rates) | 1096 | const struct ieee80211_txrx_stypes *mgmt_stypes) |
1058 | goto nla_put_failure; | 1097 | { |
1098 | u16 stypes; | ||
1099 | struct nlattr *nl_ftypes, *nl_ifs; | ||
1100 | enum nl80211_iftype ift; | ||
1101 | int i; | ||
1059 | 1102 | ||
1060 | for (i = 0; i < dev->wiphy.bands[band]->n_bitrates; i++) { | 1103 | if (!mgmt_stypes) |
1061 | nl_rate = nla_nest_start(msg, i); | 1104 | return 0; |
1062 | if (!nl_rate) | ||
1063 | goto nla_put_failure; | ||
1064 | 1105 | ||
1065 | rate = &dev->wiphy.bands[band]->bitrates[i]; | 1106 | nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES); |
1066 | if (nla_put_u32(msg, NL80211_BITRATE_ATTR_RATE, | 1107 | if (!nl_ifs) |
1067 | rate->bitrate)) | 1108 | return -ENOBUFS; |
1068 | goto nla_put_failure; | ||
1069 | if ((rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) && | ||
1070 | nla_put_flag(msg, | ||
1071 | NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE)) | ||
1072 | goto nla_put_failure; | ||
1073 | 1109 | ||
1074 | nla_nest_end(msg, nl_rate); | 1110 | for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) { |
1111 | nl_ftypes = nla_nest_start(msg, ift); | ||
1112 | if (!nl_ftypes) | ||
1113 | return -ENOBUFS; | ||
1114 | i = 0; | ||
1115 | stypes = mgmt_stypes[ift].tx; | ||
1116 | while (stypes) { | ||
1117 | if ((stypes & 1) && | ||
1118 | nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE, | ||
1119 | (i << 4) | IEEE80211_FTYPE_MGMT)) | ||
1120 | return -ENOBUFS; | ||
1121 | stypes >>= 1; | ||
1122 | i++; | ||
1075 | } | 1123 | } |
1124 | nla_nest_end(msg, nl_ftypes); | ||
1125 | } | ||
1126 | |||
1127 | nla_nest_end(msg, nl_ifs); | ||
1076 | 1128 | ||
1077 | nla_nest_end(msg, nl_rates); | 1129 | nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES); |
1130 | if (!nl_ifs) | ||
1131 | return -ENOBUFS; | ||
1078 | 1132 | ||
1079 | nla_nest_end(msg, nl_band); | 1133 | for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) { |
1134 | nl_ftypes = nla_nest_start(msg, ift); | ||
1135 | if (!nl_ftypes) | ||
1136 | return -ENOBUFS; | ||
1137 | i = 0; | ||
1138 | stypes = mgmt_stypes[ift].rx; | ||
1139 | while (stypes) { | ||
1140 | if ((stypes & 1) && | ||
1141 | nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE, | ||
1142 | (i << 4) | IEEE80211_FTYPE_MGMT)) | ||
1143 | return -ENOBUFS; | ||
1144 | stypes >>= 1; | ||
1145 | i++; | ||
1146 | } | ||
1147 | nla_nest_end(msg, nl_ftypes); | ||
1080 | } | 1148 | } |
1081 | nla_nest_end(msg, nl_bands); | 1149 | nla_nest_end(msg, nl_ifs); |
1082 | 1150 | ||
1083 | nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS); | 1151 | return 0; |
1084 | if (!nl_cmds) | 1152 | } |
1085 | goto nla_put_failure; | ||
1086 | 1153 | ||
1087 | i = 0; | 1154 | static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, |
1088 | #define CMD(op, n) \ | 1155 | struct sk_buff *msg, u32 portid, u32 seq, |
1089 | do { \ | 1156 | int flags, bool split, long *split_start, |
1090 | if (dev->ops->op) { \ | 1157 | long *band_start, long *chan_start) |
1091 | i++; \ | 1158 | { |
1092 | if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \ | 1159 | void *hdr; |
1093 | goto nla_put_failure; \ | 1160 | struct nlattr *nl_bands, *nl_band; |
1094 | } \ | 1161 | struct nlattr *nl_freqs, *nl_freq; |
1095 | } while (0) | 1162 | struct nlattr *nl_cmds; |
1096 | 1163 | enum ieee80211_band band; | |
1097 | CMD(add_virtual_intf, NEW_INTERFACE); | 1164 | struct ieee80211_channel *chan; |
1098 | CMD(change_virtual_intf, SET_INTERFACE); | 1165 | int i; |
1099 | CMD(add_key, NEW_KEY); | 1166 | const struct ieee80211_txrx_stypes *mgmt_stypes = |
1100 | CMD(start_ap, START_AP); | 1167 | dev->wiphy.mgmt_stypes; |
1101 | CMD(add_station, NEW_STATION); | 1168 | long start = 0, start_chan = 0, start_band = 0; |
1102 | CMD(add_mpath, NEW_MPATH); | 1169 | u32 features; |
1103 | CMD(update_mesh_config, SET_MESH_CONFIG); | 1170 | |
1104 | CMD(change_bss, SET_BSS); | 1171 | hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_WIPHY); |
1105 | CMD(auth, AUTHENTICATE); | 1172 | if (!hdr) |
1106 | CMD(assoc, ASSOCIATE); | 1173 | return -ENOBUFS; |
1107 | CMD(deauth, DEAUTHENTICATE); | 1174 | |
1108 | CMD(disassoc, DISASSOCIATE); | 1175 | /* allow always using the variables */ |
1109 | CMD(join_ibss, JOIN_IBSS); | 1176 | if (!split) { |
1110 | CMD(join_mesh, JOIN_MESH); | 1177 | split_start = &start; |
1111 | CMD(set_pmksa, SET_PMKSA); | 1178 | band_start = &start_band; |
1112 | CMD(del_pmksa, DEL_PMKSA); | 1179 | chan_start = &start_chan; |
1113 | CMD(flush_pmksa, FLUSH_PMKSA); | ||
1114 | if (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) | ||
1115 | CMD(remain_on_channel, REMAIN_ON_CHANNEL); | ||
1116 | CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); | ||
1117 | CMD(mgmt_tx, FRAME); | ||
1118 | CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL); | ||
1119 | if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { | ||
1120 | i++; | ||
1121 | if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS)) | ||
1122 | goto nla_put_failure; | ||
1123 | } | 1180 | } |
1124 | if (dev->ops->set_monitor_channel || dev->ops->start_ap || | 1181 | |
1125 | dev->ops->join_mesh) { | 1182 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx) || |
1126 | i++; | 1183 | nla_put_string(msg, NL80211_ATTR_WIPHY_NAME, |
1127 | if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL)) | 1184 | wiphy_name(&dev->wiphy)) || |
1185 | nla_put_u32(msg, NL80211_ATTR_GENERATION, | ||
1186 | cfg80211_rdev_list_generation)) | ||
1187 | goto nla_put_failure; | ||
1188 | |||
1189 | switch (*split_start) { | ||
1190 | case 0: | ||
1191 | if (nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, | ||
1192 | dev->wiphy.retry_short) || | ||
1193 | nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, | ||
1194 | dev->wiphy.retry_long) || | ||
1195 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, | ||
1196 | dev->wiphy.frag_threshold) || | ||
1197 | nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, | ||
1198 | dev->wiphy.rts_threshold) || | ||
1199 | nla_put_u8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, | ||
1200 | dev->wiphy.coverage_class) || | ||
1201 | nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, | ||
1202 | dev->wiphy.max_scan_ssids) || | ||
1203 | nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS, | ||
1204 | dev->wiphy.max_sched_scan_ssids) || | ||
1205 | nla_put_u16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, | ||
1206 | dev->wiphy.max_scan_ie_len) || | ||
1207 | nla_put_u16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN, | ||
1208 | dev->wiphy.max_sched_scan_ie_len) || | ||
1209 | nla_put_u8(msg, NL80211_ATTR_MAX_MATCH_SETS, | ||
1210 | dev->wiphy.max_match_sets)) | ||
1128 | goto nla_put_failure; | 1211 | goto nla_put_failure; |
1129 | } | 1212 | |
1130 | CMD(set_wds_peer, SET_WDS_PEER); | 1213 | if ((dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) && |
1131 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) { | 1214 | nla_put_flag(msg, NL80211_ATTR_SUPPORT_IBSS_RSN)) |
1132 | CMD(tdls_mgmt, TDLS_MGMT); | 1215 | goto nla_put_failure; |
1133 | CMD(tdls_oper, TDLS_OPER); | 1216 | if ((dev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) && |
1134 | } | 1217 | nla_put_flag(msg, NL80211_ATTR_SUPPORT_MESH_AUTH)) |
1135 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) | 1218 | goto nla_put_failure; |
1136 | CMD(sched_scan_start, START_SCHED_SCAN); | 1219 | if ((dev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) && |
1137 | CMD(probe_client, PROBE_CLIENT); | 1220 | nla_put_flag(msg, NL80211_ATTR_SUPPORT_AP_UAPSD)) |
1138 | CMD(set_noack_map, SET_NOACK_MAP); | 1221 | goto nla_put_failure; |
1139 | if (dev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) { | 1222 | if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) && |
1140 | i++; | 1223 | nla_put_flag(msg, NL80211_ATTR_ROAM_SUPPORT)) |
1141 | if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS)) | 1224 | goto nla_put_failure; |
1225 | if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) && | ||
1226 | nla_put_flag(msg, NL80211_ATTR_TDLS_SUPPORT)) | ||
1227 | goto nla_put_failure; | ||
1228 | if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) && | ||
1229 | nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP)) | ||
1142 | goto nla_put_failure; | 1230 | goto nla_put_failure; |
1143 | } | ||
1144 | CMD(start_p2p_device, START_P2P_DEVICE); | ||
1145 | CMD(set_mcast_rate, SET_MCAST_RATE); | ||
1146 | 1231 | ||
1147 | #ifdef CONFIG_NL80211_TESTMODE | 1232 | (*split_start)++; |
1148 | CMD(testmode_cmd, TESTMODE); | 1233 | if (split) |
1149 | #endif | 1234 | break; |
1235 | case 1: | ||
1236 | if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES, | ||
1237 | sizeof(u32) * dev->wiphy.n_cipher_suites, | ||
1238 | dev->wiphy.cipher_suites)) | ||
1239 | goto nla_put_failure; | ||
1150 | 1240 | ||
1151 | #undef CMD | 1241 | if (nla_put_u8(msg, NL80211_ATTR_MAX_NUM_PMKIDS, |
1242 | dev->wiphy.max_num_pmkids)) | ||
1243 | goto nla_put_failure; | ||
1152 | 1244 | ||
1153 | if (dev->ops->connect || dev->ops->auth) { | 1245 | if ((dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) && |
1154 | i++; | 1246 | nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE)) |
1155 | if (nla_put_u32(msg, i, NL80211_CMD_CONNECT)) | ||
1156 | goto nla_put_failure; | 1247 | goto nla_put_failure; |
1157 | } | ||
1158 | 1248 | ||
1159 | if (dev->ops->disconnect || dev->ops->deauth) { | 1249 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX, |
1160 | i++; | 1250 | dev->wiphy.available_antennas_tx) || |
1161 | if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT)) | 1251 | nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX, |
1252 | dev->wiphy.available_antennas_rx)) | ||
1162 | goto nla_put_failure; | 1253 | goto nla_put_failure; |
1163 | } | ||
1164 | 1254 | ||
1165 | nla_nest_end(msg, nl_cmds); | 1255 | if ((dev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) && |
1256 | nla_put_u32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD, | ||
1257 | dev->wiphy.probe_resp_offload)) | ||
1258 | goto nla_put_failure; | ||
1166 | 1259 | ||
1167 | if (dev->ops->remain_on_channel && | 1260 | if ((dev->wiphy.available_antennas_tx || |
1168 | (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) && | 1261 | dev->wiphy.available_antennas_rx) && |
1169 | nla_put_u32(msg, NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION, | 1262 | dev->ops->get_antenna) { |
1170 | dev->wiphy.max_remain_on_channel_duration)) | 1263 | u32 tx_ant = 0, rx_ant = 0; |
1171 | goto nla_put_failure; | 1264 | int res; |
1265 | res = rdev_get_antenna(dev, &tx_ant, &rx_ant); | ||
1266 | if (!res) { | ||
1267 | if (nla_put_u32(msg, | ||
1268 | NL80211_ATTR_WIPHY_ANTENNA_TX, | ||
1269 | tx_ant) || | ||
1270 | nla_put_u32(msg, | ||
1271 | NL80211_ATTR_WIPHY_ANTENNA_RX, | ||
1272 | rx_ant)) | ||
1273 | goto nla_put_failure; | ||
1274 | } | ||
1275 | } | ||
1172 | 1276 | ||
1173 | if ((dev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) && | 1277 | (*split_start)++; |
1174 | nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK)) | 1278 | if (split) |
1175 | goto nla_put_failure; | 1279 | break; |
1280 | case 2: | ||
1281 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES, | ||
1282 | dev->wiphy.interface_modes)) | ||
1283 | goto nla_put_failure; | ||
1284 | (*split_start)++; | ||
1285 | if (split) | ||
1286 | break; | ||
1287 | case 3: | ||
1288 | nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); | ||
1289 | if (!nl_bands) | ||
1290 | goto nla_put_failure; | ||
1176 | 1291 | ||
1177 | if (mgmt_stypes) { | 1292 | for (band = *band_start; band < IEEE80211_NUM_BANDS; band++) { |
1178 | u16 stypes; | 1293 | struct ieee80211_supported_band *sband; |
1179 | struct nlattr *nl_ftypes, *nl_ifs; | ||
1180 | enum nl80211_iftype ift; | ||
1181 | 1294 | ||
1182 | nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES); | 1295 | sband = dev->wiphy.bands[band]; |
1183 | if (!nl_ifs) | ||
1184 | goto nla_put_failure; | ||
1185 | 1296 | ||
1186 | for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) { | 1297 | if (!sband) |
1187 | nl_ftypes = nla_nest_start(msg, ift); | 1298 | continue; |
1188 | if (!nl_ftypes) | 1299 | |
1300 | nl_band = nla_nest_start(msg, band); | ||
1301 | if (!nl_band) | ||
1189 | goto nla_put_failure; | 1302 | goto nla_put_failure; |
1190 | i = 0; | 1303 | |
1191 | stypes = mgmt_stypes[ift].tx; | 1304 | switch (*chan_start) { |
1192 | while (stypes) { | 1305 | case 0: |
1193 | if ((stypes & 1) && | 1306 | if (nl80211_send_band_rateinfo(msg, sband)) |
1194 | nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE, | ||
1195 | (i << 4) | IEEE80211_FTYPE_MGMT)) | ||
1196 | goto nla_put_failure; | 1307 | goto nla_put_failure; |
1197 | stypes >>= 1; | 1308 | (*chan_start)++; |
1198 | i++; | 1309 | if (split) |
1310 | break; | ||
1311 | default: | ||
1312 | /* add frequencies */ | ||
1313 | nl_freqs = nla_nest_start( | ||
1314 | msg, NL80211_BAND_ATTR_FREQS); | ||
1315 | if (!nl_freqs) | ||
1316 | goto nla_put_failure; | ||
1317 | |||
1318 | for (i = *chan_start - 1; | ||
1319 | i < sband->n_channels; | ||
1320 | i++) { | ||
1321 | nl_freq = nla_nest_start(msg, i); | ||
1322 | if (!nl_freq) | ||
1323 | goto nla_put_failure; | ||
1324 | |||
1325 | chan = &sband->channels[i]; | ||
1326 | |||
1327 | if (nl80211_msg_put_channel(msg, chan, | ||
1328 | split)) | ||
1329 | goto nla_put_failure; | ||
1330 | |||
1331 | nla_nest_end(msg, nl_freq); | ||
1332 | if (split) | ||
1333 | break; | ||
1334 | } | ||
1335 | if (i < sband->n_channels) | ||
1336 | *chan_start = i + 2; | ||
1337 | else | ||
1338 | *chan_start = 0; | ||
1339 | nla_nest_end(msg, nl_freqs); | ||
1340 | } | ||
1341 | |||
1342 | nla_nest_end(msg, nl_band); | ||
1343 | |||
1344 | if (split) { | ||
1345 | /* start again here */ | ||
1346 | if (*chan_start) | ||
1347 | band--; | ||
1348 | break; | ||
1199 | } | 1349 | } |
1200 | nla_nest_end(msg, nl_ftypes); | ||
1201 | } | 1350 | } |
1351 | nla_nest_end(msg, nl_bands); | ||
1202 | 1352 | ||
1203 | nla_nest_end(msg, nl_ifs); | 1353 | if (band < IEEE80211_NUM_BANDS) |
1354 | *band_start = band + 1; | ||
1355 | else | ||
1356 | *band_start = 0; | ||
1204 | 1357 | ||
1205 | nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES); | 1358 | /* if bands & channels are done, continue outside */ |
1206 | if (!nl_ifs) | 1359 | if (*band_start == 0 && *chan_start == 0) |
1360 | (*split_start)++; | ||
1361 | if (split) | ||
1362 | break; | ||
1363 | case 4: | ||
1364 | nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS); | ||
1365 | if (!nl_cmds) | ||
1207 | goto nla_put_failure; | 1366 | goto nla_put_failure; |
1208 | 1367 | ||
1209 | for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) { | 1368 | i = 0; |
1210 | nl_ftypes = nla_nest_start(msg, ift); | 1369 | #define CMD(op, n) \ |
1211 | if (!nl_ftypes) | 1370 | do { \ |
1371 | if (dev->ops->op) { \ | ||
1372 | i++; \ | ||
1373 | if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \ | ||
1374 | goto nla_put_failure; \ | ||
1375 | } \ | ||
1376 | } while (0) | ||
1377 | |||
1378 | CMD(add_virtual_intf, NEW_INTERFACE); | ||
1379 | CMD(change_virtual_intf, SET_INTERFACE); | ||
1380 | CMD(add_key, NEW_KEY); | ||
1381 | CMD(start_ap, START_AP); | ||
1382 | CMD(add_station, NEW_STATION); | ||
1383 | CMD(add_mpath, NEW_MPATH); | ||
1384 | CMD(update_mesh_config, SET_MESH_CONFIG); | ||
1385 | CMD(change_bss, SET_BSS); | ||
1386 | CMD(auth, AUTHENTICATE); | ||
1387 | CMD(assoc, ASSOCIATE); | ||
1388 | CMD(deauth, DEAUTHENTICATE); | ||
1389 | CMD(disassoc, DISASSOCIATE); | ||
1390 | CMD(join_ibss, JOIN_IBSS); | ||
1391 | CMD(join_mesh, JOIN_MESH); | ||
1392 | CMD(set_pmksa, SET_PMKSA); | ||
1393 | CMD(del_pmksa, DEL_PMKSA); | ||
1394 | CMD(flush_pmksa, FLUSH_PMKSA); | ||
1395 | if (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) | ||
1396 | CMD(remain_on_channel, REMAIN_ON_CHANNEL); | ||
1397 | CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); | ||
1398 | CMD(mgmt_tx, FRAME); | ||
1399 | CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL); | ||
1400 | if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { | ||
1401 | i++; | ||
1402 | if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS)) | ||
1212 | goto nla_put_failure; | 1403 | goto nla_put_failure; |
1213 | i = 0; | ||
1214 | stypes = mgmt_stypes[ift].rx; | ||
1215 | while (stypes) { | ||
1216 | if ((stypes & 1) && | ||
1217 | nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE, | ||
1218 | (i << 4) | IEEE80211_FTYPE_MGMT)) | ||
1219 | goto nla_put_failure; | ||
1220 | stypes >>= 1; | ||
1221 | i++; | ||
1222 | } | ||
1223 | nla_nest_end(msg, nl_ftypes); | ||
1224 | } | 1404 | } |
1225 | nla_nest_end(msg, nl_ifs); | 1405 | if (dev->ops->set_monitor_channel || dev->ops->start_ap || |
1226 | } | 1406 | dev->ops->join_mesh) { |
1407 | i++; | ||
1408 | if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL)) | ||
1409 | goto nla_put_failure; | ||
1410 | } | ||
1411 | CMD(set_wds_peer, SET_WDS_PEER); | ||
1412 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) { | ||
1413 | CMD(tdls_mgmt, TDLS_MGMT); | ||
1414 | CMD(tdls_oper, TDLS_OPER); | ||
1415 | } | ||
1416 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) | ||
1417 | CMD(sched_scan_start, START_SCHED_SCAN); | ||
1418 | CMD(probe_client, PROBE_CLIENT); | ||
1419 | CMD(set_noack_map, SET_NOACK_MAP); | ||
1420 | if (dev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) { | ||
1421 | i++; | ||
1422 | if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS)) | ||
1423 | goto nla_put_failure; | ||
1424 | } | ||
1425 | CMD(start_p2p_device, START_P2P_DEVICE); | ||
1426 | CMD(set_mcast_rate, SET_MCAST_RATE); | ||
1427 | if (split) { | ||
1428 | CMD(crit_proto_start, CRIT_PROTOCOL_START); | ||
1429 | CMD(crit_proto_stop, CRIT_PROTOCOL_STOP); | ||
1430 | } | ||
1227 | 1431 | ||
1228 | #ifdef CONFIG_PM | 1432 | #ifdef CONFIG_NL80211_TESTMODE |
1229 | if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) { | 1433 | CMD(testmode_cmd, TESTMODE); |
1230 | struct nlattr *nl_wowlan; | 1434 | #endif |
1231 | 1435 | ||
1232 | nl_wowlan = nla_nest_start(msg, | 1436 | #undef CMD |
1233 | NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED); | ||
1234 | if (!nl_wowlan) | ||
1235 | goto nla_put_failure; | ||
1236 | 1437 | ||
1237 | if (((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_ANY) && | 1438 | if (dev->ops->connect || dev->ops->auth) { |
1238 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) || | 1439 | i++; |
1239 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_DISCONNECT) && | 1440 | if (nla_put_u32(msg, i, NL80211_CMD_CONNECT)) |
1240 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) || | ||
1241 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT) && | ||
1242 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) || | ||
1243 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) && | ||
1244 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) || | ||
1245 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && | ||
1246 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) || | ||
1247 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) && | ||
1248 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) || | ||
1249 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) && | ||
1250 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) || | ||
1251 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_RFKILL_RELEASE) && | ||
1252 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) | ||
1253 | goto nla_put_failure; | ||
1254 | if (dev->wiphy.wowlan.n_patterns) { | ||
1255 | struct nl80211_wowlan_pattern_support pat = { | ||
1256 | .max_patterns = dev->wiphy.wowlan.n_patterns, | ||
1257 | .min_pattern_len = | ||
1258 | dev->wiphy.wowlan.pattern_min_len, | ||
1259 | .max_pattern_len = | ||
1260 | dev->wiphy.wowlan.pattern_max_len, | ||
1261 | .max_pkt_offset = | ||
1262 | dev->wiphy.wowlan.max_pkt_offset, | ||
1263 | }; | ||
1264 | if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN, | ||
1265 | sizeof(pat), &pat)) | ||
1266 | goto nla_put_failure; | 1441 | goto nla_put_failure; |
1267 | } | 1442 | } |
1268 | 1443 | ||
1269 | nla_nest_end(msg, nl_wowlan); | 1444 | if (dev->ops->disconnect || dev->ops->deauth) { |
1270 | } | 1445 | i++; |
1446 | if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT)) | ||
1447 | goto nla_put_failure; | ||
1448 | } | ||
1449 | |||
1450 | nla_nest_end(msg, nl_cmds); | ||
1451 | (*split_start)++; | ||
1452 | if (split) | ||
1453 | break; | ||
1454 | case 5: | ||
1455 | if (dev->ops->remain_on_channel && | ||
1456 | (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) && | ||
1457 | nla_put_u32(msg, | ||
1458 | NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION, | ||
1459 | dev->wiphy.max_remain_on_channel_duration)) | ||
1460 | goto nla_put_failure; | ||
1461 | |||
1462 | if ((dev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) && | ||
1463 | nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK)) | ||
1464 | goto nla_put_failure; | ||
1465 | |||
1466 | if (nl80211_send_mgmt_stypes(msg, mgmt_stypes)) | ||
1467 | goto nla_put_failure; | ||
1468 | (*split_start)++; | ||
1469 | if (split) | ||
1470 | break; | ||
1471 | case 6: | ||
1472 | #ifdef CONFIG_PM | ||
1473 | if (nl80211_send_wowlan(msg, dev, split)) | ||
1474 | goto nla_put_failure; | ||
1475 | (*split_start)++; | ||
1476 | if (split) | ||
1477 | break; | ||
1478 | #else | ||
1479 | (*split_start)++; | ||
1271 | #endif | 1480 | #endif |
1481 | case 7: | ||
1482 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, | ||
1483 | dev->wiphy.software_iftypes)) | ||
1484 | goto nla_put_failure; | ||
1272 | 1485 | ||
1273 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, | 1486 | if (nl80211_put_iface_combinations(&dev->wiphy, msg, split)) |
1274 | dev->wiphy.software_iftypes)) | 1487 | goto nla_put_failure; |
1275 | goto nla_put_failure; | ||
1276 | 1488 | ||
1277 | if (nl80211_put_iface_combinations(&dev->wiphy, msg)) | 1489 | (*split_start)++; |
1278 | goto nla_put_failure; | 1490 | if (split) |
1491 | break; | ||
1492 | case 8: | ||
1493 | if ((dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) && | ||
1494 | nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME, | ||
1495 | dev->wiphy.ap_sme_capa)) | ||
1496 | goto nla_put_failure; | ||
1279 | 1497 | ||
1280 | if ((dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) && | 1498 | features = dev->wiphy.features; |
1281 | nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME, | 1499 | /* |
1282 | dev->wiphy.ap_sme_capa)) | 1500 | * We can only add the per-channel limit information if the |
1283 | goto nla_put_failure; | 1501 | * dump is split, otherwise it makes it too big. Therefore |
1502 | * only advertise it in that case. | ||
1503 | */ | ||
1504 | if (split) | ||
1505 | features |= NL80211_FEATURE_ADVERTISE_CHAN_LIMITS; | ||
1506 | if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS, features)) | ||
1507 | goto nla_put_failure; | ||
1284 | 1508 | ||
1285 | if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS, | 1509 | if (dev->wiphy.ht_capa_mod_mask && |
1286 | dev->wiphy.features)) | 1510 | nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK, |
1287 | goto nla_put_failure; | 1511 | sizeof(*dev->wiphy.ht_capa_mod_mask), |
1512 | dev->wiphy.ht_capa_mod_mask)) | ||
1513 | goto nla_put_failure; | ||
1288 | 1514 | ||
1289 | if (dev->wiphy.ht_capa_mod_mask && | 1515 | if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME && |
1290 | nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK, | 1516 | dev->wiphy.max_acl_mac_addrs && |
1291 | sizeof(*dev->wiphy.ht_capa_mod_mask), | 1517 | nla_put_u32(msg, NL80211_ATTR_MAC_ACL_MAX, |
1292 | dev->wiphy.ht_capa_mod_mask)) | 1518 | dev->wiphy.max_acl_mac_addrs)) |
1293 | goto nla_put_failure; | 1519 | goto nla_put_failure; |
1294 | 1520 | ||
1295 | if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME && | 1521 | /* |
1296 | dev->wiphy.max_acl_mac_addrs && | 1522 | * Any information below this point is only available to |
1297 | nla_put_u32(msg, NL80211_ATTR_MAC_ACL_MAX, | 1523 | * applications that can deal with it being split. This |
1298 | dev->wiphy.max_acl_mac_addrs)) | 1524 | * helps ensure that newly added capabilities don't break |
1299 | goto nla_put_failure; | 1525 | * older tools by overrunning their buffers. |
1526 | * | ||
1527 | * We still increment split_start so that in the split | ||
1528 | * case we'll continue with more data in the next round, | ||
1529 | * but break unconditionally so unsplit data stops here. | ||
1530 | */ | ||
1531 | (*split_start)++; | ||
1532 | break; | ||
1533 | case 9: | ||
1534 | if (dev->wiphy.extended_capabilities && | ||
1535 | (nla_put(msg, NL80211_ATTR_EXT_CAPA, | ||
1536 | dev->wiphy.extended_capabilities_len, | ||
1537 | dev->wiphy.extended_capabilities) || | ||
1538 | nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK, | ||
1539 | dev->wiphy.extended_capabilities_len, | ||
1540 | dev->wiphy.extended_capabilities_mask))) | ||
1541 | goto nla_put_failure; | ||
1542 | |||
1543 | if (dev->wiphy.vht_capa_mod_mask && | ||
1544 | nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, | ||
1545 | sizeof(*dev->wiphy.vht_capa_mod_mask), | ||
1546 | dev->wiphy.vht_capa_mod_mask)) | ||
1547 | goto nla_put_failure; | ||
1300 | 1548 | ||
1549 | /* done */ | ||
1550 | *split_start = 0; | ||
1551 | break; | ||
1552 | } | ||
1301 | return genlmsg_end(msg, hdr); | 1553 | return genlmsg_end(msg, hdr); |
1302 | 1554 | ||
1303 | nla_put_failure: | 1555 | nla_put_failure: |
@@ -1310,39 +1562,80 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | |||
1310 | int idx = 0, ret; | 1562 | int idx = 0, ret; |
1311 | int start = cb->args[0]; | 1563 | int start = cb->args[0]; |
1312 | struct cfg80211_registered_device *dev; | 1564 | struct cfg80211_registered_device *dev; |
1565 | s64 filter_wiphy = -1; | ||
1566 | bool split = false; | ||
1567 | struct nlattr **tb = nl80211_fam.attrbuf; | ||
1568 | int res; | ||
1313 | 1569 | ||
1314 | mutex_lock(&cfg80211_mutex); | 1570 | mutex_lock(&cfg80211_mutex); |
1571 | res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | ||
1572 | tb, nl80211_fam.maxattr, nl80211_policy); | ||
1573 | if (res == 0) { | ||
1574 | split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP]; | ||
1575 | if (tb[NL80211_ATTR_WIPHY]) | ||
1576 | filter_wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]); | ||
1577 | if (tb[NL80211_ATTR_WDEV]) | ||
1578 | filter_wiphy = nla_get_u64(tb[NL80211_ATTR_WDEV]) >> 32; | ||
1579 | if (tb[NL80211_ATTR_IFINDEX]) { | ||
1580 | struct net_device *netdev; | ||
1581 | int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); | ||
1582 | |||
1583 | netdev = dev_get_by_index(sock_net(skb->sk), ifidx); | ||
1584 | if (!netdev) { | ||
1585 | mutex_unlock(&cfg80211_mutex); | ||
1586 | return -ENODEV; | ||
1587 | } | ||
1588 | if (netdev->ieee80211_ptr) { | ||
1589 | dev = wiphy_to_dev( | ||
1590 | netdev->ieee80211_ptr->wiphy); | ||
1591 | filter_wiphy = dev->wiphy_idx; | ||
1592 | } | ||
1593 | dev_put(netdev); | ||
1594 | } | ||
1595 | } | ||
1596 | |||
1315 | list_for_each_entry(dev, &cfg80211_rdev_list, list) { | 1597 | list_for_each_entry(dev, &cfg80211_rdev_list, list) { |
1316 | if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) | 1598 | if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) |
1317 | continue; | 1599 | continue; |
1318 | if (++idx <= start) | 1600 | if (++idx <= start) |
1319 | continue; | 1601 | continue; |
1320 | ret = nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).portid, | 1602 | if (filter_wiphy != -1 && dev->wiphy_idx != filter_wiphy) |
1321 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 1603 | continue; |
1322 | dev); | 1604 | /* attempt to fit multiple wiphy data chunks into the skb */ |
1323 | if (ret < 0) { | 1605 | do { |
1324 | /* | 1606 | ret = nl80211_send_wiphy(dev, skb, |
1325 | * If sending the wiphy data didn't fit (ENOBUFS or | 1607 | NETLINK_CB(cb->skb).portid, |
1326 | * EMSGSIZE returned), this SKB is still empty (so | 1608 | cb->nlh->nlmsg_seq, |
1327 | * it's not too big because another wiphy dataset is | 1609 | NLM_F_MULTI, |
1328 | * already in the skb) and we've not tried to adjust | 1610 | split, &cb->args[1], |
1329 | * the dump allocation yet ... then adjust the alloc | 1611 | &cb->args[2], |
1330 | * size to be bigger, and return 1 but with the empty | 1612 | &cb->args[3]); |
1331 | * skb. This results in an empty message being RX'ed | 1613 | if (ret < 0) { |
1332 | * in userspace, but that is ignored. | 1614 | /* |
1333 | * | 1615 | * If sending the wiphy data didn't fit (ENOBUFS |
1334 | * We can then retry with the larger buffer. | 1616 | * or EMSGSIZE returned), this SKB is still |
1335 | */ | 1617 | * empty (so it's not too big because another |
1336 | if ((ret == -ENOBUFS || ret == -EMSGSIZE) && | 1618 | * wiphy dataset is already in the skb) and |
1337 | !skb->len && | 1619 | * we've not tried to adjust the dump allocation |
1338 | cb->min_dump_alloc < 4096) { | 1620 | * yet ... then adjust the alloc size to be |
1339 | cb->min_dump_alloc = 4096; | 1621 | * bigger, and return 1 but with the empty skb. |
1340 | mutex_unlock(&cfg80211_mutex); | 1622 | * This results in an empty message being RX'ed |
1341 | return 1; | 1623 | * in userspace, but that is ignored. |
1624 | * | ||
1625 | * We can then retry with the larger buffer. | ||
1626 | */ | ||
1627 | if ((ret == -ENOBUFS || ret == -EMSGSIZE) && | ||
1628 | !skb->len && | ||
1629 | cb->min_dump_alloc < 4096) { | ||
1630 | cb->min_dump_alloc = 4096; | ||
1631 | mutex_unlock(&cfg80211_mutex); | ||
1632 | return 1; | ||
1633 | } | ||
1634 | idx--; | ||
1635 | break; | ||
1342 | } | 1636 | } |
1343 | idx--; | 1637 | } while (cb->args[1] > 0); |
1344 | break; | 1638 | break; |
1345 | } | ||
1346 | } | 1639 | } |
1347 | mutex_unlock(&cfg80211_mutex); | 1640 | mutex_unlock(&cfg80211_mutex); |
1348 | 1641 | ||
@@ -1360,7 +1653,8 @@ static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1360 | if (!msg) | 1653 | if (!msg) |
1361 | return -ENOMEM; | 1654 | return -ENOMEM; |
1362 | 1655 | ||
1363 | if (nl80211_send_wiphy(msg, info->snd_portid, info->snd_seq, 0, dev) < 0) { | 1656 | if (nl80211_send_wiphy(dev, msg, info->snd_portid, info->snd_seq, 0, |
1657 | false, NULL, NULL, NULL) < 0) { | ||
1364 | nlmsg_free(msg); | 1658 | nlmsg_free(msg); |
1365 | return -ENOBUFS; | 1659 | return -ENOBUFS; |
1366 | } | 1660 | } |
@@ -2967,6 +3261,7 @@ static int parse_station_flags(struct genl_info *info, | |||
2967 | sta_flags = nla_data(nla); | 3261 | sta_flags = nla_data(nla); |
2968 | params->sta_flags_mask = sta_flags->mask; | 3262 | params->sta_flags_mask = sta_flags->mask; |
2969 | params->sta_flags_set = sta_flags->set; | 3263 | params->sta_flags_set = sta_flags->set; |
3264 | params->sta_flags_set &= params->sta_flags_mask; | ||
2970 | if ((params->sta_flags_mask | | 3265 | if ((params->sta_flags_mask | |
2971 | params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID)) | 3266 | params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID)) |
2972 | return -EINVAL; | 3267 | return -EINVAL; |
@@ -3241,15 +3536,20 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
3241 | { | 3536 | { |
3242 | struct station_info sinfo; | 3537 | struct station_info sinfo; |
3243 | struct cfg80211_registered_device *dev; | 3538 | struct cfg80211_registered_device *dev; |
3244 | struct net_device *netdev; | 3539 | struct wireless_dev *wdev; |
3245 | u8 mac_addr[ETH_ALEN]; | 3540 | u8 mac_addr[ETH_ALEN]; |
3246 | int sta_idx = cb->args[1]; | 3541 | int sta_idx = cb->args[2]; |
3247 | int err; | 3542 | int err; |
3248 | 3543 | ||
3249 | err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); | 3544 | err = nl80211_prepare_wdev_dump(skb, cb, &dev, &wdev); |
3250 | if (err) | 3545 | if (err) |
3251 | return err; | 3546 | return err; |
3252 | 3547 | ||
3548 | if (!wdev->netdev) { | ||
3549 | err = -EINVAL; | ||
3550 | goto out_err; | ||
3551 | } | ||
3552 | |||
3253 | if (!dev->ops->dump_station) { | 3553 | if (!dev->ops->dump_station) { |
3254 | err = -EOPNOTSUPP; | 3554 | err = -EOPNOTSUPP; |
3255 | goto out_err; | 3555 | goto out_err; |
@@ -3257,7 +3557,7 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
3257 | 3557 | ||
3258 | while (1) { | 3558 | while (1) { |
3259 | memset(&sinfo, 0, sizeof(sinfo)); | 3559 | memset(&sinfo, 0, sizeof(sinfo)); |
3260 | err = rdev_dump_station(dev, netdev, sta_idx, | 3560 | err = rdev_dump_station(dev, wdev->netdev, sta_idx, |
3261 | mac_addr, &sinfo); | 3561 | mac_addr, &sinfo); |
3262 | if (err == -ENOENT) | 3562 | if (err == -ENOENT) |
3263 | break; | 3563 | break; |
@@ -3267,7 +3567,7 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
3267 | if (nl80211_send_station(skb, | 3567 | if (nl80211_send_station(skb, |
3268 | NETLINK_CB(cb->skb).portid, | 3568 | NETLINK_CB(cb->skb).portid, |
3269 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 3569 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
3270 | dev, netdev, mac_addr, | 3570 | dev, wdev->netdev, mac_addr, |
3271 | &sinfo) < 0) | 3571 | &sinfo) < 0) |
3272 | goto out; | 3572 | goto out; |
3273 | 3573 | ||
@@ -3276,10 +3576,10 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
3276 | 3576 | ||
3277 | 3577 | ||
3278 | out: | 3578 | out: |
3279 | cb->args[1] = sta_idx; | 3579 | cb->args[2] = sta_idx; |
3280 | err = skb->len; | 3580 | err = skb->len; |
3281 | out_err: | 3581 | out_err: |
3282 | nl80211_finish_netdev_dump(dev); | 3582 | nl80211_finish_wdev_dump(dev); |
3283 | 3583 | ||
3284 | return err; | 3584 | return err; |
3285 | } | 3585 | } |
@@ -3320,6 +3620,136 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | |||
3320 | return genlmsg_reply(msg, info); | 3620 | return genlmsg_reply(msg, info); |
3321 | } | 3621 | } |
3322 | 3622 | ||
3623 | int cfg80211_check_station_change(struct wiphy *wiphy, | ||
3624 | struct station_parameters *params, | ||
3625 | enum cfg80211_station_type statype) | ||
3626 | { | ||
3627 | if (params->listen_interval != -1) | ||
3628 | return -EINVAL; | ||
3629 | if (params->aid) | ||
3630 | return -EINVAL; | ||
3631 | |||
3632 | /* When you run into this, adjust the code below for the new flag */ | ||
3633 | BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7); | ||
3634 | |||
3635 | switch (statype) { | ||
3636 | case CFG80211_STA_MESH_PEER_KERNEL: | ||
3637 | case CFG80211_STA_MESH_PEER_USER: | ||
3638 | /* | ||
3639 | * No ignoring the TDLS flag here -- the userspace mesh | ||
3640 | * code doesn't have the bug of including TDLS in the | ||
3641 | * mask everywhere. | ||
3642 | */ | ||
3643 | if (params->sta_flags_mask & | ||
3644 | ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
3645 | BIT(NL80211_STA_FLAG_MFP) | | ||
3646 | BIT(NL80211_STA_FLAG_AUTHORIZED))) | ||
3647 | return -EINVAL; | ||
3648 | break; | ||
3649 | case CFG80211_STA_TDLS_PEER_SETUP: | ||
3650 | case CFG80211_STA_TDLS_PEER_ACTIVE: | ||
3651 | if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) | ||
3652 | return -EINVAL; | ||
3653 | /* ignore since it can't change */ | ||
3654 | params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); | ||
3655 | break; | ||
3656 | default: | ||
3657 | /* disallow mesh-specific things */ | ||
3658 | if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION) | ||
3659 | return -EINVAL; | ||
3660 | if (params->local_pm) | ||
3661 | return -EINVAL; | ||
3662 | if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE) | ||
3663 | return -EINVAL; | ||
3664 | } | ||
3665 | |||
3666 | if (statype != CFG80211_STA_TDLS_PEER_SETUP && | ||
3667 | statype != CFG80211_STA_TDLS_PEER_ACTIVE) { | ||
3668 | /* TDLS can't be set, ... */ | ||
3669 | if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) | ||
3670 | return -EINVAL; | ||
3671 | /* | ||
3672 | * ... but don't bother the driver with it. This works around | ||
3673 | * a hostapd/wpa_supplicant issue -- it always includes the | ||
3674 | * TLDS_PEER flag in the mask even for AP mode. | ||
3675 | */ | ||
3676 | params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); | ||
3677 | } | ||
3678 | |||
3679 | if (statype != CFG80211_STA_TDLS_PEER_SETUP) { | ||
3680 | /* reject other things that can't change */ | ||
3681 | if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD) | ||
3682 | return -EINVAL; | ||
3683 | if (params->sta_modify_mask & STATION_PARAM_APPLY_CAPABILITY) | ||
3684 | return -EINVAL; | ||
3685 | if (params->supported_rates) | ||
3686 | return -EINVAL; | ||
3687 | if (params->ext_capab || params->ht_capa || params->vht_capa) | ||
3688 | return -EINVAL; | ||
3689 | } | ||
3690 | |||
3691 | if (statype != CFG80211_STA_AP_CLIENT) { | ||
3692 | if (params->vlan) | ||
3693 | return -EINVAL; | ||
3694 | } | ||
3695 | |||
3696 | switch (statype) { | ||
3697 | case CFG80211_STA_AP_MLME_CLIENT: | ||
3698 | /* Use this only for authorizing/unauthorizing a station */ | ||
3699 | if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) | ||
3700 | return -EOPNOTSUPP; | ||
3701 | break; | ||
3702 | case CFG80211_STA_AP_CLIENT: | ||
3703 | /* accept only the listed bits */ | ||
3704 | if (params->sta_flags_mask & | ||
3705 | ~(BIT(NL80211_STA_FLAG_AUTHORIZED) | | ||
3706 | BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
3707 | BIT(NL80211_STA_FLAG_ASSOCIATED) | | ||
3708 | BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) | | ||
3709 | BIT(NL80211_STA_FLAG_WME) | | ||
3710 | BIT(NL80211_STA_FLAG_MFP))) | ||
3711 | return -EINVAL; | ||
3712 | |||
3713 | /* but authenticated/associated only if driver handles it */ | ||
3714 | if (!(wiphy->features & NL80211_FEATURE_FULL_AP_CLIENT_STATE) && | ||
3715 | params->sta_flags_mask & | ||
3716 | (BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
3717 | BIT(NL80211_STA_FLAG_ASSOCIATED))) | ||
3718 | return -EINVAL; | ||
3719 | break; | ||
3720 | case CFG80211_STA_IBSS: | ||
3721 | case CFG80211_STA_AP_STA: | ||
3722 | /* reject any changes other than AUTHORIZED */ | ||
3723 | if (params->sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED)) | ||
3724 | return -EINVAL; | ||
3725 | break; | ||
3726 | case CFG80211_STA_TDLS_PEER_SETUP: | ||
3727 | /* reject any changes other than AUTHORIZED or WME */ | ||
3728 | if (params->sta_flags_mask & ~(BIT(NL80211_STA_FLAG_AUTHORIZED) | | ||
3729 | BIT(NL80211_STA_FLAG_WME))) | ||
3730 | return -EINVAL; | ||
3731 | /* force (at least) rates when authorizing */ | ||
3732 | if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED) && | ||
3733 | !params->supported_rates) | ||
3734 | return -EINVAL; | ||
3735 | break; | ||
3736 | case CFG80211_STA_TDLS_PEER_ACTIVE: | ||
3737 | /* reject any changes */ | ||
3738 | return -EINVAL; | ||
3739 | case CFG80211_STA_MESH_PEER_KERNEL: | ||
3740 | if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE) | ||
3741 | return -EINVAL; | ||
3742 | break; | ||
3743 | case CFG80211_STA_MESH_PEER_USER: | ||
3744 | if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION) | ||
3745 | return -EINVAL; | ||
3746 | break; | ||
3747 | } | ||
3748 | |||
3749 | return 0; | ||
3750 | } | ||
3751 | EXPORT_SYMBOL(cfg80211_check_station_change); | ||
3752 | |||
3323 | /* | 3753 | /* |
3324 | * Get vlan interface making sure it is running and on the right wiphy. | 3754 | * Get vlan interface making sure it is running and on the right wiphy. |
3325 | */ | 3755 | */ |
@@ -3342,6 +3772,13 @@ static struct net_device *get_vlan(struct genl_info *info, | |||
3342 | goto error; | 3772 | goto error; |
3343 | } | 3773 | } |
3344 | 3774 | ||
3775 | if (v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | ||
3776 | v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | ||
3777 | v->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { | ||
3778 | ret = -EINVAL; | ||
3779 | goto error; | ||
3780 | } | ||
3781 | |||
3345 | if (!netif_running(v)) { | 3782 | if (!netif_running(v)) { |
3346 | ret = -ENETDOWN; | 3783 | ret = -ENETDOWN; |
3347 | goto error; | 3784 | goto error; |
@@ -3359,21 +3796,13 @@ nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] __read_mostly = { | |||
3359 | [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 }, | 3796 | [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 }, |
3360 | }; | 3797 | }; |
3361 | 3798 | ||
3362 | static int nl80211_set_station_tdls(struct genl_info *info, | 3799 | static int nl80211_parse_sta_wme(struct genl_info *info, |
3363 | struct station_parameters *params) | 3800 | struct station_parameters *params) |
3364 | { | 3801 | { |
3365 | struct nlattr *tb[NL80211_STA_WME_MAX + 1]; | 3802 | struct nlattr *tb[NL80211_STA_WME_MAX + 1]; |
3366 | struct nlattr *nla; | 3803 | struct nlattr *nla; |
3367 | int err; | 3804 | int err; |
3368 | 3805 | ||
3369 | /* Dummy STA entry gets updated once the peer capabilities are known */ | ||
3370 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) | ||
3371 | params->ht_capa = | ||
3372 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | ||
3373 | if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) | ||
3374 | params->vht_capa = | ||
3375 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]); | ||
3376 | |||
3377 | /* parse WME attributes if present */ | 3806 | /* parse WME attributes if present */ |
3378 | if (!info->attrs[NL80211_ATTR_STA_WME]) | 3807 | if (!info->attrs[NL80211_ATTR_STA_WME]) |
3379 | return 0; | 3808 | return 0; |
@@ -3401,18 +3830,34 @@ static int nl80211_set_station_tdls(struct genl_info *info, | |||
3401 | return 0; | 3830 | return 0; |
3402 | } | 3831 | } |
3403 | 3832 | ||
3833 | static int nl80211_set_station_tdls(struct genl_info *info, | ||
3834 | struct station_parameters *params) | ||
3835 | { | ||
3836 | /* Dummy STA entry gets updated once the peer capabilities are known */ | ||
3837 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) | ||
3838 | params->ht_capa = | ||
3839 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | ||
3840 | if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) | ||
3841 | params->vht_capa = | ||
3842 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]); | ||
3843 | |||
3844 | return nl80211_parse_sta_wme(info, params); | ||
3845 | } | ||
3846 | |||
3404 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | 3847 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) |
3405 | { | 3848 | { |
3406 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 3849 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3407 | int err; | ||
3408 | struct net_device *dev = info->user_ptr[1]; | 3850 | struct net_device *dev = info->user_ptr[1]; |
3409 | struct station_parameters params; | 3851 | struct station_parameters params; |
3410 | u8 *mac_addr = NULL; | 3852 | u8 *mac_addr; |
3853 | int err; | ||
3411 | 3854 | ||
3412 | memset(¶ms, 0, sizeof(params)); | 3855 | memset(¶ms, 0, sizeof(params)); |
3413 | 3856 | ||
3414 | params.listen_interval = -1; | 3857 | params.listen_interval = -1; |
3415 | params.plink_state = -1; | 3858 | |
3859 | if (!rdev->ops->change_station) | ||
3860 | return -EOPNOTSUPP; | ||
3416 | 3861 | ||
3417 | if (info->attrs[NL80211_ATTR_STA_AID]) | 3862 | if (info->attrs[NL80211_ATTR_STA_AID]) |
3418 | return -EINVAL; | 3863 | return -EINVAL; |
@@ -3445,19 +3890,23 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
3445 | if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) | 3890 | if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) |
3446 | return -EINVAL; | 3891 | return -EINVAL; |
3447 | 3892 | ||
3448 | if (!rdev->ops->change_station) | ||
3449 | return -EOPNOTSUPP; | ||
3450 | |||
3451 | if (parse_station_flags(info, dev->ieee80211_ptr->iftype, ¶ms)) | 3893 | if (parse_station_flags(info, dev->ieee80211_ptr->iftype, ¶ms)) |
3452 | return -EINVAL; | 3894 | return -EINVAL; |
3453 | 3895 | ||
3454 | if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) | 3896 | if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) { |
3455 | params.plink_action = | 3897 | params.plink_action = |
3456 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); | 3898 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); |
3899 | if (params.plink_action >= NUM_NL80211_PLINK_ACTIONS) | ||
3900 | return -EINVAL; | ||
3901 | } | ||
3457 | 3902 | ||
3458 | if (info->attrs[NL80211_ATTR_STA_PLINK_STATE]) | 3903 | if (info->attrs[NL80211_ATTR_STA_PLINK_STATE]) { |
3459 | params.plink_state = | 3904 | params.plink_state = |
3460 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]); | 3905 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]); |
3906 | if (params.plink_state >= NUM_NL80211_PLINK_STATES) | ||
3907 | return -EINVAL; | ||
3908 | params.sta_modify_mask |= STATION_PARAM_APPLY_PLINK_STATE; | ||
3909 | } | ||
3461 | 3910 | ||
3462 | if (info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]) { | 3911 | if (info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]) { |
3463 | enum nl80211_mesh_power_mode pm = nla_get_u32( | 3912 | enum nl80211_mesh_power_mode pm = nla_get_u32( |
@@ -3470,127 +3919,33 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
3470 | params.local_pm = pm; | 3919 | params.local_pm = pm; |
3471 | } | 3920 | } |
3472 | 3921 | ||
3922 | /* Include parameters for TDLS peer (will check later) */ | ||
3923 | err = nl80211_set_station_tdls(info, ¶ms); | ||
3924 | if (err) | ||
3925 | return err; | ||
3926 | |||
3927 | params.vlan = get_vlan(info, rdev); | ||
3928 | if (IS_ERR(params.vlan)) | ||
3929 | return PTR_ERR(params.vlan); | ||
3930 | |||
3473 | switch (dev->ieee80211_ptr->iftype) { | 3931 | switch (dev->ieee80211_ptr->iftype) { |
3474 | case NL80211_IFTYPE_AP: | 3932 | case NL80211_IFTYPE_AP: |
3475 | case NL80211_IFTYPE_AP_VLAN: | 3933 | case NL80211_IFTYPE_AP_VLAN: |
3476 | case NL80211_IFTYPE_P2P_GO: | 3934 | case NL80211_IFTYPE_P2P_GO: |
3477 | /* disallow mesh-specific things */ | ||
3478 | if (params.plink_action) | ||
3479 | return -EINVAL; | ||
3480 | if (params.local_pm) | ||
3481 | return -EINVAL; | ||
3482 | |||
3483 | /* TDLS can't be set, ... */ | ||
3484 | if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) | ||
3485 | return -EINVAL; | ||
3486 | /* | ||
3487 | * ... but don't bother the driver with it. This works around | ||
3488 | * a hostapd/wpa_supplicant issue -- it always includes the | ||
3489 | * TLDS_PEER flag in the mask even for AP mode. | ||
3490 | */ | ||
3491 | params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); | ||
3492 | |||
3493 | /* accept only the listed bits */ | ||
3494 | if (params.sta_flags_mask & | ||
3495 | ~(BIT(NL80211_STA_FLAG_AUTHORIZED) | | ||
3496 | BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
3497 | BIT(NL80211_STA_FLAG_ASSOCIATED) | | ||
3498 | BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) | | ||
3499 | BIT(NL80211_STA_FLAG_WME) | | ||
3500 | BIT(NL80211_STA_FLAG_MFP))) | ||
3501 | return -EINVAL; | ||
3502 | |||
3503 | /* but authenticated/associated only if driver handles it */ | ||
3504 | if (!(rdev->wiphy.features & | ||
3505 | NL80211_FEATURE_FULL_AP_CLIENT_STATE) && | ||
3506 | params.sta_flags_mask & | ||
3507 | (BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
3508 | BIT(NL80211_STA_FLAG_ASSOCIATED))) | ||
3509 | return -EINVAL; | ||
3510 | |||
3511 | /* reject other things that can't change */ | ||
3512 | if (params.supported_rates) | ||
3513 | return -EINVAL; | ||
3514 | if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) | ||
3515 | return -EINVAL; | ||
3516 | if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) | ||
3517 | return -EINVAL; | ||
3518 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY] || | ||
3519 | info->attrs[NL80211_ATTR_VHT_CAPABILITY]) | ||
3520 | return -EINVAL; | ||
3521 | |||
3522 | /* must be last in here for error handling */ | ||
3523 | params.vlan = get_vlan(info, rdev); | ||
3524 | if (IS_ERR(params.vlan)) | ||
3525 | return PTR_ERR(params.vlan); | ||
3526 | break; | ||
3527 | case NL80211_IFTYPE_P2P_CLIENT: | 3935 | case NL80211_IFTYPE_P2P_CLIENT: |
3528 | case NL80211_IFTYPE_STATION: | 3936 | case NL80211_IFTYPE_STATION: |
3529 | /* | ||
3530 | * Don't allow userspace to change the TDLS_PEER flag, | ||
3531 | * but silently ignore attempts to change it since we | ||
3532 | * don't have state here to verify that it doesn't try | ||
3533 | * to change the flag. | ||
3534 | */ | ||
3535 | params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); | ||
3536 | /* Include parameters for TDLS peer (driver will check) */ | ||
3537 | err = nl80211_set_station_tdls(info, ¶ms); | ||
3538 | if (err) | ||
3539 | return err; | ||
3540 | /* disallow things sta doesn't support */ | ||
3541 | if (params.plink_action) | ||
3542 | return -EINVAL; | ||
3543 | if (params.local_pm) | ||
3544 | return -EINVAL; | ||
3545 | /* reject any changes other than AUTHORIZED or WME (for TDLS) */ | ||
3546 | if (params.sta_flags_mask & ~(BIT(NL80211_STA_FLAG_AUTHORIZED) | | ||
3547 | BIT(NL80211_STA_FLAG_WME))) | ||
3548 | return -EINVAL; | ||
3549 | break; | ||
3550 | case NL80211_IFTYPE_ADHOC: | 3937 | case NL80211_IFTYPE_ADHOC: |
3551 | /* disallow things sta doesn't support */ | ||
3552 | if (params.plink_action) | ||
3553 | return -EINVAL; | ||
3554 | if (params.local_pm) | ||
3555 | return -EINVAL; | ||
3556 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY] || | ||
3557 | info->attrs[NL80211_ATTR_VHT_CAPABILITY]) | ||
3558 | return -EINVAL; | ||
3559 | /* reject any changes other than AUTHORIZED */ | ||
3560 | if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED)) | ||
3561 | return -EINVAL; | ||
3562 | break; | ||
3563 | case NL80211_IFTYPE_MESH_POINT: | 3938 | case NL80211_IFTYPE_MESH_POINT: |
3564 | /* disallow things mesh doesn't support */ | ||
3565 | if (params.vlan) | ||
3566 | return -EINVAL; | ||
3567 | if (params.supported_rates) | ||
3568 | return -EINVAL; | ||
3569 | if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) | ||
3570 | return -EINVAL; | ||
3571 | if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) | ||
3572 | return -EINVAL; | ||
3573 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY] || | ||
3574 | info->attrs[NL80211_ATTR_VHT_CAPABILITY]) | ||
3575 | return -EINVAL; | ||
3576 | /* | ||
3577 | * No special handling for TDLS here -- the userspace | ||
3578 | * mesh code doesn't have this bug. | ||
3579 | */ | ||
3580 | if (params.sta_flags_mask & | ||
3581 | ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
3582 | BIT(NL80211_STA_FLAG_MFP) | | ||
3583 | BIT(NL80211_STA_FLAG_AUTHORIZED))) | ||
3584 | return -EINVAL; | ||
3585 | break; | 3939 | break; |
3586 | default: | 3940 | default: |
3587 | return -EOPNOTSUPP; | 3941 | err = -EOPNOTSUPP; |
3942 | goto out_put_vlan; | ||
3588 | } | 3943 | } |
3589 | 3944 | ||
3590 | /* be aware of params.vlan when changing code here */ | 3945 | /* driver will call cfg80211_check_station_change() */ |
3591 | |||
3592 | err = rdev_change_station(rdev, dev, mac_addr, ¶ms); | 3946 | err = rdev_change_station(rdev, dev, mac_addr, ¶ms); |
3593 | 3947 | ||
3948 | out_put_vlan: | ||
3594 | if (params.vlan) | 3949 | if (params.vlan) |
3595 | dev_put(params.vlan); | 3950 | dev_put(params.vlan); |
3596 | 3951 | ||
@@ -3607,6 +3962,9 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
3607 | 3962 | ||
3608 | memset(¶ms, 0, sizeof(params)); | 3963 | memset(¶ms, 0, sizeof(params)); |
3609 | 3964 | ||
3965 | if (!rdev->ops->add_station) | ||
3966 | return -EOPNOTSUPP; | ||
3967 | |||
3610 | if (!info->attrs[NL80211_ATTR_MAC]) | 3968 | if (!info->attrs[NL80211_ATTR_MAC]) |
3611 | return -EINVAL; | 3969 | return -EINVAL; |
3612 | 3970 | ||
@@ -3652,50 +4010,32 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
3652 | params.vht_capa = | 4010 | params.vht_capa = |
3653 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]); | 4011 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]); |
3654 | 4012 | ||
3655 | if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) | 4013 | if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) { |
3656 | params.plink_action = | 4014 | params.plink_action = |
3657 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); | 4015 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); |
4016 | if (params.plink_action >= NUM_NL80211_PLINK_ACTIONS) | ||
4017 | return -EINVAL; | ||
4018 | } | ||
3658 | 4019 | ||
3659 | if (!rdev->ops->add_station) | 4020 | err = nl80211_parse_sta_wme(info, ¶ms); |
3660 | return -EOPNOTSUPP; | 4021 | if (err) |
4022 | return err; | ||
3661 | 4023 | ||
3662 | if (parse_station_flags(info, dev->ieee80211_ptr->iftype, ¶ms)) | 4024 | if (parse_station_flags(info, dev->ieee80211_ptr->iftype, ¶ms)) |
3663 | return -EINVAL; | 4025 | return -EINVAL; |
3664 | 4026 | ||
4027 | /* When you run into this, adjust the code below for the new flag */ | ||
4028 | BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7); | ||
4029 | |||
3665 | switch (dev->ieee80211_ptr->iftype) { | 4030 | switch (dev->ieee80211_ptr->iftype) { |
3666 | case NL80211_IFTYPE_AP: | 4031 | case NL80211_IFTYPE_AP: |
3667 | case NL80211_IFTYPE_AP_VLAN: | 4032 | case NL80211_IFTYPE_AP_VLAN: |
3668 | case NL80211_IFTYPE_P2P_GO: | 4033 | case NL80211_IFTYPE_P2P_GO: |
3669 | /* parse WME attributes if sta is WME capable */ | 4034 | /* ignore WME attributes if iface/sta is not capable */ |
3670 | if ((rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) && | 4035 | if (!(rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) || |
3671 | (params.sta_flags_set & BIT(NL80211_STA_FLAG_WME)) && | 4036 | !(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME))) |
3672 | info->attrs[NL80211_ATTR_STA_WME]) { | 4037 | params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD; |
3673 | struct nlattr *tb[NL80211_STA_WME_MAX + 1]; | ||
3674 | struct nlattr *nla; | ||
3675 | |||
3676 | nla = info->attrs[NL80211_ATTR_STA_WME]; | ||
3677 | err = nla_parse_nested(tb, NL80211_STA_WME_MAX, nla, | ||
3678 | nl80211_sta_wme_policy); | ||
3679 | if (err) | ||
3680 | return err; | ||
3681 | 4038 | ||
3682 | if (tb[NL80211_STA_WME_UAPSD_QUEUES]) | ||
3683 | params.uapsd_queues = | ||
3684 | nla_get_u8(tb[NL80211_STA_WME_UAPSD_QUEUES]); | ||
3685 | if (params.uapsd_queues & | ||
3686 | ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) | ||
3687 | return -EINVAL; | ||
3688 | |||
3689 | if (tb[NL80211_STA_WME_MAX_SP]) | ||
3690 | params.max_sp = | ||
3691 | nla_get_u8(tb[NL80211_STA_WME_MAX_SP]); | ||
3692 | |||
3693 | if (params.max_sp & | ||
3694 | ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK) | ||
3695 | return -EINVAL; | ||
3696 | |||
3697 | params.sta_modify_mask |= STATION_PARAM_APPLY_UAPSD; | ||
3698 | } | ||
3699 | /* TDLS peers cannot be added */ | 4039 | /* TDLS peers cannot be added */ |
3700 | if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) | 4040 | if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) |
3701 | return -EINVAL; | 4041 | return -EINVAL; |
@@ -3716,6 +4056,9 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
3716 | return PTR_ERR(params.vlan); | 4056 | return PTR_ERR(params.vlan); |
3717 | break; | 4057 | break; |
3718 | case NL80211_IFTYPE_MESH_POINT: | 4058 | case NL80211_IFTYPE_MESH_POINT: |
4059 | /* ignore uAPSD data */ | ||
4060 | params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD; | ||
4061 | |||
3719 | /* associated is disallowed */ | 4062 | /* associated is disallowed */ |
3720 | if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED)) | 4063 | if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED)) |
3721 | return -EINVAL; | 4064 | return -EINVAL; |
@@ -3724,8 +4067,14 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
3724 | return -EINVAL; | 4067 | return -EINVAL; |
3725 | break; | 4068 | break; |
3726 | case NL80211_IFTYPE_STATION: | 4069 | case NL80211_IFTYPE_STATION: |
3727 | /* associated is disallowed */ | 4070 | case NL80211_IFTYPE_P2P_CLIENT: |
3728 | if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED)) | 4071 | /* ignore uAPSD data */ |
4072 | params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD; | ||
4073 | |||
4074 | /* these are disallowed */ | ||
4075 | if (params.sta_flags_mask & | ||
4076 | (BIT(NL80211_STA_FLAG_ASSOCIATED) | | ||
4077 | BIT(NL80211_STA_FLAG_AUTHENTICATED))) | ||
3729 | return -EINVAL; | 4078 | return -EINVAL; |
3730 | /* Only TDLS peers can be added */ | 4079 | /* Only TDLS peers can be added */ |
3731 | if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) | 4080 | if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) |
@@ -3736,6 +4085,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
3736 | /* ... with external setup is supported */ | 4085 | /* ... with external setup is supported */ |
3737 | if (!(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP)) | 4086 | if (!(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP)) |
3738 | return -EOPNOTSUPP; | 4087 | return -EOPNOTSUPP; |
4088 | /* | ||
4089 | * Older wpa_supplicant versions always mark the TDLS peer | ||
4090 | * as authorized, but it shouldn't yet be. | ||
4091 | */ | ||
4092 | params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_AUTHORIZED); | ||
3739 | break; | 4093 | break; |
3740 | default: | 4094 | default: |
3741 | return -EOPNOTSUPP; | 4095 | return -EOPNOTSUPP; |
@@ -3829,13 +4183,13 @@ static int nl80211_dump_mpath(struct sk_buff *skb, | |||
3829 | { | 4183 | { |
3830 | struct mpath_info pinfo; | 4184 | struct mpath_info pinfo; |
3831 | struct cfg80211_registered_device *dev; | 4185 | struct cfg80211_registered_device *dev; |
3832 | struct net_device *netdev; | 4186 | struct wireless_dev *wdev; |
3833 | u8 dst[ETH_ALEN]; | 4187 | u8 dst[ETH_ALEN]; |
3834 | u8 next_hop[ETH_ALEN]; | 4188 | u8 next_hop[ETH_ALEN]; |
3835 | int path_idx = cb->args[1]; | 4189 | int path_idx = cb->args[2]; |
3836 | int err; | 4190 | int err; |
3837 | 4191 | ||
3838 | err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); | 4192 | err = nl80211_prepare_wdev_dump(skb, cb, &dev, &wdev); |
3839 | if (err) | 4193 | if (err) |
3840 | return err; | 4194 | return err; |
3841 | 4195 | ||
@@ -3844,14 +4198,14 @@ static int nl80211_dump_mpath(struct sk_buff *skb, | |||
3844 | goto out_err; | 4198 | goto out_err; |
3845 | } | 4199 | } |
3846 | 4200 | ||
3847 | if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { | 4201 | if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) { |
3848 | err = -EOPNOTSUPP; | 4202 | err = -EOPNOTSUPP; |
3849 | goto out_err; | 4203 | goto out_err; |
3850 | } | 4204 | } |
3851 | 4205 | ||
3852 | while (1) { | 4206 | while (1) { |
3853 | err = rdev_dump_mpath(dev, netdev, path_idx, dst, next_hop, | 4207 | err = rdev_dump_mpath(dev, wdev->netdev, path_idx, dst, |
3854 | &pinfo); | 4208 | next_hop, &pinfo); |
3855 | if (err == -ENOENT) | 4209 | if (err == -ENOENT) |
3856 | break; | 4210 | break; |
3857 | if (err) | 4211 | if (err) |
@@ -3859,7 +4213,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb, | |||
3859 | 4213 | ||
3860 | if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid, | 4214 | if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid, |
3861 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 4215 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
3862 | netdev, dst, next_hop, | 4216 | wdev->netdev, dst, next_hop, |
3863 | &pinfo) < 0) | 4217 | &pinfo) < 0) |
3864 | goto out; | 4218 | goto out; |
3865 | 4219 | ||
@@ -3868,10 +4222,10 @@ static int nl80211_dump_mpath(struct sk_buff *skb, | |||
3868 | 4222 | ||
3869 | 4223 | ||
3870 | out: | 4224 | out: |
3871 | cb->args[1] = path_idx; | 4225 | cb->args[2] = path_idx; |
3872 | err = skb->len; | 4226 | err = skb->len; |
3873 | out_err: | 4227 | out_err: |
3874 | nl80211_finish_netdev_dump(dev); | 4228 | nl80211_finish_wdev_dump(dev); |
3875 | return err; | 4229 | return err; |
3876 | } | 4230 | } |
3877 | 4231 | ||
@@ -4280,6 +4634,7 @@ static const struct nla_policy | |||
4280 | [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 }, | 4634 | [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 }, |
4281 | [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 }, | 4635 | [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 }, |
4282 | [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG }, | 4636 | [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG }, |
4637 | [NL80211_MESH_SETUP_USERSPACE_MPM] = { .type = NLA_FLAG }, | ||
4283 | [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY, | 4638 | [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY, |
4284 | .len = IEEE80211_MAX_DATA_LEN }, | 4639 | .len = IEEE80211_MAX_DATA_LEN }, |
4285 | [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG }, | 4640 | [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG }, |
@@ -4418,6 +4773,7 @@ do { \ | |||
4418 | static int nl80211_parse_mesh_setup(struct genl_info *info, | 4773 | static int nl80211_parse_mesh_setup(struct genl_info *info, |
4419 | struct mesh_setup *setup) | 4774 | struct mesh_setup *setup) |
4420 | { | 4775 | { |
4776 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
4421 | struct nlattr *tb[NL80211_MESH_SETUP_ATTR_MAX + 1]; | 4777 | struct nlattr *tb[NL80211_MESH_SETUP_ATTR_MAX + 1]; |
4422 | 4778 | ||
4423 | if (!info->attrs[NL80211_ATTR_MESH_SETUP]) | 4779 | if (!info->attrs[NL80211_ATTR_MESH_SETUP]) |
@@ -4454,8 +4810,14 @@ static int nl80211_parse_mesh_setup(struct genl_info *info, | |||
4454 | setup->ie = nla_data(ieattr); | 4810 | setup->ie = nla_data(ieattr); |
4455 | setup->ie_len = nla_len(ieattr); | 4811 | setup->ie_len = nla_len(ieattr); |
4456 | } | 4812 | } |
4813 | if (tb[NL80211_MESH_SETUP_USERSPACE_MPM] && | ||
4814 | !(rdev->wiphy.features & NL80211_FEATURE_USERSPACE_MPM)) | ||
4815 | return -EINVAL; | ||
4816 | setup->user_mpm = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_MPM]); | ||
4457 | setup->is_authenticated = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AUTH]); | 4817 | setup->is_authenticated = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AUTH]); |
4458 | setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AMPE]); | 4818 | setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AMPE]); |
4819 | if (setup->is_secure) | ||
4820 | setup->user_mpm = true; | ||
4459 | 4821 | ||
4460 | return 0; | 4822 | return 0; |
4461 | } | 4823 | } |
@@ -4702,14 +5064,19 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
4702 | if (!rdev->ops->scan) | 5064 | if (!rdev->ops->scan) |
4703 | return -EOPNOTSUPP; | 5065 | return -EOPNOTSUPP; |
4704 | 5066 | ||
4705 | if (rdev->scan_req) | 5067 | mutex_lock(&rdev->sched_scan_mtx); |
4706 | return -EBUSY; | 5068 | if (rdev->scan_req) { |
5069 | err = -EBUSY; | ||
5070 | goto unlock; | ||
5071 | } | ||
4707 | 5072 | ||
4708 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { | 5073 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { |
4709 | n_channels = validate_scan_freqs( | 5074 | n_channels = validate_scan_freqs( |
4710 | info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]); | 5075 | info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]); |
4711 | if (!n_channels) | 5076 | if (!n_channels) { |
4712 | return -EINVAL; | 5077 | err = -EINVAL; |
5078 | goto unlock; | ||
5079 | } | ||
4713 | } else { | 5080 | } else { |
4714 | enum ieee80211_band band; | 5081 | enum ieee80211_band band; |
4715 | n_channels = 0; | 5082 | n_channels = 0; |
@@ -4723,23 +5090,29 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
4723 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) | 5090 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) |
4724 | n_ssids++; | 5091 | n_ssids++; |
4725 | 5092 | ||
4726 | if (n_ssids > wiphy->max_scan_ssids) | 5093 | if (n_ssids > wiphy->max_scan_ssids) { |
4727 | return -EINVAL; | 5094 | err = -EINVAL; |
5095 | goto unlock; | ||
5096 | } | ||
4728 | 5097 | ||
4729 | if (info->attrs[NL80211_ATTR_IE]) | 5098 | if (info->attrs[NL80211_ATTR_IE]) |
4730 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 5099 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
4731 | else | 5100 | else |
4732 | ie_len = 0; | 5101 | ie_len = 0; |
4733 | 5102 | ||
4734 | if (ie_len > wiphy->max_scan_ie_len) | 5103 | if (ie_len > wiphy->max_scan_ie_len) { |
4735 | return -EINVAL; | 5104 | err = -EINVAL; |
5105 | goto unlock; | ||
5106 | } | ||
4736 | 5107 | ||
4737 | request = kzalloc(sizeof(*request) | 5108 | request = kzalloc(sizeof(*request) |
4738 | + sizeof(*request->ssids) * n_ssids | 5109 | + sizeof(*request->ssids) * n_ssids |
4739 | + sizeof(*request->channels) * n_channels | 5110 | + sizeof(*request->channels) * n_channels |
4740 | + ie_len, GFP_KERNEL); | 5111 | + ie_len, GFP_KERNEL); |
4741 | if (!request) | 5112 | if (!request) { |
4742 | return -ENOMEM; | 5113 | err = -ENOMEM; |
5114 | goto unlock; | ||
5115 | } | ||
4743 | 5116 | ||
4744 | if (n_ssids) | 5117 | if (n_ssids) |
4745 | request->ssids = (void *)&request->channels[n_channels]; | 5118 | request->ssids = (void *)&request->channels[n_channels]; |
@@ -4876,6 +5249,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
4876 | kfree(request); | 5249 | kfree(request); |
4877 | } | 5250 | } |
4878 | 5251 | ||
5252 | unlock: | ||
5253 | mutex_unlock(&rdev->sched_scan_mtx); | ||
4879 | return err; | 5254 | return err; |
4880 | } | 5255 | } |
4881 | 5256 | ||
@@ -5206,9 +5581,13 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, | |||
5206 | 5581 | ||
5207 | genl_dump_check_consistent(cb, hdr, &nl80211_fam); | 5582 | genl_dump_check_consistent(cb, hdr, &nl80211_fam); |
5208 | 5583 | ||
5209 | if (nla_put_u32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation) || | 5584 | if (nla_put_u32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation)) |
5585 | goto nla_put_failure; | ||
5586 | if (wdev->netdev && | ||
5210 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex)) | 5587 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex)) |
5211 | goto nla_put_failure; | 5588 | goto nla_put_failure; |
5589 | if (nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev))) | ||
5590 | goto nla_put_failure; | ||
5212 | 5591 | ||
5213 | bss = nla_nest_start(msg, NL80211_ATTR_BSS); | 5592 | bss = nla_nest_start(msg, NL80211_ATTR_BSS); |
5214 | if (!bss) | 5593 | if (!bss) |
@@ -5288,22 +5667,18 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, | |||
5288 | return -EMSGSIZE; | 5667 | return -EMSGSIZE; |
5289 | } | 5668 | } |
5290 | 5669 | ||
5291 | static int nl80211_dump_scan(struct sk_buff *skb, | 5670 | static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb) |
5292 | struct netlink_callback *cb) | ||
5293 | { | 5671 | { |
5294 | struct cfg80211_registered_device *rdev; | 5672 | struct cfg80211_registered_device *rdev; |
5295 | struct net_device *dev; | ||
5296 | struct cfg80211_internal_bss *scan; | 5673 | struct cfg80211_internal_bss *scan; |
5297 | struct wireless_dev *wdev; | 5674 | struct wireless_dev *wdev; |
5298 | int start = cb->args[1], idx = 0; | 5675 | int start = cb->args[2], idx = 0; |
5299 | int err; | 5676 | int err; |
5300 | 5677 | ||
5301 | err = nl80211_prepare_netdev_dump(skb, cb, &rdev, &dev); | 5678 | err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); |
5302 | if (err) | 5679 | if (err) |
5303 | return err; | 5680 | return err; |
5304 | 5681 | ||
5305 | wdev = dev->ieee80211_ptr; | ||
5306 | |||
5307 | wdev_lock(wdev); | 5682 | wdev_lock(wdev); |
5308 | spin_lock_bh(&rdev->bss_lock); | 5683 | spin_lock_bh(&rdev->bss_lock); |
5309 | cfg80211_bss_expire(rdev); | 5684 | cfg80211_bss_expire(rdev); |
@@ -5324,8 +5699,8 @@ static int nl80211_dump_scan(struct sk_buff *skb, | |||
5324 | spin_unlock_bh(&rdev->bss_lock); | 5699 | spin_unlock_bh(&rdev->bss_lock); |
5325 | wdev_unlock(wdev); | 5700 | wdev_unlock(wdev); |
5326 | 5701 | ||
5327 | cb->args[1] = idx; | 5702 | cb->args[2] = idx; |
5328 | nl80211_finish_netdev_dump(rdev); | 5703 | nl80211_finish_wdev_dump(rdev); |
5329 | 5704 | ||
5330 | return skb->len; | 5705 | return skb->len; |
5331 | } | 5706 | } |
@@ -5394,14 +5769,19 @@ static int nl80211_dump_survey(struct sk_buff *skb, | |||
5394 | { | 5769 | { |
5395 | struct survey_info survey; | 5770 | struct survey_info survey; |
5396 | struct cfg80211_registered_device *dev; | 5771 | struct cfg80211_registered_device *dev; |
5397 | struct net_device *netdev; | 5772 | struct wireless_dev *wdev; |
5398 | int survey_idx = cb->args[1]; | 5773 | int survey_idx = cb->args[2]; |
5399 | int res; | 5774 | int res; |
5400 | 5775 | ||
5401 | res = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); | 5776 | res = nl80211_prepare_wdev_dump(skb, cb, &dev, &wdev); |
5402 | if (res) | 5777 | if (res) |
5403 | return res; | 5778 | return res; |
5404 | 5779 | ||
5780 | if (!wdev->netdev) { | ||
5781 | res = -EINVAL; | ||
5782 | goto out_err; | ||
5783 | } | ||
5784 | |||
5405 | if (!dev->ops->dump_survey) { | 5785 | if (!dev->ops->dump_survey) { |
5406 | res = -EOPNOTSUPP; | 5786 | res = -EOPNOTSUPP; |
5407 | goto out_err; | 5787 | goto out_err; |
@@ -5410,7 +5790,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, | |||
5410 | while (1) { | 5790 | while (1) { |
5411 | struct ieee80211_channel *chan; | 5791 | struct ieee80211_channel *chan; |
5412 | 5792 | ||
5413 | res = rdev_dump_survey(dev, netdev, survey_idx, &survey); | 5793 | res = rdev_dump_survey(dev, wdev->netdev, survey_idx, &survey); |
5414 | if (res == -ENOENT) | 5794 | if (res == -ENOENT) |
5415 | break; | 5795 | break; |
5416 | if (res) | 5796 | if (res) |
@@ -5432,17 +5812,16 @@ static int nl80211_dump_survey(struct sk_buff *skb, | |||
5432 | if (nl80211_send_survey(skb, | 5812 | if (nl80211_send_survey(skb, |
5433 | NETLINK_CB(cb->skb).portid, | 5813 | NETLINK_CB(cb->skb).portid, |
5434 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 5814 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
5435 | netdev, | 5815 | wdev->netdev, &survey) < 0) |
5436 | &survey) < 0) | ||
5437 | goto out; | 5816 | goto out; |
5438 | survey_idx++; | 5817 | survey_idx++; |
5439 | } | 5818 | } |
5440 | 5819 | ||
5441 | out: | 5820 | out: |
5442 | cb->args[1] = survey_idx; | 5821 | cb->args[2] = survey_idx; |
5443 | res = skb->len; | 5822 | res = skb->len; |
5444 | out_err: | 5823 | out_err: |
5445 | nl80211_finish_netdev_dump(dev); | 5824 | nl80211_finish_wdev_dump(dev); |
5446 | return res; | 5825 | return res; |
5447 | } | 5826 | } |
5448 | 5827 | ||
@@ -5650,14 +6029,10 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
5650 | { | 6029 | { |
5651 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6030 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5652 | struct net_device *dev = info->user_ptr[1]; | 6031 | struct net_device *dev = info->user_ptr[1]; |
5653 | struct cfg80211_crypto_settings crypto; | ||
5654 | struct ieee80211_channel *chan; | 6032 | struct ieee80211_channel *chan; |
5655 | const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; | 6033 | struct cfg80211_assoc_request req = {}; |
5656 | int err, ssid_len, ie_len = 0; | 6034 | const u8 *bssid, *ssid; |
5657 | bool use_mfp = false; | 6035 | int err, ssid_len = 0; |
5658 | u32 flags = 0; | ||
5659 | struct ieee80211_ht_cap *ht_capa = NULL; | ||
5660 | struct ieee80211_ht_cap *ht_capa_mask = NULL; | ||
5661 | 6036 | ||
5662 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 6037 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
5663 | return -EINVAL; | 6038 | return -EINVAL; |
@@ -5685,41 +6060,58 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
5685 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | 6060 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); |
5686 | 6061 | ||
5687 | if (info->attrs[NL80211_ATTR_IE]) { | 6062 | if (info->attrs[NL80211_ATTR_IE]) { |
5688 | ie = nla_data(info->attrs[NL80211_ATTR_IE]); | 6063 | req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); |
5689 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 6064 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
5690 | } | 6065 | } |
5691 | 6066 | ||
5692 | if (info->attrs[NL80211_ATTR_USE_MFP]) { | 6067 | if (info->attrs[NL80211_ATTR_USE_MFP]) { |
5693 | enum nl80211_mfp mfp = | 6068 | enum nl80211_mfp mfp = |
5694 | nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); | 6069 | nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); |
5695 | if (mfp == NL80211_MFP_REQUIRED) | 6070 | if (mfp == NL80211_MFP_REQUIRED) |
5696 | use_mfp = true; | 6071 | req.use_mfp = true; |
5697 | else if (mfp != NL80211_MFP_NO) | 6072 | else if (mfp != NL80211_MFP_NO) |
5698 | return -EINVAL; | 6073 | return -EINVAL; |
5699 | } | 6074 | } |
5700 | 6075 | ||
5701 | if (info->attrs[NL80211_ATTR_PREV_BSSID]) | 6076 | if (info->attrs[NL80211_ATTR_PREV_BSSID]) |
5702 | prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]); | 6077 | req.prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]); |
5703 | 6078 | ||
5704 | if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT])) | 6079 | if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT])) |
5705 | flags |= ASSOC_REQ_DISABLE_HT; | 6080 | req.flags |= ASSOC_REQ_DISABLE_HT; |
5706 | 6081 | ||
5707 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) | 6082 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) |
5708 | ht_capa_mask = | 6083 | memcpy(&req.ht_capa_mask, |
5709 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]); | 6084 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]), |
6085 | sizeof(req.ht_capa_mask)); | ||
5710 | 6086 | ||
5711 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) { | 6087 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) { |
5712 | if (!ht_capa_mask) | 6088 | if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) |
5713 | return -EINVAL; | 6089 | return -EINVAL; |
5714 | ht_capa = nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | 6090 | memcpy(&req.ht_capa, |
6091 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]), | ||
6092 | sizeof(req.ht_capa)); | ||
5715 | } | 6093 | } |
5716 | 6094 | ||
5717 | err = nl80211_crypto_settings(rdev, info, &crypto, 1); | 6095 | if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT])) |
6096 | req.flags |= ASSOC_REQ_DISABLE_VHT; | ||
6097 | |||
6098 | if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) | ||
6099 | memcpy(&req.vht_capa_mask, | ||
6100 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]), | ||
6101 | sizeof(req.vht_capa_mask)); | ||
6102 | |||
6103 | if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) { | ||
6104 | if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) | ||
6105 | return -EINVAL; | ||
6106 | memcpy(&req.vht_capa, | ||
6107 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]), | ||
6108 | sizeof(req.vht_capa)); | ||
6109 | } | ||
6110 | |||
6111 | err = nl80211_crypto_settings(rdev, info, &req.crypto, 1); | ||
5718 | if (!err) | 6112 | if (!err) |
5719 | err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, | 6113 | err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, |
5720 | ssid, ssid_len, ie, ie_len, use_mfp, | 6114 | ssid, ssid_len, &req); |
5721 | &crypto, flags, ht_capa, | ||
5722 | ht_capa_mask); | ||
5723 | 6115 | ||
5724 | return err; | 6116 | return err; |
5725 | } | 6117 | } |
@@ -6299,6 +6691,24 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | |||
6299 | sizeof(connect.ht_capa)); | 6691 | sizeof(connect.ht_capa)); |
6300 | } | 6692 | } |
6301 | 6693 | ||
6694 | if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT])) | ||
6695 | connect.flags |= ASSOC_REQ_DISABLE_VHT; | ||
6696 | |||
6697 | if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) | ||
6698 | memcpy(&connect.vht_capa_mask, | ||
6699 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]), | ||
6700 | sizeof(connect.vht_capa_mask)); | ||
6701 | |||
6702 | if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) { | ||
6703 | if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) { | ||
6704 | kfree(connkeys); | ||
6705 | return -EINVAL; | ||
6706 | } | ||
6707 | memcpy(&connect.vht_capa, | ||
6708 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]), | ||
6709 | sizeof(connect.vht_capa)); | ||
6710 | } | ||
6711 | |||
6302 | err = cfg80211_connect(rdev, dev, &connect, connkeys); | 6712 | err = cfg80211_connect(rdev, dev, &connect, connkeys); |
6303 | if (err) | 6713 | if (err) |
6304 | kfree(connkeys); | 6714 | kfree(connkeys); |
@@ -7072,6 +7482,9 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) | |||
7072 | return err; | 7482 | return err; |
7073 | } | 7483 | } |
7074 | 7484 | ||
7485 | if (setup.user_mpm) | ||
7486 | cfg.auto_open_plinks = false; | ||
7487 | |||
7075 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | 7488 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { |
7076 | err = nl80211_parse_chandef(rdev, info, &setup.chandef); | 7489 | err = nl80211_parse_chandef(rdev, info, &setup.chandef); |
7077 | if (err) | 7490 | if (err) |
@@ -7271,7 +7684,8 @@ static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev, | |||
7271 | return -EINVAL; | 7684 | return -EINVAL; |
7272 | 7685 | ||
7273 | if (nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) > | 7686 | if (nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) > |
7274 | rdev->wiphy.wowlan.tcp->data_interval_max) | 7687 | rdev->wiphy.wowlan.tcp->data_interval_max || |
7688 | nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) == 0) | ||
7275 | return -EINVAL; | 7689 | return -EINVAL; |
7276 | 7690 | ||
7277 | wake_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]); | 7691 | wake_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]); |
@@ -7749,21 +8163,118 @@ static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info) | |||
7749 | if (!rdev->ops->stop_p2p_device) | 8163 | if (!rdev->ops->stop_p2p_device) |
7750 | return -EOPNOTSUPP; | 8164 | return -EOPNOTSUPP; |
7751 | 8165 | ||
7752 | if (!wdev->p2p_started) | ||
7753 | return 0; | ||
7754 | |||
7755 | rdev_stop_p2p_device(rdev, wdev); | ||
7756 | wdev->p2p_started = false; | ||
7757 | |||
7758 | mutex_lock(&rdev->devlist_mtx); | 8166 | mutex_lock(&rdev->devlist_mtx); |
7759 | rdev->opencount--; | 8167 | mutex_lock(&rdev->sched_scan_mtx); |
8168 | cfg80211_stop_p2p_device(rdev, wdev); | ||
8169 | mutex_unlock(&rdev->sched_scan_mtx); | ||
7760 | mutex_unlock(&rdev->devlist_mtx); | 8170 | mutex_unlock(&rdev->devlist_mtx); |
7761 | 8171 | ||
7762 | if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) { | 8172 | return 0; |
7763 | rdev->scan_req->aborted = true; | 8173 | } |
7764 | ___cfg80211_scan_done(rdev, true); | 8174 | |
7765 | } | 8175 | static int nl80211_get_protocol_features(struct sk_buff *skb, |
8176 | struct genl_info *info) | ||
8177 | { | ||
8178 | void *hdr; | ||
8179 | struct sk_buff *msg; | ||
8180 | |||
8181 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
8182 | if (!msg) | ||
8183 | return -ENOMEM; | ||
8184 | |||
8185 | hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0, | ||
8186 | NL80211_CMD_GET_PROTOCOL_FEATURES); | ||
8187 | if (!hdr) | ||
8188 | goto nla_put_failure; | ||
8189 | |||
8190 | if (nla_put_u32(msg, NL80211_ATTR_PROTOCOL_FEATURES, | ||
8191 | NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)) | ||
8192 | goto nla_put_failure; | ||
8193 | |||
8194 | genlmsg_end(msg, hdr); | ||
8195 | return genlmsg_reply(msg, info); | ||
8196 | |||
8197 | nla_put_failure: | ||
8198 | kfree_skb(msg); | ||
8199 | return -ENOBUFS; | ||
8200 | } | ||
8201 | |||
8202 | static int nl80211_update_ft_ies(struct sk_buff *skb, struct genl_info *info) | ||
8203 | { | ||
8204 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
8205 | struct cfg80211_update_ft_ies_params ft_params; | ||
8206 | struct net_device *dev = info->user_ptr[1]; | ||
8207 | |||
8208 | if (!rdev->ops->update_ft_ies) | ||
8209 | return -EOPNOTSUPP; | ||
8210 | |||
8211 | if (!info->attrs[NL80211_ATTR_MDID] || | ||
8212 | !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | ||
8213 | return -EINVAL; | ||
8214 | |||
8215 | memset(&ft_params, 0, sizeof(ft_params)); | ||
8216 | ft_params.md = nla_get_u16(info->attrs[NL80211_ATTR_MDID]); | ||
8217 | ft_params.ie = nla_data(info->attrs[NL80211_ATTR_IE]); | ||
8218 | ft_params.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
8219 | |||
8220 | return rdev_update_ft_ies(rdev, dev, &ft_params); | ||
8221 | } | ||
8222 | |||
8223 | static int nl80211_crit_protocol_start(struct sk_buff *skb, | ||
8224 | struct genl_info *info) | ||
8225 | { | ||
8226 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
8227 | struct wireless_dev *wdev = info->user_ptr[1]; | ||
8228 | enum nl80211_crit_proto_id proto = NL80211_CRIT_PROTO_UNSPEC; | ||
8229 | u16 duration; | ||
8230 | int ret; | ||
8231 | |||
8232 | if (!rdev->ops->crit_proto_start) | ||
8233 | return -EOPNOTSUPP; | ||
8234 | |||
8235 | if (WARN_ON(!rdev->ops->crit_proto_stop)) | ||
8236 | return -EINVAL; | ||
8237 | |||
8238 | if (rdev->crit_proto_nlportid) | ||
8239 | return -EBUSY; | ||
8240 | |||
8241 | /* determine protocol if provided */ | ||
8242 | if (info->attrs[NL80211_ATTR_CRIT_PROT_ID]) | ||
8243 | proto = nla_get_u16(info->attrs[NL80211_ATTR_CRIT_PROT_ID]); | ||
8244 | |||
8245 | if (proto >= NUM_NL80211_CRIT_PROTO) | ||
8246 | return -EINVAL; | ||
8247 | |||
8248 | /* timeout must be provided */ | ||
8249 | if (!info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION]) | ||
8250 | return -EINVAL; | ||
8251 | |||
8252 | duration = | ||
8253 | nla_get_u16(info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION]); | ||
7766 | 8254 | ||
8255 | if (duration > NL80211_CRIT_PROTO_MAX_DURATION) | ||
8256 | return -ERANGE; | ||
8257 | |||
8258 | ret = rdev_crit_proto_start(rdev, wdev, proto, duration); | ||
8259 | if (!ret) | ||
8260 | rdev->crit_proto_nlportid = info->snd_portid; | ||
8261 | |||
8262 | return ret; | ||
8263 | } | ||
8264 | |||
8265 | static int nl80211_crit_protocol_stop(struct sk_buff *skb, | ||
8266 | struct genl_info *info) | ||
8267 | { | ||
8268 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
8269 | struct wireless_dev *wdev = info->user_ptr[1]; | ||
8270 | |||
8271 | if (!rdev->ops->crit_proto_stop) | ||
8272 | return -EOPNOTSUPP; | ||
8273 | |||
8274 | if (rdev->crit_proto_nlportid) { | ||
8275 | rdev->crit_proto_nlportid = 0; | ||
8276 | rdev_crit_proto_stop(rdev, wdev); | ||
8277 | } | ||
7767 | return 0; | 8278 | return 0; |
7768 | } | 8279 | } |
7769 | 8280 | ||
@@ -8443,6 +8954,35 @@ static struct genl_ops nl80211_ops[] = { | |||
8443 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 8954 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
8444 | NL80211_FLAG_NEED_RTNL, | 8955 | NL80211_FLAG_NEED_RTNL, |
8445 | }, | 8956 | }, |
8957 | { | ||
8958 | .cmd = NL80211_CMD_GET_PROTOCOL_FEATURES, | ||
8959 | .doit = nl80211_get_protocol_features, | ||
8960 | .policy = nl80211_policy, | ||
8961 | }, | ||
8962 | { | ||
8963 | .cmd = NL80211_CMD_UPDATE_FT_IES, | ||
8964 | .doit = nl80211_update_ft_ies, | ||
8965 | .policy = nl80211_policy, | ||
8966 | .flags = GENL_ADMIN_PERM, | ||
8967 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
8968 | NL80211_FLAG_NEED_RTNL, | ||
8969 | }, | ||
8970 | { | ||
8971 | .cmd = NL80211_CMD_CRIT_PROTOCOL_START, | ||
8972 | .doit = nl80211_crit_protocol_start, | ||
8973 | .policy = nl80211_policy, | ||
8974 | .flags = GENL_ADMIN_PERM, | ||
8975 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | | ||
8976 | NL80211_FLAG_NEED_RTNL, | ||
8977 | }, | ||
8978 | { | ||
8979 | .cmd = NL80211_CMD_CRIT_PROTOCOL_STOP, | ||
8980 | .doit = nl80211_crit_protocol_stop, | ||
8981 | .policy = nl80211_policy, | ||
8982 | .flags = GENL_ADMIN_PERM, | ||
8983 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | | ||
8984 | NL80211_FLAG_NEED_RTNL, | ||
8985 | } | ||
8446 | }; | 8986 | }; |
8447 | 8987 | ||
8448 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 8988 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
@@ -8470,7 +9010,8 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) | |||
8470 | if (!msg) | 9010 | if (!msg) |
8471 | return; | 9011 | return; |
8472 | 9012 | ||
8473 | if (nl80211_send_wiphy(msg, 0, 0, 0, rdev) < 0) { | 9013 | if (nl80211_send_wiphy(rdev, msg, 0, 0, 0, |
9014 | false, NULL, NULL, NULL) < 0) { | ||
8474 | nlmsg_free(msg); | 9015 | nlmsg_free(msg); |
8475 | return; | 9016 | return; |
8476 | } | 9017 | } |
@@ -8486,7 +9027,7 @@ static int nl80211_add_scan_req(struct sk_buff *msg, | |||
8486 | struct nlattr *nest; | 9027 | struct nlattr *nest; |
8487 | int i; | 9028 | int i; |
8488 | 9029 | ||
8489 | ASSERT_RDEV_LOCK(rdev); | 9030 | lockdep_assert_held(&rdev->sched_scan_mtx); |
8490 | 9031 | ||
8491 | if (WARN_ON(!req)) | 9032 | if (WARN_ON(!req)) |
8492 | return 0; | 9033 | return 0; |
@@ -8794,21 +9335,31 @@ void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, | |||
8794 | NL80211_CMD_DISASSOCIATE, gfp); | 9335 | NL80211_CMD_DISASSOCIATE, gfp); |
8795 | } | 9336 | } |
8796 | 9337 | ||
8797 | void nl80211_send_unprot_deauth(struct cfg80211_registered_device *rdev, | 9338 | void cfg80211_send_unprot_deauth(struct net_device *dev, const u8 *buf, |
8798 | struct net_device *netdev, const u8 *buf, | 9339 | size_t len) |
8799 | size_t len, gfp_t gfp) | ||
8800 | { | 9340 | { |
8801 | nl80211_send_mlme_event(rdev, netdev, buf, len, | 9341 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
8802 | NL80211_CMD_UNPROT_DEAUTHENTICATE, gfp); | 9342 | struct wiphy *wiphy = wdev->wiphy; |
9343 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9344 | |||
9345 | trace_cfg80211_send_unprot_deauth(dev); | ||
9346 | nl80211_send_mlme_event(rdev, dev, buf, len, | ||
9347 | NL80211_CMD_UNPROT_DEAUTHENTICATE, GFP_ATOMIC); | ||
8803 | } | 9348 | } |
9349 | EXPORT_SYMBOL(cfg80211_send_unprot_deauth); | ||
8804 | 9350 | ||
8805 | void nl80211_send_unprot_disassoc(struct cfg80211_registered_device *rdev, | 9351 | void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf, |
8806 | struct net_device *netdev, const u8 *buf, | 9352 | size_t len) |
8807 | size_t len, gfp_t gfp) | ||
8808 | { | 9353 | { |
8809 | nl80211_send_mlme_event(rdev, netdev, buf, len, | 9354 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
8810 | NL80211_CMD_UNPROT_DISASSOCIATE, gfp); | 9355 | struct wiphy *wiphy = wdev->wiphy; |
9356 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9357 | |||
9358 | trace_cfg80211_send_unprot_disassoc(dev); | ||
9359 | nl80211_send_mlme_event(rdev, dev, buf, len, | ||
9360 | NL80211_CMD_UNPROT_DISASSOCIATE, GFP_ATOMIC); | ||
8811 | } | 9361 | } |
9362 | EXPORT_SYMBOL(cfg80211_send_unprot_disassoc); | ||
8812 | 9363 | ||
8813 | static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, | 9364 | static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, |
8814 | struct net_device *netdev, int cmd, | 9365 | struct net_device *netdev, int cmd, |
@@ -9011,14 +9562,19 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, | |||
9011 | nlmsg_free(msg); | 9562 | nlmsg_free(msg); |
9012 | } | 9563 | } |
9013 | 9564 | ||
9014 | void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev, | 9565 | void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr, |
9015 | struct net_device *netdev, | 9566 | const u8* ie, u8 ie_len, gfp_t gfp) |
9016 | const u8 *macaddr, const u8* ie, u8 ie_len, | ||
9017 | gfp_t gfp) | ||
9018 | { | 9567 | { |
9568 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
9569 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
9019 | struct sk_buff *msg; | 9570 | struct sk_buff *msg; |
9020 | void *hdr; | 9571 | void *hdr; |
9021 | 9572 | ||
9573 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT)) | ||
9574 | return; | ||
9575 | |||
9576 | trace_cfg80211_notify_new_peer_candidate(dev, addr); | ||
9577 | |||
9022 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | 9578 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
9023 | if (!msg) | 9579 | if (!msg) |
9024 | return; | 9580 | return; |
@@ -9030,8 +9586,8 @@ void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev, | |||
9030 | } | 9586 | } |
9031 | 9587 | ||
9032 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 9588 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
9033 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | 9589 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || |
9034 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, macaddr) || | 9590 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) || |
9035 | (ie_len && ie && | 9591 | (ie_len && ie && |
9036 | nla_put(msg, NL80211_ATTR_IE, ie_len , ie))) | 9592 | nla_put(msg, NL80211_ATTR_IE, ie_len , ie))) |
9037 | goto nla_put_failure; | 9593 | goto nla_put_failure; |
@@ -9046,6 +9602,7 @@ void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev, | |||
9046 | genlmsg_cancel(msg, hdr); | 9602 | genlmsg_cancel(msg, hdr); |
9047 | nlmsg_free(msg); | 9603 | nlmsg_free(msg); |
9048 | } | 9604 | } |
9605 | EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate); | ||
9049 | 9606 | ||
9050 | void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, | 9607 | void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, |
9051 | struct net_device *netdev, const u8 *addr, | 9608 | struct net_device *netdev, const u8 *addr, |
@@ -9114,7 +9671,7 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy, | |||
9114 | nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_BEFORE); | 9671 | nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_BEFORE); |
9115 | if (!nl_freq) | 9672 | if (!nl_freq) |
9116 | goto nla_put_failure; | 9673 | goto nla_put_failure; |
9117 | if (nl80211_msg_put_channel(msg, channel_before)) | 9674 | if (nl80211_msg_put_channel(msg, channel_before, false)) |
9118 | goto nla_put_failure; | 9675 | goto nla_put_failure; |
9119 | nla_nest_end(msg, nl_freq); | 9676 | nla_nest_end(msg, nl_freq); |
9120 | 9677 | ||
@@ -9122,7 +9679,7 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy, | |||
9122 | nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_AFTER); | 9679 | nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_AFTER); |
9123 | if (!nl_freq) | 9680 | if (!nl_freq) |
9124 | goto nla_put_failure; | 9681 | goto nla_put_failure; |
9125 | if (nl80211_msg_put_channel(msg, channel_after)) | 9682 | if (nl80211_msg_put_channel(msg, channel_after, false)) |
9126 | goto nla_put_failure; | 9683 | goto nla_put_failure; |
9127 | nla_nest_end(msg, nl_freq); | 9684 | nla_nest_end(msg, nl_freq); |
9128 | 9685 | ||
@@ -9184,31 +9741,42 @@ static void nl80211_send_remain_on_chan_event( | |||
9184 | nlmsg_free(msg); | 9741 | nlmsg_free(msg); |
9185 | } | 9742 | } |
9186 | 9743 | ||
9187 | void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, | 9744 | void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie, |
9188 | struct wireless_dev *wdev, u64 cookie, | 9745 | struct ieee80211_channel *chan, |
9189 | struct ieee80211_channel *chan, | 9746 | unsigned int duration, gfp_t gfp) |
9190 | unsigned int duration, gfp_t gfp) | ||
9191 | { | 9747 | { |
9748 | struct wiphy *wiphy = wdev->wiphy; | ||
9749 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9750 | |||
9751 | trace_cfg80211_ready_on_channel(wdev, cookie, chan, duration); | ||
9192 | nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL, | 9752 | nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL, |
9193 | rdev, wdev, cookie, chan, | 9753 | rdev, wdev, cookie, chan, |
9194 | duration, gfp); | 9754 | duration, gfp); |
9195 | } | 9755 | } |
9756 | EXPORT_SYMBOL(cfg80211_ready_on_channel); | ||
9196 | 9757 | ||
9197 | void nl80211_send_remain_on_channel_cancel( | 9758 | void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie, |
9198 | struct cfg80211_registered_device *rdev, | 9759 | struct ieee80211_channel *chan, |
9199 | struct wireless_dev *wdev, | 9760 | gfp_t gfp) |
9200 | u64 cookie, struct ieee80211_channel *chan, gfp_t gfp) | ||
9201 | { | 9761 | { |
9762 | struct wiphy *wiphy = wdev->wiphy; | ||
9763 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9764 | |||
9765 | trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan); | ||
9202 | nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, | 9766 | nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, |
9203 | rdev, wdev, cookie, chan, 0, gfp); | 9767 | rdev, wdev, cookie, chan, 0, gfp); |
9204 | } | 9768 | } |
9769 | EXPORT_SYMBOL(cfg80211_remain_on_channel_expired); | ||
9205 | 9770 | ||
9206 | void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, | 9771 | void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, |
9207 | struct net_device *dev, const u8 *mac_addr, | 9772 | struct station_info *sinfo, gfp_t gfp) |
9208 | struct station_info *sinfo, gfp_t gfp) | ||
9209 | { | 9773 | { |
9774 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
9775 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9210 | struct sk_buff *msg; | 9776 | struct sk_buff *msg; |
9211 | 9777 | ||
9778 | trace_cfg80211_new_sta(dev, mac_addr, sinfo); | ||
9779 | |||
9212 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | 9780 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
9213 | if (!msg) | 9781 | if (!msg) |
9214 | return; | 9782 | return; |
@@ -9222,14 +9790,17 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, | |||
9222 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 9790 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
9223 | nl80211_mlme_mcgrp.id, gfp); | 9791 | nl80211_mlme_mcgrp.id, gfp); |
9224 | } | 9792 | } |
9793 | EXPORT_SYMBOL(cfg80211_new_sta); | ||
9225 | 9794 | ||
9226 | void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, | 9795 | void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp) |
9227 | struct net_device *dev, const u8 *mac_addr, | ||
9228 | gfp_t gfp) | ||
9229 | { | 9796 | { |
9797 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
9798 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9230 | struct sk_buff *msg; | 9799 | struct sk_buff *msg; |
9231 | void *hdr; | 9800 | void *hdr; |
9232 | 9801 | ||
9802 | trace_cfg80211_del_sta(dev, mac_addr); | ||
9803 | |||
9233 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | 9804 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
9234 | if (!msg) | 9805 | if (!msg) |
9235 | return; | 9806 | return; |
@@ -9254,12 +9825,14 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, | |||
9254 | genlmsg_cancel(msg, hdr); | 9825 | genlmsg_cancel(msg, hdr); |
9255 | nlmsg_free(msg); | 9826 | nlmsg_free(msg); |
9256 | } | 9827 | } |
9828 | EXPORT_SYMBOL(cfg80211_del_sta); | ||
9257 | 9829 | ||
9258 | void nl80211_send_conn_failed_event(struct cfg80211_registered_device *rdev, | 9830 | void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, |
9259 | struct net_device *dev, const u8 *mac_addr, | 9831 | enum nl80211_connect_failed_reason reason, |
9260 | enum nl80211_connect_failed_reason reason, | 9832 | gfp_t gfp) |
9261 | gfp_t gfp) | ||
9262 | { | 9833 | { |
9834 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
9835 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9263 | struct sk_buff *msg; | 9836 | struct sk_buff *msg; |
9264 | void *hdr; | 9837 | void *hdr; |
9265 | 9838 | ||
@@ -9288,6 +9861,7 @@ void nl80211_send_conn_failed_event(struct cfg80211_registered_device *rdev, | |||
9288 | genlmsg_cancel(msg, hdr); | 9861 | genlmsg_cancel(msg, hdr); |
9289 | nlmsg_free(msg); | 9862 | nlmsg_free(msg); |
9290 | } | 9863 | } |
9864 | EXPORT_SYMBOL(cfg80211_conn_failed); | ||
9291 | 9865 | ||
9292 | static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd, | 9866 | static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd, |
9293 | const u8 *addr, gfp_t gfp) | 9867 | const u8 *addr, gfp_t gfp) |
@@ -9332,19 +9906,47 @@ static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd, | |||
9332 | return true; | 9906 | return true; |
9333 | } | 9907 | } |
9334 | 9908 | ||
9335 | bool nl80211_unexpected_frame(struct net_device *dev, const u8 *addr, gfp_t gfp) | 9909 | bool cfg80211_rx_spurious_frame(struct net_device *dev, |
9910 | const u8 *addr, gfp_t gfp) | ||
9336 | { | 9911 | { |
9337 | return __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME, | 9912 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
9338 | addr, gfp); | 9913 | bool ret; |
9914 | |||
9915 | trace_cfg80211_rx_spurious_frame(dev, addr); | ||
9916 | |||
9917 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && | ||
9918 | wdev->iftype != NL80211_IFTYPE_P2P_GO)) { | ||
9919 | trace_cfg80211_return_bool(false); | ||
9920 | return false; | ||
9921 | } | ||
9922 | ret = __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME, | ||
9923 | addr, gfp); | ||
9924 | trace_cfg80211_return_bool(ret); | ||
9925 | return ret; | ||
9339 | } | 9926 | } |
9927 | EXPORT_SYMBOL(cfg80211_rx_spurious_frame); | ||
9340 | 9928 | ||
9341 | bool nl80211_unexpected_4addr_frame(struct net_device *dev, | 9929 | bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev, |
9342 | const u8 *addr, gfp_t gfp) | 9930 | const u8 *addr, gfp_t gfp) |
9343 | { | 9931 | { |
9344 | return __nl80211_unexpected_frame(dev, | 9932 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
9345 | NL80211_CMD_UNEXPECTED_4ADDR_FRAME, | 9933 | bool ret; |
9346 | addr, gfp); | 9934 | |
9935 | trace_cfg80211_rx_unexpected_4addr_frame(dev, addr); | ||
9936 | |||
9937 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && | ||
9938 | wdev->iftype != NL80211_IFTYPE_P2P_GO && | ||
9939 | wdev->iftype != NL80211_IFTYPE_AP_VLAN)) { | ||
9940 | trace_cfg80211_return_bool(false); | ||
9941 | return false; | ||
9942 | } | ||
9943 | ret = __nl80211_unexpected_frame(dev, | ||
9944 | NL80211_CMD_UNEXPECTED_4ADDR_FRAME, | ||
9945 | addr, gfp); | ||
9946 | trace_cfg80211_return_bool(ret); | ||
9947 | return ret; | ||
9347 | } | 9948 | } |
9949 | EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame); | ||
9348 | 9950 | ||
9349 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | 9951 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, |
9350 | struct wireless_dev *wdev, u32 nlportid, | 9952 | struct wireless_dev *wdev, u32 nlportid, |
@@ -9384,15 +9986,17 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | |||
9384 | return -ENOBUFS; | 9986 | return -ENOBUFS; |
9385 | } | 9987 | } |
9386 | 9988 | ||
9387 | void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, | 9989 | void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, |
9388 | struct wireless_dev *wdev, u64 cookie, | 9990 | const u8 *buf, size_t len, bool ack, gfp_t gfp) |
9389 | const u8 *buf, size_t len, bool ack, | ||
9390 | gfp_t gfp) | ||
9391 | { | 9991 | { |
9992 | struct wiphy *wiphy = wdev->wiphy; | ||
9993 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9392 | struct net_device *netdev = wdev->netdev; | 9994 | struct net_device *netdev = wdev->netdev; |
9393 | struct sk_buff *msg; | 9995 | struct sk_buff *msg; |
9394 | void *hdr; | 9996 | void *hdr; |
9395 | 9997 | ||
9998 | trace_cfg80211_mgmt_tx_status(wdev, cookie, ack); | ||
9999 | |||
9396 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | 10000 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
9397 | if (!msg) | 10001 | if (!msg) |
9398 | return; | 10002 | return; |
@@ -9420,17 +10024,21 @@ void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, | |||
9420 | genlmsg_cancel(msg, hdr); | 10024 | genlmsg_cancel(msg, hdr); |
9421 | nlmsg_free(msg); | 10025 | nlmsg_free(msg); |
9422 | } | 10026 | } |
10027 | EXPORT_SYMBOL(cfg80211_mgmt_tx_status); | ||
9423 | 10028 | ||
9424 | void | 10029 | void cfg80211_cqm_rssi_notify(struct net_device *dev, |
9425 | nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, | 10030 | enum nl80211_cqm_rssi_threshold_event rssi_event, |
9426 | struct net_device *netdev, | 10031 | gfp_t gfp) |
9427 | enum nl80211_cqm_rssi_threshold_event rssi_event, | ||
9428 | gfp_t gfp) | ||
9429 | { | 10032 | { |
10033 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
10034 | struct wiphy *wiphy = wdev->wiphy; | ||
10035 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9430 | struct sk_buff *msg; | 10036 | struct sk_buff *msg; |
9431 | struct nlattr *pinfoattr; | 10037 | struct nlattr *pinfoattr; |
9432 | void *hdr; | 10038 | void *hdr; |
9433 | 10039 | ||
10040 | trace_cfg80211_cqm_rssi_notify(dev, rssi_event); | ||
10041 | |||
9434 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | 10042 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
9435 | if (!msg) | 10043 | if (!msg) |
9436 | return; | 10044 | return; |
@@ -9442,7 +10050,7 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, | |||
9442 | } | 10050 | } |
9443 | 10051 | ||
9444 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 10052 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
9445 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex)) | 10053 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex)) |
9446 | goto nla_put_failure; | 10054 | goto nla_put_failure; |
9447 | 10055 | ||
9448 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM); | 10056 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM); |
@@ -9465,10 +10073,11 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, | |||
9465 | genlmsg_cancel(msg, hdr); | 10073 | genlmsg_cancel(msg, hdr); |
9466 | nlmsg_free(msg); | 10074 | nlmsg_free(msg); |
9467 | } | 10075 | } |
10076 | EXPORT_SYMBOL(cfg80211_cqm_rssi_notify); | ||
9468 | 10077 | ||
9469 | void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, | 10078 | static void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, |
9470 | struct net_device *netdev, const u8 *bssid, | 10079 | struct net_device *netdev, const u8 *bssid, |
9471 | const u8 *replay_ctr, gfp_t gfp) | 10080 | const u8 *replay_ctr, gfp_t gfp) |
9472 | { | 10081 | { |
9473 | struct sk_buff *msg; | 10082 | struct sk_buff *msg; |
9474 | struct nlattr *rekey_attr; | 10083 | struct nlattr *rekey_attr; |
@@ -9510,9 +10119,22 @@ void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, | |||
9510 | nlmsg_free(msg); | 10119 | nlmsg_free(msg); |
9511 | } | 10120 | } |
9512 | 10121 | ||
9513 | void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev, | 10122 | void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid, |
9514 | struct net_device *netdev, int index, | 10123 | const u8 *replay_ctr, gfp_t gfp) |
9515 | const u8 *bssid, bool preauth, gfp_t gfp) | 10124 | { |
10125 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
10126 | struct wiphy *wiphy = wdev->wiphy; | ||
10127 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
10128 | |||
10129 | trace_cfg80211_gtk_rekey_notify(dev, bssid); | ||
10130 | nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp); | ||
10131 | } | ||
10132 | EXPORT_SYMBOL(cfg80211_gtk_rekey_notify); | ||
10133 | |||
10134 | static void | ||
10135 | nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev, | ||
10136 | struct net_device *netdev, int index, | ||
10137 | const u8 *bssid, bool preauth, gfp_t gfp) | ||
9516 | { | 10138 | { |
9517 | struct sk_buff *msg; | 10139 | struct sk_buff *msg; |
9518 | struct nlattr *attr; | 10140 | struct nlattr *attr; |
@@ -9555,9 +10177,22 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev, | |||
9555 | nlmsg_free(msg); | 10177 | nlmsg_free(msg); |
9556 | } | 10178 | } |
9557 | 10179 | ||
9558 | void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | 10180 | void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index, |
9559 | struct net_device *netdev, | 10181 | const u8 *bssid, bool preauth, gfp_t gfp) |
9560 | struct cfg80211_chan_def *chandef, gfp_t gfp) | 10182 | { |
10183 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
10184 | struct wiphy *wiphy = wdev->wiphy; | ||
10185 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
10186 | |||
10187 | trace_cfg80211_pmksa_candidate_notify(dev, index, bssid, preauth); | ||
10188 | nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp); | ||
10189 | } | ||
10190 | EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify); | ||
10191 | |||
10192 | static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | ||
10193 | struct net_device *netdev, | ||
10194 | struct cfg80211_chan_def *chandef, | ||
10195 | gfp_t gfp) | ||
9561 | { | 10196 | { |
9562 | struct sk_buff *msg; | 10197 | struct sk_buff *msg; |
9563 | void *hdr; | 10198 | void *hdr; |
@@ -9589,11 +10224,36 @@ void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | |||
9589 | nlmsg_free(msg); | 10224 | nlmsg_free(msg); |
9590 | } | 10225 | } |
9591 | 10226 | ||
9592 | void | 10227 | void cfg80211_ch_switch_notify(struct net_device *dev, |
9593 | nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev, | 10228 | struct cfg80211_chan_def *chandef) |
9594 | struct net_device *netdev, const u8 *peer, | ||
9595 | u32 num_packets, u32 rate, u32 intvl, gfp_t gfp) | ||
9596 | { | 10229 | { |
10230 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
10231 | struct wiphy *wiphy = wdev->wiphy; | ||
10232 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
10233 | |||
10234 | trace_cfg80211_ch_switch_notify(dev, chandef); | ||
10235 | |||
10236 | wdev_lock(wdev); | ||
10237 | |||
10238 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && | ||
10239 | wdev->iftype != NL80211_IFTYPE_P2P_GO)) | ||
10240 | goto out; | ||
10241 | |||
10242 | wdev->channel = chandef->chan; | ||
10243 | nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL); | ||
10244 | out: | ||
10245 | wdev_unlock(wdev); | ||
10246 | return; | ||
10247 | } | ||
10248 | EXPORT_SYMBOL(cfg80211_ch_switch_notify); | ||
10249 | |||
10250 | void cfg80211_cqm_txe_notify(struct net_device *dev, | ||
10251 | const u8 *peer, u32 num_packets, | ||
10252 | u32 rate, u32 intvl, gfp_t gfp) | ||
10253 | { | ||
10254 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
10255 | struct wiphy *wiphy = wdev->wiphy; | ||
10256 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9597 | struct sk_buff *msg; | 10257 | struct sk_buff *msg; |
9598 | struct nlattr *pinfoattr; | 10258 | struct nlattr *pinfoattr; |
9599 | void *hdr; | 10259 | void *hdr; |
@@ -9609,7 +10269,7 @@ nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev, | |||
9609 | } | 10269 | } |
9610 | 10270 | ||
9611 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 10271 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
9612 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | 10272 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || |
9613 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) | 10273 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) |
9614 | goto nla_put_failure; | 10274 | goto nla_put_failure; |
9615 | 10275 | ||
@@ -9638,6 +10298,7 @@ nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev, | |||
9638 | genlmsg_cancel(msg, hdr); | 10298 | genlmsg_cancel(msg, hdr); |
9639 | nlmsg_free(msg); | 10299 | nlmsg_free(msg); |
9640 | } | 10300 | } |
10301 | EXPORT_SYMBOL(cfg80211_cqm_txe_notify); | ||
9641 | 10302 | ||
9642 | void | 10303 | void |
9643 | nl80211_radar_notify(struct cfg80211_registered_device *rdev, | 10304 | nl80211_radar_notify(struct cfg80211_registered_device *rdev, |
@@ -9690,15 +10351,18 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev, | |||
9690 | nlmsg_free(msg); | 10351 | nlmsg_free(msg); |
9691 | } | 10352 | } |
9692 | 10353 | ||
9693 | void | 10354 | void cfg80211_cqm_pktloss_notify(struct net_device *dev, |
9694 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | 10355 | const u8 *peer, u32 num_packets, gfp_t gfp) |
9695 | struct net_device *netdev, const u8 *peer, | ||
9696 | u32 num_packets, gfp_t gfp) | ||
9697 | { | 10356 | { |
10357 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
10358 | struct wiphy *wiphy = wdev->wiphy; | ||
10359 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9698 | struct sk_buff *msg; | 10360 | struct sk_buff *msg; |
9699 | struct nlattr *pinfoattr; | 10361 | struct nlattr *pinfoattr; |
9700 | void *hdr; | 10362 | void *hdr; |
9701 | 10363 | ||
10364 | trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets); | ||
10365 | |||
9702 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | 10366 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
9703 | if (!msg) | 10367 | if (!msg) |
9704 | return; | 10368 | return; |
@@ -9710,7 +10374,7 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | |||
9710 | } | 10374 | } |
9711 | 10375 | ||
9712 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 10376 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
9713 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | 10377 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || |
9714 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) | 10378 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) |
9715 | goto nla_put_failure; | 10379 | goto nla_put_failure; |
9716 | 10380 | ||
@@ -9733,6 +10397,7 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | |||
9733 | genlmsg_cancel(msg, hdr); | 10397 | genlmsg_cancel(msg, hdr); |
9734 | nlmsg_free(msg); | 10398 | nlmsg_free(msg); |
9735 | } | 10399 | } |
10400 | EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify); | ||
9736 | 10401 | ||
9737 | void cfg80211_probe_status(struct net_device *dev, const u8 *addr, | 10402 | void cfg80211_probe_status(struct net_device *dev, const u8 *addr, |
9738 | u64 cookie, bool acked, gfp_t gfp) | 10403 | u64 cookie, bool acked, gfp_t gfp) |
@@ -10019,6 +10684,89 @@ static struct notifier_block nl80211_netlink_notifier = { | |||
10019 | .notifier_call = nl80211_netlink_notify, | 10684 | .notifier_call = nl80211_netlink_notify, |
10020 | }; | 10685 | }; |
10021 | 10686 | ||
10687 | void cfg80211_ft_event(struct net_device *netdev, | ||
10688 | struct cfg80211_ft_event_params *ft_event) | ||
10689 | { | ||
10690 | struct wiphy *wiphy = netdev->ieee80211_ptr->wiphy; | ||
10691 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
10692 | struct sk_buff *msg; | ||
10693 | void *hdr; | ||
10694 | int err; | ||
10695 | |||
10696 | trace_cfg80211_ft_event(wiphy, netdev, ft_event); | ||
10697 | |||
10698 | if (!ft_event->target_ap) | ||
10699 | return; | ||
10700 | |||
10701 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
10702 | if (!msg) | ||
10703 | return; | ||
10704 | |||
10705 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FT_EVENT); | ||
10706 | if (!hdr) { | ||
10707 | nlmsg_free(msg); | ||
10708 | return; | ||
10709 | } | ||
10710 | |||
10711 | nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
10712 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
10713 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, ft_event->target_ap); | ||
10714 | if (ft_event->ies) | ||
10715 | nla_put(msg, NL80211_ATTR_IE, ft_event->ies_len, ft_event->ies); | ||
10716 | if (ft_event->ric_ies) | ||
10717 | nla_put(msg, NL80211_ATTR_IE_RIC, ft_event->ric_ies_len, | ||
10718 | ft_event->ric_ies); | ||
10719 | |||
10720 | err = genlmsg_end(msg, hdr); | ||
10721 | if (err < 0) { | ||
10722 | nlmsg_free(msg); | ||
10723 | return; | ||
10724 | } | ||
10725 | |||
10726 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
10727 | nl80211_mlme_mcgrp.id, GFP_KERNEL); | ||
10728 | } | ||
10729 | EXPORT_SYMBOL(cfg80211_ft_event); | ||
10730 | |||
10731 | void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp) | ||
10732 | { | ||
10733 | struct cfg80211_registered_device *rdev; | ||
10734 | struct sk_buff *msg; | ||
10735 | void *hdr; | ||
10736 | u32 nlportid; | ||
10737 | |||
10738 | rdev = wiphy_to_dev(wdev->wiphy); | ||
10739 | if (!rdev->crit_proto_nlportid) | ||
10740 | return; | ||
10741 | |||
10742 | nlportid = rdev->crit_proto_nlportid; | ||
10743 | rdev->crit_proto_nlportid = 0; | ||
10744 | |||
10745 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | ||
10746 | if (!msg) | ||
10747 | return; | ||
10748 | |||
10749 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CRIT_PROTOCOL_STOP); | ||
10750 | if (!hdr) | ||
10751 | goto nla_put_failure; | ||
10752 | |||
10753 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | ||
10754 | nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev))) | ||
10755 | goto nla_put_failure; | ||
10756 | |||
10757 | genlmsg_end(msg, hdr); | ||
10758 | |||
10759 | genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid); | ||
10760 | return; | ||
10761 | |||
10762 | nla_put_failure: | ||
10763 | if (hdr) | ||
10764 | genlmsg_cancel(msg, hdr); | ||
10765 | nlmsg_free(msg); | ||
10766 | |||
10767 | } | ||
10768 | EXPORT_SYMBOL(cfg80211_crit_proto_stopped); | ||
10769 | |||
10022 | /* initialisation/exit functions */ | 10770 | /* initialisation/exit functions */ |
10023 | 10771 | ||
10024 | int nl80211_init(void) | 10772 | int nl80211_init(void) |
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index b061da4919e1..a4073e808c13 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
@@ -29,12 +29,6 @@ void nl80211_send_deauth(struct cfg80211_registered_device *rdev, | |||
29 | void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, | 29 | void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, |
30 | struct net_device *netdev, | 30 | struct net_device *netdev, |
31 | const u8 *buf, size_t len, gfp_t gfp); | 31 | const u8 *buf, size_t len, gfp_t gfp); |
32 | void nl80211_send_unprot_deauth(struct cfg80211_registered_device *rdev, | ||
33 | struct net_device *netdev, | ||
34 | const u8 *buf, size_t len, gfp_t gfp); | ||
35 | void nl80211_send_unprot_disassoc(struct cfg80211_registered_device *rdev, | ||
36 | struct net_device *netdev, | ||
37 | const u8 *buf, size_t len, gfp_t gfp); | ||
38 | void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev, | 32 | void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev, |
39 | struct net_device *netdev, | 33 | struct net_device *netdev, |
40 | const u8 *addr, gfp_t gfp); | 34 | const u8 *addr, gfp_t gfp); |
@@ -54,10 +48,6 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, | |||
54 | struct net_device *netdev, u16 reason, | 48 | struct net_device *netdev, u16 reason, |
55 | const u8 *ie, size_t ie_len, bool from_ap); | 49 | const u8 *ie, size_t ie_len, bool from_ap); |
56 | 50 | ||
57 | void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev, | ||
58 | struct net_device *netdev, | ||
59 | const u8 *macaddr, const u8* ie, u8 ie_len, | ||
60 | gfp_t gfp); | ||
61 | void | 51 | void |
62 | nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, | 52 | nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, |
63 | struct net_device *netdev, const u8 *addr, | 53 | struct net_device *netdev, const u8 *addr, |
@@ -73,41 +63,10 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, | |||
73 | struct net_device *netdev, const u8 *bssid, | 63 | struct net_device *netdev, const u8 *bssid, |
74 | gfp_t gfp); | 64 | gfp_t gfp); |
75 | 65 | ||
76 | void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, | ||
77 | struct wireless_dev *wdev, u64 cookie, | ||
78 | struct ieee80211_channel *chan, | ||
79 | unsigned int duration, gfp_t gfp); | ||
80 | void nl80211_send_remain_on_channel_cancel( | ||
81 | struct cfg80211_registered_device *rdev, | ||
82 | struct wireless_dev *wdev, | ||
83 | u64 cookie, struct ieee80211_channel *chan, gfp_t gfp); | ||
84 | |||
85 | void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, | ||
86 | struct net_device *dev, const u8 *mac_addr, | ||
87 | struct station_info *sinfo, gfp_t gfp); | ||
88 | void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, | ||
89 | struct net_device *dev, const u8 *mac_addr, | ||
90 | gfp_t gfp); | ||
91 | |||
92 | void nl80211_send_conn_failed_event(struct cfg80211_registered_device *rdev, | ||
93 | struct net_device *dev, const u8 *mac_addr, | ||
94 | enum nl80211_connect_failed_reason reason, | ||
95 | gfp_t gfp); | ||
96 | |||
97 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | 66 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, |
98 | struct wireless_dev *wdev, u32 nlpid, | 67 | struct wireless_dev *wdev, u32 nlpid, |
99 | int freq, int sig_dbm, | 68 | int freq, int sig_dbm, |
100 | const u8 *buf, size_t len, gfp_t gfp); | 69 | const u8 *buf, size_t len, gfp_t gfp); |
101 | void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, | ||
102 | struct wireless_dev *wdev, u64 cookie, | ||
103 | const u8 *buf, size_t len, bool ack, | ||
104 | gfp_t gfp); | ||
105 | |||
106 | void | ||
107 | nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, | ||
108 | struct net_device *netdev, | ||
109 | enum nl80211_cqm_rssi_threshold_event rssi_event, | ||
110 | gfp_t gfp); | ||
111 | 70 | ||
112 | void | 71 | void |
113 | nl80211_radar_notify(struct cfg80211_registered_device *rdev, | 72 | nl80211_radar_notify(struct cfg80211_registered_device *rdev, |
@@ -115,31 +74,4 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev, | |||
115 | enum nl80211_radar_event event, | 74 | enum nl80211_radar_event event, |
116 | struct net_device *netdev, gfp_t gfp); | 75 | struct net_device *netdev, gfp_t gfp); |
117 | 76 | ||
118 | void | ||
119 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | ||
120 | struct net_device *netdev, const u8 *peer, | ||
121 | u32 num_packets, gfp_t gfp); | ||
122 | |||
123 | void | ||
124 | nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev, | ||
125 | struct net_device *netdev, const u8 *peer, | ||
126 | u32 num_packets, u32 rate, u32 intvl, gfp_t gfp); | ||
127 | |||
128 | void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, | ||
129 | struct net_device *netdev, const u8 *bssid, | ||
130 | const u8 *replay_ctr, gfp_t gfp); | ||
131 | |||
132 | void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev, | ||
133 | struct net_device *netdev, int index, | ||
134 | const u8 *bssid, bool preauth, gfp_t gfp); | ||
135 | |||
136 | void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | ||
137 | struct net_device *dev, | ||
138 | struct cfg80211_chan_def *chandef, gfp_t gfp); | ||
139 | |||
140 | bool nl80211_unexpected_frame(struct net_device *dev, | ||
141 | const u8 *addr, gfp_t gfp); | ||
142 | bool nl80211_unexpected_4addr_frame(struct net_device *dev, | ||
143 | const u8 *addr, gfp_t gfp); | ||
144 | |||
145 | #endif /* __NET_WIRELESS_NL80211_H */ | 77 | #endif /* __NET_WIRELESS_NL80211_H */ |
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 422d38291d66..9f15f0ac824d 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h | |||
@@ -6,11 +6,12 @@ | |||
6 | #include "core.h" | 6 | #include "core.h" |
7 | #include "trace.h" | 7 | #include "trace.h" |
8 | 8 | ||
9 | static inline int rdev_suspend(struct cfg80211_registered_device *rdev) | 9 | static inline int rdev_suspend(struct cfg80211_registered_device *rdev, |
10 | struct cfg80211_wowlan *wowlan) | ||
10 | { | 11 | { |
11 | int ret; | 12 | int ret; |
12 | trace_rdev_suspend(&rdev->wiphy, rdev->wowlan); | 13 | trace_rdev_suspend(&rdev->wiphy, wowlan); |
13 | ret = rdev->ops->suspend(&rdev->wiphy, rdev->wowlan); | 14 | ret = rdev->ops->suspend(&rdev->wiphy, wowlan); |
14 | trace_rdev_return_int(&rdev->wiphy, ret); | 15 | trace_rdev_return_int(&rdev->wiphy, ret); |
15 | return ret; | 16 | return ret; |
16 | } | 17 | } |
@@ -874,7 +875,7 @@ static inline void rdev_stop_p2p_device(struct cfg80211_registered_device *rdev, | |||
874 | trace_rdev_stop_p2p_device(&rdev->wiphy, wdev); | 875 | trace_rdev_stop_p2p_device(&rdev->wiphy, wdev); |
875 | rdev->ops->stop_p2p_device(&rdev->wiphy, wdev); | 876 | rdev->ops->stop_p2p_device(&rdev->wiphy, wdev); |
876 | trace_rdev_return_void(&rdev->wiphy); | 877 | trace_rdev_return_void(&rdev->wiphy); |
877 | } | 878 | } |
878 | 879 | ||
879 | static inline int rdev_set_mac_acl(struct cfg80211_registered_device *rdev, | 880 | static inline int rdev_set_mac_acl(struct cfg80211_registered_device *rdev, |
880 | struct net_device *dev, | 881 | struct net_device *dev, |
@@ -887,4 +888,39 @@ static inline int rdev_set_mac_acl(struct cfg80211_registered_device *rdev, | |||
887 | trace_rdev_return_int(&rdev->wiphy, ret); | 888 | trace_rdev_return_int(&rdev->wiphy, ret); |
888 | return ret; | 889 | return ret; |
889 | } | 890 | } |
891 | |||
892 | static inline int rdev_update_ft_ies(struct cfg80211_registered_device *rdev, | ||
893 | struct net_device *dev, | ||
894 | struct cfg80211_update_ft_ies_params *ftie) | ||
895 | { | ||
896 | int ret; | ||
897 | |||
898 | trace_rdev_update_ft_ies(&rdev->wiphy, dev, ftie); | ||
899 | ret = rdev->ops->update_ft_ies(&rdev->wiphy, dev, ftie); | ||
900 | trace_rdev_return_int(&rdev->wiphy, ret); | ||
901 | return ret; | ||
902 | } | ||
903 | |||
904 | static inline int rdev_crit_proto_start(struct cfg80211_registered_device *rdev, | ||
905 | struct wireless_dev *wdev, | ||
906 | enum nl80211_crit_proto_id protocol, | ||
907 | u16 duration) | ||
908 | { | ||
909 | int ret; | ||
910 | |||
911 | trace_rdev_crit_proto_start(&rdev->wiphy, wdev, protocol, duration); | ||
912 | ret = rdev->ops->crit_proto_start(&rdev->wiphy, wdev, | ||
913 | protocol, duration); | ||
914 | trace_rdev_return_int(&rdev->wiphy, ret); | ||
915 | return ret; | ||
916 | } | ||
917 | |||
918 | static inline void rdev_crit_proto_stop(struct cfg80211_registered_device *rdev, | ||
919 | struct wireless_dev *wdev) | ||
920 | { | ||
921 | trace_rdev_crit_proto_stop(&rdev->wiphy, wdev); | ||
922 | rdev->ops->crit_proto_stop(&rdev->wiphy, wdev); | ||
923 | trace_rdev_return_void(&rdev->wiphy); | ||
924 | } | ||
925 | |||
890 | #endif /* __CFG80211_RDEV_OPS */ | 926 | #endif /* __CFG80211_RDEV_OPS */ |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 98532c00242d..cc35fbaa4578 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -184,14 +184,14 @@ static const struct ieee80211_regdomain world_regdom = { | |||
184 | NL80211_RRF_NO_IBSS | | 184 | NL80211_RRF_NO_IBSS | |
185 | NL80211_RRF_NO_OFDM), | 185 | NL80211_RRF_NO_OFDM), |
186 | /* IEEE 802.11a, channel 36..48 */ | 186 | /* IEEE 802.11a, channel 36..48 */ |
187 | REG_RULE(5180-10, 5240+10, 40, 6, 20, | 187 | REG_RULE(5180-10, 5240+10, 80, 6, 20, |
188 | NL80211_RRF_PASSIVE_SCAN | | 188 | NL80211_RRF_PASSIVE_SCAN | |
189 | NL80211_RRF_NO_IBSS), | 189 | NL80211_RRF_NO_IBSS), |
190 | 190 | ||
191 | /* NB: 5260 MHz - 5700 MHz requies DFS */ | 191 | /* NB: 5260 MHz - 5700 MHz requires DFS */ |
192 | 192 | ||
193 | /* IEEE 802.11a, channel 149..165 */ | 193 | /* IEEE 802.11a, channel 149..165 */ |
194 | REG_RULE(5745-10, 5825+10, 40, 6, 20, | 194 | REG_RULE(5745-10, 5825+10, 80, 6, 20, |
195 | NL80211_RRF_PASSIVE_SCAN | | 195 | NL80211_RRF_PASSIVE_SCAN | |
196 | NL80211_RRF_NO_IBSS), | 196 | NL80211_RRF_NO_IBSS), |
197 | 197 | ||
@@ -855,7 +855,7 @@ static void handle_channel(struct wiphy *wiphy, | |||
855 | return; | 855 | return; |
856 | 856 | ||
857 | REG_DBG_PRINT("Disabling freq %d MHz\n", chan->center_freq); | 857 | REG_DBG_PRINT("Disabling freq %d MHz\n", chan->center_freq); |
858 | chan->flags = IEEE80211_CHAN_DISABLED; | 858 | chan->flags |= IEEE80211_CHAN_DISABLED; |
859 | return; | 859 | return; |
860 | } | 860 | } |
861 | 861 | ||
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 674aadca0079..fd99ea495b7e 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -169,7 +169,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) | |||
169 | union iwreq_data wrqu; | 169 | union iwreq_data wrqu; |
170 | #endif | 170 | #endif |
171 | 171 | ||
172 | ASSERT_RDEV_LOCK(rdev); | 172 | lockdep_assert_held(&rdev->sched_scan_mtx); |
173 | 173 | ||
174 | request = rdev->scan_req; | 174 | request = rdev->scan_req; |
175 | 175 | ||
@@ -230,9 +230,9 @@ void __cfg80211_scan_done(struct work_struct *wk) | |||
230 | rdev = container_of(wk, struct cfg80211_registered_device, | 230 | rdev = container_of(wk, struct cfg80211_registered_device, |
231 | scan_done_wk); | 231 | scan_done_wk); |
232 | 232 | ||
233 | cfg80211_lock_rdev(rdev); | 233 | mutex_lock(&rdev->sched_scan_mtx); |
234 | ___cfg80211_scan_done(rdev, false); | 234 | ___cfg80211_scan_done(rdev, false); |
235 | cfg80211_unlock_rdev(rdev); | 235 | mutex_unlock(&rdev->sched_scan_mtx); |
236 | } | 236 | } |
237 | 237 | ||
238 | void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) | 238 | void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) |
@@ -698,11 +698,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, | |||
698 | found = rb_find_bss(dev, tmp, BSS_CMP_REGULAR); | 698 | found = rb_find_bss(dev, tmp, BSS_CMP_REGULAR); |
699 | 699 | ||
700 | if (found) { | 700 | if (found) { |
701 | found->pub.beacon_interval = tmp->pub.beacon_interval; | ||
702 | found->pub.signal = tmp->pub.signal; | ||
703 | found->pub.capability = tmp->pub.capability; | ||
704 | found->ts = tmp->ts; | ||
705 | |||
706 | /* Update IEs */ | 701 | /* Update IEs */ |
707 | if (rcu_access_pointer(tmp->pub.proberesp_ies)) { | 702 | if (rcu_access_pointer(tmp->pub.proberesp_ies)) { |
708 | const struct cfg80211_bss_ies *old; | 703 | const struct cfg80211_bss_ies *old; |
@@ -723,6 +718,8 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, | |||
723 | 718 | ||
724 | if (found->pub.hidden_beacon_bss && | 719 | if (found->pub.hidden_beacon_bss && |
725 | !list_empty(&found->hidden_list)) { | 720 | !list_empty(&found->hidden_list)) { |
721 | const struct cfg80211_bss_ies *f; | ||
722 | |||
726 | /* | 723 | /* |
727 | * The found BSS struct is one of the probe | 724 | * The found BSS struct is one of the probe |
728 | * response members of a group, but we're | 725 | * response members of a group, but we're |
@@ -732,6 +729,10 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, | |||
732 | * SSID to showing it, which is confusing so | 729 | * SSID to showing it, which is confusing so |
733 | * drop this information. | 730 | * drop this information. |
734 | */ | 731 | */ |
732 | |||
733 | f = rcu_access_pointer(tmp->pub.beacon_ies); | ||
734 | kfree_rcu((struct cfg80211_bss_ies *)f, | ||
735 | rcu_head); | ||
735 | goto drop; | 736 | goto drop; |
736 | } | 737 | } |
737 | 738 | ||
@@ -761,6 +762,11 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, | |||
761 | kfree_rcu((struct cfg80211_bss_ies *)old, | 762 | kfree_rcu((struct cfg80211_bss_ies *)old, |
762 | rcu_head); | 763 | rcu_head); |
763 | } | 764 | } |
765 | |||
766 | found->pub.beacon_interval = tmp->pub.beacon_interval; | ||
767 | found->pub.signal = tmp->pub.signal; | ||
768 | found->pub.capability = tmp->pub.capability; | ||
769 | found->ts = tmp->ts; | ||
764 | } else { | 770 | } else { |
765 | struct cfg80211_internal_bss *new; | 771 | struct cfg80211_internal_bss *new; |
766 | struct cfg80211_internal_bss *hidden; | 772 | struct cfg80211_internal_bss *hidden; |
@@ -1056,6 +1062,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
1056 | if (IS_ERR(rdev)) | 1062 | if (IS_ERR(rdev)) |
1057 | return PTR_ERR(rdev); | 1063 | return PTR_ERR(rdev); |
1058 | 1064 | ||
1065 | mutex_lock(&rdev->sched_scan_mtx); | ||
1059 | if (rdev->scan_req) { | 1066 | if (rdev->scan_req) { |
1060 | err = -EBUSY; | 1067 | err = -EBUSY; |
1061 | goto out; | 1068 | goto out; |
@@ -1162,6 +1169,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
1162 | dev_hold(dev); | 1169 | dev_hold(dev); |
1163 | } | 1170 | } |
1164 | out: | 1171 | out: |
1172 | mutex_unlock(&rdev->sched_scan_mtx); | ||
1165 | kfree(creq); | 1173 | kfree(creq); |
1166 | cfg80211_unlock_rdev(rdev); | 1174 | cfg80211_unlock_rdev(rdev); |
1167 | return err; | 1175 | return err; |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index f432bd3755b1..a9dc5c736df0 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -85,6 +85,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) | |||
85 | ASSERT_RTNL(); | 85 | ASSERT_RTNL(); |
86 | ASSERT_RDEV_LOCK(rdev); | 86 | ASSERT_RDEV_LOCK(rdev); |
87 | ASSERT_WDEV_LOCK(wdev); | 87 | ASSERT_WDEV_LOCK(wdev); |
88 | lockdep_assert_held(&rdev->sched_scan_mtx); | ||
88 | 89 | ||
89 | if (rdev->scan_req) | 90 | if (rdev->scan_req) |
90 | return -EBUSY; | 91 | return -EBUSY; |
@@ -159,7 +160,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
159 | { | 160 | { |
160 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 161 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
161 | struct cfg80211_connect_params *params; | 162 | struct cfg80211_connect_params *params; |
162 | const u8 *prev_bssid = NULL; | 163 | struct cfg80211_assoc_request req = {}; |
163 | int err; | 164 | int err; |
164 | 165 | ||
165 | ASSERT_WDEV_LOCK(wdev); | 166 | ASSERT_WDEV_LOCK(wdev); |
@@ -186,16 +187,20 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
186 | BUG_ON(!rdev->ops->assoc); | 187 | BUG_ON(!rdev->ops->assoc); |
187 | wdev->conn->state = CFG80211_CONN_ASSOCIATING; | 188 | wdev->conn->state = CFG80211_CONN_ASSOCIATING; |
188 | if (wdev->conn->prev_bssid_valid) | 189 | if (wdev->conn->prev_bssid_valid) |
189 | prev_bssid = wdev->conn->prev_bssid; | 190 | req.prev_bssid = wdev->conn->prev_bssid; |
190 | err = __cfg80211_mlme_assoc(rdev, wdev->netdev, | 191 | req.ie = params->ie; |
191 | params->channel, params->bssid, | 192 | req.ie_len = params->ie_len; |
192 | prev_bssid, | 193 | req.use_mfp = params->mfp != NL80211_MFP_NO; |
193 | params->ssid, params->ssid_len, | 194 | req.crypto = params->crypto; |
194 | params->ie, params->ie_len, | 195 | req.flags = params->flags; |
195 | params->mfp != NL80211_MFP_NO, | 196 | req.ht_capa = params->ht_capa; |
196 | ¶ms->crypto, | 197 | req.ht_capa_mask = params->ht_capa_mask; |
197 | params->flags, ¶ms->ht_capa, | 198 | req.vht_capa = params->vht_capa; |
198 | ¶ms->ht_capa_mask); | 199 | req.vht_capa_mask = params->vht_capa_mask; |
200 | |||
201 | err = __cfg80211_mlme_assoc(rdev, wdev->netdev, params->channel, | ||
202 | params->bssid, params->ssid, | ||
203 | params->ssid_len, &req); | ||
199 | if (err) | 204 | if (err) |
200 | __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, | 205 | __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, |
201 | NULL, 0, | 206 | NULL, 0, |
@@ -223,6 +228,7 @@ void cfg80211_conn_work(struct work_struct *work) | |||
223 | rtnl_lock(); | 228 | rtnl_lock(); |
224 | cfg80211_lock_rdev(rdev); | 229 | cfg80211_lock_rdev(rdev); |
225 | mutex_lock(&rdev->devlist_mtx); | 230 | mutex_lock(&rdev->devlist_mtx); |
231 | mutex_lock(&rdev->sched_scan_mtx); | ||
226 | 232 | ||
227 | list_for_each_entry(wdev, &rdev->wdev_list, list) { | 233 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
228 | wdev_lock(wdev); | 234 | wdev_lock(wdev); |
@@ -230,7 +236,7 @@ void cfg80211_conn_work(struct work_struct *work) | |||
230 | wdev_unlock(wdev); | 236 | wdev_unlock(wdev); |
231 | continue; | 237 | continue; |
232 | } | 238 | } |
233 | if (wdev->sme_state != CFG80211_SME_CONNECTING) { | 239 | if (wdev->sme_state != CFG80211_SME_CONNECTING || !wdev->conn) { |
234 | wdev_unlock(wdev); | 240 | wdev_unlock(wdev); |
235 | continue; | 241 | continue; |
236 | } | 242 | } |
@@ -247,6 +253,7 @@ void cfg80211_conn_work(struct work_struct *work) | |||
247 | wdev_unlock(wdev); | 253 | wdev_unlock(wdev); |
248 | } | 254 | } |
249 | 255 | ||
256 | mutex_unlock(&rdev->sched_scan_mtx); | ||
250 | mutex_unlock(&rdev->devlist_mtx); | 257 | mutex_unlock(&rdev->devlist_mtx); |
251 | cfg80211_unlock_rdev(rdev); | 258 | cfg80211_unlock_rdev(rdev); |
252 | rtnl_unlock(); | 259 | rtnl_unlock(); |
@@ -320,11 +327,9 @@ void cfg80211_sme_scan_done(struct net_device *dev) | |||
320 | { | 327 | { |
321 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 328 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
322 | 329 | ||
323 | mutex_lock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx); | ||
324 | wdev_lock(wdev); | 330 | wdev_lock(wdev); |
325 | __cfg80211_sme_scan_done(dev); | 331 | __cfg80211_sme_scan_done(dev); |
326 | wdev_unlock(wdev); | 332 | wdev_unlock(wdev); |
327 | mutex_unlock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx); | ||
328 | } | 333 | } |
329 | 334 | ||
330 | void cfg80211_sme_rx_auth(struct net_device *dev, | 335 | void cfg80211_sme_rx_auth(struct net_device *dev, |
@@ -924,9 +929,12 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
924 | int err; | 929 | int err; |
925 | 930 | ||
926 | mutex_lock(&rdev->devlist_mtx); | 931 | mutex_lock(&rdev->devlist_mtx); |
932 | /* might request scan - scan_mtx -> wdev_mtx dependency */ | ||
933 | mutex_lock(&rdev->sched_scan_mtx); | ||
927 | wdev_lock(dev->ieee80211_ptr); | 934 | wdev_lock(dev->ieee80211_ptr); |
928 | err = __cfg80211_connect(rdev, dev, connect, connkeys, NULL); | 935 | err = __cfg80211_connect(rdev, dev, connect, connkeys, NULL); |
929 | wdev_unlock(dev->ieee80211_ptr); | 936 | wdev_unlock(dev->ieee80211_ptr); |
937 | mutex_unlock(&rdev->sched_scan_mtx); | ||
930 | mutex_unlock(&rdev->devlist_mtx); | 938 | mutex_unlock(&rdev->devlist_mtx); |
931 | 939 | ||
932 | return err; | 940 | return err; |
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 238ee49b3868..8f28b9f798d8 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c | |||
@@ -83,6 +83,14 @@ static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
83 | return 0; | 83 | return 0; |
84 | } | 84 | } |
85 | 85 | ||
86 | static void cfg80211_leave_all(struct cfg80211_registered_device *rdev) | ||
87 | { | ||
88 | struct wireless_dev *wdev; | ||
89 | |||
90 | list_for_each_entry(wdev, &rdev->wdev_list, list) | ||
91 | cfg80211_leave(rdev, wdev); | ||
92 | } | ||
93 | |||
86 | static int wiphy_suspend(struct device *dev, pm_message_t state) | 94 | static int wiphy_suspend(struct device *dev, pm_message_t state) |
87 | { | 95 | { |
88 | struct cfg80211_registered_device *rdev = dev_to_rdev(dev); | 96 | struct cfg80211_registered_device *rdev = dev_to_rdev(dev); |
@@ -90,12 +98,19 @@ static int wiphy_suspend(struct device *dev, pm_message_t state) | |||
90 | 98 | ||
91 | rdev->suspend_at = get_seconds(); | 99 | rdev->suspend_at = get_seconds(); |
92 | 100 | ||
93 | if (rdev->ops->suspend) { | 101 | rtnl_lock(); |
94 | rtnl_lock(); | 102 | if (rdev->wiphy.registered) { |
95 | if (rdev->wiphy.registered) | 103 | if (!rdev->wowlan) |
96 | ret = rdev_suspend(rdev); | 104 | cfg80211_leave_all(rdev); |
97 | rtnl_unlock(); | 105 | if (rdev->ops->suspend) |
106 | ret = rdev_suspend(rdev, rdev->wowlan); | ||
107 | if (ret == 1) { | ||
108 | /* Driver refuse to configure wowlan */ | ||
109 | cfg80211_leave_all(rdev); | ||
110 | ret = rdev_suspend(rdev, NULL); | ||
111 | } | ||
98 | } | 112 | } |
113 | rtnl_unlock(); | ||
99 | 114 | ||
100 | return ret; | 115 | return ret; |
101 | } | 116 | } |
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index b7a531380e19..ecd4fcec3c94 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
@@ -27,7 +27,8 @@ | |||
27 | #define WIPHY_PR_ARG __entry->wiphy_name | 27 | #define WIPHY_PR_ARG __entry->wiphy_name |
28 | 28 | ||
29 | #define WDEV_ENTRY __field(u32, id) | 29 | #define WDEV_ENTRY __field(u32, id) |
30 | #define WDEV_ASSIGN (__entry->id) = (wdev ? wdev->identifier : 0) | 30 | #define WDEV_ASSIGN (__entry->id) = (!IS_ERR_OR_NULL(wdev) \ |
31 | ? wdev->identifier : 0) | ||
31 | #define WDEV_PR_FMT "wdev(%u)" | 32 | #define WDEV_PR_FMT "wdev(%u)" |
32 | #define WDEV_PR_ARG (__entry->id) | 33 | #define WDEV_PR_ARG (__entry->id) |
33 | 34 | ||
@@ -1778,13 +1779,68 @@ TRACE_EVENT(rdev_set_mac_acl, | |||
1778 | ), | 1779 | ), |
1779 | TP_fast_assign( | 1780 | TP_fast_assign( |
1780 | WIPHY_ASSIGN; | 1781 | WIPHY_ASSIGN; |
1781 | WIPHY_ASSIGN; | 1782 | NETDEV_ASSIGN; |
1782 | __entry->acl_policy = params->acl_policy; | 1783 | __entry->acl_policy = params->acl_policy; |
1783 | ), | 1784 | ), |
1784 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", acl policy: %d", | 1785 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", acl policy: %d", |
1785 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->acl_policy) | 1786 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->acl_policy) |
1786 | ); | 1787 | ); |
1787 | 1788 | ||
1789 | TRACE_EVENT(rdev_update_ft_ies, | ||
1790 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, | ||
1791 | struct cfg80211_update_ft_ies_params *ftie), | ||
1792 | TP_ARGS(wiphy, netdev, ftie), | ||
1793 | TP_STRUCT__entry( | ||
1794 | WIPHY_ENTRY | ||
1795 | NETDEV_ENTRY | ||
1796 | __field(u16, md) | ||
1797 | __dynamic_array(u8, ie, ftie->ie_len) | ||
1798 | ), | ||
1799 | TP_fast_assign( | ||
1800 | WIPHY_ASSIGN; | ||
1801 | NETDEV_ASSIGN; | ||
1802 | __entry->md = ftie->md; | ||
1803 | memcpy(__get_dynamic_array(ie), ftie->ie, ftie->ie_len); | ||
1804 | ), | ||
1805 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", md: 0x%x", | ||
1806 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->md) | ||
1807 | ); | ||
1808 | |||
1809 | TRACE_EVENT(rdev_crit_proto_start, | ||
1810 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
1811 | enum nl80211_crit_proto_id protocol, u16 duration), | ||
1812 | TP_ARGS(wiphy, wdev, protocol, duration), | ||
1813 | TP_STRUCT__entry( | ||
1814 | WIPHY_ENTRY | ||
1815 | WDEV_ENTRY | ||
1816 | __field(u16, proto) | ||
1817 | __field(u16, duration) | ||
1818 | ), | ||
1819 | TP_fast_assign( | ||
1820 | WIPHY_ASSIGN; | ||
1821 | WDEV_ASSIGN; | ||
1822 | __entry->proto = protocol; | ||
1823 | __entry->duration = duration; | ||
1824 | ), | ||
1825 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", proto=%x, duration=%u", | ||
1826 | WIPHY_PR_ARG, WDEV_PR_ARG, __entry->proto, __entry->duration) | ||
1827 | ); | ||
1828 | |||
1829 | TRACE_EVENT(rdev_crit_proto_stop, | ||
1830 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), | ||
1831 | TP_ARGS(wiphy, wdev), | ||
1832 | TP_STRUCT__entry( | ||
1833 | WIPHY_ENTRY | ||
1834 | WDEV_ENTRY | ||
1835 | ), | ||
1836 | TP_fast_assign( | ||
1837 | WIPHY_ASSIGN; | ||
1838 | WDEV_ASSIGN; | ||
1839 | ), | ||
1840 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, | ||
1841 | WIPHY_PR_ARG, WDEV_PR_ARG) | ||
1842 | ); | ||
1843 | |||
1788 | /************************************************************* | 1844 | /************************************************************* |
1789 | * cfg80211 exported functions traces * | 1845 | * cfg80211 exported functions traces * |
1790 | *************************************************************/ | 1846 | *************************************************************/ |
@@ -2413,6 +2469,32 @@ TRACE_EVENT(cfg80211_report_wowlan_wakeup, | |||
2413 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG) | 2469 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG) |
2414 | ); | 2470 | ); |
2415 | 2471 | ||
2472 | TRACE_EVENT(cfg80211_ft_event, | ||
2473 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, | ||
2474 | struct cfg80211_ft_event_params *ft_event), | ||
2475 | TP_ARGS(wiphy, netdev, ft_event), | ||
2476 | TP_STRUCT__entry( | ||
2477 | WIPHY_ENTRY | ||
2478 | NETDEV_ENTRY | ||
2479 | __dynamic_array(u8, ies, ft_event->ies_len) | ||
2480 | MAC_ENTRY(target_ap) | ||
2481 | __dynamic_array(u8, ric_ies, ft_event->ric_ies_len) | ||
2482 | ), | ||
2483 | TP_fast_assign( | ||
2484 | WIPHY_ASSIGN; | ||
2485 | NETDEV_ASSIGN; | ||
2486 | if (ft_event->ies) | ||
2487 | memcpy(__get_dynamic_array(ies), ft_event->ies, | ||
2488 | ft_event->ies_len); | ||
2489 | MAC_ASSIGN(target_ap, ft_event->target_ap); | ||
2490 | if (ft_event->ric_ies) | ||
2491 | memcpy(__get_dynamic_array(ric_ies), ft_event->ric_ies, | ||
2492 | ft_event->ric_ies_len); | ||
2493 | ), | ||
2494 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", target_ap: " MAC_PR_FMT, | ||
2495 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(target_ap)) | ||
2496 | ); | ||
2497 | |||
2416 | #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ | 2498 | #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ |
2417 | 2499 | ||
2418 | #undef TRACE_INCLUDE_PATH | 2500 | #undef TRACE_INCLUDE_PATH |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 37a56ee1e1ed..f5ad4d94ba88 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -511,7 +511,7 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, | |||
511 | encaps_data = bridge_tunnel_header; | 511 | encaps_data = bridge_tunnel_header; |
512 | encaps_len = sizeof(bridge_tunnel_header); | 512 | encaps_len = sizeof(bridge_tunnel_header); |
513 | skip_header_bytes -= 2; | 513 | skip_header_bytes -= 2; |
514 | } else if (ethertype > 0x600) { | 514 | } else if (ethertype >= ETH_P_802_3_MIN) { |
515 | encaps_data = rfc1042_header; | 515 | encaps_data = rfc1042_header; |
516 | encaps_len = sizeof(rfc1042_header); | 516 | encaps_len = sizeof(rfc1042_header); |
517 | skip_header_bytes -= 2; | 517 | skip_header_bytes -= 2; |
@@ -1155,6 +1155,26 @@ int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len, | |||
1155 | } | 1155 | } |
1156 | EXPORT_SYMBOL(cfg80211_get_p2p_attr); | 1156 | EXPORT_SYMBOL(cfg80211_get_p2p_attr); |
1157 | 1157 | ||
1158 | bool ieee80211_operating_class_to_band(u8 operating_class, | ||
1159 | enum ieee80211_band *band) | ||
1160 | { | ||
1161 | switch (operating_class) { | ||
1162 | case 112: | ||
1163 | case 115 ... 127: | ||
1164 | *band = IEEE80211_BAND_5GHZ; | ||
1165 | return true; | ||
1166 | case 81: | ||
1167 | case 82: | ||
1168 | case 83: | ||
1169 | case 84: | ||
1170 | *band = IEEE80211_BAND_2GHZ; | ||
1171 | return true; | ||
1172 | } | ||
1173 | |||
1174 | return false; | ||
1175 | } | ||
1176 | EXPORT_SYMBOL(ieee80211_operating_class_to_band); | ||
1177 | |||
1158 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | 1178 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, |
1159 | u32 beacon_int) | 1179 | u32 beacon_int) |
1160 | { | 1180 | { |
@@ -1258,12 +1278,12 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, | |||
1258 | list_for_each_entry(wdev_iter, &rdev->wdev_list, list) { | 1278 | list_for_each_entry(wdev_iter, &rdev->wdev_list, list) { |
1259 | if (wdev_iter == wdev) | 1279 | if (wdev_iter == wdev) |
1260 | continue; | 1280 | continue; |
1261 | if (wdev_iter->netdev) { | 1281 | if (wdev_iter->iftype == NL80211_IFTYPE_P2P_DEVICE) { |
1262 | if (!netif_running(wdev_iter->netdev)) | ||
1263 | continue; | ||
1264 | } else if (wdev_iter->iftype == NL80211_IFTYPE_P2P_DEVICE) { | ||
1265 | if (!wdev_iter->p2p_started) | 1282 | if (!wdev_iter->p2p_started) |
1266 | continue; | 1283 | continue; |
1284 | } else if (wdev_iter->netdev) { | ||
1285 | if (!netif_running(wdev_iter->netdev)) | ||
1286 | continue; | ||
1267 | } else { | 1287 | } else { |
1268 | WARN_ON(1); | 1288 | WARN_ON(1); |
1269 | } | 1289 | } |
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index fb9622f6d99c..e79cb5c0655a 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c | |||
@@ -89,6 +89,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, | |||
89 | 89 | ||
90 | cfg80211_lock_rdev(rdev); | 90 | cfg80211_lock_rdev(rdev); |
91 | mutex_lock(&rdev->devlist_mtx); | 91 | mutex_lock(&rdev->devlist_mtx); |
92 | mutex_lock(&rdev->sched_scan_mtx); | ||
92 | wdev_lock(wdev); | 93 | wdev_lock(wdev); |
93 | 94 | ||
94 | if (wdev->sme_state != CFG80211_SME_IDLE) { | 95 | if (wdev->sme_state != CFG80211_SME_IDLE) { |
@@ -135,6 +136,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, | |||
135 | err = cfg80211_mgd_wext_connect(rdev, wdev); | 136 | err = cfg80211_mgd_wext_connect(rdev, wdev); |
136 | out: | 137 | out: |
137 | wdev_unlock(wdev); | 138 | wdev_unlock(wdev); |
139 | mutex_unlock(&rdev->sched_scan_mtx); | ||
138 | mutex_unlock(&rdev->devlist_mtx); | 140 | mutex_unlock(&rdev->devlist_mtx); |
139 | cfg80211_unlock_rdev(rdev); | 141 | cfg80211_unlock_rdev(rdev); |
140 | return err; | 142 | return err; |
@@ -190,6 +192,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, | |||
190 | 192 | ||
191 | cfg80211_lock_rdev(rdev); | 193 | cfg80211_lock_rdev(rdev); |
192 | mutex_lock(&rdev->devlist_mtx); | 194 | mutex_lock(&rdev->devlist_mtx); |
195 | mutex_lock(&rdev->sched_scan_mtx); | ||
193 | wdev_lock(wdev); | 196 | wdev_lock(wdev); |
194 | 197 | ||
195 | err = 0; | 198 | err = 0; |
@@ -223,6 +226,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, | |||
223 | err = cfg80211_mgd_wext_connect(rdev, wdev); | 226 | err = cfg80211_mgd_wext_connect(rdev, wdev); |
224 | out: | 227 | out: |
225 | wdev_unlock(wdev); | 228 | wdev_unlock(wdev); |
229 | mutex_unlock(&rdev->sched_scan_mtx); | ||
226 | mutex_unlock(&rdev->devlist_mtx); | 230 | mutex_unlock(&rdev->devlist_mtx); |
227 | cfg80211_unlock_rdev(rdev); | 231 | cfg80211_unlock_rdev(rdev); |
228 | return err; | 232 | return err; |
@@ -285,6 +289,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, | |||
285 | 289 | ||
286 | cfg80211_lock_rdev(rdev); | 290 | cfg80211_lock_rdev(rdev); |
287 | mutex_lock(&rdev->devlist_mtx); | 291 | mutex_lock(&rdev->devlist_mtx); |
292 | mutex_lock(&rdev->sched_scan_mtx); | ||
288 | wdev_lock(wdev); | 293 | wdev_lock(wdev); |
289 | 294 | ||
290 | if (wdev->sme_state != CFG80211_SME_IDLE) { | 295 | if (wdev->sme_state != CFG80211_SME_IDLE) { |
@@ -313,6 +318,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, | |||
313 | err = cfg80211_mgd_wext_connect(rdev, wdev); | 318 | err = cfg80211_mgd_wext_connect(rdev, wdev); |
314 | out: | 319 | out: |
315 | wdev_unlock(wdev); | 320 | wdev_unlock(wdev); |
321 | mutex_unlock(&rdev->sched_scan_mtx); | ||
316 | mutex_unlock(&rdev->devlist_mtx); | 322 | mutex_unlock(&rdev->devlist_mtx); |
317 | cfg80211_unlock_rdev(rdev); | 323 | cfg80211_unlock_rdev(rdev); |
318 | return err; | 324 | return err; |