Linux 4.16.11
[linux/fpc-iii.git] / drivers / net / wireless / ath / wil6210 / p2p.c
blob7dbee2c3e482c3702812ec393060fce2d7fd636e
1 /*
2 * Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include "wil6210.h"
18 #include "wmi.h"
20 #define P2P_WILDCARD_SSID "DIRECT-"
21 #define P2P_DMG_SOCIAL_CHANNEL 2
22 #define P2P_SEARCH_DURATION_MS 500
23 #define P2P_DEFAULT_BI 100
25 static int wil_p2p_start_listen(struct wil6210_priv *wil)
27 struct wil_p2p_info *p2p = &wil->p2p;
28 u8 channel = p2p->listen_chan.hw_value;
29 int rc;
31 lockdep_assert_held(&wil->mutex);
33 rc = wmi_p2p_cfg(wil, channel, P2P_DEFAULT_BI);
34 if (rc) {
35 wil_err(wil, "wmi_p2p_cfg failed\n");
36 goto out;
39 rc = wmi_set_ssid(wil, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
40 if (rc) {
41 wil_err(wil, "wmi_set_ssid failed\n");
42 goto out_stop;
45 rc = wmi_start_listen(wil);
46 if (rc) {
47 wil_err(wil, "wmi_start_listen failed\n");
48 goto out_stop;
51 INIT_WORK(&p2p->discovery_expired_work, wil_p2p_listen_expired);
52 mod_timer(&p2p->discovery_timer,
53 jiffies + msecs_to_jiffies(p2p->listen_duration));
54 out_stop:
55 if (rc)
56 wmi_stop_discovery(wil);
58 out:
59 return rc;
62 bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request)
64 return (request->n_channels == 1) &&
65 (request->channels[0]->hw_value == P2P_DMG_SOCIAL_CHANNEL);
68 void wil_p2p_discovery_timer_fn(struct timer_list *t)
70 struct wil6210_priv *wil = from_timer(wil, t, p2p.discovery_timer);
72 wil_dbg_misc(wil, "p2p_discovery_timer_fn\n");
74 schedule_work(&wil->p2p.discovery_expired_work);
77 int wil_p2p_search(struct wil6210_priv *wil,
78 struct cfg80211_scan_request *request)
80 int rc;
81 struct wil_p2p_info *p2p = &wil->p2p;
83 wil_dbg_misc(wil, "p2p_search: channel %d\n", P2P_DMG_SOCIAL_CHANNEL);
85 lockdep_assert_held(&wil->mutex);
87 if (p2p->discovery_started) {
88 wil_err(wil, "search failed. discovery already ongoing\n");
89 rc = -EBUSY;
90 goto out;
93 rc = wmi_p2p_cfg(wil, P2P_DMG_SOCIAL_CHANNEL, P2P_DEFAULT_BI);
94 if (rc) {
95 wil_err(wil, "wmi_p2p_cfg failed\n");
96 goto out;
99 rc = wmi_set_ssid(wil, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
100 if (rc) {
101 wil_err(wil, "wmi_set_ssid failed\n");
102 goto out_stop;
105 /* Set application IE to probe request and probe response */
106 rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ,
107 request->ie_len, request->ie);
108 if (rc) {
109 wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_REQ) failed\n");
110 goto out_stop;
113 /* supplicant doesn't provide Probe Response IEs. As a workaround -
114 * re-use Probe Request IEs
116 rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP,
117 request->ie_len, request->ie);
118 if (rc) {
119 wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_RESP) failed\n");
120 goto out_stop;
123 rc = wmi_start_search(wil);
124 if (rc) {
125 wil_err(wil, "wmi_start_search failed\n");
126 goto out_stop;
129 p2p->discovery_started = 1;
130 INIT_WORK(&p2p->discovery_expired_work, wil_p2p_search_expired);
131 mod_timer(&p2p->discovery_timer,
132 jiffies + msecs_to_jiffies(P2P_SEARCH_DURATION_MS));
134 out_stop:
135 if (rc)
136 wmi_stop_discovery(wil);
138 out:
139 return rc;
142 int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
143 unsigned int duration, struct ieee80211_channel *chan,
144 u64 *cookie)
146 struct wil_p2p_info *p2p = &wil->p2p;
147 int rc;
149 if (!chan)
150 return -EINVAL;
152 wil_dbg_misc(wil, "p2p_listen: duration %d\n", duration);
154 mutex_lock(&wil->mutex);
156 if (p2p->discovery_started) {
157 wil_err(wil, "discovery already ongoing\n");
158 rc = -EBUSY;
159 goto out;
162 memcpy(&p2p->listen_chan, chan, sizeof(*chan));
163 *cookie = ++p2p->cookie;
164 p2p->listen_duration = duration;
166 mutex_lock(&wil->p2p_wdev_mutex);
167 if (wil->scan_request) {
168 wil_dbg_misc(wil, "Delaying p2p listen until scan done\n");
169 p2p->pending_listen_wdev = wdev;
170 p2p->discovery_started = 1;
171 rc = 0;
172 mutex_unlock(&wil->p2p_wdev_mutex);
173 goto out;
175 mutex_unlock(&wil->p2p_wdev_mutex);
177 rc = wil_p2p_start_listen(wil);
178 if (rc)
179 goto out;
181 p2p->discovery_started = 1;
182 wil->radio_wdev = wdev;
184 cfg80211_ready_on_channel(wdev, *cookie, chan, duration,
185 GFP_KERNEL);
187 out:
188 mutex_unlock(&wil->mutex);
189 return rc;
192 u8 wil_p2p_stop_discovery(struct wil6210_priv *wil)
194 struct wil_p2p_info *p2p = &wil->p2p;
195 u8 started = p2p->discovery_started;
197 if (p2p->discovery_started) {
198 if (p2p->pending_listen_wdev) {
199 /* discovery not really started, only pending */
200 p2p->pending_listen_wdev = NULL;
201 } else {
202 del_timer_sync(&p2p->discovery_timer);
203 wmi_stop_discovery(wil);
205 p2p->discovery_started = 0;
208 return started;
211 int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie)
213 struct wil_p2p_info *p2p = &wil->p2p;
214 u8 started;
216 mutex_lock(&wil->mutex);
218 if (cookie != p2p->cookie) {
219 wil_info(wil, "Cookie mismatch: 0x%016llx vs. 0x%016llx\n",
220 p2p->cookie, cookie);
221 mutex_unlock(&wil->mutex);
222 return -ENOENT;
225 started = wil_p2p_stop_discovery(wil);
227 mutex_unlock(&wil->mutex);
229 if (!started) {
230 wil_err(wil, "listen not started\n");
231 return -ENOENT;
234 mutex_lock(&wil->p2p_wdev_mutex);
235 cfg80211_remain_on_channel_expired(wil->radio_wdev,
236 p2p->cookie,
237 &p2p->listen_chan,
238 GFP_KERNEL);
239 wil->radio_wdev = wil->wdev;
240 mutex_unlock(&wil->p2p_wdev_mutex);
241 return 0;
244 void wil_p2p_listen_expired(struct work_struct *work)
246 struct wil_p2p_info *p2p = container_of(work,
247 struct wil_p2p_info, discovery_expired_work);
248 struct wil6210_priv *wil = container_of(p2p,
249 struct wil6210_priv, p2p);
250 u8 started;
252 wil_dbg_misc(wil, "p2p_listen_expired\n");
254 mutex_lock(&wil->mutex);
255 started = wil_p2p_stop_discovery(wil);
256 mutex_unlock(&wil->mutex);
258 if (started) {
259 mutex_lock(&wil->p2p_wdev_mutex);
260 cfg80211_remain_on_channel_expired(wil->radio_wdev,
261 p2p->cookie,
262 &p2p->listen_chan,
263 GFP_KERNEL);
264 wil->radio_wdev = wil->wdev;
265 mutex_unlock(&wil->p2p_wdev_mutex);
270 void wil_p2p_search_expired(struct work_struct *work)
272 struct wil_p2p_info *p2p = container_of(work,
273 struct wil_p2p_info, discovery_expired_work);
274 struct wil6210_priv *wil = container_of(p2p,
275 struct wil6210_priv, p2p);
276 u8 started;
278 wil_dbg_misc(wil, "p2p_search_expired\n");
280 mutex_lock(&wil->mutex);
281 started = wil_p2p_stop_discovery(wil);
282 mutex_unlock(&wil->mutex);
284 if (started) {
285 struct cfg80211_scan_info info = {
286 .aborted = false,
289 mutex_lock(&wil->p2p_wdev_mutex);
290 if (wil->scan_request) {
291 cfg80211_scan_done(wil->scan_request, &info);
292 wil->scan_request = NULL;
293 wil->radio_wdev = wil->wdev;
295 mutex_unlock(&wil->p2p_wdev_mutex);
299 void wil_p2p_delayed_listen_work(struct work_struct *work)
301 struct wil_p2p_info *p2p = container_of(work,
302 struct wil_p2p_info, delayed_listen_work);
303 struct wil6210_priv *wil = container_of(p2p,
304 struct wil6210_priv, p2p);
305 int rc;
307 mutex_lock(&wil->mutex);
309 wil_dbg_misc(wil, "Checking delayed p2p listen\n");
310 if (!p2p->discovery_started || !p2p->pending_listen_wdev)
311 goto out;
313 mutex_lock(&wil->p2p_wdev_mutex);
314 if (wil->scan_request) {
315 /* another scan started, wait again... */
316 mutex_unlock(&wil->p2p_wdev_mutex);
317 goto out;
319 mutex_unlock(&wil->p2p_wdev_mutex);
321 rc = wil_p2p_start_listen(wil);
323 mutex_lock(&wil->p2p_wdev_mutex);
324 if (rc) {
325 cfg80211_remain_on_channel_expired(p2p->pending_listen_wdev,
326 p2p->cookie,
327 &p2p->listen_chan,
328 GFP_KERNEL);
329 wil->radio_wdev = wil->wdev;
330 } else {
331 cfg80211_ready_on_channel(p2p->pending_listen_wdev, p2p->cookie,
332 &p2p->listen_chan,
333 p2p->listen_duration, GFP_KERNEL);
334 wil->radio_wdev = p2p->pending_listen_wdev;
336 p2p->pending_listen_wdev = NULL;
337 mutex_unlock(&wil->p2p_wdev_mutex);
339 out:
340 mutex_unlock(&wil->mutex);
343 void wil_p2p_stop_radio_operations(struct wil6210_priv *wil)
345 struct wil_p2p_info *p2p = &wil->p2p;
346 struct cfg80211_scan_info info = {
347 .aborted = true,
350 lockdep_assert_held(&wil->mutex);
351 lockdep_assert_held(&wil->p2p_wdev_mutex);
353 if (wil->radio_wdev != wil->p2p_wdev)
354 goto out;
356 if (!p2p->discovery_started) {
357 /* Regular scan on the p2p device */
358 if (wil->scan_request &&
359 wil->scan_request->wdev == wil->p2p_wdev)
360 wil_abort_scan(wil, true);
361 goto out;
364 /* Search or listen on p2p device */
365 mutex_unlock(&wil->p2p_wdev_mutex);
366 wil_p2p_stop_discovery(wil);
367 mutex_lock(&wil->p2p_wdev_mutex);
369 if (wil->scan_request) {
370 /* search */
371 cfg80211_scan_done(wil->scan_request, &info);
372 wil->scan_request = NULL;
373 } else {
374 /* listen */
375 cfg80211_remain_on_channel_expired(wil->radio_wdev,
376 p2p->cookie,
377 &p2p->listen_chan,
378 GFP_KERNEL);
381 out:
382 wil->radio_wdev = wil->wdev;