Loading...
1// SPDX-License-Identifier: ISC
2/*
3 * Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
4 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
5 */
6
7#include "wil6210.h"
8#include "wmi.h"
9
10#define P2P_WILDCARD_SSID "DIRECT-"
11#define P2P_DMG_SOCIAL_CHANNEL 2
12#define P2P_SEARCH_DURATION_MS 500
13#define P2P_DEFAULT_BI 100
14
15static int wil_p2p_start_listen(struct wil6210_vif *vif)
16{
17 struct wil6210_priv *wil = vif_to_wil(vif);
18 struct wil_p2p_info *p2p = &vif->p2p;
19 u8 channel = p2p->listen_chan.hw_value;
20 int rc;
21
22 lockdep_assert_held(&wil->mutex);
23
24 rc = wmi_p2p_cfg(vif, channel, P2P_DEFAULT_BI);
25 if (rc) {
26 wil_err(wil, "wmi_p2p_cfg failed\n");
27 goto out;
28 }
29
30 rc = wmi_set_ssid(vif, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
31 if (rc) {
32 wil_err(wil, "wmi_set_ssid failed\n");
33 goto out_stop;
34 }
35
36 rc = wmi_start_listen(vif);
37 if (rc) {
38 wil_err(wil, "wmi_start_listen failed\n");
39 goto out_stop;
40 }
41
42 INIT_WORK(&p2p->discovery_expired_work, wil_p2p_listen_expired);
43 mod_timer(&p2p->discovery_timer,
44 jiffies + msecs_to_jiffies(p2p->listen_duration));
45out_stop:
46 if (rc)
47 wmi_stop_discovery(vif);
48
49out:
50 return rc;
51}
52
53bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request)
54{
55 return (request->n_channels == 1) &&
56 (request->channels[0]->hw_value == P2P_DMG_SOCIAL_CHANNEL);
57}
58
59int wil_p2p_search(struct wil6210_vif *vif,
60 struct cfg80211_scan_request *request)
61{
62 struct wil6210_priv *wil = vif_to_wil(vif);
63 int rc;
64 struct wil_p2p_info *p2p = &vif->p2p;
65
66 wil_dbg_misc(wil, "p2p_search: channel %d\n", P2P_DMG_SOCIAL_CHANNEL);
67
68 lockdep_assert_held(&wil->mutex);
69
70 if (p2p->discovery_started) {
71 wil_err(wil, "search failed. discovery already ongoing\n");
72 rc = -EBUSY;
73 goto out;
74 }
75
76 rc = wmi_p2p_cfg(vif, P2P_DMG_SOCIAL_CHANNEL, P2P_DEFAULT_BI);
77 if (rc) {
78 wil_err(wil, "wmi_p2p_cfg failed\n");
79 goto out;
80 }
81
82 rc = wmi_set_ssid(vif, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
83 if (rc) {
84 wil_err(wil, "wmi_set_ssid failed\n");
85 goto out_stop;
86 }
87
88 /* Set application IE to probe request and probe response */
89 rc = wmi_set_ie(vif, WMI_FRAME_PROBE_REQ,
90 request->ie_len, request->ie);
91 if (rc) {
92 wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_REQ) failed\n");
93 goto out_stop;
94 }
95
96 /* supplicant doesn't provide Probe Response IEs. As a workaround -
97 * re-use Probe Request IEs
98 */
99 rc = wmi_set_ie(vif, WMI_FRAME_PROBE_RESP,
100 request->ie_len, request->ie);
101 if (rc) {
102 wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_RESP) failed\n");
103 goto out_stop;
104 }
105
106 rc = wmi_start_search(vif);
107 if (rc) {
108 wil_err(wil, "wmi_start_search failed\n");
109 goto out_stop;
110 }
111
112 p2p->discovery_started = 1;
113 INIT_WORK(&p2p->discovery_expired_work, wil_p2p_search_expired);
114 mod_timer(&p2p->discovery_timer,
115 jiffies + msecs_to_jiffies(P2P_SEARCH_DURATION_MS));
116
117out_stop:
118 if (rc)
119 wmi_stop_discovery(vif);
120
121out:
122 return rc;
123}
124
125int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
126 unsigned int duration, struct ieee80211_channel *chan,
127 u64 *cookie)
128{
129 struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
130 struct wil_p2p_info *p2p = &vif->p2p;
131 int rc;
132
133 if (!chan)
134 return -EINVAL;
135
136 wil_dbg_misc(wil, "p2p_listen: duration %d\n", duration);
137
138 mutex_lock(&wil->mutex);
139
140 if (p2p->discovery_started) {
141 wil_err(wil, "discovery already ongoing\n");
142 rc = -EBUSY;
143 goto out;
144 }
145
146 memcpy(&p2p->listen_chan, chan, sizeof(*chan));
147 *cookie = ++p2p->cookie;
148 p2p->listen_duration = duration;
149
150 mutex_lock(&wil->vif_mutex);
151 if (vif->scan_request) {
152 wil_dbg_misc(wil, "Delaying p2p listen until scan done\n");
153 p2p->pending_listen_wdev = wdev;
154 p2p->discovery_started = 1;
155 rc = 0;
156 mutex_unlock(&wil->vif_mutex);
157 goto out;
158 }
159 mutex_unlock(&wil->vif_mutex);
160
161 rc = wil_p2p_start_listen(vif);
162 if (rc)
163 goto out;
164
165 p2p->discovery_started = 1;
166 if (vif->mid == 0)
167 wil->radio_wdev = wdev;
168
169 cfg80211_ready_on_channel(wdev, *cookie, chan, duration,
170 GFP_KERNEL);
171
172out:
173 mutex_unlock(&wil->mutex);
174 return rc;
175}
176
177u8 wil_p2p_stop_discovery(struct wil6210_vif *vif)
178{
179 struct wil_p2p_info *p2p = &vif->p2p;
180 u8 started = p2p->discovery_started;
181
182 if (p2p->discovery_started) {
183 if (p2p->pending_listen_wdev) {
184 /* discovery not really started, only pending */
185 p2p->pending_listen_wdev = NULL;
186 } else {
187 del_timer_sync(&p2p->discovery_timer);
188 wmi_stop_discovery(vif);
189 }
190 p2p->discovery_started = 0;
191 }
192
193 return started;
194}
195
196int wil_p2p_cancel_listen(struct wil6210_vif *vif, u64 cookie)
197{
198 struct wil6210_priv *wil = vif_to_wil(vif);
199 struct wil_p2p_info *p2p = &vif->p2p;
200 u8 started;
201
202 mutex_lock(&wil->mutex);
203
204 if (cookie != p2p->cookie) {
205 wil_info(wil, "Cookie mismatch: 0x%016llx vs. 0x%016llx\n",
206 p2p->cookie, cookie);
207 mutex_unlock(&wil->mutex);
208 return -ENOENT;
209 }
210
211 started = wil_p2p_stop_discovery(vif);
212
213 mutex_unlock(&wil->mutex);
214
215 if (!started) {
216 wil_err(wil, "listen not started\n");
217 return -ENOENT;
218 }
219
220 mutex_lock(&wil->vif_mutex);
221 cfg80211_remain_on_channel_expired(vif_to_radio_wdev(wil, vif),
222 p2p->cookie,
223 &p2p->listen_chan,
224 GFP_KERNEL);
225 if (vif->mid == 0)
226 wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
227 mutex_unlock(&wil->vif_mutex);
228 return 0;
229}
230
231void wil_p2p_listen_expired(struct work_struct *work)
232{
233 struct wil_p2p_info *p2p = container_of(work,
234 struct wil_p2p_info, discovery_expired_work);
235 struct wil6210_vif *vif = container_of(p2p,
236 struct wil6210_vif, p2p);
237 struct wil6210_priv *wil = vif_to_wil(vif);
238 u8 started;
239
240 wil_dbg_misc(wil, "p2p_listen_expired\n");
241
242 mutex_lock(&wil->mutex);
243 started = wil_p2p_stop_discovery(vif);
244 mutex_unlock(&wil->mutex);
245
246 if (!started)
247 return;
248
249 mutex_lock(&wil->vif_mutex);
250 cfg80211_remain_on_channel_expired(vif_to_radio_wdev(wil, vif),
251 p2p->cookie,
252 &p2p->listen_chan,
253 GFP_KERNEL);
254 if (vif->mid == 0)
255 wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
256 mutex_unlock(&wil->vif_mutex);
257}
258
259void wil_p2p_search_expired(struct work_struct *work)
260{
261 struct wil_p2p_info *p2p = container_of(work,
262 struct wil_p2p_info, discovery_expired_work);
263 struct wil6210_vif *vif = container_of(p2p,
264 struct wil6210_vif, p2p);
265 struct wil6210_priv *wil = vif_to_wil(vif);
266 u8 started;
267
268 wil_dbg_misc(wil, "p2p_search_expired\n");
269
270 mutex_lock(&wil->mutex);
271 started = wil_p2p_stop_discovery(vif);
272 mutex_unlock(&wil->mutex);
273
274 if (started) {
275 struct cfg80211_scan_info info = {
276 .aborted = false,
277 };
278
279 mutex_lock(&wil->vif_mutex);
280 if (vif->scan_request) {
281 cfg80211_scan_done(vif->scan_request, &info);
282 vif->scan_request = NULL;
283 if (vif->mid == 0)
284 wil->radio_wdev =
285 wil->main_ndev->ieee80211_ptr;
286 }
287 mutex_unlock(&wil->vif_mutex);
288 }
289}
290
291void wil_p2p_delayed_listen_work(struct work_struct *work)
292{
293 struct wil_p2p_info *p2p = container_of(work,
294 struct wil_p2p_info, delayed_listen_work);
295 struct wil6210_vif *vif = container_of(p2p,
296 struct wil6210_vif, p2p);
297 struct wil6210_priv *wil = vif_to_wil(vif);
298 int rc;
299
300 mutex_lock(&wil->mutex);
301
302 wil_dbg_misc(wil, "Checking delayed p2p listen\n");
303 if (!p2p->discovery_started || !p2p->pending_listen_wdev)
304 goto out;
305
306 mutex_lock(&wil->vif_mutex);
307 if (vif->scan_request) {
308 /* another scan started, wait again... */
309 mutex_unlock(&wil->vif_mutex);
310 goto out;
311 }
312 mutex_unlock(&wil->vif_mutex);
313
314 rc = wil_p2p_start_listen(vif);
315
316 mutex_lock(&wil->vif_mutex);
317 if (rc) {
318 cfg80211_remain_on_channel_expired(p2p->pending_listen_wdev,
319 p2p->cookie,
320 &p2p->listen_chan,
321 GFP_KERNEL);
322 if (vif->mid == 0)
323 wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
324 } else {
325 cfg80211_ready_on_channel(p2p->pending_listen_wdev, p2p->cookie,
326 &p2p->listen_chan,
327 p2p->listen_duration, GFP_KERNEL);
328 if (vif->mid == 0)
329 wil->radio_wdev = p2p->pending_listen_wdev;
330 }
331 p2p->pending_listen_wdev = NULL;
332 mutex_unlock(&wil->vif_mutex);
333
334out:
335 mutex_unlock(&wil->mutex);
336}
337
338void wil_p2p_stop_radio_operations(struct wil6210_priv *wil)
339{
340 struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
341 struct wil_p2p_info *p2p = &vif->p2p;
342 struct cfg80211_scan_info info = {
343 .aborted = true,
344 };
345
346 lockdep_assert_held(&wil->mutex);
347 lockdep_assert_held(&wil->vif_mutex);
348
349 if (wil->radio_wdev != wil->p2p_wdev)
350 goto out;
351
352 if (!p2p->discovery_started) {
353 /* Regular scan on the p2p device */
354 if (vif->scan_request &&
355 vif->scan_request->wdev == wil->p2p_wdev)
356 wil_abort_scan(vif, true);
357 goto out;
358 }
359
360 /* Search or listen on p2p device */
361 mutex_unlock(&wil->vif_mutex);
362 wil_p2p_stop_discovery(vif);
363 mutex_lock(&wil->vif_mutex);
364
365 if (vif->scan_request) {
366 /* search */
367 cfg80211_scan_done(vif->scan_request, &info);
368 vif->scan_request = NULL;
369 } else {
370 /* listen */
371 cfg80211_remain_on_channel_expired(wil->radio_wdev,
372 p2p->cookie,
373 &p2p->listen_chan,
374 GFP_KERNEL);
375 }
376
377out:
378 wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
379}
1/*
2 * Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
3 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include "wil6210.h"
19#include "wmi.h"
20
21#define P2P_WILDCARD_SSID "DIRECT-"
22#define P2P_DMG_SOCIAL_CHANNEL 2
23#define P2P_SEARCH_DURATION_MS 500
24#define P2P_DEFAULT_BI 100
25
26static int wil_p2p_start_listen(struct wil6210_vif *vif)
27{
28 struct wil6210_priv *wil = vif_to_wil(vif);
29 struct wil_p2p_info *p2p = &vif->p2p;
30 u8 channel = p2p->listen_chan.hw_value;
31 int rc;
32
33 lockdep_assert_held(&wil->mutex);
34
35 rc = wmi_p2p_cfg(vif, channel, P2P_DEFAULT_BI);
36 if (rc) {
37 wil_err(wil, "wmi_p2p_cfg failed\n");
38 goto out;
39 }
40
41 rc = wmi_set_ssid(vif, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
42 if (rc) {
43 wil_err(wil, "wmi_set_ssid failed\n");
44 goto out_stop;
45 }
46
47 rc = wmi_start_listen(vif);
48 if (rc) {
49 wil_err(wil, "wmi_start_listen failed\n");
50 goto out_stop;
51 }
52
53 INIT_WORK(&p2p->discovery_expired_work, wil_p2p_listen_expired);
54 mod_timer(&p2p->discovery_timer,
55 jiffies + msecs_to_jiffies(p2p->listen_duration));
56out_stop:
57 if (rc)
58 wmi_stop_discovery(vif);
59
60out:
61 return rc;
62}
63
64bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request)
65{
66 return (request->n_channels == 1) &&
67 (request->channels[0]->hw_value == P2P_DMG_SOCIAL_CHANNEL);
68}
69
70int wil_p2p_search(struct wil6210_vif *vif,
71 struct cfg80211_scan_request *request)
72{
73 struct wil6210_priv *wil = vif_to_wil(vif);
74 int rc;
75 struct wil_p2p_info *p2p = &vif->p2p;
76
77 wil_dbg_misc(wil, "p2p_search: channel %d\n", P2P_DMG_SOCIAL_CHANNEL);
78
79 lockdep_assert_held(&wil->mutex);
80
81 if (p2p->discovery_started) {
82 wil_err(wil, "search failed. discovery already ongoing\n");
83 rc = -EBUSY;
84 goto out;
85 }
86
87 rc = wmi_p2p_cfg(vif, P2P_DMG_SOCIAL_CHANNEL, P2P_DEFAULT_BI);
88 if (rc) {
89 wil_err(wil, "wmi_p2p_cfg failed\n");
90 goto out;
91 }
92
93 rc = wmi_set_ssid(vif, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
94 if (rc) {
95 wil_err(wil, "wmi_set_ssid failed\n");
96 goto out_stop;
97 }
98
99 /* Set application IE to probe request and probe response */
100 rc = wmi_set_ie(vif, WMI_FRAME_PROBE_REQ,
101 request->ie_len, request->ie);
102 if (rc) {
103 wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_REQ) failed\n");
104 goto out_stop;
105 }
106
107 /* supplicant doesn't provide Probe Response IEs. As a workaround -
108 * re-use Probe Request IEs
109 */
110 rc = wmi_set_ie(vif, WMI_FRAME_PROBE_RESP,
111 request->ie_len, request->ie);
112 if (rc) {
113 wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_RESP) failed\n");
114 goto out_stop;
115 }
116
117 rc = wmi_start_search(vif);
118 if (rc) {
119 wil_err(wil, "wmi_start_search failed\n");
120 goto out_stop;
121 }
122
123 p2p->discovery_started = 1;
124 INIT_WORK(&p2p->discovery_expired_work, wil_p2p_search_expired);
125 mod_timer(&p2p->discovery_timer,
126 jiffies + msecs_to_jiffies(P2P_SEARCH_DURATION_MS));
127
128out_stop:
129 if (rc)
130 wmi_stop_discovery(vif);
131
132out:
133 return rc;
134}
135
136int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
137 unsigned int duration, struct ieee80211_channel *chan,
138 u64 *cookie)
139{
140 struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
141 struct wil_p2p_info *p2p = &vif->p2p;
142 int rc;
143
144 if (!chan)
145 return -EINVAL;
146
147 wil_dbg_misc(wil, "p2p_listen: duration %d\n", duration);
148
149 mutex_lock(&wil->mutex);
150
151 if (p2p->discovery_started) {
152 wil_err(wil, "discovery already ongoing\n");
153 rc = -EBUSY;
154 goto out;
155 }
156
157 memcpy(&p2p->listen_chan, chan, sizeof(*chan));
158 *cookie = ++p2p->cookie;
159 p2p->listen_duration = duration;
160
161 mutex_lock(&wil->vif_mutex);
162 if (vif->scan_request) {
163 wil_dbg_misc(wil, "Delaying p2p listen until scan done\n");
164 p2p->pending_listen_wdev = wdev;
165 p2p->discovery_started = 1;
166 rc = 0;
167 mutex_unlock(&wil->vif_mutex);
168 goto out;
169 }
170 mutex_unlock(&wil->vif_mutex);
171
172 rc = wil_p2p_start_listen(vif);
173 if (rc)
174 goto out;
175
176 p2p->discovery_started = 1;
177 if (vif->mid == 0)
178 wil->radio_wdev = wdev;
179
180 cfg80211_ready_on_channel(wdev, *cookie, chan, duration,
181 GFP_KERNEL);
182
183out:
184 mutex_unlock(&wil->mutex);
185 return rc;
186}
187
188u8 wil_p2p_stop_discovery(struct wil6210_vif *vif)
189{
190 struct wil_p2p_info *p2p = &vif->p2p;
191 u8 started = p2p->discovery_started;
192
193 if (p2p->discovery_started) {
194 if (p2p->pending_listen_wdev) {
195 /* discovery not really started, only pending */
196 p2p->pending_listen_wdev = NULL;
197 } else {
198 del_timer_sync(&p2p->discovery_timer);
199 wmi_stop_discovery(vif);
200 }
201 p2p->discovery_started = 0;
202 }
203
204 return started;
205}
206
207int wil_p2p_cancel_listen(struct wil6210_vif *vif, u64 cookie)
208{
209 struct wil6210_priv *wil = vif_to_wil(vif);
210 struct wil_p2p_info *p2p = &vif->p2p;
211 u8 started;
212
213 mutex_lock(&wil->mutex);
214
215 if (cookie != p2p->cookie) {
216 wil_info(wil, "Cookie mismatch: 0x%016llx vs. 0x%016llx\n",
217 p2p->cookie, cookie);
218 mutex_unlock(&wil->mutex);
219 return -ENOENT;
220 }
221
222 started = wil_p2p_stop_discovery(vif);
223
224 mutex_unlock(&wil->mutex);
225
226 if (!started) {
227 wil_err(wil, "listen not started\n");
228 return -ENOENT;
229 }
230
231 mutex_lock(&wil->vif_mutex);
232 cfg80211_remain_on_channel_expired(vif_to_radio_wdev(wil, vif),
233 p2p->cookie,
234 &p2p->listen_chan,
235 GFP_KERNEL);
236 if (vif->mid == 0)
237 wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
238 mutex_unlock(&wil->vif_mutex);
239 return 0;
240}
241
242void wil_p2p_listen_expired(struct work_struct *work)
243{
244 struct wil_p2p_info *p2p = container_of(work,
245 struct wil_p2p_info, discovery_expired_work);
246 struct wil6210_vif *vif = container_of(p2p,
247 struct wil6210_vif, p2p);
248 struct wil6210_priv *wil = vif_to_wil(vif);
249 u8 started;
250
251 wil_dbg_misc(wil, "p2p_listen_expired\n");
252
253 mutex_lock(&wil->mutex);
254 started = wil_p2p_stop_discovery(vif);
255 mutex_unlock(&wil->mutex);
256
257 if (!started)
258 return;
259
260 mutex_lock(&wil->vif_mutex);
261 cfg80211_remain_on_channel_expired(vif_to_radio_wdev(wil, vif),
262 p2p->cookie,
263 &p2p->listen_chan,
264 GFP_KERNEL);
265 if (vif->mid == 0)
266 wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
267 mutex_unlock(&wil->vif_mutex);
268}
269
270void wil_p2p_search_expired(struct work_struct *work)
271{
272 struct wil_p2p_info *p2p = container_of(work,
273 struct wil_p2p_info, discovery_expired_work);
274 struct wil6210_vif *vif = container_of(p2p,
275 struct wil6210_vif, p2p);
276 struct wil6210_priv *wil = vif_to_wil(vif);
277 u8 started;
278
279 wil_dbg_misc(wil, "p2p_search_expired\n");
280
281 mutex_lock(&wil->mutex);
282 started = wil_p2p_stop_discovery(vif);
283 mutex_unlock(&wil->mutex);
284
285 if (started) {
286 struct cfg80211_scan_info info = {
287 .aborted = false,
288 };
289
290 mutex_lock(&wil->vif_mutex);
291 if (vif->scan_request) {
292 cfg80211_scan_done(vif->scan_request, &info);
293 vif->scan_request = NULL;
294 if (vif->mid == 0)
295 wil->radio_wdev =
296 wil->main_ndev->ieee80211_ptr;
297 }
298 mutex_unlock(&wil->vif_mutex);
299 }
300}
301
302void wil_p2p_delayed_listen_work(struct work_struct *work)
303{
304 struct wil_p2p_info *p2p = container_of(work,
305 struct wil_p2p_info, delayed_listen_work);
306 struct wil6210_vif *vif = container_of(p2p,
307 struct wil6210_vif, p2p);
308 struct wil6210_priv *wil = vif_to_wil(vif);
309 int rc;
310
311 mutex_lock(&wil->mutex);
312
313 wil_dbg_misc(wil, "Checking delayed p2p listen\n");
314 if (!p2p->discovery_started || !p2p->pending_listen_wdev)
315 goto out;
316
317 mutex_lock(&wil->vif_mutex);
318 if (vif->scan_request) {
319 /* another scan started, wait again... */
320 mutex_unlock(&wil->vif_mutex);
321 goto out;
322 }
323 mutex_unlock(&wil->vif_mutex);
324
325 rc = wil_p2p_start_listen(vif);
326
327 mutex_lock(&wil->vif_mutex);
328 if (rc) {
329 cfg80211_remain_on_channel_expired(p2p->pending_listen_wdev,
330 p2p->cookie,
331 &p2p->listen_chan,
332 GFP_KERNEL);
333 if (vif->mid == 0)
334 wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
335 } else {
336 cfg80211_ready_on_channel(p2p->pending_listen_wdev, p2p->cookie,
337 &p2p->listen_chan,
338 p2p->listen_duration, GFP_KERNEL);
339 if (vif->mid == 0)
340 wil->radio_wdev = p2p->pending_listen_wdev;
341 }
342 p2p->pending_listen_wdev = NULL;
343 mutex_unlock(&wil->vif_mutex);
344
345out:
346 mutex_unlock(&wil->mutex);
347}
348
349void wil_p2p_stop_radio_operations(struct wil6210_priv *wil)
350{
351 struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
352 struct wil_p2p_info *p2p = &vif->p2p;
353 struct cfg80211_scan_info info = {
354 .aborted = true,
355 };
356
357 lockdep_assert_held(&wil->mutex);
358 lockdep_assert_held(&wil->vif_mutex);
359
360 if (wil->radio_wdev != wil->p2p_wdev)
361 goto out;
362
363 if (!p2p->discovery_started) {
364 /* Regular scan on the p2p device */
365 if (vif->scan_request &&
366 vif->scan_request->wdev == wil->p2p_wdev)
367 wil_abort_scan(vif, true);
368 goto out;
369 }
370
371 /* Search or listen on p2p device */
372 mutex_unlock(&wil->vif_mutex);
373 wil_p2p_stop_discovery(vif);
374 mutex_lock(&wil->vif_mutex);
375
376 if (vif->scan_request) {
377 /* search */
378 cfg80211_scan_done(vif->scan_request, &info);
379 vif->scan_request = NULL;
380 } else {
381 /* listen */
382 cfg80211_remain_on_channel_expired(wil->radio_wdev,
383 p2p->cookie,
384 &p2p->listen_chan,
385 GFP_KERNEL);
386 }
387
388out:
389 wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
390}