]> Git Repo - linux.git/blob - drivers/net/wireless/ath/wil6210/p2p.c
Linux 6.14-rc3
[linux.git] / drivers / net / wireless / ath / wil6210 / p2p.c
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
15 static 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));
45 out_stop:
46         if (rc)
47                 wmi_stop_discovery(vif);
48
49 out:
50         return rc;
51 }
52
53 bool 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
59 int 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
117 out_stop:
118         if (rc)
119                 wmi_stop_discovery(vif);
120
121 out:
122         return rc;
123 }
124
125 int 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
172 out:
173         mutex_unlock(&wil->mutex);
174         return rc;
175 }
176
177 u8 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
196 int 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
231 void 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
259 void 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
291 void 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
334 out:
335         mutex_unlock(&wil->mutex);
336 }
337
338 void 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
377 out:
378         wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
379 }
This page took 0.052262 seconds and 4 git commands to generate.