xref: /linux/drivers/net/wireless/ath/wil6210/p2p.c (revision e58e871becec2d3b04ed91c0c16fe8deac9c9dfa)
1 /*
2  * Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
3  *
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.
7  *
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.
15  */
16 
17 #include "wil6210.h"
18 #include "wmi.h"
19 
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
24 
25 static int wil_p2p_start_listen(struct wil6210_priv *wil)
26 {
27 	struct wil_p2p_info *p2p = &wil->p2p;
28 	u8 channel = p2p->listen_chan.hw_value;
29 	int rc;
30 
31 	lockdep_assert_held(&wil->mutex);
32 
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;
37 	}
38 
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;
43 	}
44 
45 	rc = wmi_start_listen(wil);
46 	if (rc) {
47 		wil_err(wil, "wmi_start_listen failed\n");
48 		goto out_stop;
49 	}
50 
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);
57 
58 out:
59 	return rc;
60 }
61 
62 bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request)
63 {
64 	return (request->n_channels == 1) &&
65 	       (request->channels[0]->hw_value == P2P_DMG_SOCIAL_CHANNEL);
66 }
67 
68 void wil_p2p_discovery_timer_fn(ulong x)
69 {
70 	struct wil6210_priv *wil = (void *)x;
71 
72 	wil_dbg_misc(wil, "p2p_discovery_timer_fn\n");
73 
74 	schedule_work(&wil->p2p.discovery_expired_work);
75 }
76 
77 int wil_p2p_search(struct wil6210_priv *wil,
78 		   struct cfg80211_scan_request *request)
79 {
80 	int rc;
81 	struct wil_p2p_info *p2p = &wil->p2p;
82 
83 	wil_dbg_misc(wil, "p2p_search: channel %d\n", P2P_DMG_SOCIAL_CHANNEL);
84 
85 	lockdep_assert_held(&wil->mutex);
86 
87 	if (p2p->discovery_started) {
88 		wil_err(wil, "search failed. discovery already ongoing\n");
89 		rc = -EBUSY;
90 		goto out;
91 	}
92 
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;
97 	}
98 
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;
103 	}
104 
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;
111 	}
112 
113 	/* supplicant doesn't provide Probe Response IEs. As a workaround -
114 	 * re-use Probe Request IEs
115 	 */
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;
121 	}
122 
123 	rc = wmi_start_search(wil);
124 	if (rc) {
125 		wil_err(wil, "wmi_start_search failed\n");
126 		goto out_stop;
127 	}
128 
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));
133 
134 out_stop:
135 	if (rc)
136 		wmi_stop_discovery(wil);
137 
138 out:
139 	return rc;
140 }
141 
142 int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
143 		   unsigned int duration, struct ieee80211_channel *chan,
144 		   u64 *cookie)
145 {
146 	struct wil_p2p_info *p2p = &wil->p2p;
147 	int rc;
148 
149 	if (!chan)
150 		return -EINVAL;
151 
152 	wil_dbg_misc(wil, "p2p_listen: duration %d\n", duration);
153 
154 	mutex_lock(&wil->mutex);
155 
156 	if (p2p->discovery_started) {
157 		wil_err(wil, "discovery already ongoing\n");
158 		rc = -EBUSY;
159 		goto out;
160 	}
161 
162 	memcpy(&p2p->listen_chan, chan, sizeof(*chan));
163 	*cookie = ++p2p->cookie;
164 	p2p->listen_duration = duration;
165 
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;
174 	}
175 	mutex_unlock(&wil->p2p_wdev_mutex);
176 
177 	rc = wil_p2p_start_listen(wil);
178 	if (rc)
179 		goto out;
180 
181 	p2p->discovery_started = 1;
182 	wil->radio_wdev = wdev;
183 
184 	cfg80211_ready_on_channel(wdev, *cookie, chan, duration,
185 				  GFP_KERNEL);
186 
187 out:
188 	mutex_unlock(&wil->mutex);
189 	return rc;
190 }
191 
192 u8 wil_p2p_stop_discovery(struct wil6210_priv *wil)
193 {
194 	struct wil_p2p_info *p2p = &wil->p2p;
195 	u8 started = p2p->discovery_started;
196 
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);
204 		}
205 		p2p->discovery_started = 0;
206 	}
207 
208 	return started;
209 }
210 
211 int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie)
212 {
213 	struct wil_p2p_info *p2p = &wil->p2p;
214 	u8 started;
215 
216 	mutex_lock(&wil->mutex);
217 
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;
223 	}
224 
225 	started = wil_p2p_stop_discovery(wil);
226 
227 	mutex_unlock(&wil->mutex);
228 
229 	if (!started) {
230 		wil_err(wil, "listen not started\n");
231 		return -ENOENT;
232 	}
233 
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;
242 }
243 
244 void wil_p2p_listen_expired(struct work_struct *work)
245 {
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;
251 
252 	wil_dbg_misc(wil, "p2p_listen_expired\n");
253 
254 	mutex_lock(&wil->mutex);
255 	started = wil_p2p_stop_discovery(wil);
256 	mutex_unlock(&wil->mutex);
257 
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);
266 	}
267 
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_priv *wil = container_of(p2p,
275 			struct wil6210_priv, p2p);
276 	u8 started;
277 
278 	wil_dbg_misc(wil, "p2p_search_expired\n");
279 
280 	mutex_lock(&wil->mutex);
281 	started = wil_p2p_stop_discovery(wil);
282 	mutex_unlock(&wil->mutex);
283 
284 	if (started) {
285 		struct cfg80211_scan_info info = {
286 			.aborted = false,
287 		};
288 
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;
294 		}
295 		mutex_unlock(&wil->p2p_wdev_mutex);
296 	}
297 }
298 
299 void wil_p2p_delayed_listen_work(struct work_struct *work)
300 {
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;
306 
307 	mutex_lock(&wil->mutex);
308 
309 	wil_dbg_misc(wil, "Checking delayed p2p listen\n");
310 	if (!p2p->discovery_started || !p2p->pending_listen_wdev)
311 		goto out;
312 
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;
318 	}
319 	mutex_unlock(&wil->p2p_wdev_mutex);
320 
321 	rc = wil_p2p_start_listen(wil);
322 
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;
335 	}
336 	p2p->pending_listen_wdev = NULL;
337 	mutex_unlock(&wil->p2p_wdev_mutex);
338 
339 out:
340 	mutex_unlock(&wil->mutex);
341 }
342 
343 void wil_p2p_stop_radio_operations(struct wil6210_priv *wil)
344 {
345 	struct wil_p2p_info *p2p = &wil->p2p;
346 	struct cfg80211_scan_info info = {
347 		.aborted = true,
348 	};
349 
350 	lockdep_assert_held(&wil->mutex);
351 	lockdep_assert_held(&wil->p2p_wdev_mutex);
352 
353 	if (wil->radio_wdev != wil->p2p_wdev)
354 		goto out;
355 
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;
362 	}
363 
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);
368 
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);
379 	}
380 
381 out:
382 	wil->radio_wdev = wil->wdev;
383 }
384