diff options
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/ap.c | 62 | ||||
-rw-r--r-- | net/wireless/core.c | 77 | ||||
-rw-r--r-- | net/wireless/core.h | 22 | ||||
-rw-r--r-- | net/wireless/mesh.c | 15 | ||||
-rw-r--r-- | net/wireless/mlme.c | 230 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 1857 | ||||
-rw-r--r-- | net/wireless/nl80211.h | 68 | ||||
-rw-r--r-- | net/wireless/rdev-ops.h | 20 | ||||
-rw-r--r-- | net/wireless/reg.c | 6 | ||||
-rw-r--r-- | net/wireless/sme.c | 28 | ||||
-rw-r--r-- | net/wireless/sysfs.c | 25 | ||||
-rw-r--r-- | net/wireless/trace.h | 46 |
12 files changed, 1426 insertions, 1030 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 6ddf74f0ae1e..84c9ad7e1dca 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -842,6 +842,46 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | |||
842 | rdev->num_running_monitor_ifaces += num; | 842 | rdev->num_running_monitor_ifaces += num; |
843 | } | 843 | } |
844 | 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 | |||
845 | static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | 885 | static int cfg80211_netdev_notifier_call(struct notifier_block *nb, |
846 | unsigned long state, | 886 | unsigned long state, |
847 | void *ndev) | 887 | void *ndev) |
@@ -910,38 +950,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
910 | dev->priv_flags |= IFF_DONT_BRIDGE; | 950 | dev->priv_flags |= IFF_DONT_BRIDGE; |
911 | break; | 951 | break; |
912 | case NETDEV_GOING_DOWN: | 952 | case NETDEV_GOING_DOWN: |
913 | switch (wdev->iftype) { | 953 | cfg80211_leave(rdev, wdev); |
914 | case NL80211_IFTYPE_ADHOC: | ||
915 | cfg80211_leave_ibss(rdev, dev, true); | ||
916 | break; | ||
917 | case NL80211_IFTYPE_P2P_CLIENT: | ||
918 | case NL80211_IFTYPE_STATION: | ||
919 | mutex_lock(&rdev->sched_scan_mtx); | ||
920 | __cfg80211_stop_sched_scan(rdev, false); | ||
921 | mutex_unlock(&rdev->sched_scan_mtx); | ||
922 | |||
923 | wdev_lock(wdev); | ||
924 | #ifdef CONFIG_CFG80211_WEXT | ||
925 | kfree(wdev->wext.ie); | ||
926 | wdev->wext.ie = NULL; | ||
927 | wdev->wext.ie_len = 0; | ||
928 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; | ||
929 | #endif | ||
930 | __cfg80211_disconnect(rdev, dev, | ||
931 | WLAN_REASON_DEAUTH_LEAVING, true); | ||
932 | cfg80211_mlme_down(rdev, dev); | ||
933 | wdev_unlock(wdev); | ||
934 | break; | ||
935 | case NL80211_IFTYPE_MESH_POINT: | ||
936 | cfg80211_leave_mesh(rdev, dev); | ||
937 | break; | ||
938 | case NL80211_IFTYPE_AP: | ||
939 | cfg80211_stop_ap(rdev, dev); | ||
940 | break; | ||
941 | default: | ||
942 | break; | ||
943 | } | ||
944 | wdev->beacon_interval = 0; | ||
945 | break; | 954 | break; |
946 | case NETDEV_DOWN: | 955 | case NETDEV_DOWN: |
947 | cfg80211_update_iface_num(rdev, wdev->iftype, -1); | 956 | cfg80211_update_iface_num(rdev, wdev->iftype, -1); |
@@ -1117,8 +1126,10 @@ static int __init cfg80211_init(void) | |||
1117 | goto out_fail_reg; | 1126 | goto out_fail_reg; |
1118 | 1127 | ||
1119 | cfg80211_wq = create_singlethread_workqueue("cfg80211"); | 1128 | cfg80211_wq = create_singlethread_workqueue("cfg80211"); |
1120 | if (!cfg80211_wq) | 1129 | if (!cfg80211_wq) { |
1130 | err = -ENOMEM; | ||
1121 | goto out_fail_wq; | 1131 | goto out_fail_wq; |
1132 | } | ||
1122 | 1133 | ||
1123 | return 0; | 1134 | return 0; |
1124 | 1135 | ||
diff --git a/net/wireless/core.h b/net/wireless/core.h index 5845c2b37aa8..124e5e773fbc 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -330,20 +330,15 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | |||
330 | int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | 330 | int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, |
331 | struct net_device *dev, | 331 | struct net_device *dev, |
332 | struct ieee80211_channel *chan, | 332 | struct ieee80211_channel *chan, |
333 | const u8 *bssid, const u8 *prev_bssid, | 333 | const u8 *bssid, |
334 | const u8 *ssid, int ssid_len, | 334 | const u8 *ssid, int ssid_len, |
335 | const u8 *ie, int ie_len, bool use_mfp, | 335 | 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, | 336 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, |
340 | struct net_device *dev, struct ieee80211_channel *chan, | 337 | struct net_device *dev, |
341 | const u8 *bssid, const u8 *prev_bssid, | 338 | struct ieee80211_channel *chan, |
339 | const u8 *bssid, | ||
342 | const u8 *ssid, int ssid_len, | 340 | const u8 *ssid, int ssid_len, |
343 | const u8 *ie, int ie_len, bool use_mfp, | 341 | 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, | 342 | int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, |
348 | struct net_device *dev, const u8 *bssid, | 343 | struct net_device *dev, const u8 *bssid, |
349 | const u8 *ie, int ie_len, u16 reason, | 344 | const u8 *ie, int ie_len, u16 reason, |
@@ -375,6 +370,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | |||
375 | bool no_cck, bool dont_wait_for_ack, u64 *cookie); | 370 | bool no_cck, bool dont_wait_for_ack, u64 *cookie); |
376 | void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, | 371 | void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, |
377 | const struct ieee80211_ht_cap *ht_capa_mask); | 372 | const struct ieee80211_ht_cap *ht_capa_mask); |
373 | void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa, | ||
374 | const struct ieee80211_vht_cap *vht_capa_mask); | ||
378 | 375 | ||
379 | /* SME */ | 376 | /* SME */ |
380 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | 377 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, |
@@ -503,6 +500,9 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | |||
503 | void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | 500 | void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, |
504 | enum nl80211_iftype iftype, int num); | 501 | enum nl80211_iftype iftype, int num); |
505 | 502 | ||
503 | void cfg80211_leave(struct cfg80211_registered_device *rdev, | ||
504 | struct wireless_dev *wdev); | ||
505 | |||
506 | void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, | 506 | void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, |
507 | struct wireless_dev *wdev); | 507 | struct wireless_dev *wdev); |
508 | 508 | ||
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..390198bf4b36 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 | ||
@@ -909,85 +826,6 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm, | |||
909 | } | 826 | } |
910 | EXPORT_SYMBOL(cfg80211_rx_mgmt); | 827 | EXPORT_SYMBOL(cfg80211_rx_mgmt); |
911 | 828 | ||
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) | 829 | void cfg80211_dfs_channels_update_work(struct work_struct *work) |
992 | { | 830 | { |
993 | struct delayed_work *delayed_work; | 831 | struct delayed_work *delayed_work; |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 58e13a8c95f9..671b69a3c136 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 */ |
@@ -539,7 +547,8 @@ static inline void *nl80211hdr_put(struct sk_buff *skb, u32 portid, u32 seq, | |||
539 | } | 547 | } |
540 | 548 | ||
541 | static int nl80211_msg_put_channel(struct sk_buff *msg, | 549 | static int nl80211_msg_put_channel(struct sk_buff *msg, |
542 | struct ieee80211_channel *chan) | 550 | struct ieee80211_channel *chan, |
551 | bool large) | ||
543 | { | 552 | { |
544 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_FREQ, | 553 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_FREQ, |
545 | chan->center_freq)) | 554 | chan->center_freq)) |
@@ -554,9 +563,37 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, | |||
554 | if ((chan->flags & IEEE80211_CHAN_NO_IBSS) && | 563 | if ((chan->flags & IEEE80211_CHAN_NO_IBSS) && |
555 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS)) | 564 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS)) |
556 | goto nla_put_failure; | 565 | goto nla_put_failure; |
557 | if ((chan->flags & IEEE80211_CHAN_RADAR) && | 566 | if (chan->flags & IEEE80211_CHAN_RADAR) { |
558 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR)) | 567 | if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR)) |
559 | goto nla_put_failure; | 568 | goto nla_put_failure; |
569 | if (large) { | ||
570 | u32 time; | ||
571 | |||
572 | time = elapsed_jiffies_msecs(chan->dfs_state_entered); | ||
573 | |||
574 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_STATE, | ||
575 | chan->dfs_state)) | ||
576 | goto nla_put_failure; | ||
577 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME, | ||
578 | time)) | ||
579 | goto nla_put_failure; | ||
580 | } | ||
581 | } | ||
582 | |||
583 | if (large) { | ||
584 | if ((chan->flags & IEEE80211_CHAN_NO_HT40MINUS) && | ||
585 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_MINUS)) | ||
586 | goto nla_put_failure; | ||
587 | if ((chan->flags & IEEE80211_CHAN_NO_HT40PLUS) && | ||
588 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_PLUS)) | ||
589 | goto nla_put_failure; | ||
590 | if ((chan->flags & IEEE80211_CHAN_NO_80MHZ) && | ||
591 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_80MHZ)) | ||
592 | goto nla_put_failure; | ||
593 | if ((chan->flags & IEEE80211_CHAN_NO_160MHZ) && | ||
594 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_160MHZ)) | ||
595 | goto nla_put_failure; | ||
596 | } | ||
560 | 597 | ||
561 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, | 598 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, |
562 | DBM_TO_MBM(chan->max_power))) | 599 | DBM_TO_MBM(chan->max_power))) |
@@ -832,7 +869,8 @@ nla_put_failure: | |||
832 | } | 869 | } |
833 | 870 | ||
834 | static int nl80211_put_iface_combinations(struct wiphy *wiphy, | 871 | static int nl80211_put_iface_combinations(struct wiphy *wiphy, |
835 | struct sk_buff *msg) | 872 | struct sk_buff *msg, |
873 | bool large) | ||
836 | { | 874 | { |
837 | struct nlattr *nl_combis; | 875 | struct nlattr *nl_combis; |
838 | int i, j; | 876 | int i, j; |
@@ -881,6 +919,10 @@ static int nl80211_put_iface_combinations(struct wiphy *wiphy, | |||
881 | nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM, | 919 | nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM, |
882 | c->max_interfaces)) | 920 | c->max_interfaces)) |
883 | goto nla_put_failure; | 921 | goto nla_put_failure; |
922 | if (large && | ||
923 | nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS, | ||
924 | c->radar_detect_widths)) | ||
925 | goto nla_put_failure; | ||
884 | 926 | ||
885 | nla_nest_end(msg, nl_combi); | 927 | nla_nest_end(msg, nl_combi); |
886 | } | 928 | } |
@@ -892,412 +934,611 @@ nla_put_failure: | |||
892 | return -ENOBUFS; | 934 | return -ENOBUFS; |
893 | } | 935 | } |
894 | 936 | ||
895 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flags, | 937 | #ifdef CONFIG_PM |
896 | struct cfg80211_registered_device *dev) | 938 | static int nl80211_send_wowlan_tcp_caps(struct cfg80211_registered_device *rdev, |
939 | struct sk_buff *msg) | ||
897 | { | 940 | { |
898 | void *hdr; | 941 | const struct wiphy_wowlan_tcp_support *tcp = rdev->wiphy.wowlan.tcp; |
899 | struct nlattr *nl_bands, *nl_band; | 942 | 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 | 943 | ||
910 | hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_WIPHY); | 944 | if (!tcp) |
911 | if (!hdr) | 945 | return 0; |
912 | return -1; | ||
913 | 946 | ||
914 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx) || | 947 | nl_tcp = nla_nest_start(msg, NL80211_WOWLAN_TRIG_TCP_CONNECTION); |
915 | nla_put_string(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)) || | 948 | if (!nl_tcp) |
916 | nla_put_u32(msg, NL80211_ATTR_GENERATION, | 949 | 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 | 950 | ||
940 | if ((dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) && | 951 | if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD, |
941 | nla_put_flag(msg, NL80211_ATTR_SUPPORT_IBSS_RSN)) | 952 | tcp->data_payload_max)) |
942 | goto nla_put_failure; | 953 | 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 | 954 | ||
959 | if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES, | 955 | if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD, |
960 | sizeof(u32) * dev->wiphy.n_cipher_suites, | 956 | tcp->data_payload_max)) |
961 | dev->wiphy.cipher_suites)) | 957 | return -ENOBUFS; |
962 | goto nla_put_failure; | ||
963 | 958 | ||
964 | if (nla_put_u8(msg, NL80211_ATTR_MAX_NUM_PMKIDS, | 959 | if (tcp->seq && nla_put_flag(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ)) |
965 | dev->wiphy.max_num_pmkids)) | 960 | return -ENOBUFS; |
966 | goto nla_put_failure; | ||
967 | 961 | ||
968 | if ((dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) && | 962 | if (tcp->tok && nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN, |
969 | nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE)) | 963 | sizeof(*tcp->tok), tcp->tok)) |
970 | goto nla_put_failure; | 964 | return -ENOBUFS; |
971 | 965 | ||
972 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX, | 966 | if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL, |
973 | dev->wiphy.available_antennas_tx) || | 967 | tcp->data_interval_max)) |
974 | nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX, | 968 | return -ENOBUFS; |
975 | dev->wiphy.available_antennas_rx)) | ||
976 | goto nla_put_failure; | ||
977 | 969 | ||
978 | if ((dev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) && | 970 | if (nla_put_u32(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD, |
979 | nla_put_u32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD, | 971 | tcp->wake_payload_max)) |
980 | dev->wiphy.probe_resp_offload)) | 972 | return -ENOBUFS; |
981 | goto nla_put_failure; | ||
982 | 973 | ||
983 | if ((dev->wiphy.available_antennas_tx || | 974 | nla_nest_end(msg, nl_tcp); |
984 | dev->wiphy.available_antennas_rx) && dev->ops->get_antenna) { | 975 | return 0; |
985 | u32 tx_ant = 0, rx_ant = 0; | 976 | } |
986 | int res; | 977 | |
987 | res = rdev_get_antenna(dev, &tx_ant, &rx_ant); | 978 | static int nl80211_send_wowlan(struct sk_buff *msg, |
988 | if (!res) { | 979 | struct cfg80211_registered_device *dev, |
989 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX, | 980 | bool large) |
990 | tx_ant) || | 981 | { |
991 | nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_RX, | 982 | struct nlattr *nl_wowlan; |
992 | rx_ant)) | 983 | |
993 | goto nla_put_failure; | 984 | if (!dev->wiphy.wowlan.flags && !dev->wiphy.wowlan.n_patterns) |
994 | } | 985 | return 0; |
986 | |||
987 | nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED); | ||
988 | if (!nl_wowlan) | ||
989 | return -ENOBUFS; | ||
990 | |||
991 | if (((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_ANY) && | ||
992 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) || | ||
993 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_DISCONNECT) && | ||
994 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) || | ||
995 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT) && | ||
996 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) || | ||
997 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) && | ||
998 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) || | ||
999 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && | ||
1000 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) || | ||
1001 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) && | ||
1002 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) || | ||
1003 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) && | ||
1004 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) || | ||
1005 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_RFKILL_RELEASE) && | ||
1006 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) | ||
1007 | return -ENOBUFS; | ||
1008 | |||
1009 | if (dev->wiphy.wowlan.n_patterns) { | ||
1010 | struct nl80211_wowlan_pattern_support pat = { | ||
1011 | .max_patterns = dev->wiphy.wowlan.n_patterns, | ||
1012 | .min_pattern_len = dev->wiphy.wowlan.pattern_min_len, | ||
1013 | .max_pattern_len = dev->wiphy.wowlan.pattern_max_len, | ||
1014 | .max_pkt_offset = dev->wiphy.wowlan.max_pkt_offset, | ||
1015 | }; | ||
1016 | |||
1017 | if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN, | ||
1018 | sizeof(pat), &pat)) | ||
1019 | return -ENOBUFS; | ||
995 | } | 1020 | } |
996 | 1021 | ||
997 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES, | 1022 | if (large && nl80211_send_wowlan_tcp_caps(dev, msg)) |
998 | dev->wiphy.interface_modes)) | 1023 | return -ENOBUFS; |
999 | goto nla_put_failure; | ||
1000 | 1024 | ||
1001 | nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); | 1025 | nla_nest_end(msg, nl_wowlan); |
1002 | if (!nl_bands) | ||
1003 | goto nla_put_failure; | ||
1004 | 1026 | ||
1005 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 1027 | return 0; |
1006 | if (!dev->wiphy.bands[band]) | 1028 | } |
1007 | continue; | 1029 | #endif |
1008 | 1030 | ||
1009 | nl_band = nla_nest_start(msg, band); | 1031 | static int nl80211_send_band_rateinfo(struct sk_buff *msg, |
1010 | if (!nl_band) | 1032 | struct ieee80211_supported_band *sband) |
1011 | goto nla_put_failure; | 1033 | { |
1034 | struct nlattr *nl_rates, *nl_rate; | ||
1035 | struct ieee80211_rate *rate; | ||
1036 | int i; | ||
1012 | 1037 | ||
1013 | /* add HT info */ | 1038 | /* add HT info */ |
1014 | if (dev->wiphy.bands[band]->ht_cap.ht_supported && | 1039 | if (sband->ht_cap.ht_supported && |
1015 | (nla_put(msg, NL80211_BAND_ATTR_HT_MCS_SET, | 1040 | (nla_put(msg, NL80211_BAND_ATTR_HT_MCS_SET, |
1016 | sizeof(dev->wiphy.bands[band]->ht_cap.mcs), | 1041 | sizeof(sband->ht_cap.mcs), |
1017 | &dev->wiphy.bands[band]->ht_cap.mcs) || | 1042 | &sband->ht_cap.mcs) || |
1018 | nla_put_u16(msg, NL80211_BAND_ATTR_HT_CAPA, | 1043 | nla_put_u16(msg, NL80211_BAND_ATTR_HT_CAPA, |
1019 | dev->wiphy.bands[band]->ht_cap.cap) || | 1044 | sband->ht_cap.cap) || |
1020 | nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR, | 1045 | nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR, |
1021 | dev->wiphy.bands[band]->ht_cap.ampdu_factor) || | 1046 | sband->ht_cap.ampdu_factor) || |
1022 | nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY, | 1047 | nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY, |
1023 | dev->wiphy.bands[band]->ht_cap.ampdu_density))) | 1048 | sband->ht_cap.ampdu_density))) |
1024 | goto nla_put_failure; | 1049 | return -ENOBUFS; |
1025 | 1050 | ||
1026 | /* add VHT info */ | 1051 | /* add VHT info */ |
1027 | if (dev->wiphy.bands[band]->vht_cap.vht_supported && | 1052 | if (sband->vht_cap.vht_supported && |
1028 | (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET, | 1053 | (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET, |
1029 | sizeof(dev->wiphy.bands[band]->vht_cap.vht_mcs), | 1054 | sizeof(sband->vht_cap.vht_mcs), |
1030 | &dev->wiphy.bands[band]->vht_cap.vht_mcs) || | 1055 | &sband->vht_cap.vht_mcs) || |
1031 | nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA, | 1056 | nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA, |
1032 | dev->wiphy.bands[band]->vht_cap.cap))) | 1057 | sband->vht_cap.cap))) |
1033 | goto nla_put_failure; | 1058 | return -ENOBUFS; |
1034 | 1059 | ||
1035 | /* add frequencies */ | 1060 | /* add bitrates */ |
1036 | nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); | 1061 | nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES); |
1037 | if (!nl_freqs) | 1062 | if (!nl_rates) |
1038 | goto nla_put_failure; | 1063 | return -ENOBUFS; |
1039 | 1064 | ||
1040 | for (i = 0; i < dev->wiphy.bands[band]->n_channels; i++) { | 1065 | for (i = 0; i < sband->n_bitrates; i++) { |
1041 | nl_freq = nla_nest_start(msg, i); | 1066 | nl_rate = nla_nest_start(msg, i); |
1042 | if (!nl_freq) | 1067 | if (!nl_rate) |
1043 | goto nla_put_failure; | 1068 | return -ENOBUFS; |
1044 | 1069 | ||
1045 | chan = &dev->wiphy.bands[band]->channels[i]; | 1070 | rate = &sband->bitrates[i]; |
1071 | if (nla_put_u32(msg, NL80211_BITRATE_ATTR_RATE, | ||
1072 | rate->bitrate)) | ||
1073 | return -ENOBUFS; | ||
1074 | if ((rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) && | ||
1075 | nla_put_flag(msg, | ||
1076 | NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE)) | ||
1077 | return -ENOBUFS; | ||
1046 | 1078 | ||
1047 | if (nl80211_msg_put_channel(msg, chan)) | 1079 | nla_nest_end(msg, nl_rate); |
1048 | goto nla_put_failure; | 1080 | } |
1049 | 1081 | ||
1050 | nla_nest_end(msg, nl_freq); | 1082 | nla_nest_end(msg, nl_rates); |
1051 | } | ||
1052 | 1083 | ||
1053 | nla_nest_end(msg, nl_freqs); | 1084 | return 0; |
1085 | } | ||
1054 | 1086 | ||
1055 | /* add bitrates */ | 1087 | static int |
1056 | nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES); | 1088 | nl80211_send_mgmt_stypes(struct sk_buff *msg, |
1057 | if (!nl_rates) | 1089 | const struct ieee80211_txrx_stypes *mgmt_stypes) |
1058 | goto nla_put_failure; | 1090 | { |
1091 | u16 stypes; | ||
1092 | struct nlattr *nl_ftypes, *nl_ifs; | ||
1093 | enum nl80211_iftype ift; | ||
1094 | int i; | ||
1059 | 1095 | ||
1060 | for (i = 0; i < dev->wiphy.bands[band]->n_bitrates; i++) { | 1096 | if (!mgmt_stypes) |
1061 | nl_rate = nla_nest_start(msg, i); | 1097 | return 0; |
1062 | if (!nl_rate) | ||
1063 | goto nla_put_failure; | ||
1064 | 1098 | ||
1065 | rate = &dev->wiphy.bands[band]->bitrates[i]; | 1099 | nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES); |
1066 | if (nla_put_u32(msg, NL80211_BITRATE_ATTR_RATE, | 1100 | if (!nl_ifs) |
1067 | rate->bitrate)) | 1101 | 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 | 1102 | ||
1074 | nla_nest_end(msg, nl_rate); | 1103 | for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) { |
1104 | nl_ftypes = nla_nest_start(msg, ift); | ||
1105 | if (!nl_ftypes) | ||
1106 | return -ENOBUFS; | ||
1107 | i = 0; | ||
1108 | stypes = mgmt_stypes[ift].tx; | ||
1109 | while (stypes) { | ||
1110 | if ((stypes & 1) && | ||
1111 | nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE, | ||
1112 | (i << 4) | IEEE80211_FTYPE_MGMT)) | ||
1113 | return -ENOBUFS; | ||
1114 | stypes >>= 1; | ||
1115 | i++; | ||
1075 | } | 1116 | } |
1117 | nla_nest_end(msg, nl_ftypes); | ||
1118 | } | ||
1076 | 1119 | ||
1077 | nla_nest_end(msg, nl_rates); | 1120 | nla_nest_end(msg, nl_ifs); |
1078 | 1121 | ||
1079 | nla_nest_end(msg, nl_band); | 1122 | nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES); |
1123 | if (!nl_ifs) | ||
1124 | return -ENOBUFS; | ||
1125 | |||
1126 | for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) { | ||
1127 | nl_ftypes = nla_nest_start(msg, ift); | ||
1128 | if (!nl_ftypes) | ||
1129 | return -ENOBUFS; | ||
1130 | i = 0; | ||
1131 | stypes = mgmt_stypes[ift].rx; | ||
1132 | while (stypes) { | ||
1133 | if ((stypes & 1) && | ||
1134 | nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE, | ||
1135 | (i << 4) | IEEE80211_FTYPE_MGMT)) | ||
1136 | return -ENOBUFS; | ||
1137 | stypes >>= 1; | ||
1138 | i++; | ||
1139 | } | ||
1140 | nla_nest_end(msg, nl_ftypes); | ||
1080 | } | 1141 | } |
1081 | nla_nest_end(msg, nl_bands); | 1142 | nla_nest_end(msg, nl_ifs); |
1082 | 1143 | ||
1083 | nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS); | 1144 | return 0; |
1084 | if (!nl_cmds) | 1145 | } |
1085 | goto nla_put_failure; | ||
1086 | 1146 | ||
1087 | i = 0; | 1147 | static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, |
1088 | #define CMD(op, n) \ | 1148 | struct sk_buff *msg, u32 portid, u32 seq, |
1089 | do { \ | 1149 | int flags, bool split, long *split_start, |
1090 | if (dev->ops->op) { \ | 1150 | long *band_start, long *chan_start) |
1091 | i++; \ | 1151 | { |
1092 | if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \ | 1152 | void *hdr; |
1093 | goto nla_put_failure; \ | 1153 | struct nlattr *nl_bands, *nl_band; |
1094 | } \ | 1154 | struct nlattr *nl_freqs, *nl_freq; |
1095 | } while (0) | 1155 | struct nlattr *nl_cmds; |
1096 | 1156 | enum ieee80211_band band; | |
1097 | CMD(add_virtual_intf, NEW_INTERFACE); | 1157 | struct ieee80211_channel *chan; |
1098 | CMD(change_virtual_intf, SET_INTERFACE); | 1158 | int i; |
1099 | CMD(add_key, NEW_KEY); | 1159 | const struct ieee80211_txrx_stypes *mgmt_stypes = |
1100 | CMD(start_ap, START_AP); | 1160 | dev->wiphy.mgmt_stypes; |
1101 | CMD(add_station, NEW_STATION); | 1161 | long start = 0, start_chan = 0, start_band = 0; |
1102 | CMD(add_mpath, NEW_MPATH); | 1162 | u32 features; |
1103 | CMD(update_mesh_config, SET_MESH_CONFIG); | 1163 | |
1104 | CMD(change_bss, SET_BSS); | 1164 | hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_WIPHY); |
1105 | CMD(auth, AUTHENTICATE); | 1165 | if (!hdr) |
1106 | CMD(assoc, ASSOCIATE); | 1166 | return -ENOBUFS; |
1107 | CMD(deauth, DEAUTHENTICATE); | 1167 | |
1108 | CMD(disassoc, DISASSOCIATE); | 1168 | /* allow always using the variables */ |
1109 | CMD(join_ibss, JOIN_IBSS); | 1169 | if (!split) { |
1110 | CMD(join_mesh, JOIN_MESH); | 1170 | split_start = &start; |
1111 | CMD(set_pmksa, SET_PMKSA); | 1171 | band_start = &start_band; |
1112 | CMD(del_pmksa, DEL_PMKSA); | 1172 | 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 | } | 1173 | } |
1124 | if (dev->ops->set_monitor_channel || dev->ops->start_ap || | 1174 | |
1125 | dev->ops->join_mesh) { | 1175 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx) || |
1126 | i++; | 1176 | nla_put_string(msg, NL80211_ATTR_WIPHY_NAME, |
1127 | if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL)) | 1177 | wiphy_name(&dev->wiphy)) || |
1178 | nla_put_u32(msg, NL80211_ATTR_GENERATION, | ||
1179 | cfg80211_rdev_list_generation)) | ||
1180 | goto nla_put_failure; | ||
1181 | |||
1182 | switch (*split_start) { | ||
1183 | case 0: | ||
1184 | if (nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, | ||
1185 | dev->wiphy.retry_short) || | ||
1186 | nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, | ||
1187 | dev->wiphy.retry_long) || | ||
1188 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, | ||
1189 | dev->wiphy.frag_threshold) || | ||
1190 | nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, | ||
1191 | dev->wiphy.rts_threshold) || | ||
1192 | nla_put_u8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, | ||
1193 | dev->wiphy.coverage_class) || | ||
1194 | nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, | ||
1195 | dev->wiphy.max_scan_ssids) || | ||
1196 | nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS, | ||
1197 | dev->wiphy.max_sched_scan_ssids) || | ||
1198 | nla_put_u16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, | ||
1199 | dev->wiphy.max_scan_ie_len) || | ||
1200 | nla_put_u16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN, | ||
1201 | dev->wiphy.max_sched_scan_ie_len) || | ||
1202 | nla_put_u8(msg, NL80211_ATTR_MAX_MATCH_SETS, | ||
1203 | dev->wiphy.max_match_sets)) | ||
1128 | goto nla_put_failure; | 1204 | goto nla_put_failure; |
1129 | } | 1205 | |
1130 | CMD(set_wds_peer, SET_WDS_PEER); | 1206 | if ((dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) && |
1131 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) { | 1207 | nla_put_flag(msg, NL80211_ATTR_SUPPORT_IBSS_RSN)) |
1132 | CMD(tdls_mgmt, TDLS_MGMT); | 1208 | goto nla_put_failure; |
1133 | CMD(tdls_oper, TDLS_OPER); | 1209 | if ((dev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) && |
1134 | } | 1210 | nla_put_flag(msg, NL80211_ATTR_SUPPORT_MESH_AUTH)) |
1135 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) | 1211 | goto nla_put_failure; |
1136 | CMD(sched_scan_start, START_SCHED_SCAN); | 1212 | if ((dev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) && |
1137 | CMD(probe_client, PROBE_CLIENT); | 1213 | nla_put_flag(msg, NL80211_ATTR_SUPPORT_AP_UAPSD)) |
1138 | CMD(set_noack_map, SET_NOACK_MAP); | 1214 | goto nla_put_failure; |
1139 | if (dev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) { | 1215 | if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) && |
1140 | i++; | 1216 | nla_put_flag(msg, NL80211_ATTR_ROAM_SUPPORT)) |
1141 | if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS)) | 1217 | goto nla_put_failure; |
1218 | if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) && | ||
1219 | nla_put_flag(msg, NL80211_ATTR_TDLS_SUPPORT)) | ||
1220 | goto nla_put_failure; | ||
1221 | if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) && | ||
1222 | nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP)) | ||
1142 | goto nla_put_failure; | 1223 | goto nla_put_failure; |
1143 | } | ||
1144 | CMD(start_p2p_device, START_P2P_DEVICE); | ||
1145 | CMD(set_mcast_rate, SET_MCAST_RATE); | ||
1146 | 1224 | ||
1147 | #ifdef CONFIG_NL80211_TESTMODE | 1225 | (*split_start)++; |
1148 | CMD(testmode_cmd, TESTMODE); | 1226 | if (split) |
1149 | #endif | 1227 | break; |
1228 | case 1: | ||
1229 | if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES, | ||
1230 | sizeof(u32) * dev->wiphy.n_cipher_suites, | ||
1231 | dev->wiphy.cipher_suites)) | ||
1232 | goto nla_put_failure; | ||
1150 | 1233 | ||
1151 | #undef CMD | 1234 | if (nla_put_u8(msg, NL80211_ATTR_MAX_NUM_PMKIDS, |
1235 | dev->wiphy.max_num_pmkids)) | ||
1236 | goto nla_put_failure; | ||
1152 | 1237 | ||
1153 | if (dev->ops->connect || dev->ops->auth) { | 1238 | if ((dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) && |
1154 | i++; | 1239 | nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE)) |
1155 | if (nla_put_u32(msg, i, NL80211_CMD_CONNECT)) | ||
1156 | goto nla_put_failure; | 1240 | goto nla_put_failure; |
1157 | } | ||
1158 | 1241 | ||
1159 | if (dev->ops->disconnect || dev->ops->deauth) { | 1242 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX, |
1160 | i++; | 1243 | dev->wiphy.available_antennas_tx) || |
1161 | if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT)) | 1244 | nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX, |
1245 | dev->wiphy.available_antennas_rx)) | ||
1162 | goto nla_put_failure; | 1246 | goto nla_put_failure; |
1163 | } | ||
1164 | 1247 | ||
1165 | nla_nest_end(msg, nl_cmds); | 1248 | if ((dev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) && |
1249 | nla_put_u32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD, | ||
1250 | dev->wiphy.probe_resp_offload)) | ||
1251 | goto nla_put_failure; | ||
1166 | 1252 | ||
1167 | if (dev->ops->remain_on_channel && | 1253 | if ((dev->wiphy.available_antennas_tx || |
1168 | (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) && | 1254 | dev->wiphy.available_antennas_rx) && |
1169 | nla_put_u32(msg, NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION, | 1255 | dev->ops->get_antenna) { |
1170 | dev->wiphy.max_remain_on_channel_duration)) | 1256 | u32 tx_ant = 0, rx_ant = 0; |
1171 | goto nla_put_failure; | 1257 | int res; |
1258 | res = rdev_get_antenna(dev, &tx_ant, &rx_ant); | ||
1259 | if (!res) { | ||
1260 | if (nla_put_u32(msg, | ||
1261 | NL80211_ATTR_WIPHY_ANTENNA_TX, | ||
1262 | tx_ant) || | ||
1263 | nla_put_u32(msg, | ||
1264 | NL80211_ATTR_WIPHY_ANTENNA_RX, | ||
1265 | rx_ant)) | ||
1266 | goto nla_put_failure; | ||
1267 | } | ||
1268 | } | ||
1172 | 1269 | ||
1173 | if ((dev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) && | 1270 | (*split_start)++; |
1174 | nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK)) | 1271 | if (split) |
1175 | goto nla_put_failure; | 1272 | break; |
1273 | case 2: | ||
1274 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES, | ||
1275 | dev->wiphy.interface_modes)) | ||
1276 | goto nla_put_failure; | ||
1277 | (*split_start)++; | ||
1278 | if (split) | ||
1279 | break; | ||
1280 | case 3: | ||
1281 | nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); | ||
1282 | if (!nl_bands) | ||
1283 | goto nla_put_failure; | ||
1176 | 1284 | ||
1177 | if (mgmt_stypes) { | 1285 | for (band = *band_start; band < IEEE80211_NUM_BANDS; band++) { |
1178 | u16 stypes; | 1286 | struct ieee80211_supported_band *sband; |
1179 | struct nlattr *nl_ftypes, *nl_ifs; | ||
1180 | enum nl80211_iftype ift; | ||
1181 | 1287 | ||
1182 | nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES); | 1288 | sband = dev->wiphy.bands[band]; |
1183 | if (!nl_ifs) | ||
1184 | goto nla_put_failure; | ||
1185 | 1289 | ||
1186 | for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) { | 1290 | if (!sband) |
1187 | nl_ftypes = nla_nest_start(msg, ift); | 1291 | continue; |
1188 | if (!nl_ftypes) | 1292 | |
1293 | nl_band = nla_nest_start(msg, band); | ||
1294 | if (!nl_band) | ||
1189 | goto nla_put_failure; | 1295 | goto nla_put_failure; |
1190 | i = 0; | 1296 | |
1191 | stypes = mgmt_stypes[ift].tx; | 1297 | switch (*chan_start) { |
1192 | while (stypes) { | 1298 | case 0: |
1193 | if ((stypes & 1) && | 1299 | 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; | 1300 | goto nla_put_failure; |
1197 | stypes >>= 1; | 1301 | (*chan_start)++; |
1198 | i++; | 1302 | if (split) |
1303 | break; | ||
1304 | default: | ||
1305 | /* add frequencies */ | ||
1306 | nl_freqs = nla_nest_start( | ||
1307 | msg, NL80211_BAND_ATTR_FREQS); | ||
1308 | if (!nl_freqs) | ||
1309 | goto nla_put_failure; | ||
1310 | |||
1311 | for (i = *chan_start - 1; | ||
1312 | i < sband->n_channels; | ||
1313 | i++) { | ||
1314 | nl_freq = nla_nest_start(msg, i); | ||
1315 | if (!nl_freq) | ||
1316 | goto nla_put_failure; | ||
1317 | |||
1318 | chan = &sband->channels[i]; | ||
1319 | |||
1320 | if (nl80211_msg_put_channel(msg, chan, | ||
1321 | split)) | ||
1322 | goto nla_put_failure; | ||
1323 | |||
1324 | nla_nest_end(msg, nl_freq); | ||
1325 | if (split) | ||
1326 | break; | ||
1327 | } | ||
1328 | if (i < sband->n_channels) | ||
1329 | *chan_start = i + 2; | ||
1330 | else | ||
1331 | *chan_start = 0; | ||
1332 | nla_nest_end(msg, nl_freqs); | ||
1333 | } | ||
1334 | |||
1335 | nla_nest_end(msg, nl_band); | ||
1336 | |||
1337 | if (split) { | ||
1338 | /* start again here */ | ||
1339 | if (*chan_start) | ||
1340 | band--; | ||
1341 | break; | ||
1199 | } | 1342 | } |
1200 | nla_nest_end(msg, nl_ftypes); | ||
1201 | } | 1343 | } |
1344 | nla_nest_end(msg, nl_bands); | ||
1202 | 1345 | ||
1203 | nla_nest_end(msg, nl_ifs); | 1346 | if (band < IEEE80211_NUM_BANDS) |
1347 | *band_start = band + 1; | ||
1348 | else | ||
1349 | *band_start = 0; | ||
1204 | 1350 | ||
1205 | nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES); | 1351 | /* if bands & channels are done, continue outside */ |
1206 | if (!nl_ifs) | 1352 | if (*band_start == 0 && *chan_start == 0) |
1353 | (*split_start)++; | ||
1354 | if (split) | ||
1355 | break; | ||
1356 | case 4: | ||
1357 | nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS); | ||
1358 | if (!nl_cmds) | ||
1207 | goto nla_put_failure; | 1359 | goto nla_put_failure; |
1208 | 1360 | ||
1209 | for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) { | 1361 | i = 0; |
1210 | nl_ftypes = nla_nest_start(msg, ift); | 1362 | #define CMD(op, n) \ |
1211 | if (!nl_ftypes) | 1363 | do { \ |
1364 | if (dev->ops->op) { \ | ||
1365 | i++; \ | ||
1366 | if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \ | ||
1367 | goto nla_put_failure; \ | ||
1368 | } \ | ||
1369 | } while (0) | ||
1370 | |||
1371 | CMD(add_virtual_intf, NEW_INTERFACE); | ||
1372 | CMD(change_virtual_intf, SET_INTERFACE); | ||
1373 | CMD(add_key, NEW_KEY); | ||
1374 | CMD(start_ap, START_AP); | ||
1375 | CMD(add_station, NEW_STATION); | ||
1376 | CMD(add_mpath, NEW_MPATH); | ||
1377 | CMD(update_mesh_config, SET_MESH_CONFIG); | ||
1378 | CMD(change_bss, SET_BSS); | ||
1379 | CMD(auth, AUTHENTICATE); | ||
1380 | CMD(assoc, ASSOCIATE); | ||
1381 | CMD(deauth, DEAUTHENTICATE); | ||
1382 | CMD(disassoc, DISASSOCIATE); | ||
1383 | CMD(join_ibss, JOIN_IBSS); | ||
1384 | CMD(join_mesh, JOIN_MESH); | ||
1385 | CMD(set_pmksa, SET_PMKSA); | ||
1386 | CMD(del_pmksa, DEL_PMKSA); | ||
1387 | CMD(flush_pmksa, FLUSH_PMKSA); | ||
1388 | if (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) | ||
1389 | CMD(remain_on_channel, REMAIN_ON_CHANNEL); | ||
1390 | CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); | ||
1391 | CMD(mgmt_tx, FRAME); | ||
1392 | CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL); | ||
1393 | if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { | ||
1394 | i++; | ||
1395 | if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS)) | ||
1212 | goto nla_put_failure; | 1396 | 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 | } | 1397 | } |
1225 | nla_nest_end(msg, nl_ifs); | 1398 | if (dev->ops->set_monitor_channel || dev->ops->start_ap || |
1226 | } | 1399 | dev->ops->join_mesh) { |
1400 | i++; | ||
1401 | if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL)) | ||
1402 | goto nla_put_failure; | ||
1403 | } | ||
1404 | CMD(set_wds_peer, SET_WDS_PEER); | ||
1405 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) { | ||
1406 | CMD(tdls_mgmt, TDLS_MGMT); | ||
1407 | CMD(tdls_oper, TDLS_OPER); | ||
1408 | } | ||
1409 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) | ||
1410 | CMD(sched_scan_start, START_SCHED_SCAN); | ||
1411 | CMD(probe_client, PROBE_CLIENT); | ||
1412 | CMD(set_noack_map, SET_NOACK_MAP); | ||
1413 | if (dev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) { | ||
1414 | i++; | ||
1415 | if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS)) | ||
1416 | goto nla_put_failure; | ||
1417 | } | ||
1418 | CMD(start_p2p_device, START_P2P_DEVICE); | ||
1419 | CMD(set_mcast_rate, SET_MCAST_RATE); | ||
1227 | 1420 | ||
1228 | #ifdef CONFIG_PM | 1421 | #ifdef CONFIG_NL80211_TESTMODE |
1229 | if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) { | 1422 | CMD(testmode_cmd, TESTMODE); |
1230 | struct nlattr *nl_wowlan; | 1423 | #endif |
1231 | 1424 | ||
1232 | nl_wowlan = nla_nest_start(msg, | 1425 | #undef CMD |
1233 | NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED); | ||
1234 | if (!nl_wowlan) | ||
1235 | goto nla_put_failure; | ||
1236 | 1426 | ||
1237 | if (((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_ANY) && | 1427 | if (dev->ops->connect || dev->ops->auth) { |
1238 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) || | 1428 | i++; |
1239 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_DISCONNECT) && | 1429 | 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; | 1430 | goto nla_put_failure; |
1267 | } | 1431 | } |
1268 | 1432 | ||
1269 | nla_nest_end(msg, nl_wowlan); | 1433 | if (dev->ops->disconnect || dev->ops->deauth) { |
1270 | } | 1434 | i++; |
1435 | if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT)) | ||
1436 | goto nla_put_failure; | ||
1437 | } | ||
1438 | |||
1439 | nla_nest_end(msg, nl_cmds); | ||
1440 | (*split_start)++; | ||
1441 | if (split) | ||
1442 | break; | ||
1443 | case 5: | ||
1444 | if (dev->ops->remain_on_channel && | ||
1445 | (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) && | ||
1446 | nla_put_u32(msg, | ||
1447 | NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION, | ||
1448 | dev->wiphy.max_remain_on_channel_duration)) | ||
1449 | goto nla_put_failure; | ||
1450 | |||
1451 | if ((dev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) && | ||
1452 | nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK)) | ||
1453 | goto nla_put_failure; | ||
1454 | |||
1455 | if (nl80211_send_mgmt_stypes(msg, mgmt_stypes)) | ||
1456 | goto nla_put_failure; | ||
1457 | (*split_start)++; | ||
1458 | if (split) | ||
1459 | break; | ||
1460 | case 6: | ||
1461 | #ifdef CONFIG_PM | ||
1462 | if (nl80211_send_wowlan(msg, dev, split)) | ||
1463 | goto nla_put_failure; | ||
1464 | (*split_start)++; | ||
1465 | if (split) | ||
1466 | break; | ||
1467 | #else | ||
1468 | (*split_start)++; | ||
1271 | #endif | 1469 | #endif |
1470 | case 7: | ||
1471 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, | ||
1472 | dev->wiphy.software_iftypes)) | ||
1473 | goto nla_put_failure; | ||
1272 | 1474 | ||
1273 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, | 1475 | if (nl80211_put_iface_combinations(&dev->wiphy, msg, split)) |
1274 | dev->wiphy.software_iftypes)) | 1476 | goto nla_put_failure; |
1275 | goto nla_put_failure; | ||
1276 | 1477 | ||
1277 | if (nl80211_put_iface_combinations(&dev->wiphy, msg)) | 1478 | (*split_start)++; |
1278 | goto nla_put_failure; | 1479 | if (split) |
1480 | break; | ||
1481 | case 8: | ||
1482 | if ((dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) && | ||
1483 | nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME, | ||
1484 | dev->wiphy.ap_sme_capa)) | ||
1485 | goto nla_put_failure; | ||
1279 | 1486 | ||
1280 | if ((dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) && | 1487 | features = dev->wiphy.features; |
1281 | nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME, | 1488 | /* |
1282 | dev->wiphy.ap_sme_capa)) | 1489 | * We can only add the per-channel limit information if the |
1283 | goto nla_put_failure; | 1490 | * dump is split, otherwise it makes it too big. Therefore |
1491 | * only advertise it in that case. | ||
1492 | */ | ||
1493 | if (split) | ||
1494 | features |= NL80211_FEATURE_ADVERTISE_CHAN_LIMITS; | ||
1495 | if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS, features)) | ||
1496 | goto nla_put_failure; | ||
1284 | 1497 | ||
1285 | if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS, | 1498 | if (dev->wiphy.ht_capa_mod_mask && |
1286 | dev->wiphy.features)) | 1499 | nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK, |
1287 | goto nla_put_failure; | 1500 | sizeof(*dev->wiphy.ht_capa_mod_mask), |
1501 | dev->wiphy.ht_capa_mod_mask)) | ||
1502 | goto nla_put_failure; | ||
1288 | 1503 | ||
1289 | if (dev->wiphy.ht_capa_mod_mask && | 1504 | if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME && |
1290 | nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK, | 1505 | dev->wiphy.max_acl_mac_addrs && |
1291 | sizeof(*dev->wiphy.ht_capa_mod_mask), | 1506 | nla_put_u32(msg, NL80211_ATTR_MAC_ACL_MAX, |
1292 | dev->wiphy.ht_capa_mod_mask)) | 1507 | dev->wiphy.max_acl_mac_addrs)) |
1293 | goto nla_put_failure; | 1508 | goto nla_put_failure; |
1294 | 1509 | ||
1295 | if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME && | 1510 | /* |
1296 | dev->wiphy.max_acl_mac_addrs && | 1511 | * Any information below this point is only available to |
1297 | nla_put_u32(msg, NL80211_ATTR_MAC_ACL_MAX, | 1512 | * applications that can deal with it being split. This |
1298 | dev->wiphy.max_acl_mac_addrs)) | 1513 | * helps ensure that newly added capabilities don't break |
1299 | goto nla_put_failure; | 1514 | * older tools by overrunning their buffers. |
1515 | * | ||
1516 | * We still increment split_start so that in the split | ||
1517 | * case we'll continue with more data in the next round, | ||
1518 | * but break unconditionally so unsplit data stops here. | ||
1519 | */ | ||
1520 | (*split_start)++; | ||
1521 | break; | ||
1522 | case 9: | ||
1523 | if (dev->wiphy.extended_capabilities && | ||
1524 | (nla_put(msg, NL80211_ATTR_EXT_CAPA, | ||
1525 | dev->wiphy.extended_capabilities_len, | ||
1526 | dev->wiphy.extended_capabilities) || | ||
1527 | nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK, | ||
1528 | dev->wiphy.extended_capabilities_len, | ||
1529 | dev->wiphy.extended_capabilities_mask))) | ||
1530 | goto nla_put_failure; | ||
1300 | 1531 | ||
1532 | if (dev->wiphy.vht_capa_mod_mask && | ||
1533 | nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, | ||
1534 | sizeof(*dev->wiphy.vht_capa_mod_mask), | ||
1535 | dev->wiphy.vht_capa_mod_mask)) | ||
1536 | goto nla_put_failure; | ||
1537 | |||
1538 | /* done */ | ||
1539 | *split_start = 0; | ||
1540 | break; | ||
1541 | } | ||
1301 | return genlmsg_end(msg, hdr); | 1542 | return genlmsg_end(msg, hdr); |
1302 | 1543 | ||
1303 | nla_put_failure: | 1544 | nla_put_failure: |
@@ -1310,39 +1551,80 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | |||
1310 | int idx = 0, ret; | 1551 | int idx = 0, ret; |
1311 | int start = cb->args[0]; | 1552 | int start = cb->args[0]; |
1312 | struct cfg80211_registered_device *dev; | 1553 | struct cfg80211_registered_device *dev; |
1554 | s64 filter_wiphy = -1; | ||
1555 | bool split = false; | ||
1556 | struct nlattr **tb = nl80211_fam.attrbuf; | ||
1557 | int res; | ||
1313 | 1558 | ||
1314 | mutex_lock(&cfg80211_mutex); | 1559 | mutex_lock(&cfg80211_mutex); |
1560 | res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | ||
1561 | tb, nl80211_fam.maxattr, nl80211_policy); | ||
1562 | if (res == 0) { | ||
1563 | split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP]; | ||
1564 | if (tb[NL80211_ATTR_WIPHY]) | ||
1565 | filter_wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]); | ||
1566 | if (tb[NL80211_ATTR_WDEV]) | ||
1567 | filter_wiphy = nla_get_u64(tb[NL80211_ATTR_WDEV]) >> 32; | ||
1568 | if (tb[NL80211_ATTR_IFINDEX]) { | ||
1569 | struct net_device *netdev; | ||
1570 | int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); | ||
1571 | |||
1572 | netdev = dev_get_by_index(sock_net(skb->sk), ifidx); | ||
1573 | if (!netdev) { | ||
1574 | mutex_unlock(&cfg80211_mutex); | ||
1575 | return -ENODEV; | ||
1576 | } | ||
1577 | if (netdev->ieee80211_ptr) { | ||
1578 | dev = wiphy_to_dev( | ||
1579 | netdev->ieee80211_ptr->wiphy); | ||
1580 | filter_wiphy = dev->wiphy_idx; | ||
1581 | } | ||
1582 | dev_put(netdev); | ||
1583 | } | ||
1584 | } | ||
1585 | |||
1315 | list_for_each_entry(dev, &cfg80211_rdev_list, list) { | 1586 | list_for_each_entry(dev, &cfg80211_rdev_list, list) { |
1316 | if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) | 1587 | if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) |
1317 | continue; | 1588 | continue; |
1318 | if (++idx <= start) | 1589 | if (++idx <= start) |
1319 | continue; | 1590 | continue; |
1320 | ret = nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).portid, | 1591 | if (filter_wiphy != -1 && dev->wiphy_idx != filter_wiphy) |
1321 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 1592 | continue; |
1322 | dev); | 1593 | /* attempt to fit multiple wiphy data chunks into the skb */ |
1323 | if (ret < 0) { | 1594 | do { |
1324 | /* | 1595 | ret = nl80211_send_wiphy(dev, skb, |
1325 | * If sending the wiphy data didn't fit (ENOBUFS or | 1596 | NETLINK_CB(cb->skb).portid, |
1326 | * EMSGSIZE returned), this SKB is still empty (so | 1597 | cb->nlh->nlmsg_seq, |
1327 | * it's not too big because another wiphy dataset is | 1598 | NLM_F_MULTI, |
1328 | * already in the skb) and we've not tried to adjust | 1599 | split, &cb->args[1], |
1329 | * the dump allocation yet ... then adjust the alloc | 1600 | &cb->args[2], |
1330 | * size to be bigger, and return 1 but with the empty | 1601 | &cb->args[3]); |
1331 | * skb. This results in an empty message being RX'ed | 1602 | if (ret < 0) { |
1332 | * in userspace, but that is ignored. | 1603 | /* |
1333 | * | 1604 | * If sending the wiphy data didn't fit (ENOBUFS |
1334 | * We can then retry with the larger buffer. | 1605 | * or EMSGSIZE returned), this SKB is still |
1335 | */ | 1606 | * empty (so it's not too big because another |
1336 | if ((ret == -ENOBUFS || ret == -EMSGSIZE) && | 1607 | * wiphy dataset is already in the skb) and |
1337 | !skb->len && | 1608 | * we've not tried to adjust the dump allocation |
1338 | cb->min_dump_alloc < 4096) { | 1609 | * yet ... then adjust the alloc size to be |
1339 | cb->min_dump_alloc = 4096; | 1610 | * bigger, and return 1 but with the empty skb. |
1340 | mutex_unlock(&cfg80211_mutex); | 1611 | * This results in an empty message being RX'ed |
1341 | return 1; | 1612 | * in userspace, but that is ignored. |
1613 | * | ||
1614 | * We can then retry with the larger buffer. | ||
1615 | */ | ||
1616 | if ((ret == -ENOBUFS || ret == -EMSGSIZE) && | ||
1617 | !skb->len && | ||
1618 | cb->min_dump_alloc < 4096) { | ||
1619 | cb->min_dump_alloc = 4096; | ||
1620 | mutex_unlock(&cfg80211_mutex); | ||
1621 | return 1; | ||
1622 | } | ||
1623 | idx--; | ||
1624 | break; | ||
1342 | } | 1625 | } |
1343 | idx--; | 1626 | } while (cb->args[1] > 0); |
1344 | break; | 1627 | break; |
1345 | } | ||
1346 | } | 1628 | } |
1347 | mutex_unlock(&cfg80211_mutex); | 1629 | mutex_unlock(&cfg80211_mutex); |
1348 | 1630 | ||
@@ -1360,7 +1642,8 @@ static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1360 | if (!msg) | 1642 | if (!msg) |
1361 | return -ENOMEM; | 1643 | return -ENOMEM; |
1362 | 1644 | ||
1363 | if (nl80211_send_wiphy(msg, info->snd_portid, info->snd_seq, 0, dev) < 0) { | 1645 | if (nl80211_send_wiphy(dev, msg, info->snd_portid, info->snd_seq, 0, |
1646 | false, NULL, NULL, NULL) < 0) { | ||
1364 | nlmsg_free(msg); | 1647 | nlmsg_free(msg); |
1365 | return -ENOBUFS; | 1648 | return -ENOBUFS; |
1366 | } | 1649 | } |
@@ -2967,6 +3250,7 @@ static int parse_station_flags(struct genl_info *info, | |||
2967 | sta_flags = nla_data(nla); | 3250 | sta_flags = nla_data(nla); |
2968 | params->sta_flags_mask = sta_flags->mask; | 3251 | params->sta_flags_mask = sta_flags->mask; |
2969 | params->sta_flags_set = sta_flags->set; | 3252 | params->sta_flags_set = sta_flags->set; |
3253 | params->sta_flags_set &= params->sta_flags_mask; | ||
2970 | if ((params->sta_flags_mask | | 3254 | if ((params->sta_flags_mask | |
2971 | params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID)) | 3255 | params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID)) |
2972 | return -EINVAL; | 3256 | return -EINVAL; |
@@ -3320,6 +3604,136 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | |||
3320 | return genlmsg_reply(msg, info); | 3604 | return genlmsg_reply(msg, info); |
3321 | } | 3605 | } |
3322 | 3606 | ||
3607 | int cfg80211_check_station_change(struct wiphy *wiphy, | ||
3608 | struct station_parameters *params, | ||
3609 | enum cfg80211_station_type statype) | ||
3610 | { | ||
3611 | if (params->listen_interval != -1) | ||
3612 | return -EINVAL; | ||
3613 | if (params->aid) | ||
3614 | return -EINVAL; | ||
3615 | |||
3616 | /* When you run into this, adjust the code below for the new flag */ | ||
3617 | BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7); | ||
3618 | |||
3619 | switch (statype) { | ||
3620 | case CFG80211_STA_MESH_PEER_KERNEL: | ||
3621 | case CFG80211_STA_MESH_PEER_USER: | ||
3622 | /* | ||
3623 | * No ignoring the TDLS flag here -- the userspace mesh | ||
3624 | * code doesn't have the bug of including TDLS in the | ||
3625 | * mask everywhere. | ||
3626 | */ | ||
3627 | if (params->sta_flags_mask & | ||
3628 | ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
3629 | BIT(NL80211_STA_FLAG_MFP) | | ||
3630 | BIT(NL80211_STA_FLAG_AUTHORIZED))) | ||
3631 | return -EINVAL; | ||
3632 | break; | ||
3633 | case CFG80211_STA_TDLS_PEER_SETUP: | ||
3634 | case CFG80211_STA_TDLS_PEER_ACTIVE: | ||
3635 | if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) | ||
3636 | return -EINVAL; | ||
3637 | /* ignore since it can't change */ | ||
3638 | params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); | ||
3639 | break; | ||
3640 | default: | ||
3641 | /* disallow mesh-specific things */ | ||
3642 | if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION) | ||
3643 | return -EINVAL; | ||
3644 | if (params->local_pm) | ||
3645 | return -EINVAL; | ||
3646 | if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE) | ||
3647 | return -EINVAL; | ||
3648 | } | ||
3649 | |||
3650 | if (statype != CFG80211_STA_TDLS_PEER_SETUP && | ||
3651 | statype != CFG80211_STA_TDLS_PEER_ACTIVE) { | ||
3652 | /* TDLS can't be set, ... */ | ||
3653 | if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) | ||
3654 | return -EINVAL; | ||
3655 | /* | ||
3656 | * ... but don't bother the driver with it. This works around | ||
3657 | * a hostapd/wpa_supplicant issue -- it always includes the | ||
3658 | * TLDS_PEER flag in the mask even for AP mode. | ||
3659 | */ | ||
3660 | params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); | ||
3661 | } | ||
3662 | |||
3663 | if (statype != CFG80211_STA_TDLS_PEER_SETUP) { | ||
3664 | /* reject other things that can't change */ | ||
3665 | if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD) | ||
3666 | return -EINVAL; | ||
3667 | if (params->sta_modify_mask & STATION_PARAM_APPLY_CAPABILITY) | ||
3668 | return -EINVAL; | ||
3669 | if (params->supported_rates) | ||
3670 | return -EINVAL; | ||
3671 | if (params->ext_capab || params->ht_capa || params->vht_capa) | ||
3672 | return -EINVAL; | ||
3673 | } | ||
3674 | |||
3675 | if (statype != CFG80211_STA_AP_CLIENT) { | ||
3676 | if (params->vlan) | ||
3677 | return -EINVAL; | ||
3678 | } | ||
3679 | |||
3680 | switch (statype) { | ||
3681 | case CFG80211_STA_AP_MLME_CLIENT: | ||
3682 | /* Use this only for authorizing/unauthorizing a station */ | ||
3683 | if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) | ||
3684 | return -EOPNOTSUPP; | ||
3685 | break; | ||
3686 | case CFG80211_STA_AP_CLIENT: | ||
3687 | /* accept only the listed bits */ | ||
3688 | if (params->sta_flags_mask & | ||
3689 | ~(BIT(NL80211_STA_FLAG_AUTHORIZED) | | ||
3690 | BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
3691 | BIT(NL80211_STA_FLAG_ASSOCIATED) | | ||
3692 | BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) | | ||
3693 | BIT(NL80211_STA_FLAG_WME) | | ||
3694 | BIT(NL80211_STA_FLAG_MFP))) | ||
3695 | return -EINVAL; | ||
3696 | |||
3697 | /* but authenticated/associated only if driver handles it */ | ||
3698 | if (!(wiphy->features & NL80211_FEATURE_FULL_AP_CLIENT_STATE) && | ||
3699 | params->sta_flags_mask & | ||
3700 | (BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
3701 | BIT(NL80211_STA_FLAG_ASSOCIATED))) | ||
3702 | return -EINVAL; | ||
3703 | break; | ||
3704 | case CFG80211_STA_IBSS: | ||
3705 | case CFG80211_STA_AP_STA: | ||
3706 | /* reject any changes other than AUTHORIZED */ | ||
3707 | if (params->sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED)) | ||
3708 | return -EINVAL; | ||
3709 | break; | ||
3710 | case CFG80211_STA_TDLS_PEER_SETUP: | ||
3711 | /* reject any changes other than AUTHORIZED or WME */ | ||
3712 | if (params->sta_flags_mask & ~(BIT(NL80211_STA_FLAG_AUTHORIZED) | | ||
3713 | BIT(NL80211_STA_FLAG_WME))) | ||
3714 | return -EINVAL; | ||
3715 | /* force (at least) rates when authorizing */ | ||
3716 | if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED) && | ||
3717 | !params->supported_rates) | ||
3718 | return -EINVAL; | ||
3719 | break; | ||
3720 | case CFG80211_STA_TDLS_PEER_ACTIVE: | ||
3721 | /* reject any changes */ | ||
3722 | return -EINVAL; | ||
3723 | case CFG80211_STA_MESH_PEER_KERNEL: | ||
3724 | if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE) | ||
3725 | return -EINVAL; | ||
3726 | break; | ||
3727 | case CFG80211_STA_MESH_PEER_USER: | ||
3728 | if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION) | ||
3729 | return -EINVAL; | ||
3730 | break; | ||
3731 | } | ||
3732 | |||
3733 | return 0; | ||
3734 | } | ||
3735 | EXPORT_SYMBOL(cfg80211_check_station_change); | ||
3736 | |||
3323 | /* | 3737 | /* |
3324 | * Get vlan interface making sure it is running and on the right wiphy. | 3738 | * Get vlan interface making sure it is running and on the right wiphy. |
3325 | */ | 3739 | */ |
@@ -3342,6 +3756,13 @@ static struct net_device *get_vlan(struct genl_info *info, | |||
3342 | goto error; | 3756 | goto error; |
3343 | } | 3757 | } |
3344 | 3758 | ||
3759 | if (v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | ||
3760 | v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | ||
3761 | v->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { | ||
3762 | ret = -EINVAL; | ||
3763 | goto error; | ||
3764 | } | ||
3765 | |||
3345 | if (!netif_running(v)) { | 3766 | if (!netif_running(v)) { |
3346 | ret = -ENETDOWN; | 3767 | ret = -ENETDOWN; |
3347 | goto error; | 3768 | goto error; |
@@ -3359,21 +3780,13 @@ nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] __read_mostly = { | |||
3359 | [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 }, | 3780 | [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 }, |
3360 | }; | 3781 | }; |
3361 | 3782 | ||
3362 | static int nl80211_set_station_tdls(struct genl_info *info, | 3783 | static int nl80211_parse_sta_wme(struct genl_info *info, |
3363 | struct station_parameters *params) | 3784 | struct station_parameters *params) |
3364 | { | 3785 | { |
3365 | struct nlattr *tb[NL80211_STA_WME_MAX + 1]; | 3786 | struct nlattr *tb[NL80211_STA_WME_MAX + 1]; |
3366 | struct nlattr *nla; | 3787 | struct nlattr *nla; |
3367 | int err; | 3788 | int err; |
3368 | 3789 | ||
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 */ | 3790 | /* parse WME attributes if present */ |
3378 | if (!info->attrs[NL80211_ATTR_STA_WME]) | 3791 | if (!info->attrs[NL80211_ATTR_STA_WME]) |
3379 | return 0; | 3792 | return 0; |
@@ -3401,18 +3814,34 @@ static int nl80211_set_station_tdls(struct genl_info *info, | |||
3401 | return 0; | 3814 | return 0; |
3402 | } | 3815 | } |
3403 | 3816 | ||
3817 | static int nl80211_set_station_tdls(struct genl_info *info, | ||
3818 | struct station_parameters *params) | ||
3819 | { | ||
3820 | /* Dummy STA entry gets updated once the peer capabilities are known */ | ||
3821 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) | ||
3822 | params->ht_capa = | ||
3823 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | ||
3824 | if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) | ||
3825 | params->vht_capa = | ||
3826 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]); | ||
3827 | |||
3828 | return nl80211_parse_sta_wme(info, params); | ||
3829 | } | ||
3830 | |||
3404 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | 3831 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) |
3405 | { | 3832 | { |
3406 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 3833 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3407 | int err; | ||
3408 | struct net_device *dev = info->user_ptr[1]; | 3834 | struct net_device *dev = info->user_ptr[1]; |
3409 | struct station_parameters params; | 3835 | struct station_parameters params; |
3410 | u8 *mac_addr = NULL; | 3836 | u8 *mac_addr; |
3837 | int err; | ||
3411 | 3838 | ||
3412 | memset(¶ms, 0, sizeof(params)); | 3839 | memset(¶ms, 0, sizeof(params)); |
3413 | 3840 | ||
3414 | params.listen_interval = -1; | 3841 | params.listen_interval = -1; |
3415 | params.plink_state = -1; | 3842 | |
3843 | if (!rdev->ops->change_station) | ||
3844 | return -EOPNOTSUPP; | ||
3416 | 3845 | ||
3417 | if (info->attrs[NL80211_ATTR_STA_AID]) | 3846 | if (info->attrs[NL80211_ATTR_STA_AID]) |
3418 | return -EINVAL; | 3847 | return -EINVAL; |
@@ -3445,19 +3874,23 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
3445 | if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) | 3874 | if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) |
3446 | return -EINVAL; | 3875 | return -EINVAL; |
3447 | 3876 | ||
3448 | if (!rdev->ops->change_station) | ||
3449 | return -EOPNOTSUPP; | ||
3450 | |||
3451 | if (parse_station_flags(info, dev->ieee80211_ptr->iftype, ¶ms)) | 3877 | if (parse_station_flags(info, dev->ieee80211_ptr->iftype, ¶ms)) |
3452 | return -EINVAL; | 3878 | return -EINVAL; |
3453 | 3879 | ||
3454 | if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) | 3880 | if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) { |
3455 | params.plink_action = | 3881 | params.plink_action = |
3456 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); | 3882 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); |
3883 | if (params.plink_action >= NUM_NL80211_PLINK_ACTIONS) | ||
3884 | return -EINVAL; | ||
3885 | } | ||
3457 | 3886 | ||
3458 | if (info->attrs[NL80211_ATTR_STA_PLINK_STATE]) | 3887 | if (info->attrs[NL80211_ATTR_STA_PLINK_STATE]) { |
3459 | params.plink_state = | 3888 | params.plink_state = |
3460 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]); | 3889 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]); |
3890 | if (params.plink_state >= NUM_NL80211_PLINK_STATES) | ||
3891 | return -EINVAL; | ||
3892 | params.sta_modify_mask |= STATION_PARAM_APPLY_PLINK_STATE; | ||
3893 | } | ||
3461 | 3894 | ||
3462 | if (info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]) { | 3895 | if (info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]) { |
3463 | enum nl80211_mesh_power_mode pm = nla_get_u32( | 3896 | enum nl80211_mesh_power_mode pm = nla_get_u32( |
@@ -3470,127 +3903,33 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
3470 | params.local_pm = pm; | 3903 | params.local_pm = pm; |
3471 | } | 3904 | } |
3472 | 3905 | ||
3906 | /* Include parameters for TDLS peer (will check later) */ | ||
3907 | err = nl80211_set_station_tdls(info, ¶ms); | ||
3908 | if (err) | ||
3909 | return err; | ||
3910 | |||
3911 | params.vlan = get_vlan(info, rdev); | ||
3912 | if (IS_ERR(params.vlan)) | ||
3913 | return PTR_ERR(params.vlan); | ||
3914 | |||
3473 | switch (dev->ieee80211_ptr->iftype) { | 3915 | switch (dev->ieee80211_ptr->iftype) { |
3474 | case NL80211_IFTYPE_AP: | 3916 | case NL80211_IFTYPE_AP: |
3475 | case NL80211_IFTYPE_AP_VLAN: | 3917 | case NL80211_IFTYPE_AP_VLAN: |
3476 | case NL80211_IFTYPE_P2P_GO: | 3918 | 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: | 3919 | case NL80211_IFTYPE_P2P_CLIENT: |
3528 | case NL80211_IFTYPE_STATION: | 3920 | 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: | 3921 | 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: | 3922 | 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; | 3923 | break; |
3586 | default: | 3924 | default: |
3587 | return -EOPNOTSUPP; | 3925 | err = -EOPNOTSUPP; |
3926 | goto out_put_vlan; | ||
3588 | } | 3927 | } |
3589 | 3928 | ||
3590 | /* be aware of params.vlan when changing code here */ | 3929 | /* driver will call cfg80211_check_station_change() */ |
3591 | |||
3592 | err = rdev_change_station(rdev, dev, mac_addr, ¶ms); | 3930 | err = rdev_change_station(rdev, dev, mac_addr, ¶ms); |
3593 | 3931 | ||
3932 | out_put_vlan: | ||
3594 | if (params.vlan) | 3933 | if (params.vlan) |
3595 | dev_put(params.vlan); | 3934 | dev_put(params.vlan); |
3596 | 3935 | ||
@@ -3607,6 +3946,9 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
3607 | 3946 | ||
3608 | memset(¶ms, 0, sizeof(params)); | 3947 | memset(¶ms, 0, sizeof(params)); |
3609 | 3948 | ||
3949 | if (!rdev->ops->add_station) | ||
3950 | return -EOPNOTSUPP; | ||
3951 | |||
3610 | if (!info->attrs[NL80211_ATTR_MAC]) | 3952 | if (!info->attrs[NL80211_ATTR_MAC]) |
3611 | return -EINVAL; | 3953 | return -EINVAL; |
3612 | 3954 | ||
@@ -3652,50 +3994,32 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
3652 | params.vht_capa = | 3994 | params.vht_capa = |
3653 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]); | 3995 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]); |
3654 | 3996 | ||
3655 | if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) | 3997 | if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) { |
3656 | params.plink_action = | 3998 | params.plink_action = |
3657 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); | 3999 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); |
4000 | if (params.plink_action >= NUM_NL80211_PLINK_ACTIONS) | ||
4001 | return -EINVAL; | ||
4002 | } | ||
3658 | 4003 | ||
3659 | if (!rdev->ops->add_station) | 4004 | err = nl80211_parse_sta_wme(info, ¶ms); |
3660 | return -EOPNOTSUPP; | 4005 | if (err) |
4006 | return err; | ||
3661 | 4007 | ||
3662 | if (parse_station_flags(info, dev->ieee80211_ptr->iftype, ¶ms)) | 4008 | if (parse_station_flags(info, dev->ieee80211_ptr->iftype, ¶ms)) |
3663 | return -EINVAL; | 4009 | return -EINVAL; |
3664 | 4010 | ||
4011 | /* When you run into this, adjust the code below for the new flag */ | ||
4012 | BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7); | ||
4013 | |||
3665 | switch (dev->ieee80211_ptr->iftype) { | 4014 | switch (dev->ieee80211_ptr->iftype) { |
3666 | case NL80211_IFTYPE_AP: | 4015 | case NL80211_IFTYPE_AP: |
3667 | case NL80211_IFTYPE_AP_VLAN: | 4016 | case NL80211_IFTYPE_AP_VLAN: |
3668 | case NL80211_IFTYPE_P2P_GO: | 4017 | case NL80211_IFTYPE_P2P_GO: |
3669 | /* parse WME attributes if sta is WME capable */ | 4018 | /* ignore WME attributes if iface/sta is not capable */ |
3670 | if ((rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) && | 4019 | if (!(rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) || |
3671 | (params.sta_flags_set & BIT(NL80211_STA_FLAG_WME)) && | 4020 | !(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME))) |
3672 | info->attrs[NL80211_ATTR_STA_WME]) { | 4021 | 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 | 4022 | ||
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 */ | 4023 | /* TDLS peers cannot be added */ |
3700 | if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) | 4024 | if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) |
3701 | return -EINVAL; | 4025 | return -EINVAL; |
@@ -3716,6 +4040,9 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
3716 | return PTR_ERR(params.vlan); | 4040 | return PTR_ERR(params.vlan); |
3717 | break; | 4041 | break; |
3718 | case NL80211_IFTYPE_MESH_POINT: | 4042 | case NL80211_IFTYPE_MESH_POINT: |
4043 | /* ignore uAPSD data */ | ||
4044 | params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD; | ||
4045 | |||
3719 | /* associated is disallowed */ | 4046 | /* associated is disallowed */ |
3720 | if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED)) | 4047 | if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED)) |
3721 | return -EINVAL; | 4048 | return -EINVAL; |
@@ -3724,8 +4051,14 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
3724 | return -EINVAL; | 4051 | return -EINVAL; |
3725 | break; | 4052 | break; |
3726 | case NL80211_IFTYPE_STATION: | 4053 | case NL80211_IFTYPE_STATION: |
3727 | /* associated is disallowed */ | 4054 | case NL80211_IFTYPE_P2P_CLIENT: |
3728 | if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED)) | 4055 | /* ignore uAPSD data */ |
4056 | params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD; | ||
4057 | |||
4058 | /* these are disallowed */ | ||
4059 | if (params.sta_flags_mask & | ||
4060 | (BIT(NL80211_STA_FLAG_ASSOCIATED) | | ||
4061 | BIT(NL80211_STA_FLAG_AUTHENTICATED))) | ||
3729 | return -EINVAL; | 4062 | return -EINVAL; |
3730 | /* Only TDLS peers can be added */ | 4063 | /* Only TDLS peers can be added */ |
3731 | if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) | 4064 | if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) |
@@ -3736,6 +4069,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
3736 | /* ... with external setup is supported */ | 4069 | /* ... with external setup is supported */ |
3737 | if (!(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP)) | 4070 | if (!(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP)) |
3738 | return -EOPNOTSUPP; | 4071 | return -EOPNOTSUPP; |
4072 | /* | ||
4073 | * Older wpa_supplicant versions always mark the TDLS peer | ||
4074 | * as authorized, but it shouldn't yet be. | ||
4075 | */ | ||
4076 | params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_AUTHORIZED); | ||
3739 | break; | 4077 | break; |
3740 | default: | 4078 | default: |
3741 | return -EOPNOTSUPP; | 4079 | return -EOPNOTSUPP; |
@@ -4280,6 +4618,7 @@ static const struct nla_policy | |||
4280 | [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 }, | 4618 | [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 }, |
4281 | [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 }, | 4619 | [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 }, |
4282 | [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG }, | 4620 | [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG }, |
4621 | [NL80211_MESH_SETUP_USERSPACE_MPM] = { .type = NLA_FLAG }, | ||
4283 | [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY, | 4622 | [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY, |
4284 | .len = IEEE80211_MAX_DATA_LEN }, | 4623 | .len = IEEE80211_MAX_DATA_LEN }, |
4285 | [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG }, | 4624 | [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG }, |
@@ -4418,6 +4757,7 @@ do { \ | |||
4418 | static int nl80211_parse_mesh_setup(struct genl_info *info, | 4757 | static int nl80211_parse_mesh_setup(struct genl_info *info, |
4419 | struct mesh_setup *setup) | 4758 | struct mesh_setup *setup) |
4420 | { | 4759 | { |
4760 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
4421 | struct nlattr *tb[NL80211_MESH_SETUP_ATTR_MAX + 1]; | 4761 | struct nlattr *tb[NL80211_MESH_SETUP_ATTR_MAX + 1]; |
4422 | 4762 | ||
4423 | if (!info->attrs[NL80211_ATTR_MESH_SETUP]) | 4763 | if (!info->attrs[NL80211_ATTR_MESH_SETUP]) |
@@ -4454,8 +4794,14 @@ static int nl80211_parse_mesh_setup(struct genl_info *info, | |||
4454 | setup->ie = nla_data(ieattr); | 4794 | setup->ie = nla_data(ieattr); |
4455 | setup->ie_len = nla_len(ieattr); | 4795 | setup->ie_len = nla_len(ieattr); |
4456 | } | 4796 | } |
4797 | if (tb[NL80211_MESH_SETUP_USERSPACE_MPM] && | ||
4798 | !(rdev->wiphy.features & NL80211_FEATURE_USERSPACE_MPM)) | ||
4799 | return -EINVAL; | ||
4800 | 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]); | 4801 | 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]); | 4802 | setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AMPE]); |
4803 | if (setup->is_secure) | ||
4804 | setup->user_mpm = true; | ||
4459 | 4805 | ||
4460 | return 0; | 4806 | return 0; |
4461 | } | 4807 | } |
@@ -5663,14 +6009,10 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
5663 | { | 6009 | { |
5664 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6010 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5665 | struct net_device *dev = info->user_ptr[1]; | 6011 | struct net_device *dev = info->user_ptr[1]; |
5666 | struct cfg80211_crypto_settings crypto; | ||
5667 | struct ieee80211_channel *chan; | 6012 | struct ieee80211_channel *chan; |
5668 | const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; | 6013 | struct cfg80211_assoc_request req = {}; |
5669 | int err, ssid_len, ie_len = 0; | 6014 | const u8 *bssid, *ssid; |
5670 | bool use_mfp = false; | 6015 | int err, ssid_len = 0; |
5671 | u32 flags = 0; | ||
5672 | struct ieee80211_ht_cap *ht_capa = NULL; | ||
5673 | struct ieee80211_ht_cap *ht_capa_mask = NULL; | ||
5674 | 6016 | ||
5675 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 6017 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
5676 | return -EINVAL; | 6018 | return -EINVAL; |
@@ -5698,41 +6040,58 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
5698 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | 6040 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); |
5699 | 6041 | ||
5700 | if (info->attrs[NL80211_ATTR_IE]) { | 6042 | if (info->attrs[NL80211_ATTR_IE]) { |
5701 | ie = nla_data(info->attrs[NL80211_ATTR_IE]); | 6043 | req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); |
5702 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 6044 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
5703 | } | 6045 | } |
5704 | 6046 | ||
5705 | if (info->attrs[NL80211_ATTR_USE_MFP]) { | 6047 | if (info->attrs[NL80211_ATTR_USE_MFP]) { |
5706 | enum nl80211_mfp mfp = | 6048 | enum nl80211_mfp mfp = |
5707 | nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); | 6049 | nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); |
5708 | if (mfp == NL80211_MFP_REQUIRED) | 6050 | if (mfp == NL80211_MFP_REQUIRED) |
5709 | use_mfp = true; | 6051 | req.use_mfp = true; |
5710 | else if (mfp != NL80211_MFP_NO) | 6052 | else if (mfp != NL80211_MFP_NO) |
5711 | return -EINVAL; | 6053 | return -EINVAL; |
5712 | } | 6054 | } |
5713 | 6055 | ||
5714 | if (info->attrs[NL80211_ATTR_PREV_BSSID]) | 6056 | if (info->attrs[NL80211_ATTR_PREV_BSSID]) |
5715 | prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]); | 6057 | req.prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]); |
5716 | 6058 | ||
5717 | if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT])) | 6059 | if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT])) |
5718 | flags |= ASSOC_REQ_DISABLE_HT; | 6060 | req.flags |= ASSOC_REQ_DISABLE_HT; |
5719 | 6061 | ||
5720 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) | 6062 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) |
5721 | ht_capa_mask = | 6063 | memcpy(&req.ht_capa_mask, |
5722 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]); | 6064 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]), |
6065 | sizeof(req.ht_capa_mask)); | ||
5723 | 6066 | ||
5724 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) { | 6067 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) { |
5725 | if (!ht_capa_mask) | 6068 | if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) |
5726 | return -EINVAL; | 6069 | return -EINVAL; |
5727 | ht_capa = nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | 6070 | memcpy(&req.ht_capa, |
6071 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]), | ||
6072 | sizeof(req.ht_capa)); | ||
5728 | } | 6073 | } |
5729 | 6074 | ||
5730 | err = nl80211_crypto_settings(rdev, info, &crypto, 1); | 6075 | if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT])) |
6076 | req.flags |= ASSOC_REQ_DISABLE_VHT; | ||
6077 | |||
6078 | if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) | ||
6079 | memcpy(&req.vht_capa_mask, | ||
6080 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]), | ||
6081 | sizeof(req.vht_capa_mask)); | ||
6082 | |||
6083 | if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) { | ||
6084 | if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) | ||
6085 | return -EINVAL; | ||
6086 | memcpy(&req.vht_capa, | ||
6087 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]), | ||
6088 | sizeof(req.vht_capa)); | ||
6089 | } | ||
6090 | |||
6091 | err = nl80211_crypto_settings(rdev, info, &req.crypto, 1); | ||
5731 | if (!err) | 6092 | if (!err) |
5732 | err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, | 6093 | err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, |
5733 | ssid, ssid_len, ie, ie_len, use_mfp, | 6094 | ssid, ssid_len, &req); |
5734 | &crypto, flags, ht_capa, | ||
5735 | ht_capa_mask); | ||
5736 | 6095 | ||
5737 | return err; | 6096 | return err; |
5738 | } | 6097 | } |
@@ -6312,6 +6671,24 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | |||
6312 | sizeof(connect.ht_capa)); | 6671 | sizeof(connect.ht_capa)); |
6313 | } | 6672 | } |
6314 | 6673 | ||
6674 | if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT])) | ||
6675 | connect.flags |= ASSOC_REQ_DISABLE_VHT; | ||
6676 | |||
6677 | if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) | ||
6678 | memcpy(&connect.vht_capa_mask, | ||
6679 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]), | ||
6680 | sizeof(connect.vht_capa_mask)); | ||
6681 | |||
6682 | if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) { | ||
6683 | if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) { | ||
6684 | kfree(connkeys); | ||
6685 | return -EINVAL; | ||
6686 | } | ||
6687 | memcpy(&connect.vht_capa, | ||
6688 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]), | ||
6689 | sizeof(connect.vht_capa)); | ||
6690 | } | ||
6691 | |||
6315 | err = cfg80211_connect(rdev, dev, &connect, connkeys); | 6692 | err = cfg80211_connect(rdev, dev, &connect, connkeys); |
6316 | if (err) | 6693 | if (err) |
6317 | kfree(connkeys); | 6694 | kfree(connkeys); |
@@ -7085,6 +7462,9 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) | |||
7085 | return err; | 7462 | return err; |
7086 | } | 7463 | } |
7087 | 7464 | ||
7465 | if (setup.user_mpm) | ||
7466 | cfg.auto_open_plinks = false; | ||
7467 | |||
7088 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | 7468 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { |
7089 | err = nl80211_parse_chandef(rdev, info, &setup.chandef); | 7469 | err = nl80211_parse_chandef(rdev, info, &setup.chandef); |
7090 | if (err) | 7470 | if (err) |
@@ -7284,7 +7664,8 @@ static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev, | |||
7284 | return -EINVAL; | 7664 | return -EINVAL; |
7285 | 7665 | ||
7286 | if (nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) > | 7666 | if (nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) > |
7287 | rdev->wiphy.wowlan.tcp->data_interval_max) | 7667 | rdev->wiphy.wowlan.tcp->data_interval_max || |
7668 | nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) == 0) | ||
7288 | return -EINVAL; | 7669 | return -EINVAL; |
7289 | 7670 | ||
7290 | wake_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]); | 7671 | wake_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]); |
@@ -7769,6 +8150,54 @@ static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info) | |||
7769 | return 0; | 8150 | return 0; |
7770 | } | 8151 | } |
7771 | 8152 | ||
8153 | static int nl80211_get_protocol_features(struct sk_buff *skb, | ||
8154 | struct genl_info *info) | ||
8155 | { | ||
8156 | void *hdr; | ||
8157 | struct sk_buff *msg; | ||
8158 | |||
8159 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
8160 | if (!msg) | ||
8161 | return -ENOMEM; | ||
8162 | |||
8163 | hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0, | ||
8164 | NL80211_CMD_GET_PROTOCOL_FEATURES); | ||
8165 | if (!hdr) | ||
8166 | goto nla_put_failure; | ||
8167 | |||
8168 | if (nla_put_u32(msg, NL80211_ATTR_PROTOCOL_FEATURES, | ||
8169 | NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)) | ||
8170 | goto nla_put_failure; | ||
8171 | |||
8172 | genlmsg_end(msg, hdr); | ||
8173 | return genlmsg_reply(msg, info); | ||
8174 | |||
8175 | nla_put_failure: | ||
8176 | kfree_skb(msg); | ||
8177 | return -ENOBUFS; | ||
8178 | } | ||
8179 | |||
8180 | static int nl80211_update_ft_ies(struct sk_buff *skb, struct genl_info *info) | ||
8181 | { | ||
8182 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
8183 | struct cfg80211_update_ft_ies_params ft_params; | ||
8184 | struct net_device *dev = info->user_ptr[1]; | ||
8185 | |||
8186 | if (!rdev->ops->update_ft_ies) | ||
8187 | return -EOPNOTSUPP; | ||
8188 | |||
8189 | if (!info->attrs[NL80211_ATTR_MDID] || | ||
8190 | !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | ||
8191 | return -EINVAL; | ||
8192 | |||
8193 | memset(&ft_params, 0, sizeof(ft_params)); | ||
8194 | ft_params.md = nla_get_u16(info->attrs[NL80211_ATTR_MDID]); | ||
8195 | ft_params.ie = nla_data(info->attrs[NL80211_ATTR_IE]); | ||
8196 | ft_params.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
8197 | |||
8198 | return rdev_update_ft_ies(rdev, dev, &ft_params); | ||
8199 | } | ||
8200 | |||
7772 | #define NL80211_FLAG_NEED_WIPHY 0x01 | 8201 | #define NL80211_FLAG_NEED_WIPHY 0x01 |
7773 | #define NL80211_FLAG_NEED_NETDEV 0x02 | 8202 | #define NL80211_FLAG_NEED_NETDEV 0x02 |
7774 | #define NL80211_FLAG_NEED_RTNL 0x04 | 8203 | #define NL80211_FLAG_NEED_RTNL 0x04 |
@@ -8445,6 +8874,19 @@ static struct genl_ops nl80211_ops[] = { | |||
8445 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 8874 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
8446 | NL80211_FLAG_NEED_RTNL, | 8875 | NL80211_FLAG_NEED_RTNL, |
8447 | }, | 8876 | }, |
8877 | { | ||
8878 | .cmd = NL80211_CMD_GET_PROTOCOL_FEATURES, | ||
8879 | .doit = nl80211_get_protocol_features, | ||
8880 | .policy = nl80211_policy, | ||
8881 | }, | ||
8882 | { | ||
8883 | .cmd = NL80211_CMD_UPDATE_FT_IES, | ||
8884 | .doit = nl80211_update_ft_ies, | ||
8885 | .policy = nl80211_policy, | ||
8886 | .flags = GENL_ADMIN_PERM, | ||
8887 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
8888 | NL80211_FLAG_NEED_RTNL, | ||
8889 | }, | ||
8448 | }; | 8890 | }; |
8449 | 8891 | ||
8450 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 8892 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
@@ -8472,7 +8914,8 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) | |||
8472 | if (!msg) | 8914 | if (!msg) |
8473 | return; | 8915 | return; |
8474 | 8916 | ||
8475 | if (nl80211_send_wiphy(msg, 0, 0, 0, rdev) < 0) { | 8917 | if (nl80211_send_wiphy(rdev, msg, 0, 0, 0, |
8918 | false, NULL, NULL, NULL) < 0) { | ||
8476 | nlmsg_free(msg); | 8919 | nlmsg_free(msg); |
8477 | return; | 8920 | return; |
8478 | } | 8921 | } |
@@ -8796,21 +9239,31 @@ void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, | |||
8796 | NL80211_CMD_DISASSOCIATE, gfp); | 9239 | NL80211_CMD_DISASSOCIATE, gfp); |
8797 | } | 9240 | } |
8798 | 9241 | ||
8799 | void nl80211_send_unprot_deauth(struct cfg80211_registered_device *rdev, | 9242 | void cfg80211_send_unprot_deauth(struct net_device *dev, const u8 *buf, |
8800 | struct net_device *netdev, const u8 *buf, | 9243 | size_t len) |
8801 | size_t len, gfp_t gfp) | ||
8802 | { | 9244 | { |
8803 | nl80211_send_mlme_event(rdev, netdev, buf, len, | 9245 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
8804 | NL80211_CMD_UNPROT_DEAUTHENTICATE, gfp); | 9246 | struct wiphy *wiphy = wdev->wiphy; |
9247 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9248 | |||
9249 | trace_cfg80211_send_unprot_deauth(dev); | ||
9250 | nl80211_send_mlme_event(rdev, dev, buf, len, | ||
9251 | NL80211_CMD_UNPROT_DEAUTHENTICATE, GFP_ATOMIC); | ||
8805 | } | 9252 | } |
9253 | EXPORT_SYMBOL(cfg80211_send_unprot_deauth); | ||
8806 | 9254 | ||
8807 | void nl80211_send_unprot_disassoc(struct cfg80211_registered_device *rdev, | 9255 | void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf, |
8808 | struct net_device *netdev, const u8 *buf, | 9256 | size_t len) |
8809 | size_t len, gfp_t gfp) | ||
8810 | { | 9257 | { |
8811 | nl80211_send_mlme_event(rdev, netdev, buf, len, | 9258 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
8812 | NL80211_CMD_UNPROT_DISASSOCIATE, gfp); | 9259 | struct wiphy *wiphy = wdev->wiphy; |
9260 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9261 | |||
9262 | trace_cfg80211_send_unprot_disassoc(dev); | ||
9263 | nl80211_send_mlme_event(rdev, dev, buf, len, | ||
9264 | NL80211_CMD_UNPROT_DISASSOCIATE, GFP_ATOMIC); | ||
8813 | } | 9265 | } |
9266 | EXPORT_SYMBOL(cfg80211_send_unprot_disassoc); | ||
8814 | 9267 | ||
8815 | static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, | 9268 | static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, |
8816 | struct net_device *netdev, int cmd, | 9269 | struct net_device *netdev, int cmd, |
@@ -9013,14 +9466,19 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, | |||
9013 | nlmsg_free(msg); | 9466 | nlmsg_free(msg); |
9014 | } | 9467 | } |
9015 | 9468 | ||
9016 | void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev, | 9469 | void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr, |
9017 | struct net_device *netdev, | 9470 | const u8* ie, u8 ie_len, gfp_t gfp) |
9018 | const u8 *macaddr, const u8* ie, u8 ie_len, | ||
9019 | gfp_t gfp) | ||
9020 | { | 9471 | { |
9472 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
9473 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
9021 | struct sk_buff *msg; | 9474 | struct sk_buff *msg; |
9022 | void *hdr; | 9475 | void *hdr; |
9023 | 9476 | ||
9477 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT)) | ||
9478 | return; | ||
9479 | |||
9480 | trace_cfg80211_notify_new_peer_candidate(dev, addr); | ||
9481 | |||
9024 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | 9482 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
9025 | if (!msg) | 9483 | if (!msg) |
9026 | return; | 9484 | return; |
@@ -9032,8 +9490,8 @@ void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev, | |||
9032 | } | 9490 | } |
9033 | 9491 | ||
9034 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 9492 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
9035 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | 9493 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || |
9036 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, macaddr) || | 9494 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) || |
9037 | (ie_len && ie && | 9495 | (ie_len && ie && |
9038 | nla_put(msg, NL80211_ATTR_IE, ie_len , ie))) | 9496 | nla_put(msg, NL80211_ATTR_IE, ie_len , ie))) |
9039 | goto nla_put_failure; | 9497 | goto nla_put_failure; |
@@ -9048,6 +9506,7 @@ void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev, | |||
9048 | genlmsg_cancel(msg, hdr); | 9506 | genlmsg_cancel(msg, hdr); |
9049 | nlmsg_free(msg); | 9507 | nlmsg_free(msg); |
9050 | } | 9508 | } |
9509 | EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate); | ||
9051 | 9510 | ||
9052 | void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, | 9511 | void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, |
9053 | struct net_device *netdev, const u8 *addr, | 9512 | struct net_device *netdev, const u8 *addr, |
@@ -9116,7 +9575,7 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy, | |||
9116 | nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_BEFORE); | 9575 | nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_BEFORE); |
9117 | if (!nl_freq) | 9576 | if (!nl_freq) |
9118 | goto nla_put_failure; | 9577 | goto nla_put_failure; |
9119 | if (nl80211_msg_put_channel(msg, channel_before)) | 9578 | if (nl80211_msg_put_channel(msg, channel_before, false)) |
9120 | goto nla_put_failure; | 9579 | goto nla_put_failure; |
9121 | nla_nest_end(msg, nl_freq); | 9580 | nla_nest_end(msg, nl_freq); |
9122 | 9581 | ||
@@ -9124,7 +9583,7 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy, | |||
9124 | nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_AFTER); | 9583 | nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_AFTER); |
9125 | if (!nl_freq) | 9584 | if (!nl_freq) |
9126 | goto nla_put_failure; | 9585 | goto nla_put_failure; |
9127 | if (nl80211_msg_put_channel(msg, channel_after)) | 9586 | if (nl80211_msg_put_channel(msg, channel_after, false)) |
9128 | goto nla_put_failure; | 9587 | goto nla_put_failure; |
9129 | nla_nest_end(msg, nl_freq); | 9588 | nla_nest_end(msg, nl_freq); |
9130 | 9589 | ||
@@ -9186,31 +9645,42 @@ static void nl80211_send_remain_on_chan_event( | |||
9186 | nlmsg_free(msg); | 9645 | nlmsg_free(msg); |
9187 | } | 9646 | } |
9188 | 9647 | ||
9189 | void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, | 9648 | void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie, |
9190 | struct wireless_dev *wdev, u64 cookie, | 9649 | struct ieee80211_channel *chan, |
9191 | struct ieee80211_channel *chan, | 9650 | unsigned int duration, gfp_t gfp) |
9192 | unsigned int duration, gfp_t gfp) | ||
9193 | { | 9651 | { |
9652 | struct wiphy *wiphy = wdev->wiphy; | ||
9653 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9654 | |||
9655 | trace_cfg80211_ready_on_channel(wdev, cookie, chan, duration); | ||
9194 | nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL, | 9656 | nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL, |
9195 | rdev, wdev, cookie, chan, | 9657 | rdev, wdev, cookie, chan, |
9196 | duration, gfp); | 9658 | duration, gfp); |
9197 | } | 9659 | } |
9660 | EXPORT_SYMBOL(cfg80211_ready_on_channel); | ||
9198 | 9661 | ||
9199 | void nl80211_send_remain_on_channel_cancel( | 9662 | void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie, |
9200 | struct cfg80211_registered_device *rdev, | 9663 | struct ieee80211_channel *chan, |
9201 | struct wireless_dev *wdev, | 9664 | gfp_t gfp) |
9202 | u64 cookie, struct ieee80211_channel *chan, gfp_t gfp) | ||
9203 | { | 9665 | { |
9666 | struct wiphy *wiphy = wdev->wiphy; | ||
9667 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9668 | |||
9669 | trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan); | ||
9204 | nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, | 9670 | nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, |
9205 | rdev, wdev, cookie, chan, 0, gfp); | 9671 | rdev, wdev, cookie, chan, 0, gfp); |
9206 | } | 9672 | } |
9673 | EXPORT_SYMBOL(cfg80211_remain_on_channel_expired); | ||
9207 | 9674 | ||
9208 | void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, | 9675 | void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, |
9209 | struct net_device *dev, const u8 *mac_addr, | 9676 | struct station_info *sinfo, gfp_t gfp) |
9210 | struct station_info *sinfo, gfp_t gfp) | ||
9211 | { | 9677 | { |
9678 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
9679 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9212 | struct sk_buff *msg; | 9680 | struct sk_buff *msg; |
9213 | 9681 | ||
9682 | trace_cfg80211_new_sta(dev, mac_addr, sinfo); | ||
9683 | |||
9214 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | 9684 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
9215 | if (!msg) | 9685 | if (!msg) |
9216 | return; | 9686 | return; |
@@ -9224,14 +9694,17 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, | |||
9224 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 9694 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
9225 | nl80211_mlme_mcgrp.id, gfp); | 9695 | nl80211_mlme_mcgrp.id, gfp); |
9226 | } | 9696 | } |
9697 | EXPORT_SYMBOL(cfg80211_new_sta); | ||
9227 | 9698 | ||
9228 | void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, | 9699 | void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp) |
9229 | struct net_device *dev, const u8 *mac_addr, | ||
9230 | gfp_t gfp) | ||
9231 | { | 9700 | { |
9701 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
9702 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9232 | struct sk_buff *msg; | 9703 | struct sk_buff *msg; |
9233 | void *hdr; | 9704 | void *hdr; |
9234 | 9705 | ||
9706 | trace_cfg80211_del_sta(dev, mac_addr); | ||
9707 | |||
9235 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | 9708 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
9236 | if (!msg) | 9709 | if (!msg) |
9237 | return; | 9710 | return; |
@@ -9256,12 +9729,14 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, | |||
9256 | genlmsg_cancel(msg, hdr); | 9729 | genlmsg_cancel(msg, hdr); |
9257 | nlmsg_free(msg); | 9730 | nlmsg_free(msg); |
9258 | } | 9731 | } |
9732 | EXPORT_SYMBOL(cfg80211_del_sta); | ||
9259 | 9733 | ||
9260 | void nl80211_send_conn_failed_event(struct cfg80211_registered_device *rdev, | 9734 | void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, |
9261 | struct net_device *dev, const u8 *mac_addr, | 9735 | enum nl80211_connect_failed_reason reason, |
9262 | enum nl80211_connect_failed_reason reason, | 9736 | gfp_t gfp) |
9263 | gfp_t gfp) | ||
9264 | { | 9737 | { |
9738 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
9739 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9265 | struct sk_buff *msg; | 9740 | struct sk_buff *msg; |
9266 | void *hdr; | 9741 | void *hdr; |
9267 | 9742 | ||
@@ -9290,6 +9765,7 @@ void nl80211_send_conn_failed_event(struct cfg80211_registered_device *rdev, | |||
9290 | genlmsg_cancel(msg, hdr); | 9765 | genlmsg_cancel(msg, hdr); |
9291 | nlmsg_free(msg); | 9766 | nlmsg_free(msg); |
9292 | } | 9767 | } |
9768 | EXPORT_SYMBOL(cfg80211_conn_failed); | ||
9293 | 9769 | ||
9294 | static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd, | 9770 | static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd, |
9295 | const u8 *addr, gfp_t gfp) | 9771 | const u8 *addr, gfp_t gfp) |
@@ -9334,19 +9810,47 @@ static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd, | |||
9334 | return true; | 9810 | return true; |
9335 | } | 9811 | } |
9336 | 9812 | ||
9337 | bool nl80211_unexpected_frame(struct net_device *dev, const u8 *addr, gfp_t gfp) | 9813 | bool cfg80211_rx_spurious_frame(struct net_device *dev, |
9814 | const u8 *addr, gfp_t gfp) | ||
9338 | { | 9815 | { |
9339 | return __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME, | 9816 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
9340 | addr, gfp); | 9817 | bool ret; |
9818 | |||
9819 | trace_cfg80211_rx_spurious_frame(dev, addr); | ||
9820 | |||
9821 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && | ||
9822 | wdev->iftype != NL80211_IFTYPE_P2P_GO)) { | ||
9823 | trace_cfg80211_return_bool(false); | ||
9824 | return false; | ||
9825 | } | ||
9826 | ret = __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME, | ||
9827 | addr, gfp); | ||
9828 | trace_cfg80211_return_bool(ret); | ||
9829 | return ret; | ||
9341 | } | 9830 | } |
9831 | EXPORT_SYMBOL(cfg80211_rx_spurious_frame); | ||
9342 | 9832 | ||
9343 | bool nl80211_unexpected_4addr_frame(struct net_device *dev, | 9833 | bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev, |
9344 | const u8 *addr, gfp_t gfp) | 9834 | const u8 *addr, gfp_t gfp) |
9345 | { | 9835 | { |
9346 | return __nl80211_unexpected_frame(dev, | 9836 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
9347 | NL80211_CMD_UNEXPECTED_4ADDR_FRAME, | 9837 | bool ret; |
9348 | addr, gfp); | 9838 | |
9839 | trace_cfg80211_rx_unexpected_4addr_frame(dev, addr); | ||
9840 | |||
9841 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && | ||
9842 | wdev->iftype != NL80211_IFTYPE_P2P_GO && | ||
9843 | wdev->iftype != NL80211_IFTYPE_AP_VLAN)) { | ||
9844 | trace_cfg80211_return_bool(false); | ||
9845 | return false; | ||
9846 | } | ||
9847 | ret = __nl80211_unexpected_frame(dev, | ||
9848 | NL80211_CMD_UNEXPECTED_4ADDR_FRAME, | ||
9849 | addr, gfp); | ||
9850 | trace_cfg80211_return_bool(ret); | ||
9851 | return ret; | ||
9349 | } | 9852 | } |
9853 | EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame); | ||
9350 | 9854 | ||
9351 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | 9855 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, |
9352 | struct wireless_dev *wdev, u32 nlportid, | 9856 | struct wireless_dev *wdev, u32 nlportid, |
@@ -9386,15 +9890,17 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | |||
9386 | return -ENOBUFS; | 9890 | return -ENOBUFS; |
9387 | } | 9891 | } |
9388 | 9892 | ||
9389 | void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, | 9893 | void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, |
9390 | struct wireless_dev *wdev, u64 cookie, | 9894 | const u8 *buf, size_t len, bool ack, gfp_t gfp) |
9391 | const u8 *buf, size_t len, bool ack, | ||
9392 | gfp_t gfp) | ||
9393 | { | 9895 | { |
9896 | struct wiphy *wiphy = wdev->wiphy; | ||
9897 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9394 | struct net_device *netdev = wdev->netdev; | 9898 | struct net_device *netdev = wdev->netdev; |
9395 | struct sk_buff *msg; | 9899 | struct sk_buff *msg; |
9396 | void *hdr; | 9900 | void *hdr; |
9397 | 9901 | ||
9902 | trace_cfg80211_mgmt_tx_status(wdev, cookie, ack); | ||
9903 | |||
9398 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | 9904 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
9399 | if (!msg) | 9905 | if (!msg) |
9400 | return; | 9906 | return; |
@@ -9422,17 +9928,21 @@ void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, | |||
9422 | genlmsg_cancel(msg, hdr); | 9928 | genlmsg_cancel(msg, hdr); |
9423 | nlmsg_free(msg); | 9929 | nlmsg_free(msg); |
9424 | } | 9930 | } |
9931 | EXPORT_SYMBOL(cfg80211_mgmt_tx_status); | ||
9425 | 9932 | ||
9426 | void | 9933 | void cfg80211_cqm_rssi_notify(struct net_device *dev, |
9427 | nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, | 9934 | enum nl80211_cqm_rssi_threshold_event rssi_event, |
9428 | struct net_device *netdev, | 9935 | gfp_t gfp) |
9429 | enum nl80211_cqm_rssi_threshold_event rssi_event, | ||
9430 | gfp_t gfp) | ||
9431 | { | 9936 | { |
9937 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
9938 | struct wiphy *wiphy = wdev->wiphy; | ||
9939 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9432 | struct sk_buff *msg; | 9940 | struct sk_buff *msg; |
9433 | struct nlattr *pinfoattr; | 9941 | struct nlattr *pinfoattr; |
9434 | void *hdr; | 9942 | void *hdr; |
9435 | 9943 | ||
9944 | trace_cfg80211_cqm_rssi_notify(dev, rssi_event); | ||
9945 | |||
9436 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | 9946 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
9437 | if (!msg) | 9947 | if (!msg) |
9438 | return; | 9948 | return; |
@@ -9444,7 +9954,7 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, | |||
9444 | } | 9954 | } |
9445 | 9955 | ||
9446 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 9956 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
9447 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex)) | 9957 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex)) |
9448 | goto nla_put_failure; | 9958 | goto nla_put_failure; |
9449 | 9959 | ||
9450 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM); | 9960 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM); |
@@ -9467,10 +9977,11 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, | |||
9467 | genlmsg_cancel(msg, hdr); | 9977 | genlmsg_cancel(msg, hdr); |
9468 | nlmsg_free(msg); | 9978 | nlmsg_free(msg); |
9469 | } | 9979 | } |
9980 | EXPORT_SYMBOL(cfg80211_cqm_rssi_notify); | ||
9470 | 9981 | ||
9471 | void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, | 9982 | static void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, |
9472 | struct net_device *netdev, const u8 *bssid, | 9983 | struct net_device *netdev, const u8 *bssid, |
9473 | const u8 *replay_ctr, gfp_t gfp) | 9984 | const u8 *replay_ctr, gfp_t gfp) |
9474 | { | 9985 | { |
9475 | struct sk_buff *msg; | 9986 | struct sk_buff *msg; |
9476 | struct nlattr *rekey_attr; | 9987 | struct nlattr *rekey_attr; |
@@ -9512,9 +10023,22 @@ void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, | |||
9512 | nlmsg_free(msg); | 10023 | nlmsg_free(msg); |
9513 | } | 10024 | } |
9514 | 10025 | ||
9515 | void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev, | 10026 | void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid, |
9516 | struct net_device *netdev, int index, | 10027 | const u8 *replay_ctr, gfp_t gfp) |
9517 | const u8 *bssid, bool preauth, gfp_t gfp) | 10028 | { |
10029 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
10030 | struct wiphy *wiphy = wdev->wiphy; | ||
10031 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
10032 | |||
10033 | trace_cfg80211_gtk_rekey_notify(dev, bssid); | ||
10034 | nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp); | ||
10035 | } | ||
10036 | EXPORT_SYMBOL(cfg80211_gtk_rekey_notify); | ||
10037 | |||
10038 | static void | ||
10039 | nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev, | ||
10040 | struct net_device *netdev, int index, | ||
10041 | const u8 *bssid, bool preauth, gfp_t gfp) | ||
9518 | { | 10042 | { |
9519 | struct sk_buff *msg; | 10043 | struct sk_buff *msg; |
9520 | struct nlattr *attr; | 10044 | struct nlattr *attr; |
@@ -9557,9 +10081,22 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev, | |||
9557 | nlmsg_free(msg); | 10081 | nlmsg_free(msg); |
9558 | } | 10082 | } |
9559 | 10083 | ||
9560 | void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | 10084 | void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index, |
9561 | struct net_device *netdev, | 10085 | const u8 *bssid, bool preauth, gfp_t gfp) |
9562 | struct cfg80211_chan_def *chandef, gfp_t gfp) | 10086 | { |
10087 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
10088 | struct wiphy *wiphy = wdev->wiphy; | ||
10089 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
10090 | |||
10091 | trace_cfg80211_pmksa_candidate_notify(dev, index, bssid, preauth); | ||
10092 | nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp); | ||
10093 | } | ||
10094 | EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify); | ||
10095 | |||
10096 | static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | ||
10097 | struct net_device *netdev, | ||
10098 | struct cfg80211_chan_def *chandef, | ||
10099 | gfp_t gfp) | ||
9563 | { | 10100 | { |
9564 | struct sk_buff *msg; | 10101 | struct sk_buff *msg; |
9565 | void *hdr; | 10102 | void *hdr; |
@@ -9591,11 +10128,36 @@ void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | |||
9591 | nlmsg_free(msg); | 10128 | nlmsg_free(msg); |
9592 | } | 10129 | } |
9593 | 10130 | ||
9594 | void | 10131 | void cfg80211_ch_switch_notify(struct net_device *dev, |
9595 | nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev, | 10132 | struct cfg80211_chan_def *chandef) |
9596 | struct net_device *netdev, const u8 *peer, | ||
9597 | u32 num_packets, u32 rate, u32 intvl, gfp_t gfp) | ||
9598 | { | 10133 | { |
10134 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
10135 | struct wiphy *wiphy = wdev->wiphy; | ||
10136 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
10137 | |||
10138 | trace_cfg80211_ch_switch_notify(dev, chandef); | ||
10139 | |||
10140 | wdev_lock(wdev); | ||
10141 | |||
10142 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && | ||
10143 | wdev->iftype != NL80211_IFTYPE_P2P_GO)) | ||
10144 | goto out; | ||
10145 | |||
10146 | wdev->channel = chandef->chan; | ||
10147 | nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL); | ||
10148 | out: | ||
10149 | wdev_unlock(wdev); | ||
10150 | return; | ||
10151 | } | ||
10152 | EXPORT_SYMBOL(cfg80211_ch_switch_notify); | ||
10153 | |||
10154 | void cfg80211_cqm_txe_notify(struct net_device *dev, | ||
10155 | const u8 *peer, u32 num_packets, | ||
10156 | u32 rate, u32 intvl, gfp_t gfp) | ||
10157 | { | ||
10158 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
10159 | struct wiphy *wiphy = wdev->wiphy; | ||
10160 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9599 | struct sk_buff *msg; | 10161 | struct sk_buff *msg; |
9600 | struct nlattr *pinfoattr; | 10162 | struct nlattr *pinfoattr; |
9601 | void *hdr; | 10163 | void *hdr; |
@@ -9611,7 +10173,7 @@ nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev, | |||
9611 | } | 10173 | } |
9612 | 10174 | ||
9613 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 10175 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
9614 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | 10176 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || |
9615 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) | 10177 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) |
9616 | goto nla_put_failure; | 10178 | goto nla_put_failure; |
9617 | 10179 | ||
@@ -9640,6 +10202,7 @@ nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev, | |||
9640 | genlmsg_cancel(msg, hdr); | 10202 | genlmsg_cancel(msg, hdr); |
9641 | nlmsg_free(msg); | 10203 | nlmsg_free(msg); |
9642 | } | 10204 | } |
10205 | EXPORT_SYMBOL(cfg80211_cqm_txe_notify); | ||
9643 | 10206 | ||
9644 | void | 10207 | void |
9645 | nl80211_radar_notify(struct cfg80211_registered_device *rdev, | 10208 | nl80211_radar_notify(struct cfg80211_registered_device *rdev, |
@@ -9692,15 +10255,18 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev, | |||
9692 | nlmsg_free(msg); | 10255 | nlmsg_free(msg); |
9693 | } | 10256 | } |
9694 | 10257 | ||
9695 | void | 10258 | void cfg80211_cqm_pktloss_notify(struct net_device *dev, |
9696 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | 10259 | const u8 *peer, u32 num_packets, gfp_t gfp) |
9697 | struct net_device *netdev, const u8 *peer, | ||
9698 | u32 num_packets, gfp_t gfp) | ||
9699 | { | 10260 | { |
10261 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
10262 | struct wiphy *wiphy = wdev->wiphy; | ||
10263 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9700 | struct sk_buff *msg; | 10264 | struct sk_buff *msg; |
9701 | struct nlattr *pinfoattr; | 10265 | struct nlattr *pinfoattr; |
9702 | void *hdr; | 10266 | void *hdr; |
9703 | 10267 | ||
10268 | trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets); | ||
10269 | |||
9704 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | 10270 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
9705 | if (!msg) | 10271 | if (!msg) |
9706 | return; | 10272 | return; |
@@ -9712,7 +10278,7 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | |||
9712 | } | 10278 | } |
9713 | 10279 | ||
9714 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 10280 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
9715 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | 10281 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || |
9716 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) | 10282 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) |
9717 | goto nla_put_failure; | 10283 | goto nla_put_failure; |
9718 | 10284 | ||
@@ -9735,6 +10301,7 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | |||
9735 | genlmsg_cancel(msg, hdr); | 10301 | genlmsg_cancel(msg, hdr); |
9736 | nlmsg_free(msg); | 10302 | nlmsg_free(msg); |
9737 | } | 10303 | } |
10304 | EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify); | ||
9738 | 10305 | ||
9739 | void cfg80211_probe_status(struct net_device *dev, const u8 *addr, | 10306 | void cfg80211_probe_status(struct net_device *dev, const u8 *addr, |
9740 | u64 cookie, bool acked, gfp_t gfp) | 10307 | u64 cookie, bool acked, gfp_t gfp) |
@@ -10021,6 +10588,50 @@ static struct notifier_block nl80211_netlink_notifier = { | |||
10021 | .notifier_call = nl80211_netlink_notify, | 10588 | .notifier_call = nl80211_netlink_notify, |
10022 | }; | 10589 | }; |
10023 | 10590 | ||
10591 | void cfg80211_ft_event(struct net_device *netdev, | ||
10592 | struct cfg80211_ft_event_params *ft_event) | ||
10593 | { | ||
10594 | struct wiphy *wiphy = netdev->ieee80211_ptr->wiphy; | ||
10595 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
10596 | struct sk_buff *msg; | ||
10597 | void *hdr; | ||
10598 | int err; | ||
10599 | |||
10600 | trace_cfg80211_ft_event(wiphy, netdev, ft_event); | ||
10601 | |||
10602 | if (!ft_event->target_ap) | ||
10603 | return; | ||
10604 | |||
10605 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
10606 | if (!msg) | ||
10607 | return; | ||
10608 | |||
10609 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FT_EVENT); | ||
10610 | if (!hdr) { | ||
10611 | nlmsg_free(msg); | ||
10612 | return; | ||
10613 | } | ||
10614 | |||
10615 | nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
10616 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
10617 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, ft_event->target_ap); | ||
10618 | if (ft_event->ies) | ||
10619 | nla_put(msg, NL80211_ATTR_IE, ft_event->ies_len, ft_event->ies); | ||
10620 | if (ft_event->ric_ies) | ||
10621 | nla_put(msg, NL80211_ATTR_IE_RIC, ft_event->ric_ies_len, | ||
10622 | ft_event->ric_ies); | ||
10623 | |||
10624 | err = genlmsg_end(msg, hdr); | ||
10625 | if (err < 0) { | ||
10626 | nlmsg_free(msg); | ||
10627 | return; | ||
10628 | } | ||
10629 | |||
10630 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
10631 | nl80211_mlme_mcgrp.id, GFP_KERNEL); | ||
10632 | } | ||
10633 | EXPORT_SYMBOL(cfg80211_ft_event); | ||
10634 | |||
10024 | /* initialisation/exit functions */ | 10635 | /* initialisation/exit functions */ |
10025 | 10636 | ||
10026 | int nl80211_init(void) | 10637 | 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..d77e1c1d3a0e 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 | } |
@@ -887,4 +888,17 @@ 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 | |||
890 | #endif /* __CFG80211_RDEV_OPS */ | 904 | #endif /* __CFG80211_RDEV_OPS */ |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 98532c00242d..e6df52dc8c69 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 | ||
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 09d994d192ff..818ad637819a 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -160,7 +160,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
160 | { | 160 | { |
161 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 161 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
162 | struct cfg80211_connect_params *params; | 162 | struct cfg80211_connect_params *params; |
163 | const u8 *prev_bssid = NULL; | 163 | struct cfg80211_assoc_request req = {}; |
164 | int err; | 164 | int err; |
165 | 165 | ||
166 | ASSERT_WDEV_LOCK(wdev); | 166 | ASSERT_WDEV_LOCK(wdev); |
@@ -187,16 +187,20 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
187 | BUG_ON(!rdev->ops->assoc); | 187 | BUG_ON(!rdev->ops->assoc); |
188 | wdev->conn->state = CFG80211_CONN_ASSOCIATING; | 188 | wdev->conn->state = CFG80211_CONN_ASSOCIATING; |
189 | if (wdev->conn->prev_bssid_valid) | 189 | if (wdev->conn->prev_bssid_valid) |
190 | prev_bssid = wdev->conn->prev_bssid; | 190 | req.prev_bssid = wdev->conn->prev_bssid; |
191 | err = __cfg80211_mlme_assoc(rdev, wdev->netdev, | 191 | req.ie = params->ie; |
192 | params->channel, params->bssid, | 192 | req.ie_len = params->ie_len; |
193 | prev_bssid, | 193 | req.use_mfp = params->mfp != NL80211_MFP_NO; |
194 | params->ssid, params->ssid_len, | 194 | req.crypto = params->crypto; |
195 | params->ie, params->ie_len, | 195 | req.flags = params->flags; |
196 | params->mfp != NL80211_MFP_NO, | 196 | req.ht_capa = params->ht_capa; |
197 | ¶ms->crypto, | 197 | req.ht_capa_mask = params->ht_capa_mask; |
198 | params->flags, ¶ms->ht_capa, | 198 | req.vht_capa = params->vht_capa; |
199 | ¶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); | ||
200 | if (err) | 204 | if (err) |
201 | __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, | 205 | __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, |
202 | NULL, 0, | 206 | NULL, 0, |
@@ -231,7 +235,7 @@ void cfg80211_conn_work(struct work_struct *work) | |||
231 | wdev_unlock(wdev); | 235 | wdev_unlock(wdev); |
232 | continue; | 236 | continue; |
233 | } | 237 | } |
234 | if (wdev->sme_state != CFG80211_SME_CONNECTING) { | 238 | if (wdev->sme_state != CFG80211_SME_CONNECTING || !wdev->conn) { |
235 | wdev_unlock(wdev); | 239 | wdev_unlock(wdev); |
236 | continue; | 240 | continue; |
237 | } | 241 | } |
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 7586de77a2f8..3c2033b8f596 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
@@ -1786,6 +1786,26 @@ TRACE_EVENT(rdev_set_mac_acl, | |||
1786 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->acl_policy) | 1786 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->acl_policy) |
1787 | ); | 1787 | ); |
1788 | 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 | |||
1789 | /************************************************************* | 1809 | /************************************************************* |
1790 | * cfg80211 exported functions traces * | 1810 | * cfg80211 exported functions traces * |
1791 | *************************************************************/ | 1811 | *************************************************************/ |
@@ -2414,6 +2434,32 @@ TRACE_EVENT(cfg80211_report_wowlan_wakeup, | |||
2414 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG) | 2434 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG) |
2415 | ); | 2435 | ); |
2416 | 2436 | ||
2437 | TRACE_EVENT(cfg80211_ft_event, | ||
2438 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, | ||
2439 | struct cfg80211_ft_event_params *ft_event), | ||
2440 | TP_ARGS(wiphy, netdev, ft_event), | ||
2441 | TP_STRUCT__entry( | ||
2442 | WIPHY_ENTRY | ||
2443 | NETDEV_ENTRY | ||
2444 | __dynamic_array(u8, ies, ft_event->ies_len) | ||
2445 | MAC_ENTRY(target_ap) | ||
2446 | __dynamic_array(u8, ric_ies, ft_event->ric_ies_len) | ||
2447 | ), | ||
2448 | TP_fast_assign( | ||
2449 | WIPHY_ASSIGN; | ||
2450 | NETDEV_ASSIGN; | ||
2451 | if (ft_event->ies) | ||
2452 | memcpy(__get_dynamic_array(ies), ft_event->ies, | ||
2453 | ft_event->ies_len); | ||
2454 | MAC_ASSIGN(target_ap, ft_event->target_ap); | ||
2455 | if (ft_event->ric_ies) | ||
2456 | memcpy(__get_dynamic_array(ric_ies), ft_event->ric_ies, | ||
2457 | ft_event->ric_ies_len); | ||
2458 | ), | ||
2459 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", target_ap: " MAC_PR_FMT, | ||
2460 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(target_ap)) | ||
2461 | ); | ||
2462 | |||
2417 | #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ | 2463 | #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ |
2418 | 2464 | ||
2419 | #undef TRACE_INCLUDE_PATH | 2465 | #undef TRACE_INCLUDE_PATH |