xref: /kernel/linux/linux-5.10/net/wireless/pmsr.c (revision 8c2ecf20)
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Copyright (C) 2018 - 2019 Intel Corporation
4 */
5#ifndef __PMSR_H
6#define __PMSR_H
7#include <net/cfg80211.h>
8#include "core.h"
9#include "nl80211.h"
10#include "rdev-ops.h"
11
12static int pmsr_parse_ftm(struct cfg80211_registered_device *rdev,
13			  struct nlattr *ftmreq,
14			  struct cfg80211_pmsr_request_peer *out,
15			  struct genl_info *info)
16{
17	const struct cfg80211_pmsr_capabilities *capa = rdev->wiphy.pmsr_capa;
18	struct nlattr *tb[NL80211_PMSR_FTM_REQ_ATTR_MAX + 1];
19	u32 preamble = NL80211_PREAMBLE_DMG; /* only optional in DMG */
20
21	/* validate existing data */
22	if (!(rdev->wiphy.pmsr_capa->ftm.bandwidths & BIT(out->chandef.width))) {
23		NL_SET_ERR_MSG(info->extack, "FTM: unsupported bandwidth");
24		return -EINVAL;
25	}
26
27	/* no validation needed - was already done via nested policy */
28	nla_parse_nested_deprecated(tb, NL80211_PMSR_FTM_REQ_ATTR_MAX, ftmreq,
29				    NULL, NULL);
30
31	if (tb[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE])
32		preamble = nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE]);
33
34	/* set up values - struct is 0-initialized */
35	out->ftm.requested = true;
36
37	switch (out->chandef.chan->band) {
38	case NL80211_BAND_60GHZ:
39		/* optional */
40		break;
41	default:
42		if (!tb[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE]) {
43			NL_SET_ERR_MSG(info->extack,
44				       "FTM: must specify preamble");
45			return -EINVAL;
46		}
47	}
48
49	if (!(capa->ftm.preambles & BIT(preamble))) {
50		NL_SET_ERR_MSG_ATTR(info->extack,
51				    tb[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE],
52				    "FTM: invalid preamble");
53		return -EINVAL;
54	}
55
56	out->ftm.preamble = preamble;
57
58	out->ftm.burst_period = 0;
59	if (tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD])
60		out->ftm.burst_period =
61			nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD]);
62
63	out->ftm.asap = !!tb[NL80211_PMSR_FTM_REQ_ATTR_ASAP];
64	if (out->ftm.asap && !capa->ftm.asap) {
65		NL_SET_ERR_MSG_ATTR(info->extack,
66				    tb[NL80211_PMSR_FTM_REQ_ATTR_ASAP],
67				    "FTM: ASAP mode not supported");
68		return -EINVAL;
69	}
70
71	if (!out->ftm.asap && !capa->ftm.non_asap) {
72		NL_SET_ERR_MSG(info->extack,
73			       "FTM: non-ASAP mode not supported");
74		return -EINVAL;
75	}
76
77	out->ftm.num_bursts_exp = 0;
78	if (tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP])
79		out->ftm.num_bursts_exp =
80			nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP]);
81
82	if (capa->ftm.max_bursts_exponent >= 0 &&
83	    out->ftm.num_bursts_exp > capa->ftm.max_bursts_exponent) {
84		NL_SET_ERR_MSG_ATTR(info->extack,
85				    tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP],
86				    "FTM: max NUM_BURSTS_EXP must be set lower than the device limit");
87		return -EINVAL;
88	}
89
90	out->ftm.burst_duration = 15;
91	if (tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION])
92		out->ftm.burst_duration =
93			nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION]);
94
95	out->ftm.ftms_per_burst = 0;
96	if (tb[NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST])
97		out->ftm.ftms_per_burst =
98			nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST]);
99
100	if (capa->ftm.max_ftms_per_burst &&
101	    (out->ftm.ftms_per_burst > capa->ftm.max_ftms_per_burst ||
102	     out->ftm.ftms_per_burst == 0)) {
103		NL_SET_ERR_MSG_ATTR(info->extack,
104				    tb[NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST],
105				    "FTM: FTMs per burst must be set lower than the device limit but non-zero");
106		return -EINVAL;
107	}
108
109	out->ftm.ftmr_retries = 3;
110	if (tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES])
111		out->ftm.ftmr_retries =
112			nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES]);
113
114	out->ftm.request_lci = !!tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI];
115	if (out->ftm.request_lci && !capa->ftm.request_lci) {
116		NL_SET_ERR_MSG_ATTR(info->extack,
117				    tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI],
118				    "FTM: LCI request not supported");
119	}
120
121	out->ftm.request_civicloc =
122		!!tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC];
123	if (out->ftm.request_civicloc && !capa->ftm.request_civicloc) {
124		NL_SET_ERR_MSG_ATTR(info->extack,
125				    tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC],
126			    "FTM: civic location request not supported");
127	}
128
129	out->ftm.trigger_based =
130		!!tb[NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED];
131	if (out->ftm.trigger_based && !capa->ftm.trigger_based) {
132		NL_SET_ERR_MSG_ATTR(info->extack,
133				    tb[NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED],
134				    "FTM: trigger based ranging is not supported");
135		return -EINVAL;
136	}
137
138	out->ftm.non_trigger_based =
139		!!tb[NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED];
140	if (out->ftm.non_trigger_based && !capa->ftm.non_trigger_based) {
141		NL_SET_ERR_MSG_ATTR(info->extack,
142				    tb[NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED],
143				    "FTM: trigger based ranging is not supported");
144		return -EINVAL;
145	}
146
147	if (out->ftm.trigger_based && out->ftm.non_trigger_based) {
148		NL_SET_ERR_MSG(info->extack,
149			       "FTM: can't set both trigger based and non trigger based");
150		return -EINVAL;
151	}
152
153	if ((out->ftm.trigger_based || out->ftm.non_trigger_based) &&
154	    out->ftm.preamble != NL80211_PREAMBLE_HE) {
155		NL_SET_ERR_MSG_ATTR(info->extack,
156				    tb[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE],
157				    "FTM: non EDCA based ranging must use HE preamble");
158		return -EINVAL;
159	}
160
161	return 0;
162}
163
164static int pmsr_parse_peer(struct cfg80211_registered_device *rdev,
165			   struct nlattr *peer,
166			   struct cfg80211_pmsr_request_peer *out,
167			   struct genl_info *info)
168{
169	struct nlattr *tb[NL80211_PMSR_PEER_ATTR_MAX + 1];
170	struct nlattr *req[NL80211_PMSR_REQ_ATTR_MAX + 1];
171	struct nlattr *treq;
172	int err, rem;
173
174	/* no validation needed - was already done via nested policy */
175	nla_parse_nested_deprecated(tb, NL80211_PMSR_PEER_ATTR_MAX, peer,
176				    NULL, NULL);
177
178	if (!tb[NL80211_PMSR_PEER_ATTR_ADDR] ||
179	    !tb[NL80211_PMSR_PEER_ATTR_CHAN] ||
180	    !tb[NL80211_PMSR_PEER_ATTR_REQ]) {
181		NL_SET_ERR_MSG_ATTR(info->extack, peer,
182				    "insufficient peer data");
183		return -EINVAL;
184	}
185
186	memcpy(out->addr, nla_data(tb[NL80211_PMSR_PEER_ATTR_ADDR]), ETH_ALEN);
187
188	/* reuse info->attrs */
189	memset(info->attrs, 0, sizeof(*info->attrs) * (NL80211_ATTR_MAX + 1));
190	err = nla_parse_nested_deprecated(info->attrs, NL80211_ATTR_MAX,
191					  tb[NL80211_PMSR_PEER_ATTR_CHAN],
192					  NULL, info->extack);
193	if (err)
194		return err;
195
196	err = nl80211_parse_chandef(rdev, info, &out->chandef);
197	if (err)
198		return err;
199
200	/* no validation needed - was already done via nested policy */
201	nla_parse_nested_deprecated(req, NL80211_PMSR_REQ_ATTR_MAX,
202				    tb[NL80211_PMSR_PEER_ATTR_REQ], NULL,
203				    NULL);
204
205	if (!req[NL80211_PMSR_REQ_ATTR_DATA]) {
206		NL_SET_ERR_MSG_ATTR(info->extack,
207				    tb[NL80211_PMSR_PEER_ATTR_REQ],
208				    "missing request type/data");
209		return -EINVAL;
210	}
211
212	if (req[NL80211_PMSR_REQ_ATTR_GET_AP_TSF])
213		out->report_ap_tsf = true;
214
215	if (out->report_ap_tsf && !rdev->wiphy.pmsr_capa->report_ap_tsf) {
216		NL_SET_ERR_MSG_ATTR(info->extack,
217				    req[NL80211_PMSR_REQ_ATTR_GET_AP_TSF],
218				    "reporting AP TSF is not supported");
219		return -EINVAL;
220	}
221
222	nla_for_each_nested(treq, req[NL80211_PMSR_REQ_ATTR_DATA], rem) {
223		switch (nla_type(treq)) {
224		case NL80211_PMSR_TYPE_FTM:
225			err = pmsr_parse_ftm(rdev, treq, out, info);
226			break;
227		default:
228			NL_SET_ERR_MSG_ATTR(info->extack, treq,
229					    "unsupported measurement type");
230			err = -EINVAL;
231		}
232	}
233
234	if (err)
235		return err;
236
237	return 0;
238}
239
240int nl80211_pmsr_start(struct sk_buff *skb, struct genl_info *info)
241{
242	struct nlattr *reqattr = info->attrs[NL80211_ATTR_PEER_MEASUREMENTS];
243	struct cfg80211_registered_device *rdev = info->user_ptr[0];
244	struct wireless_dev *wdev = info->user_ptr[1];
245	struct cfg80211_pmsr_request *req;
246	struct nlattr *peers, *peer;
247	int count, rem, err, idx;
248
249	if (!rdev->wiphy.pmsr_capa)
250		return -EOPNOTSUPP;
251
252	if (!reqattr)
253		return -EINVAL;
254
255	peers = nla_find(nla_data(reqattr), nla_len(reqattr),
256			 NL80211_PMSR_ATTR_PEERS);
257	if (!peers)
258		return -EINVAL;
259
260	count = 0;
261	nla_for_each_nested(peer, peers, rem) {
262		count++;
263
264		if (count > rdev->wiphy.pmsr_capa->max_peers) {
265			NL_SET_ERR_MSG_ATTR(info->extack, peer,
266					    "Too many peers used");
267			return -EINVAL;
268		}
269	}
270
271	req = kzalloc(struct_size(req, peers, count), GFP_KERNEL);
272	if (!req)
273		return -ENOMEM;
274
275	if (info->attrs[NL80211_ATTR_TIMEOUT])
276		req->timeout = nla_get_u32(info->attrs[NL80211_ATTR_TIMEOUT]);
277
278	if (info->attrs[NL80211_ATTR_MAC]) {
279		if (!rdev->wiphy.pmsr_capa->randomize_mac_addr) {
280			NL_SET_ERR_MSG_ATTR(info->extack,
281					    info->attrs[NL80211_ATTR_MAC],
282					    "device cannot randomize MAC address");
283			err = -EINVAL;
284			goto out_err;
285		}
286
287		err = nl80211_parse_random_mac(info->attrs, req->mac_addr,
288					       req->mac_addr_mask);
289		if (err)
290			goto out_err;
291	} else {
292		memcpy(req->mac_addr, wdev_address(wdev), ETH_ALEN);
293		eth_broadcast_addr(req->mac_addr_mask);
294	}
295
296	idx = 0;
297	nla_for_each_nested(peer, peers, rem) {
298		/* NB: this reuses info->attrs, but we no longer need it */
299		err = pmsr_parse_peer(rdev, peer, &req->peers[idx], info);
300		if (err)
301			goto out_err;
302		idx++;
303	}
304
305	req->n_peers = count;
306	req->cookie = cfg80211_assign_cookie(rdev);
307	req->nl_portid = info->snd_portid;
308
309	err = rdev_start_pmsr(rdev, wdev, req);
310	if (err)
311		goto out_err;
312
313	list_add_tail(&req->list, &wdev->pmsr_list);
314
315	nl_set_extack_cookie_u64(info->extack, req->cookie);
316	return 0;
317out_err:
318	kfree(req);
319	return err;
320}
321
322void cfg80211_pmsr_complete(struct wireless_dev *wdev,
323			    struct cfg80211_pmsr_request *req,
324			    gfp_t gfp)
325{
326	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
327	struct cfg80211_pmsr_request *tmp, *prev, *to_free = NULL;
328	struct sk_buff *msg;
329	void *hdr;
330
331	trace_cfg80211_pmsr_complete(wdev->wiphy, wdev, req->cookie);
332
333	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
334	if (!msg)
335		goto free_request;
336
337	hdr = nl80211hdr_put(msg, 0, 0, 0,
338			     NL80211_CMD_PEER_MEASUREMENT_COMPLETE);
339	if (!hdr)
340		goto free_msg;
341
342	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
343	    nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
344			      NL80211_ATTR_PAD))
345		goto free_msg;
346
347	if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, req->cookie,
348			      NL80211_ATTR_PAD))
349		goto free_msg;
350
351	genlmsg_end(msg, hdr);
352	genlmsg_unicast(wiphy_net(wdev->wiphy), msg, req->nl_portid);
353	goto free_request;
354free_msg:
355	nlmsg_free(msg);
356free_request:
357	spin_lock_bh(&wdev->pmsr_lock);
358	/*
359	 * cfg80211_pmsr_process_abort() may have already moved this request
360	 * to the free list, and will free it later. In this case, don't free
361	 * it here.
362	 */
363	list_for_each_entry_safe(tmp, prev, &wdev->pmsr_list, list) {
364		if (tmp == req) {
365			list_del(&req->list);
366			to_free = req;
367			break;
368		}
369	}
370	spin_unlock_bh(&wdev->pmsr_lock);
371	kfree(to_free);
372}
373EXPORT_SYMBOL_GPL(cfg80211_pmsr_complete);
374
375static int nl80211_pmsr_send_ftm_res(struct sk_buff *msg,
376				     struct cfg80211_pmsr_result *res)
377{
378	if (res->status == NL80211_PMSR_STATUS_FAILURE) {
379		if (nla_put_u32(msg, NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON,
380				res->ftm.failure_reason))
381			goto error;
382
383		if (res->ftm.failure_reason ==
384			NL80211_PMSR_FTM_FAILURE_PEER_BUSY &&
385		    res->ftm.busy_retry_time &&
386		    nla_put_u32(msg, NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME,
387				res->ftm.busy_retry_time))
388			goto error;
389
390		return 0;
391	}
392
393#define PUT(tp, attr, val)						\
394	do {								\
395		if (nla_put_##tp(msg,					\
396				 NL80211_PMSR_FTM_RESP_ATTR_##attr,	\
397				 res->ftm.val))				\
398			goto error;					\
399	} while (0)
400
401#define PUTOPT(tp, attr, val)						\
402	do {								\
403		if (res->ftm.val##_valid)				\
404			PUT(tp, attr, val);				\
405	} while (0)
406
407#define PUT_U64(attr, val)						\
408	do {								\
409		if (nla_put_u64_64bit(msg,				\
410				      NL80211_PMSR_FTM_RESP_ATTR_##attr,\
411				      res->ftm.val,			\
412				      NL80211_PMSR_FTM_RESP_ATTR_PAD))	\
413			goto error;					\
414	} while (0)
415
416#define PUTOPT_U64(attr, val)						\
417	do {								\
418		if (res->ftm.val##_valid)				\
419			PUT_U64(attr, val);				\
420	} while (0)
421
422	if (res->ftm.burst_index >= 0)
423		PUT(u32, BURST_INDEX, burst_index);
424	PUTOPT(u32, NUM_FTMR_ATTEMPTS, num_ftmr_attempts);
425	PUTOPT(u32, NUM_FTMR_SUCCESSES, num_ftmr_successes);
426	PUT(u8, NUM_BURSTS_EXP, num_bursts_exp);
427	PUT(u8, BURST_DURATION, burst_duration);
428	PUT(u8, FTMS_PER_BURST, ftms_per_burst);
429	PUTOPT(s32, RSSI_AVG, rssi_avg);
430	PUTOPT(s32, RSSI_SPREAD, rssi_spread);
431	if (res->ftm.tx_rate_valid &&
432	    !nl80211_put_sta_rate(msg, &res->ftm.tx_rate,
433				  NL80211_PMSR_FTM_RESP_ATTR_TX_RATE))
434		goto error;
435	if (res->ftm.rx_rate_valid &&
436	    !nl80211_put_sta_rate(msg, &res->ftm.rx_rate,
437				  NL80211_PMSR_FTM_RESP_ATTR_RX_RATE))
438		goto error;
439	PUTOPT_U64(RTT_AVG, rtt_avg);
440	PUTOPT_U64(RTT_VARIANCE, rtt_variance);
441	PUTOPT_U64(RTT_SPREAD, rtt_spread);
442	PUTOPT_U64(DIST_AVG, dist_avg);
443	PUTOPT_U64(DIST_VARIANCE, dist_variance);
444	PUTOPT_U64(DIST_SPREAD, dist_spread);
445	if (res->ftm.lci && res->ftm.lci_len &&
446	    nla_put(msg, NL80211_PMSR_FTM_RESP_ATTR_LCI,
447		    res->ftm.lci_len, res->ftm.lci))
448		goto error;
449	if (res->ftm.civicloc && res->ftm.civicloc_len &&
450	    nla_put(msg, NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC,
451		    res->ftm.civicloc_len, res->ftm.civicloc))
452		goto error;
453#undef PUT
454#undef PUTOPT
455#undef PUT_U64
456#undef PUTOPT_U64
457
458	return 0;
459error:
460	return -ENOSPC;
461}
462
463static int nl80211_pmsr_send_result(struct sk_buff *msg,
464				    struct cfg80211_pmsr_result *res)
465{
466	struct nlattr *pmsr, *peers, *peer, *resp, *data, *typedata;
467
468	pmsr = nla_nest_start_noflag(msg, NL80211_ATTR_PEER_MEASUREMENTS);
469	if (!pmsr)
470		goto error;
471
472	peers = nla_nest_start_noflag(msg, NL80211_PMSR_ATTR_PEERS);
473	if (!peers)
474		goto error;
475
476	peer = nla_nest_start_noflag(msg, 1);
477	if (!peer)
478		goto error;
479
480	if (nla_put(msg, NL80211_PMSR_PEER_ATTR_ADDR, ETH_ALEN, res->addr))
481		goto error;
482
483	resp = nla_nest_start_noflag(msg, NL80211_PMSR_PEER_ATTR_RESP);
484	if (!resp)
485		goto error;
486
487	if (nla_put_u32(msg, NL80211_PMSR_RESP_ATTR_STATUS, res->status) ||
488	    nla_put_u64_64bit(msg, NL80211_PMSR_RESP_ATTR_HOST_TIME,
489			      res->host_time, NL80211_PMSR_RESP_ATTR_PAD))
490		goto error;
491
492	if (res->ap_tsf_valid &&
493	    nla_put_u64_64bit(msg, NL80211_PMSR_RESP_ATTR_AP_TSF,
494			      res->ap_tsf, NL80211_PMSR_RESP_ATTR_PAD))
495		goto error;
496
497	if (res->final && nla_put_flag(msg, NL80211_PMSR_RESP_ATTR_FINAL))
498		goto error;
499
500	data = nla_nest_start_noflag(msg, NL80211_PMSR_RESP_ATTR_DATA);
501	if (!data)
502		goto error;
503
504	typedata = nla_nest_start_noflag(msg, res->type);
505	if (!typedata)
506		goto error;
507
508	switch (res->type) {
509	case NL80211_PMSR_TYPE_FTM:
510		if (nl80211_pmsr_send_ftm_res(msg, res))
511			goto error;
512		break;
513	default:
514		WARN_ON(1);
515	}
516
517	nla_nest_end(msg, typedata);
518	nla_nest_end(msg, data);
519	nla_nest_end(msg, resp);
520	nla_nest_end(msg, peer);
521	nla_nest_end(msg, peers);
522	nla_nest_end(msg, pmsr);
523
524	return 0;
525error:
526	return -ENOSPC;
527}
528
529void cfg80211_pmsr_report(struct wireless_dev *wdev,
530			  struct cfg80211_pmsr_request *req,
531			  struct cfg80211_pmsr_result *result,
532			  gfp_t gfp)
533{
534	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
535	struct sk_buff *msg;
536	void *hdr;
537	int err;
538
539	trace_cfg80211_pmsr_report(wdev->wiphy, wdev, req->cookie,
540				   result->addr);
541
542	/*
543	 * Currently, only variable items are LCI and civic location,
544	 * both of which are reasonably short so we don't need to
545	 * worry about them here for the allocation.
546	 */
547	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
548	if (!msg)
549		return;
550
551	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PEER_MEASUREMENT_RESULT);
552	if (!hdr)
553		goto free;
554
555	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
556	    nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
557			      NL80211_ATTR_PAD))
558		goto free;
559
560	if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, req->cookie,
561			      NL80211_ATTR_PAD))
562		goto free;
563
564	err = nl80211_pmsr_send_result(msg, result);
565	if (err) {
566		pr_err_ratelimited("peer measurement result: message didn't fit!");
567		goto free;
568	}
569
570	genlmsg_end(msg, hdr);
571	genlmsg_unicast(wiphy_net(wdev->wiphy), msg, req->nl_portid);
572	return;
573free:
574	nlmsg_free(msg);
575}
576EXPORT_SYMBOL_GPL(cfg80211_pmsr_report);
577
578static void cfg80211_pmsr_process_abort(struct wireless_dev *wdev)
579{
580	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
581	struct cfg80211_pmsr_request *req, *tmp;
582	LIST_HEAD(free_list);
583
584	lockdep_assert_held(&wdev->mtx);
585
586	spin_lock_bh(&wdev->pmsr_lock);
587	list_for_each_entry_safe(req, tmp, &wdev->pmsr_list, list) {
588		if (req->nl_portid)
589			continue;
590		list_move_tail(&req->list, &free_list);
591	}
592	spin_unlock_bh(&wdev->pmsr_lock);
593
594	list_for_each_entry_safe(req, tmp, &free_list, list) {
595		rdev_abort_pmsr(rdev, wdev, req);
596
597		kfree(req);
598	}
599}
600
601void cfg80211_pmsr_free_wk(struct work_struct *work)
602{
603	struct wireless_dev *wdev = container_of(work, struct wireless_dev,
604						 pmsr_free_wk);
605
606	wdev_lock(wdev);
607	cfg80211_pmsr_process_abort(wdev);
608	wdev_unlock(wdev);
609}
610
611void cfg80211_pmsr_wdev_down(struct wireless_dev *wdev)
612{
613	struct cfg80211_pmsr_request *req;
614	bool found = false;
615
616	spin_lock_bh(&wdev->pmsr_lock);
617	list_for_each_entry(req, &wdev->pmsr_list, list) {
618		found = true;
619		req->nl_portid = 0;
620	}
621	spin_unlock_bh(&wdev->pmsr_lock);
622
623	if (found)
624		cfg80211_pmsr_process_abort(wdev);
625
626	WARN_ON(!list_empty(&wdev->pmsr_list));
627}
628
629void cfg80211_release_pmsr(struct wireless_dev *wdev, u32 portid)
630{
631	struct cfg80211_pmsr_request *req;
632
633	spin_lock_bh(&wdev->pmsr_lock);
634	list_for_each_entry(req, &wdev->pmsr_list, list) {
635		if (req->nl_portid == portid) {
636			req->nl_portid = 0;
637			schedule_work(&wdev->pmsr_free_wk);
638		}
639	}
640	spin_unlock_bh(&wdev->pmsr_lock);
641}
642
643#endif /* __PMSR_H */
644