~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/wireless/mlme.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  * cfg80211 MLME SAP interface
  4  *
  5  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  6  * Copyright (c) 2015           Intel Deutschland GmbH
  7  * Copyright (C) 2019-2020, 2022-2024 Intel Corporation
  8  */
  9 
 10 #include <linux/kernel.h>
 11 #include <linux/module.h>
 12 #include <linux/etherdevice.h>
 13 #include <linux/netdevice.h>
 14 #include <linux/nl80211.h>
 15 #include <linux/slab.h>
 16 #include <linux/wireless.h>
 17 #include <net/cfg80211.h>
 18 #include <net/iw_handler.h>
 19 #include "core.h"
 20 #include "nl80211.h"
 21 #include "rdev-ops.h"
 22 
 23 
 24 void cfg80211_rx_assoc_resp(struct net_device *dev,
 25                             const struct cfg80211_rx_assoc_resp_data *data)
 26 {
 27         struct wireless_dev *wdev = dev->ieee80211_ptr;
 28         struct wiphy *wiphy = wdev->wiphy;
 29         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
 30         struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)data->buf;
 31         struct cfg80211_connect_resp_params cr = {
 32                 .timeout_reason = NL80211_TIMEOUT_UNSPECIFIED,
 33                 .req_ie = data->req_ies,
 34                 .req_ie_len = data->req_ies_len,
 35                 .resp_ie = mgmt->u.assoc_resp.variable,
 36                 .resp_ie_len = data->len -
 37                                offsetof(struct ieee80211_mgmt,
 38                                         u.assoc_resp.variable),
 39                 .status = le16_to_cpu(mgmt->u.assoc_resp.status_code),
 40                 .ap_mld_addr = data->ap_mld_addr,
 41         };
 42         unsigned int link_id;
 43 
 44         for (link_id = 0; link_id < ARRAY_SIZE(data->links); link_id++) {
 45                 cr.links[link_id].status = data->links[link_id].status;
 46                 cr.links[link_id].bss = data->links[link_id].bss;
 47 
 48                 WARN_ON_ONCE(cr.links[link_id].status != WLAN_STATUS_SUCCESS &&
 49                              (!cr.ap_mld_addr || !cr.links[link_id].bss));
 50 
 51                 if (!cr.links[link_id].bss)
 52                         continue;
 53                 cr.links[link_id].bssid = data->links[link_id].bss->bssid;
 54                 cr.links[link_id].addr = data->links[link_id].addr;
 55                 /* need to have local link addresses for MLO connections */
 56                 WARN_ON(cr.ap_mld_addr &&
 57                         !is_valid_ether_addr(cr.links[link_id].addr));
 58 
 59                 BUG_ON(!cr.links[link_id].bss->channel);
 60 
 61                 if (cr.links[link_id].bss->channel->band == NL80211_BAND_S1GHZ) {
 62                         WARN_ON(link_id);
 63                         cr.resp_ie = (u8 *)&mgmt->u.s1g_assoc_resp.variable;
 64                         cr.resp_ie_len = data->len -
 65                                          offsetof(struct ieee80211_mgmt,
 66                                                   u.s1g_assoc_resp.variable);
 67                 }
 68 
 69                 if (cr.ap_mld_addr)
 70                         cr.valid_links |= BIT(link_id);
 71         }
 72 
 73         trace_cfg80211_send_rx_assoc(dev, data);
 74 
 75         /*
 76          * This is a bit of a hack, we don't notify userspace of
 77          * a (re-)association reply if we tried to send a reassoc
 78          * and got a reject -- we only try again with an assoc
 79          * frame instead of reassoc.
 80          */
 81         if (cfg80211_sme_rx_assoc_resp(wdev, cr.status)) {
 82                 for (link_id = 0; link_id < ARRAY_SIZE(data->links); link_id++) {
 83                         struct cfg80211_bss *bss = data->links[link_id].bss;
 84 
 85                         if (!bss)
 86                                 continue;
 87 
 88                         cfg80211_unhold_bss(bss_from_pub(bss));
 89                         cfg80211_put_bss(wiphy, bss);
 90                 }
 91                 return;
 92         }
 93 
 94         nl80211_send_rx_assoc(rdev, dev, data);
 95         /* update current_bss etc., consumes the bss reference */
 96         __cfg80211_connect_result(dev, &cr, cr.status == WLAN_STATUS_SUCCESS);
 97 }
 98 EXPORT_SYMBOL(cfg80211_rx_assoc_resp);
 99 
100 static void cfg80211_process_auth(struct wireless_dev *wdev,
101                                   const u8 *buf, size_t len)
102 {
103         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
104 
105         nl80211_send_rx_auth(rdev, wdev->netdev, buf, len, GFP_KERNEL);
106         cfg80211_sme_rx_auth(wdev, buf, len);
107 }
108 
109 static void cfg80211_process_deauth(struct wireless_dev *wdev,
110                                     const u8 *buf, size_t len,
111                                     bool reconnect)
112 {
113         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
114         struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
115         const u8 *bssid = mgmt->bssid;
116         u16 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
117         bool from_ap = !ether_addr_equal(mgmt->sa, wdev->netdev->dev_addr);
118 
119         nl80211_send_deauth(rdev, wdev->netdev, buf, len, reconnect, GFP_KERNEL);
120 
121         if (!wdev->connected || !ether_addr_equal(wdev->u.client.connected_addr, bssid))
122                 return;
123 
124         __cfg80211_disconnected(wdev->netdev, NULL, 0, reason_code, from_ap);
125         cfg80211_sme_deauth(wdev);
126 }
127 
128 static void cfg80211_process_disassoc(struct wireless_dev *wdev,
129                                       const u8 *buf, size_t len,
130                                       bool reconnect)
131 {
132         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
133         struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
134         const u8 *bssid = mgmt->bssid;
135         u16 reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
136         bool from_ap = !ether_addr_equal(mgmt->sa, wdev->netdev->dev_addr);
137 
138         nl80211_send_disassoc(rdev, wdev->netdev, buf, len, reconnect,
139                               GFP_KERNEL);
140 
141         if (WARN_ON(!wdev->connected ||
142                     !ether_addr_equal(wdev->u.client.connected_addr, bssid)))
143                 return;
144 
145         __cfg80211_disconnected(wdev->netdev, NULL, 0, reason_code, from_ap);
146         cfg80211_sme_disassoc(wdev);
147 }
148 
149 void cfg80211_rx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len)
150 {
151         struct wireless_dev *wdev = dev->ieee80211_ptr;
152         struct ieee80211_mgmt *mgmt = (void *)buf;
153 
154         lockdep_assert_wiphy(wdev->wiphy);
155 
156         trace_cfg80211_rx_mlme_mgmt(dev, buf, len);
157 
158         if (WARN_ON(len < 2))
159                 return;
160 
161         if (ieee80211_is_auth(mgmt->frame_control))
162                 cfg80211_process_auth(wdev, buf, len);
163         else if (ieee80211_is_deauth(mgmt->frame_control))
164                 cfg80211_process_deauth(wdev, buf, len, false);
165         else if (ieee80211_is_disassoc(mgmt->frame_control))
166                 cfg80211_process_disassoc(wdev, buf, len, false);
167 }
168 EXPORT_SYMBOL(cfg80211_rx_mlme_mgmt);
169 
170 void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr)
171 {
172         struct wireless_dev *wdev = dev->ieee80211_ptr;
173         struct wiphy *wiphy = wdev->wiphy;
174         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
175 
176         trace_cfg80211_send_auth_timeout(dev, addr);
177 
178         nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL);
179         cfg80211_sme_auth_timeout(wdev);
180 }
181 EXPORT_SYMBOL(cfg80211_auth_timeout);
182 
183 void cfg80211_assoc_failure(struct net_device *dev,
184                             struct cfg80211_assoc_failure *data)
185 {
186         struct wireless_dev *wdev = dev->ieee80211_ptr;
187         struct wiphy *wiphy = wdev->wiphy;
188         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
189         const u8 *addr = data->ap_mld_addr ?: data->bss[0]->bssid;
190         int i;
191 
192         trace_cfg80211_send_assoc_failure(dev, data);
193 
194         if (data->timeout) {
195                 nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL);
196                 cfg80211_sme_assoc_timeout(wdev);
197         } else {
198                 cfg80211_sme_abandon_assoc(wdev);
199         }
200 
201         for (i = 0; i < ARRAY_SIZE(data->bss); i++) {
202                 struct cfg80211_bss *bss = data->bss[i];
203 
204                 if (!bss)
205                         continue;
206 
207                 cfg80211_unhold_bss(bss_from_pub(bss));
208                 cfg80211_put_bss(wiphy, bss);
209         }
210 }
211 EXPORT_SYMBOL(cfg80211_assoc_failure);
212 
213 void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len,
214                            bool reconnect)
215 {
216         struct wireless_dev *wdev = dev->ieee80211_ptr;
217         struct ieee80211_mgmt *mgmt = (void *)buf;
218 
219         lockdep_assert_wiphy(wdev->wiphy);
220 
221         trace_cfg80211_tx_mlme_mgmt(dev, buf, len, reconnect);
222 
223         if (WARN_ON(len < 2))
224                 return;
225 
226         if (ieee80211_is_deauth(mgmt->frame_control))
227                 cfg80211_process_deauth(wdev, buf, len, reconnect);
228         else
229                 cfg80211_process_disassoc(wdev, buf, len, reconnect);
230 }
231 EXPORT_SYMBOL(cfg80211_tx_mlme_mgmt);
232 
233 void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
234                                   enum nl80211_key_type key_type, int key_id,
235                                   const u8 *tsc, gfp_t gfp)
236 {
237         struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
238         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
239 #ifdef CONFIG_CFG80211_WEXT
240         union iwreq_data wrqu;
241         char *buf = kmalloc(128, gfp);
242 
243         if (buf) {
244                 memset(&wrqu, 0, sizeof(wrqu));
245                 wrqu.data.length =
246                         sprintf(buf, "MLME-MICHAELMICFAILURE."
247                                 "indication(keyid=%d %scast addr=%pM)",
248                                 key_id, key_type == NL80211_KEYTYPE_GROUP
249                                 ? "broad" : "uni", addr);
250                 wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
251                 kfree(buf);
252         }
253 #endif
254 
255         trace_cfg80211_michael_mic_failure(dev, addr, key_type, key_id, tsc);
256         nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp);
257 }
258 EXPORT_SYMBOL(cfg80211_michael_mic_failure);
259 
260 /* some MLME handling for userspace SME */
261 int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
262                        struct net_device *dev,
263                        struct cfg80211_auth_request *req)
264 {
265         struct wireless_dev *wdev = dev->ieee80211_ptr;
266 
267         lockdep_assert_wiphy(wdev->wiphy);
268 
269         if (!req->bss)
270                 return -ENOENT;
271 
272         if (req->link_id >= 0 &&
273             !(wdev->wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO))
274                 return -EINVAL;
275 
276         if (req->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
277                 if (!req->key || !req->key_len ||
278                     req->key_idx < 0 || req->key_idx > 3)
279                         return -EINVAL;
280         }
281 
282         if (wdev->connected &&
283             ether_addr_equal(req->bss->bssid, wdev->u.client.connected_addr))
284                 return -EALREADY;
285 
286         if (ether_addr_equal(req->bss->bssid, dev->dev_addr) ||
287             (req->link_id >= 0 &&
288              ether_addr_equal(req->ap_mld_addr, dev->dev_addr)))
289                 return -EINVAL;
290 
291         return rdev_auth(rdev, dev, req);
292 }
293 
294 /*  Do a logical ht_capa &= ht_capa_mask.  */
295 void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa,
296                                const struct ieee80211_ht_cap *ht_capa_mask)
297 {
298         int i;
299         u8 *p1, *p2;
300         if (!ht_capa_mask) {
301                 memset(ht_capa, 0, sizeof(*ht_capa));
302                 return;
303         }
304 
305         p1 = (u8*)(ht_capa);
306         p2 = (u8*)(ht_capa_mask);
307         for (i = 0; i < sizeof(*ht_capa); i++)
308                 p1[i] &= p2[i];
309 }
310 
311 /*  Do a logical vht_capa &= vht_capa_mask.  */
312 void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa,
313                                 const struct ieee80211_vht_cap *vht_capa_mask)
314 {
315         int i;
316         u8 *p1, *p2;
317         if (!vht_capa_mask) {
318                 memset(vht_capa, 0, sizeof(*vht_capa));
319                 return;
320         }
321 
322         p1 = (u8*)(vht_capa);
323         p2 = (u8*)(vht_capa_mask);
324         for (i = 0; i < sizeof(*vht_capa); i++)
325                 p1[i] &= p2[i];
326 }
327 
328 static int
329 cfg80211_mlme_check_mlo_compat(const struct ieee80211_multi_link_elem *mle_a,
330                                const struct ieee80211_multi_link_elem *mle_b,
331                                struct netlink_ext_ack *extack)
332 {
333         const struct ieee80211_mle_basic_common_info *common_a, *common_b;
334 
335         common_a = (const void *)mle_a->variable;
336         common_b = (const void *)mle_b->variable;
337 
338         if (memcmp(common_a->mld_mac_addr, common_b->mld_mac_addr, ETH_ALEN)) {
339                 NL_SET_ERR_MSG(extack, "AP MLD address mismatch");
340                 return -EINVAL;
341         }
342 
343         if (ieee80211_mle_get_eml_med_sync_delay((const u8 *)mle_a) !=
344             ieee80211_mle_get_eml_med_sync_delay((const u8 *)mle_b)) {
345                 NL_SET_ERR_MSG(extack, "link EML medium sync delay mismatch");
346                 return -EINVAL;
347         }
348 
349         if (ieee80211_mle_get_eml_cap((const u8 *)mle_a) !=
350             ieee80211_mle_get_eml_cap((const u8 *)mle_b)) {
351                 NL_SET_ERR_MSG(extack, "link EML capabilities mismatch");
352                 return -EINVAL;
353         }
354 
355         if (ieee80211_mle_get_mld_capa_op((const u8 *)mle_a) !=
356             ieee80211_mle_get_mld_capa_op((const u8 *)mle_b)) {
357                 NL_SET_ERR_MSG(extack, "link MLD capabilities/ops mismatch");
358                 return -EINVAL;
359         }
360 
361         return 0;
362 }
363 
364 static int cfg80211_mlme_check_mlo(struct net_device *dev,
365                                    struct cfg80211_assoc_request *req,
366                                    struct netlink_ext_ack *extack)
367 {
368         const struct ieee80211_multi_link_elem *mles[ARRAY_SIZE(req->links)] = {};
369         int i;
370 
371         if (req->link_id < 0)
372                 return 0;
373 
374         if (!req->links[req->link_id].bss) {
375                 NL_SET_ERR_MSG(extack, "no BSS for assoc link");
376                 return -EINVAL;
377         }
378 
379         rcu_read_lock();
380         for (i = 0; i < ARRAY_SIZE(req->links); i++) {
381                 const struct cfg80211_bss_ies *ies;
382                 const struct element *ml;
383 
384                 if (!req->links[i].bss)
385                         continue;
386 
387                 if (ether_addr_equal(req->links[i].bss->bssid, dev->dev_addr)) {
388                         NL_SET_ERR_MSG(extack, "BSSID must not be our address");
389                         req->links[i].error = -EINVAL;
390                         goto error;
391                 }
392 
393                 ies = rcu_dereference(req->links[i].bss->ies);
394                 ml = cfg80211_find_ext_elem(WLAN_EID_EXT_EHT_MULTI_LINK,
395                                             ies->data, ies->len);
396                 if (!ml) {
397                         NL_SET_ERR_MSG(extack, "MLO BSS w/o ML element");
398                         req->links[i].error = -EINVAL;
399                         goto error;
400                 }
401 
402                 if (!ieee80211_mle_type_ok(ml->data + 1,
403                                            IEEE80211_ML_CONTROL_TYPE_BASIC,
404                                            ml->datalen - 1)) {
405                         NL_SET_ERR_MSG(extack, "BSS with invalid ML element");
406                         req->links[i].error = -EINVAL;
407                         goto error;
408                 }
409 
410                 mles[i] = (const void *)(ml->data + 1);
411 
412                 if (ieee80211_mle_get_link_id((const u8 *)mles[i]) != i) {
413                         NL_SET_ERR_MSG(extack, "link ID mismatch");
414                         req->links[i].error = -EINVAL;
415                         goto error;
416                 }
417         }
418 
419         if (WARN_ON(!mles[req->link_id]))
420                 goto error;
421 
422         for (i = 0; i < ARRAY_SIZE(req->links); i++) {
423                 if (i == req->link_id || !req->links[i].bss)
424                         continue;
425 
426                 if (WARN_ON(!mles[i]))
427                         goto error;
428 
429                 if (cfg80211_mlme_check_mlo_compat(mles[req->link_id], mles[i],
430                                                    extack)) {
431                         req->links[i].error = -EINVAL;
432                         goto error;
433                 }
434         }
435 
436         rcu_read_unlock();
437         return 0;
438 error:
439         rcu_read_unlock();
440         return -EINVAL;
441 }
442 
443 /* Note: caller must cfg80211_put_bss() regardless of result */
444 int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
445                         struct net_device *dev,
446                         struct cfg80211_assoc_request *req,
447                         struct netlink_ext_ack *extack)
448 {
449         struct wireless_dev *wdev = dev->ieee80211_ptr;
450         int err;
451 
452         lockdep_assert_wiphy(wdev->wiphy);
453 
454         err = cfg80211_mlme_check_mlo(dev, req, extack);
455         if (err)
456                 return err;
457 
458         if (wdev->connected &&
459             (!req->prev_bssid ||
460              !ether_addr_equal(wdev->u.client.connected_addr, req->prev_bssid)))
461                 return -EALREADY;
462 
463         if ((req->bss && ether_addr_equal(req->bss->bssid, dev->dev_addr)) ||
464             (req->link_id >= 0 &&
465              ether_addr_equal(req->ap_mld_addr, dev->dev_addr)))
466                 return -EINVAL;
467 
468         cfg80211_oper_and_ht_capa(&req->ht_capa_mask,
469                                   rdev->wiphy.ht_capa_mod_mask);
470         cfg80211_oper_and_vht_capa(&req->vht_capa_mask,
471                                    rdev->wiphy.vht_capa_mod_mask);
472 
473         err = rdev_assoc(rdev, dev, req);
474         if (!err) {
475                 int link_id;
476 
477                 if (req->bss) {
478                         cfg80211_ref_bss(&rdev->wiphy, req->bss);
479                         cfg80211_hold_bss(bss_from_pub(req->bss));
480                 }
481 
482                 for (link_id = 0; link_id < ARRAY_SIZE(req->links); link_id++) {
483                         if (!req->links[link_id].bss)
484                                 continue;
485                         cfg80211_ref_bss(&rdev->wiphy, req->links[link_id].bss);
486                         cfg80211_hold_bss(bss_from_pub(req->links[link_id].bss));
487                 }
488         }
489         return err;
490 }
491 
492 int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
493                          struct net_device *dev, const u8 *bssid,
494                          const u8 *ie, int ie_len, u16 reason,
495                          bool local_state_change)
496 {
497         struct wireless_dev *wdev = dev->ieee80211_ptr;
498         struct cfg80211_deauth_request req = {
499                 .bssid = bssid,
500                 .reason_code = reason,
501                 .ie = ie,
502                 .ie_len = ie_len,
503                 .local_state_change = local_state_change,
504         };
505 
506         lockdep_assert_wiphy(wdev->wiphy);
507 
508         if (local_state_change &&
509             (!wdev->connected ||
510              !ether_addr_equal(wdev->u.client.connected_addr, bssid)))
511                 return 0;
512 
513         if (ether_addr_equal(wdev->disconnect_bssid, bssid) ||
514             (wdev->connected &&
515              ether_addr_equal(wdev->u.client.connected_addr, bssid)))
516                 wdev->conn_owner_nlportid = 0;
517 
518         return rdev_deauth(rdev, dev, &req);
519 }
520 
521 int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
522                            struct net_device *dev, const u8 *ap_addr,
523                            const u8 *ie, int ie_len, u16 reason,
524                            bool local_state_change)
525 {
526         struct wireless_dev *wdev = dev->ieee80211_ptr;
527         struct cfg80211_disassoc_request req = {
528                 .reason_code = reason,
529                 .local_state_change = local_state_change,
530                 .ie = ie,
531                 .ie_len = ie_len,
532                 .ap_addr = ap_addr,
533         };
534         int err;
535 
536         lockdep_assert_wiphy(wdev->wiphy);
537 
538         if (!wdev->connected)
539                 return -ENOTCONN;
540 
541         if (memcmp(wdev->u.client.connected_addr, ap_addr, ETH_ALEN))
542                 return -ENOTCONN;
543 
544         err = rdev_disassoc(rdev, dev, &req);
545         if (err)
546                 return err;
547 
548         /* driver should have reported the disassoc */
549         WARN_ON(wdev->connected);
550         return 0;
551 }
552 
553 void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
554                         struct net_device *dev)
555 {
556         struct wireless_dev *wdev = dev->ieee80211_ptr;
557         u8 bssid[ETH_ALEN];
558 
559         lockdep_assert_wiphy(wdev->wiphy);
560 
561         if (!rdev->ops->deauth)
562                 return;
563 
564         if (!wdev->connected)
565                 return;
566 
567         memcpy(bssid, wdev->u.client.connected_addr, ETH_ALEN);
568         cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0,
569                              WLAN_REASON_DEAUTH_LEAVING, false);
570 }
571 
572 struct cfg80211_mgmt_registration {
573         struct list_head list;
574         struct wireless_dev *wdev;
575 
576         u32 nlportid;
577 
578         int match_len;
579 
580         __le16 frame_type;
581 
582         bool multicast_rx;
583 
584         u8 match[];
585 };
586 
587 static void cfg80211_mgmt_registrations_update(struct wireless_dev *wdev)
588 {
589         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
590         struct wireless_dev *tmp;
591         struct cfg80211_mgmt_registration *reg;
592         struct mgmt_frame_regs upd = {};
593 
594         lockdep_assert_held(&rdev->wiphy.mtx);
595 
596         spin_lock_bh(&rdev->mgmt_registrations_lock);
597         if (!wdev->mgmt_registrations_need_update) {
598                 spin_unlock_bh(&rdev->mgmt_registrations_lock);
599                 return;
600         }
601 
602         rcu_read_lock();
603         list_for_each_entry_rcu(tmp, &rdev->wiphy.wdev_list, list) {
604                 list_for_each_entry(reg, &tmp->mgmt_registrations, list) {
605                         u32 mask = BIT(le16_to_cpu(reg->frame_type) >> 4);
606                         u32 mcast_mask = 0;
607 
608                         if (reg->multicast_rx)
609                                 mcast_mask = mask;
610 
611                         upd.global_stypes |= mask;
612                         upd.global_mcast_stypes |= mcast_mask;
613 
614                         if (tmp == wdev) {
615                                 upd.interface_stypes |= mask;
616                                 upd.interface_mcast_stypes |= mcast_mask;
617                         }
618                 }
619         }
620         rcu_read_unlock();
621 
622         wdev->mgmt_registrations_need_update = 0;
623         spin_unlock_bh(&rdev->mgmt_registrations_lock);
624 
625         rdev_update_mgmt_frame_registrations(rdev, wdev, &upd);
626 }
627 
628 void cfg80211_mgmt_registrations_update_wk(struct work_struct *wk)
629 {
630         struct cfg80211_registered_device *rdev;
631         struct wireless_dev *wdev;
632 
633         rdev = container_of(wk, struct cfg80211_registered_device,
634                             mgmt_registrations_update_wk);
635 
636         wiphy_lock(&rdev->wiphy);
637         list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list)
638                 cfg80211_mgmt_registrations_update(wdev);
639         wiphy_unlock(&rdev->wiphy);
640 }
641 
642 int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid,
643                                 u16 frame_type, const u8 *match_data,
644                                 int match_len, bool multicast_rx,
645                                 struct netlink_ext_ack *extack)
646 {
647         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
648         struct cfg80211_mgmt_registration *reg, *nreg;
649         int err = 0;
650         u16 mgmt_type;
651         bool update_multicast = false;
652 
653         if (!wdev->wiphy->mgmt_stypes)
654                 return -EOPNOTSUPP;
655 
656         if ((frame_type & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT) {
657                 NL_SET_ERR_MSG(extack, "frame type not management");
658                 return -EINVAL;
659         }
660 
661         if (frame_type & ~(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) {
662                 NL_SET_ERR_MSG(extack, "Invalid frame type");
663                 return -EINVAL;
664         }
665 
666         mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
667         if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].rx & BIT(mgmt_type))) {
668                 NL_SET_ERR_MSG(extack,
669                                "Registration to specific type not supported");
670                 return -EINVAL;
671         }
672 
673         /*
674          * To support Pre Association Security Negotiation (PASN), registration
675          * for authentication frames should be supported. However, as some
676          * versions of the user space daemons wrongly register to all types of
677          * authentication frames (which might result in unexpected behavior)
678          * allow such registration if the request is for a specific
679          * authentication algorithm number.
680          */
681         if (wdev->iftype == NL80211_IFTYPE_STATION &&
682             (frame_type & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_AUTH &&
683             !(match_data && match_len >= 2)) {
684                 NL_SET_ERR_MSG(extack,
685                                "Authentication algorithm number required");
686                 return -EINVAL;
687         }
688 
689         nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL);
690         if (!nreg)
691                 return -ENOMEM;
692 
693         spin_lock_bh(&rdev->mgmt_registrations_lock);
694 
695         list_for_each_entry(reg, &wdev->mgmt_registrations, list) {
696                 int mlen = min(match_len, reg->match_len);
697 
698                 if (frame_type != le16_to_cpu(reg->frame_type))
699                         continue;
700 
701                 if (memcmp(reg->match, match_data, mlen) == 0) {
702                         if (reg->multicast_rx != multicast_rx) {
703                                 update_multicast = true;
704                                 reg->multicast_rx = multicast_rx;
705                                 break;
706                         }
707                         NL_SET_ERR_MSG(extack, "Match already configured");
708                         err = -EALREADY;
709                         break;
710                 }
711         }
712 
713         if (err)
714                 goto out;
715 
716         if (update_multicast) {
717                 kfree(nreg);
718         } else {
719                 memcpy(nreg->match, match_data, match_len);
720                 nreg->match_len = match_len;
721                 nreg->nlportid = snd_portid;
722                 nreg->frame_type = cpu_to_le16(frame_type);
723                 nreg->wdev = wdev;
724                 nreg->multicast_rx = multicast_rx;
725                 list_add(&nreg->list, &wdev->mgmt_registrations);
726         }
727         wdev->mgmt_registrations_need_update = 1;
728         spin_unlock_bh(&rdev->mgmt_registrations_lock);
729 
730         cfg80211_mgmt_registrations_update(wdev);
731 
732         return 0;
733 
734  out:
735         kfree(nreg);
736         spin_unlock_bh(&rdev->mgmt_registrations_lock);
737 
738         return err;
739 }
740 
741 void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid)
742 {
743         struct wiphy *wiphy = wdev->wiphy;
744         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
745         struct cfg80211_mgmt_registration *reg, *tmp;
746 
747         spin_lock_bh(&rdev->mgmt_registrations_lock);
748 
749         list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) {
750                 if (reg->nlportid != nlportid)
751                         continue;
752 
753                 list_del(&reg->list);
754                 kfree(reg);
755 
756                 wdev->mgmt_registrations_need_update = 1;
757                 schedule_work(&rdev->mgmt_registrations_update_wk);
758         }
759 
760         spin_unlock_bh(&rdev->mgmt_registrations_lock);
761 
762         if (nlportid && rdev->crit_proto_nlportid == nlportid) {
763                 rdev->crit_proto_nlportid = 0;
764                 rdev_crit_proto_stop(rdev, wdev);
765         }
766 
767         if (nlportid == wdev->ap_unexpected_nlportid)
768                 wdev->ap_unexpected_nlportid = 0;
769 }
770 
771 void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev)
772 {
773         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
774         struct cfg80211_mgmt_registration *reg, *tmp;
775 
776         spin_lock_bh(&rdev->mgmt_registrations_lock);
777         list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) {
778                 list_del(&reg->list);
779                 kfree(reg);
780         }
781         wdev->mgmt_registrations_need_update = 1;
782         spin_unlock_bh(&rdev->mgmt_registrations_lock);
783 
784         cfg80211_mgmt_registrations_update(wdev);
785 }
786 
787 static bool cfg80211_allowed_address(struct wireless_dev *wdev, const u8 *addr)
788 {
789         int i;
790 
791         for_each_valid_link(wdev, i) {
792                 if (ether_addr_equal(addr, wdev->links[i].addr))
793                         return true;
794         }
795 
796         return ether_addr_equal(addr, wdev_address(wdev));
797 }
798 
799 static bool cfg80211_allowed_random_address(struct wireless_dev *wdev,
800                                             const struct ieee80211_mgmt *mgmt)
801 {
802         if (ieee80211_is_auth(mgmt->frame_control) ||
803             ieee80211_is_deauth(mgmt->frame_control)) {
804                 /* Allow random TA to be used with authentication and
805                  * deauthentication frames if the driver has indicated support.
806                  */
807                 if (wiphy_ext_feature_isset(
808                             wdev->wiphy,
809                             NL80211_EXT_FEATURE_AUTH_AND_DEAUTH_RANDOM_TA))
810                         return true;
811         } else if (ieee80211_is_action(mgmt->frame_control) &&
812                    mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) {
813                 /* Allow random TA to be used with Public Action frames if the
814                  * driver has indicated support.
815                  */
816                 if (!wdev->connected &&
817                     wiphy_ext_feature_isset(
818                             wdev->wiphy,
819                             NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA))
820                         return true;
821 
822                 if (wdev->connected &&
823                     wiphy_ext_feature_isset(
824                             wdev->wiphy,
825                             NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED))
826                         return true;
827         }
828 
829         return false;
830 }
831 
832 int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
833                           struct wireless_dev *wdev,
834                           struct cfg80211_mgmt_tx_params *params, u64 *cookie)
835 {
836         const struct ieee80211_mgmt *mgmt;
837         u16 stype;
838 
839         lockdep_assert_wiphy(&rdev->wiphy);
840 
841         if (!wdev->wiphy->mgmt_stypes)
842                 return -EOPNOTSUPP;
843 
844         if (!rdev->ops->mgmt_tx)
845                 return -EOPNOTSUPP;
846 
847         if (params->len < 24 + 1)
848                 return -EINVAL;
849 
850         mgmt = (const struct ieee80211_mgmt *)params->buf;
851 
852         if (!ieee80211_is_mgmt(mgmt->frame_control))
853                 return -EINVAL;
854 
855         stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
856         if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].tx & BIT(stype >> 4)))
857                 return -EINVAL;
858 
859         if (ieee80211_is_action(mgmt->frame_control) &&
860             mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) {
861                 int err = 0;
862 
863                 switch (wdev->iftype) {
864                 case NL80211_IFTYPE_ADHOC:
865                         /*
866                          * check for IBSS DA must be done by driver as
867                          * cfg80211 doesn't track the stations
868                          */
869                         if (!wdev->u.ibss.current_bss ||
870                             !ether_addr_equal(wdev->u.ibss.current_bss->pub.bssid,
871                                               mgmt->bssid)) {
872                                 err = -ENOTCONN;
873                                 break;
874                         }
875                         break;
876                 case NL80211_IFTYPE_STATION:
877                 case NL80211_IFTYPE_P2P_CLIENT:
878                         if (!wdev->connected) {
879                                 err = -ENOTCONN;
880                                 break;
881                         }
882 
883                         /* FIXME: MLD may address this differently */
884 
885                         if (!ether_addr_equal(wdev->u.client.connected_addr,
886                                               mgmt->bssid)) {
887                                 err = -ENOTCONN;
888                                 break;
889                         }
890 
891                         /* for station, check that DA is the AP */
892                         if (!ether_addr_equal(wdev->u.client.connected_addr,
893                                               mgmt->da)) {
894                                 err = -ENOTCONN;
895                                 break;
896                         }
897                         break;
898                 case NL80211_IFTYPE_AP:
899                 case NL80211_IFTYPE_P2P_GO:
900                 case NL80211_IFTYPE_AP_VLAN:
901                         if (!ether_addr_equal(mgmt->bssid, wdev_address(wdev)) &&
902                             (params->link_id < 0 ||
903                              !ether_addr_equal(mgmt->bssid,
904                                                wdev->links[params->link_id].addr)))
905                                 err = -EINVAL;
906                         break;
907                 case NL80211_IFTYPE_MESH_POINT:
908                         if (!ether_addr_equal(mgmt->sa, mgmt->bssid)) {
909                                 err = -EINVAL;
910                                 break;
911                         }
912                         /*
913                          * check for mesh DA must be done by driver as
914                          * cfg80211 doesn't track the stations
915                          */
916                         break;
917                 case NL80211_IFTYPE_P2P_DEVICE:
918                         /*
919                          * fall through, P2P device only supports
920                          * public action frames
921                          */
922                 case NL80211_IFTYPE_NAN:
923                 default:
924                         err = -EOPNOTSUPP;
925                         break;
926                 }
927 
928                 if (err)
929                         return err;
930         }
931 
932         if (!cfg80211_allowed_address(wdev, mgmt->sa) &&
933             !cfg80211_allowed_random_address(wdev, mgmt))
934                 return -EINVAL;
935 
936         /* Transmit the management frame as requested by user space */
937         return rdev_mgmt_tx(rdev, wdev, params, cookie);
938 }
939 
940 bool cfg80211_rx_mgmt_ext(struct wireless_dev *wdev,
941                           struct cfg80211_rx_info *info)
942 {
943         struct wiphy *wiphy = wdev->wiphy;
944         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
945         struct cfg80211_mgmt_registration *reg;
946         const struct ieee80211_txrx_stypes *stypes =
947                 &wiphy->mgmt_stypes[wdev->iftype];
948         struct ieee80211_mgmt *mgmt = (void *)info->buf;
949         const u8 *data;
950         int data_len;
951         bool result = false;
952         __le16 ftype = mgmt->frame_control &
953                 cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE);
954         u16 stype;
955 
956         trace_cfg80211_rx_mgmt(wdev, info);
957         stype = (le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE) >> 4;
958 
959         if (!(stypes->rx & BIT(stype))) {
960                 trace_cfg80211_return_bool(false);
961                 return false;
962         }
963 
964         data = info->buf + ieee80211_hdrlen(mgmt->frame_control);
965         data_len = info->len - ieee80211_hdrlen(mgmt->frame_control);
966 
967         spin_lock_bh(&rdev->mgmt_registrations_lock);
968 
969         list_for_each_entry(reg, &wdev->mgmt_registrations, list) {
970                 if (reg->frame_type != ftype)
971                         continue;
972 
973                 if (reg->match_len > data_len)
974                         continue;
975 
976                 if (memcmp(reg->match, data, reg->match_len))
977                         continue;
978 
979                 /* found match! */
980 
981                 /* Indicate the received Action frame to user space */
982                 if (nl80211_send_mgmt(rdev, wdev, reg->nlportid, info,
983                                       GFP_ATOMIC))
984                         continue;
985 
986                 result = true;
987                 break;
988         }
989 
990         spin_unlock_bh(&rdev->mgmt_registrations_lock);
991 
992         trace_cfg80211_return_bool(result);
993         return result;
994 }
995 EXPORT_SYMBOL(cfg80211_rx_mgmt_ext);
996 
997 void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev)
998 {
999         cancel_delayed_work(&rdev->dfs_update_channels_wk);
1000         queue_delayed_work(cfg80211_wq, &rdev->dfs_update_channels_wk, 0);
1001 }
1002 
1003 void cfg80211_dfs_channels_update_work(struct work_struct *work)
1004 {
1005         struct delayed_work *delayed_work = to_delayed_work(work);
1006         struct cfg80211_registered_device *rdev;
1007         struct cfg80211_chan_def chandef;
1008         struct ieee80211_supported_band *sband;
1009         struct ieee80211_channel *c;
1010         struct wiphy *wiphy;
1011         bool check_again = false;
1012         unsigned long timeout, next_time = 0;
1013         unsigned long time_dfs_update;
1014         enum nl80211_radar_event radar_event;
1015         int bandid, i;
1016 
1017         rdev = container_of(delayed_work, struct cfg80211_registered_device,
1018                             dfs_update_channels_wk);
1019         wiphy = &rdev->wiphy;
1020 
1021         rtnl_lock();
1022         for (bandid = 0; bandid < NUM_NL80211_BANDS; bandid++) {
1023                 sband = wiphy->bands[bandid];
1024                 if (!sband)
1025                         continue;
1026 
1027                 for (i = 0; i < sband->n_channels; i++) {
1028                         c = &sband->channels[i];
1029 
1030                         if (!(c->flags & IEEE80211_CHAN_RADAR))
1031                                 continue;
1032 
1033                         if (c->dfs_state != NL80211_DFS_UNAVAILABLE &&
1034                             c->dfs_state != NL80211_DFS_AVAILABLE)
1035                                 continue;
1036 
1037                         if (c->dfs_state == NL80211_DFS_UNAVAILABLE) {
1038                                 time_dfs_update = IEEE80211_DFS_MIN_NOP_TIME_MS;
1039                                 radar_event = NL80211_RADAR_NOP_FINISHED;
1040                         } else {
1041                                 if (regulatory_pre_cac_allowed(wiphy) ||
1042                                     cfg80211_any_wiphy_oper_chan(wiphy, c))
1043                                         continue;
1044 
1045                                 time_dfs_update = REG_PRE_CAC_EXPIRY_GRACE_MS;
1046                                 radar_event = NL80211_RADAR_PRE_CAC_EXPIRED;
1047                         }
1048 
1049                         timeout = c->dfs_state_entered +
1050                                   msecs_to_jiffies(time_dfs_update);
1051 
1052                         if (time_after_eq(jiffies, timeout)) {
1053                                 c->dfs_state = NL80211_DFS_USABLE;
1054                                 c->dfs_state_entered = jiffies;
1055 
1056                                 cfg80211_chandef_create(&chandef, c,
1057                                                         NL80211_CHAN_NO_HT);
1058 
1059                                 nl80211_radar_notify(rdev, &chandef,
1060                                                      radar_event, NULL,
1061                                                      GFP_ATOMIC);
1062 
1063                                 regulatory_propagate_dfs_state(wiphy, &chandef,
1064                                                                c->dfs_state,
1065                                                                radar_event);
1066                                 continue;
1067                         }
1068 
1069                         if (!check_again)
1070                                 next_time = timeout - jiffies;
1071                         else
1072                                 next_time = min(next_time, timeout - jiffies);
1073                         check_again = true;
1074                 }
1075         }
1076         rtnl_unlock();
1077 
1078         /* reschedule if there are other channels waiting to be cleared again */
1079         if (check_again)
1080                 queue_delayed_work(cfg80211_wq, &rdev->dfs_update_channels_wk,
1081                                    next_time);
1082 }
1083 
1084 
1085 void __cfg80211_radar_event(struct wiphy *wiphy,
1086                             struct cfg80211_chan_def *chandef,
1087                             bool offchan, gfp_t gfp)
1088 {
1089         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
1090 
1091         trace_cfg80211_radar_event(wiphy, chandef, offchan);
1092 
1093         /* only set the chandef supplied channel to unavailable, in
1094          * case the radar is detected on only one of multiple channels
1095          * spanned by the chandef.
1096          */
1097         cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE);
1098 
1099         if (offchan)
1100                 queue_work(cfg80211_wq, &rdev->background_cac_abort_wk);
1101 
1102         cfg80211_sched_dfs_chan_update(rdev);
1103 
1104         nl80211_radar_notify(rdev, chandef, NL80211_RADAR_DETECTED, NULL, gfp);
1105 
1106         memcpy(&rdev->radar_chandef, chandef, sizeof(struct cfg80211_chan_def));
1107         queue_work(cfg80211_wq, &rdev->propagate_radar_detect_wk);
1108 }
1109 EXPORT_SYMBOL(__cfg80211_radar_event);
1110 
1111 void cfg80211_cac_event(struct net_device *netdev,
1112                         const struct cfg80211_chan_def *chandef,
1113                         enum nl80211_radar_event event, gfp_t gfp)
1114 {
1115         struct wireless_dev *wdev = netdev->ieee80211_ptr;
1116         struct wiphy *wiphy = wdev->wiphy;
1117         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
1118         unsigned long timeout;
1119 
1120         /* not yet supported */
1121         if (wdev->valid_links)
1122                 return;
1123 
1124         trace_cfg80211_cac_event(netdev, event);
1125 
1126         if (WARN_ON(!wdev->cac_started && event != NL80211_RADAR_CAC_STARTED))
1127                 return;
1128 
1129         switch (event) {
1130         case NL80211_RADAR_CAC_FINISHED:
1131                 timeout = wdev->cac_start_time +
1132                           msecs_to_jiffies(wdev->cac_time_ms);
1133                 WARN_ON(!time_after_eq(jiffies, timeout));
1134                 cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE);
1135                 memcpy(&rdev->cac_done_chandef, chandef,
1136                        sizeof(struct cfg80211_chan_def));
1137                 queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk);
1138                 cfg80211_sched_dfs_chan_update(rdev);
1139                 fallthrough;
1140         case NL80211_RADAR_CAC_ABORTED:
1141                 wdev->cac_started = false;
1142                 break;
1143         case NL80211_RADAR_CAC_STARTED:
1144                 wdev->cac_started = true;
1145                 break;
1146         default:
1147                 WARN_ON(1);
1148                 return;
1149         }
1150 
1151         nl80211_radar_notify(rdev, chandef, event, netdev, gfp);
1152 }
1153 EXPORT_SYMBOL(cfg80211_cac_event);
1154 
1155 static void
1156 __cfg80211_background_cac_event(struct cfg80211_registered_device *rdev,
1157                                 struct wireless_dev *wdev,
1158                                 const struct cfg80211_chan_def *chandef,
1159                                 enum nl80211_radar_event event)
1160 {
1161         struct wiphy *wiphy = &rdev->wiphy;
1162         struct net_device *netdev;
1163 
1164         lockdep_assert_wiphy(&rdev->wiphy);
1165 
1166         if (!cfg80211_chandef_valid(chandef))
1167                 return;
1168 
1169         if (!rdev->background_radar_wdev)
1170                 return;
1171 
1172         switch (event) {
1173         case NL80211_RADAR_CAC_FINISHED:
1174                 cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE);
1175                 memcpy(&rdev->cac_done_chandef, chandef, sizeof(*chandef));
1176                 queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk);
1177                 cfg80211_sched_dfs_chan_update(rdev);
1178                 wdev = rdev->background_radar_wdev;
1179                 break;
1180         case NL80211_RADAR_CAC_ABORTED:
1181                 if (!cancel_delayed_work(&rdev->background_cac_done_wk))
1182                         return;
1183                 wdev = rdev->background_radar_wdev;
1184                 break;
1185         case NL80211_RADAR_CAC_STARTED:
1186                 break;
1187         default:
1188                 return;
1189         }
1190 
1191         netdev = wdev ? wdev->netdev : NULL;
1192         nl80211_radar_notify(rdev, chandef, event, netdev, GFP_KERNEL);
1193 }
1194 
1195 static void
1196 cfg80211_background_cac_event(struct cfg80211_registered_device *rdev,
1197                               const struct cfg80211_chan_def *chandef,
1198                               enum nl80211_radar_event event)
1199 {
1200         wiphy_lock(&rdev->wiphy);
1201         __cfg80211_background_cac_event(rdev, rdev->background_radar_wdev,
1202                                         chandef, event);
1203         wiphy_unlock(&rdev->wiphy);
1204 }
1205 
1206 void cfg80211_background_cac_done_wk(struct work_struct *work)
1207 {
1208         struct delayed_work *delayed_work = to_delayed_work(work);
1209         struct cfg80211_registered_device *rdev;
1210 
1211         rdev = container_of(delayed_work, struct cfg80211_registered_device,
1212                             background_cac_done_wk);
1213         cfg80211_background_cac_event(rdev, &rdev->background_radar_chandef,
1214                                       NL80211_RADAR_CAC_FINISHED);
1215 }
1216 
1217 void cfg80211_background_cac_abort_wk(struct work_struct *work)
1218 {
1219         struct cfg80211_registered_device *rdev;
1220 
1221         rdev = container_of(work, struct cfg80211_registered_device,
1222                             background_cac_abort_wk);
1223         cfg80211_background_cac_event(rdev, &rdev->background_radar_chandef,
1224                                       NL80211_RADAR_CAC_ABORTED);
1225 }
1226 
1227 void cfg80211_background_cac_abort(struct wiphy *wiphy)
1228 {
1229         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
1230 
1231         queue_work(cfg80211_wq, &rdev->background_cac_abort_wk);
1232 }
1233 EXPORT_SYMBOL(cfg80211_background_cac_abort);
1234 
1235 int
1236 cfg80211_start_background_radar_detection(struct cfg80211_registered_device *rdev,
1237                                           struct wireless_dev *wdev,
1238                                           struct cfg80211_chan_def *chandef)
1239 {
1240         unsigned int cac_time_ms;
1241         int err;
1242 
1243         lockdep_assert_wiphy(&rdev->wiphy);
1244 
1245         if (!wiphy_ext_feature_isset(&rdev->wiphy,
1246                                      NL80211_EXT_FEATURE_RADAR_BACKGROUND))
1247                 return -EOPNOTSUPP;
1248 
1249         /* Offchannel chain already locked by another wdev */
1250         if (rdev->background_radar_wdev && rdev->background_radar_wdev != wdev)
1251                 return -EBUSY;
1252 
1253         /* CAC already in progress on the offchannel chain */
1254         if (rdev->background_radar_wdev == wdev &&
1255             delayed_work_pending(&rdev->background_cac_done_wk))
1256                 return -EBUSY;
1257 
1258         err = rdev_set_radar_background(rdev, chandef);
1259         if (err)
1260                 return err;
1261 
1262         cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, chandef);
1263         if (!cac_time_ms)
1264                 cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
1265 
1266         rdev->background_radar_chandef = *chandef;
1267         rdev->background_radar_wdev = wdev; /* Get offchain ownership */
1268 
1269         __cfg80211_background_cac_event(rdev, wdev, chandef,
1270                                         NL80211_RADAR_CAC_STARTED);
1271         queue_delayed_work(cfg80211_wq, &rdev->background_cac_done_wk,
1272                            msecs_to_jiffies(cac_time_ms));
1273 
1274         return 0;
1275 }
1276 
1277 void cfg80211_stop_background_radar_detection(struct wireless_dev *wdev)
1278 {
1279         struct wiphy *wiphy = wdev->wiphy;
1280         struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
1281 
1282         lockdep_assert_wiphy(wiphy);
1283 
1284         if (wdev != rdev->background_radar_wdev)
1285                 return;
1286 
1287         rdev_set_radar_background(rdev, NULL);
1288         rdev->background_radar_wdev = NULL; /* Release offchain ownership */
1289 
1290         __cfg80211_background_cac_event(rdev, wdev,
1291                                         &rdev->background_radar_chandef,
1292                                         NL80211_RADAR_CAC_ABORTED);
1293 }
1294 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php