Merge branch 'x86-pti-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-block.git] / drivers / net / wireless / ath / wil6210 / p2p.c
CommitLineData
85630469 1// SPDX-License-Identifier: ISC
e6d68341 2/*
af3db60a 3 * Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
e00243fa 4 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
e6d68341
DL
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
e00243fa 15static int wil_p2p_start_listen(struct wil6210_vif *vif)
bb6743f7 16{
e00243fa
LD
17 struct wil6210_priv *wil = vif_to_wil(vif);
18 struct wil_p2p_info *p2p = &vif->p2p;
bb6743f7
LD
19 u8 channel = p2p->listen_chan.hw_value;
20 int rc;
21
22 lockdep_assert_held(&wil->mutex);
23
e00243fa 24 rc = wmi_p2p_cfg(vif, channel, P2P_DEFAULT_BI);
bb6743f7
LD
25 if (rc) {
26 wil_err(wil, "wmi_p2p_cfg failed\n");
27 goto out;
28 }
29
e00243fa 30 rc = wmi_set_ssid(vif, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
bb6743f7
LD
31 if (rc) {
32 wil_err(wil, "wmi_set_ssid failed\n");
33 goto out_stop;
34 }
35
e00243fa 36 rc = wmi_start_listen(vif);
bb6743f7
LD
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)
e00243fa 47 wmi_stop_discovery(vif);
bb6743f7
LD
48
49out:
50 return rc;
51}
52
321a000b
LD
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
e00243fa 59int wil_p2p_search(struct wil6210_vif *vif,
e6d68341
DL
60 struct cfg80211_scan_request *request)
61{
e00243fa 62 struct wil6210_priv *wil = vif_to_wil(vif);
e6d68341 63 int rc;
e00243fa 64 struct wil_p2p_info *p2p = &vif->p2p;
e6d68341 65
af3db60a 66 wil_dbg_misc(wil, "p2p_search: channel %d\n", P2P_DMG_SOCIAL_CHANNEL);
e6d68341 67
bb6743f7 68 lockdep_assert_held(&wil->mutex);
e6d68341
DL
69
70 if (p2p->discovery_started) {
af3db60a 71 wil_err(wil, "search failed. discovery already ongoing\n");
e6d68341
DL
72 rc = -EBUSY;
73 goto out;
74 }
75
e00243fa 76 rc = wmi_p2p_cfg(vif, P2P_DMG_SOCIAL_CHANNEL, P2P_DEFAULT_BI);
e6d68341 77 if (rc) {
af3db60a 78 wil_err(wil, "wmi_p2p_cfg failed\n");
e6d68341
DL
79 goto out;
80 }
81
e00243fa 82 rc = wmi_set_ssid(vif, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
e6d68341 83 if (rc) {
af3db60a 84 wil_err(wil, "wmi_set_ssid failed\n");
e6d68341
DL
85 goto out_stop;
86 }
87
88 /* Set application IE to probe request and probe response */
e00243fa 89 rc = wmi_set_ie(vif, WMI_FRAME_PROBE_REQ,
e6d68341
DL
90 request->ie_len, request->ie);
91 if (rc) {
af3db60a 92 wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_REQ) failed\n");
e6d68341
DL
93 goto out_stop;
94 }
95
96 /* supplicant doesn't provide Probe Response IEs. As a workaround -
97 * re-use Probe Request IEs
98 */
e00243fa 99 rc = wmi_set_ie(vif, WMI_FRAME_PROBE_RESP,
e6d68341
DL
100 request->ie_len, request->ie);
101 if (rc) {
af3db60a 102 wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_RESP) failed\n");
e6d68341
DL
103 goto out_stop;
104 }
105
e00243fa 106 rc = wmi_start_search(vif);
e6d68341 107 if (rc) {
af3db60a 108 wil_err(wil, "wmi_start_search failed\n");
e6d68341
DL
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)
e00243fa 119 wmi_stop_discovery(vif);
e6d68341
DL
120
121out:
e6d68341
DL
122 return rc;
123}
124
bb6743f7
LD
125int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
126 unsigned int duration, struct ieee80211_channel *chan,
127 u64 *cookie)
e6d68341 128{
e00243fa
LD
129 struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
130 struct wil_p2p_info *p2p = &vif->p2p;
e6d68341
DL
131 int rc;
132
9c830abe
ME
133 if (!chan)
134 return -EINVAL;
135
af3db60a 136 wil_dbg_misc(wil, "p2p_listen: duration %d\n", duration);
e6d68341
DL
137
138 mutex_lock(&wil->mutex);
139
140 if (p2p->discovery_started) {
af3db60a 141 wil_err(wil, "discovery already ongoing\n");
e6d68341
DL
142 rc = -EBUSY;
143 goto out;
144 }
145
bb6743f7
LD
146 memcpy(&p2p->listen_chan, chan, sizeof(*chan));
147 *cookie = ++p2p->cookie;
148 p2p->listen_duration = duration;
e6d68341 149
404bbb3c 150 mutex_lock(&wil->vif_mutex);
e00243fa 151 if (vif->scan_request) {
bb6743f7
LD
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;
404bbb3c 156 mutex_unlock(&wil->vif_mutex);
bb6743f7 157 goto out;
e6d68341 158 }
404bbb3c 159 mutex_unlock(&wil->vif_mutex);
e6d68341 160
e00243fa 161 rc = wil_p2p_start_listen(vif);
bb6743f7
LD
162 if (rc)
163 goto out;
e6d68341
DL
164
165 p2p->discovery_started = 1;
e00243fa
LD
166 if (vif->mid == 0)
167 wil->radio_wdev = wdev;
e6d68341 168
bb6743f7
LD
169 cfg80211_ready_on_channel(wdev, *cookie, chan, duration,
170 GFP_KERNEL);
e6d68341
DL
171
172out:
173 mutex_unlock(&wil->mutex);
174 return rc;
175}
176
e00243fa 177u8 wil_p2p_stop_discovery(struct wil6210_vif *vif)
e6d68341 178{
e00243fa 179 struct wil_p2p_info *p2p = &vif->p2p;
280ab987 180 u8 started = p2p->discovery_started;
e6d68341
DL
181
182 if (p2p->discovery_started) {
bb6743f7
LD
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);
e00243fa 188 wmi_stop_discovery(vif);
bb6743f7 189 }
e6d68341 190 p2p->discovery_started = 0;
e6d68341 191 }
280ab987
LD
192
193 return started;
e6d68341
DL
194}
195
e00243fa 196int wil_p2p_cancel_listen(struct wil6210_vif *vif, u64 cookie)
e6d68341 197{
e00243fa
LD
198 struct wil6210_priv *wil = vif_to_wil(vif);
199 struct wil_p2p_info *p2p = &vif->p2p;
280ab987
LD
200 u8 started;
201
202 mutex_lock(&wil->mutex);
e6d68341 203
280ab987 204 if (cookie != p2p->cookie) {
af3db60a
LA
205 wil_info(wil, "Cookie mismatch: 0x%016llx vs. 0x%016llx\n",
206 p2p->cookie, cookie);
280ab987
LD
207 mutex_unlock(&wil->mutex);
208 return -ENOENT;
209 }
210
e00243fa 211 started = wil_p2p_stop_discovery(vif);
280ab987
LD
212
213 mutex_unlock(&wil->mutex);
e6d68341 214
280ab987 215 if (!started) {
af3db60a 216 wil_err(wil, "listen not started\n");
280ab987
LD
217 return -ENOENT;
218 }
4332cac1 219
404bbb3c 220 mutex_lock(&wil->vif_mutex);
e00243fa 221 cfg80211_remain_on_channel_expired(vif_to_radio_wdev(wil, vif),
e6d68341
DL
222 p2p->cookie,
223 &p2p->listen_chan,
224 GFP_KERNEL);
e00243fa
LD
225 if (vif->mid == 0)
226 wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
404bbb3c 227 mutex_unlock(&wil->vif_mutex);
280ab987 228 return 0;
e6d68341
DL
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);
e00243fa
LD
235 struct wil6210_vif *vif = container_of(p2p,
236 struct wil6210_vif, p2p);
237 struct wil6210_priv *wil = vif_to_wil(vif);
280ab987 238 u8 started;
e6d68341 239
af3db60a 240 wil_dbg_misc(wil, "p2p_listen_expired\n");
e6d68341 241
280ab987 242 mutex_lock(&wil->mutex);
e00243fa 243 started = wil_p2p_stop_discovery(vif);
280ab987 244 mutex_unlock(&wil->mutex);
4332cac1 245
e00243fa
LD
246 if (!started)
247 return;
4332cac1 248
404bbb3c 249 mutex_lock(&wil->vif_mutex);
e00243fa
LD
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;
404bbb3c 256 mutex_unlock(&wil->vif_mutex);
e6d68341
DL
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);
e00243fa
LD
263 struct wil6210_vif *vif = container_of(p2p,
264 struct wil6210_vif, p2p);
265 struct wil6210_priv *wil = vif_to_wil(vif);
280ab987 266 u8 started;
e6d68341 267
af3db60a 268 wil_dbg_misc(wil, "p2p_search_expired\n");
e6d68341 269
280ab987 270 mutex_lock(&wil->mutex);
e00243fa 271 started = wil_p2p_stop_discovery(vif);
280ab987 272 mutex_unlock(&wil->mutex);
4332cac1 273
280ab987 274 if (started) {
1d76250b
AS
275 struct cfg80211_scan_info info = {
276 .aborted = false,
277 };
278
404bbb3c 279 mutex_lock(&wil->vif_mutex);
e00243fa
LD
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;
bb6743f7 286 }
404bbb3c 287 mutex_unlock(&wil->vif_mutex);
bb6743f7
LD
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);
e00243fa
LD
295 struct wil6210_vif *vif = container_of(p2p,
296 struct wil6210_vif, p2p);
297 struct wil6210_priv *wil = vif_to_wil(vif);
bb6743f7
LD
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
404bbb3c 306 mutex_lock(&wil->vif_mutex);
e00243fa 307 if (vif->scan_request) {
bb6743f7 308 /* another scan started, wait again... */
404bbb3c 309 mutex_unlock(&wil->vif_mutex);
bb6743f7 310 goto out;
280ab987 311 }
404bbb3c 312 mutex_unlock(&wil->vif_mutex);
bb6743f7 313
e00243fa 314 rc = wil_p2p_start_listen(vif);
bb6743f7 315
404bbb3c 316 mutex_lock(&wil->vif_mutex);
bb6743f7
LD
317 if (rc) {
318 cfg80211_remain_on_channel_expired(p2p->pending_listen_wdev,
319 p2p->cookie,
320 &p2p->listen_chan,
321 GFP_KERNEL);
e00243fa
LD
322 if (vif->mid == 0)
323 wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
bb6743f7
LD
324 } else {
325 cfg80211_ready_on_channel(p2p->pending_listen_wdev, p2p->cookie,
326 &p2p->listen_chan,
327 p2p->listen_duration, GFP_KERNEL);
e00243fa
LD
328 if (vif->mid == 0)
329 wil->radio_wdev = p2p->pending_listen_wdev;
bb6743f7
LD
330 }
331 p2p->pending_listen_wdev = NULL;
404bbb3c 332 mutex_unlock(&wil->vif_mutex);
bb6743f7
LD
333
334out:
335 mutex_unlock(&wil->mutex);
e6d68341 336}
d35c2b6f
ME
337
338void wil_p2p_stop_radio_operations(struct wil6210_priv *wil)
339{
e00243fa
LD
340 struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
341 struct wil_p2p_info *p2p = &vif->p2p;
d35c2b6f
ME
342 struct cfg80211_scan_info info = {
343 .aborted = true,
344 };
345
346 lockdep_assert_held(&wil->mutex);
404bbb3c 347 lockdep_assert_held(&wil->vif_mutex);
d35c2b6f
ME
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 */
e00243fa
LD
354 if (vif->scan_request &&
355 vif->scan_request->wdev == wil->p2p_wdev)
356 wil_abort_scan(vif, true);
d35c2b6f
ME
357 goto out;
358 }
359
360 /* Search or listen on p2p device */
404bbb3c 361 mutex_unlock(&wil->vif_mutex);
e00243fa 362 wil_p2p_stop_discovery(vif);
404bbb3c 363 mutex_lock(&wil->vif_mutex);
d35c2b6f 364
e00243fa 365 if (vif->scan_request) {
d35c2b6f 366 /* search */
e00243fa
LD
367 cfg80211_scan_done(vif->scan_request, &info);
368 vif->scan_request = NULL;
d35c2b6f
ME
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:
e00243fa 378 wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
d35c2b6f 379}