Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / net / wireless / ath / wil6210 / p2p.c
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
26 static 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));
56 out_stop:
57         if (rc)
58                 wmi_stop_discovery(vif);
59
60 out:
61         return rc;
62 }
63
64 bool 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
70 int 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
128 out_stop:
129         if (rc)
130                 wmi_stop_discovery(vif);
131
132 out:
133         return rc;
134 }
135
136 int 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
183 out:
184         mutex_unlock(&wil->mutex);
185         return rc;
186 }
187
188 u8 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
207 int 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
242 void 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
270 void 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
302 void 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
345 out:
346         mutex_unlock(&wil->mutex);
347 }
348
349 void 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
388 out:
389         wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
390 }