1 /*
2  * Copyright (c) 2014-2016 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, "%s\n", __func__);
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, "%s: channel %d\n",
84 		     __func__, P2P_DMG_SOCIAL_CHANNEL);
85 
86 	lockdep_assert_held(&wil->mutex);
87 
88 	if (p2p->discovery_started) {
89 		wil_err(wil, "%s: search failed. discovery already ongoing\n",
90 			__func__);
91 		rc = -EBUSY;
92 		goto out;
93 	}
94 
95 	rc = wmi_p2p_cfg(wil, P2P_DMG_SOCIAL_CHANNEL, P2P_DEFAULT_BI);
96 	if (rc) {
97 		wil_err(wil, "%s: wmi_p2p_cfg failed\n", __func__);
98 		goto out;
99 	}
100 
101 	rc = wmi_set_ssid(wil, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
102 	if (rc) {
103 		wil_err(wil, "%s: wmi_set_ssid failed\n", __func__);
104 		goto out_stop;
105 	}
106 
107 	/* Set application IE to probe request and probe response */
108 	rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ,
109 			request->ie_len, request->ie);
110 	if (rc) {
111 		wil_err(wil, "%s: wmi_set_ie(WMI_FRAME_PROBE_REQ) failed\n",
112 			__func__);
113 		goto out_stop;
114 	}
115 
116 	/* supplicant doesn't provide Probe Response IEs. As a workaround -
117 	 * re-use Probe Request IEs
118 	 */
119 	rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP,
120 			request->ie_len, request->ie);
121 	if (rc) {
122 		wil_err(wil, "%s: wmi_set_ie(WMI_FRAME_PROBE_RESP) failed\n",
123 			__func__);
124 		goto out_stop;
125 	}
126 
127 	rc = wmi_start_search(wil);
128 	if (rc) {
129 		wil_err(wil, "%s: wmi_start_search failed\n", __func__);
130 		goto out_stop;
131 	}
132 
133 	p2p->discovery_started = 1;
134 	INIT_WORK(&p2p->discovery_expired_work, wil_p2p_search_expired);
135 	mod_timer(&p2p->discovery_timer,
136 		  jiffies + msecs_to_jiffies(P2P_SEARCH_DURATION_MS));
137 
138 out_stop:
139 	if (rc)
140 		wmi_stop_discovery(wil);
141 
142 out:
143 	return rc;
144 }
145 
146 int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
147 		   unsigned int duration, struct ieee80211_channel *chan,
148 		   u64 *cookie)
149 {
150 	struct wil_p2p_info *p2p = &wil->p2p;
151 	int rc;
152 
153 	if (!chan)
154 		return -EINVAL;
155 
156 	wil_dbg_misc(wil, "%s: duration %d\n", __func__, duration);
157 
158 	mutex_lock(&wil->mutex);
159 
160 	if (p2p->discovery_started) {
161 		wil_err(wil, "%s: discovery already ongoing\n", __func__);
162 		rc = -EBUSY;
163 		goto out;
164 	}
165 
166 	memcpy(&p2p->listen_chan, chan, sizeof(*chan));
167 	*cookie = ++p2p->cookie;
168 	p2p->listen_duration = duration;
169 
170 	mutex_lock(&wil->p2p_wdev_mutex);
171 	if (wil->scan_request) {
172 		wil_dbg_misc(wil, "Delaying p2p listen until scan done\n");
173 		p2p->pending_listen_wdev = wdev;
174 		p2p->discovery_started = 1;
175 		rc = 0;
176 		mutex_unlock(&wil->p2p_wdev_mutex);
177 		goto out;
178 	}
179 	mutex_unlock(&wil->p2p_wdev_mutex);
180 
181 	rc = wil_p2p_start_listen(wil);
182 	if (rc)
183 		goto out;
184 
185 	p2p->discovery_started = 1;
186 	wil->radio_wdev = wdev;
187 
188 	cfg80211_ready_on_channel(wdev, *cookie, chan, duration,
189 				  GFP_KERNEL);
190 
191 out:
192 	mutex_unlock(&wil->mutex);
193 	return rc;
194 }
195 
196 u8 wil_p2p_stop_discovery(struct wil6210_priv *wil)
197 {
198 	struct wil_p2p_info *p2p = &wil->p2p;
199 	u8 started = p2p->discovery_started;
200 
201 	if (p2p->discovery_started) {
202 		if (p2p->pending_listen_wdev) {
203 			/* discovery not really started, only pending */
204 			p2p->pending_listen_wdev = NULL;
205 		} else {
206 			del_timer_sync(&p2p->discovery_timer);
207 			wmi_stop_discovery(wil);
208 		}
209 		p2p->discovery_started = 0;
210 	}
211 
212 	return started;
213 }
214 
215 int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie)
216 {
217 	struct wil_p2p_info *p2p = &wil->p2p;
218 	u8 started;
219 
220 	mutex_lock(&wil->mutex);
221 
222 	if (cookie != p2p->cookie) {
223 		wil_info(wil, "%s: Cookie mismatch: 0x%016llx vs. 0x%016llx\n",
224 			 __func__, p2p->cookie, cookie);
225 		mutex_unlock(&wil->mutex);
226 		return -ENOENT;
227 	}
228 
229 	started = wil_p2p_stop_discovery(wil);
230 
231 	mutex_unlock(&wil->mutex);
232 
233 	if (!started) {
234 		wil_err(wil, "%s: listen not started\n", __func__);
235 		return -ENOENT;
236 	}
237 
238 	mutex_lock(&wil->p2p_wdev_mutex);
239 	cfg80211_remain_on_channel_expired(wil->radio_wdev,
240 					   p2p->cookie,
241 					   &p2p->listen_chan,
242 					   GFP_KERNEL);
243 	wil->radio_wdev = wil->wdev;
244 	mutex_unlock(&wil->p2p_wdev_mutex);
245 	return 0;
246 }
247 
248 void wil_p2p_listen_expired(struct work_struct *work)
249 {
250 	struct wil_p2p_info *p2p = container_of(work,
251 			struct wil_p2p_info, discovery_expired_work);
252 	struct wil6210_priv *wil = container_of(p2p,
253 			struct wil6210_priv, p2p);
254 	u8 started;
255 
256 	wil_dbg_misc(wil, "%s()\n", __func__);
257 
258 	mutex_lock(&wil->mutex);
259 	started = wil_p2p_stop_discovery(wil);
260 	mutex_unlock(&wil->mutex);
261 
262 	if (started) {
263 		mutex_lock(&wil->p2p_wdev_mutex);
264 		cfg80211_remain_on_channel_expired(wil->radio_wdev,
265 						   p2p->cookie,
266 						   &p2p->listen_chan,
267 						   GFP_KERNEL);
268 		wil->radio_wdev = wil->wdev;
269 		mutex_unlock(&wil->p2p_wdev_mutex);
270 	}
271 
272 }
273 
274 void wil_p2p_search_expired(struct work_struct *work)
275 {
276 	struct wil_p2p_info *p2p = container_of(work,
277 			struct wil_p2p_info, discovery_expired_work);
278 	struct wil6210_priv *wil = container_of(p2p,
279 			struct wil6210_priv, p2p);
280 	u8 started;
281 
282 	wil_dbg_misc(wil, "%s()\n", __func__);
283 
284 	mutex_lock(&wil->mutex);
285 	started = wil_p2p_stop_discovery(wil);
286 	mutex_unlock(&wil->mutex);
287 
288 	if (started) {
289 		struct cfg80211_scan_info info = {
290 			.aborted = false,
291 		};
292 
293 		mutex_lock(&wil->p2p_wdev_mutex);
294 		if (wil->scan_request) {
295 			cfg80211_scan_done(wil->scan_request, &info);
296 			wil->scan_request = NULL;
297 			wil->radio_wdev = wil->wdev;
298 		}
299 		mutex_unlock(&wil->p2p_wdev_mutex);
300 	}
301 }
302 
303 void wil_p2p_delayed_listen_work(struct work_struct *work)
304 {
305 	struct wil_p2p_info *p2p = container_of(work,
306 			struct wil_p2p_info, delayed_listen_work);
307 	struct wil6210_priv *wil = container_of(p2p,
308 			struct wil6210_priv, p2p);
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->p2p_wdev_mutex);
318 	if (wil->scan_request) {
319 		/* another scan started, wait again... */
320 		mutex_unlock(&wil->p2p_wdev_mutex);
321 		goto out;
322 	}
323 	mutex_unlock(&wil->p2p_wdev_mutex);
324 
325 	rc = wil_p2p_start_listen(wil);
326 
327 	mutex_lock(&wil->p2p_wdev_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 		wil->radio_wdev = wil->wdev;
334 	} else {
335 		cfg80211_ready_on_channel(p2p->pending_listen_wdev, p2p->cookie,
336 					  &p2p->listen_chan,
337 					  p2p->listen_duration, GFP_KERNEL);
338 		wil->radio_wdev = p2p->pending_listen_wdev;
339 	}
340 	p2p->pending_listen_wdev = NULL;
341 	mutex_unlock(&wil->p2p_wdev_mutex);
342 
343 out:
344 	mutex_unlock(&wil->mutex);
345 }
346 
347 void wil_p2p_stop_radio_operations(struct wil6210_priv *wil)
348 {
349 	struct wil_p2p_info *p2p = &wil->p2p;
350 	struct cfg80211_scan_info info = {
351 		.aborted = true,
352 	};
353 
354 	lockdep_assert_held(&wil->mutex);
355 	lockdep_assert_held(&wil->p2p_wdev_mutex);
356 
357 	if (wil->radio_wdev != wil->p2p_wdev)
358 		goto out;
359 
360 	if (!p2p->discovery_started) {
361 		/* Regular scan on the p2p device */
362 		if (wil->scan_request &&
363 		    wil->scan_request->wdev == wil->p2p_wdev)
364 			wil_abort_scan(wil, true);
365 		goto out;
366 	}
367 
368 	/* Search or listen on p2p device */
369 	mutex_unlock(&wil->p2p_wdev_mutex);
370 	wil_p2p_stop_discovery(wil);
371 	mutex_lock(&wil->p2p_wdev_mutex);
372 
373 	if (wil->scan_request) {
374 		/* search */
375 		cfg80211_scan_done(wil->scan_request, &info);
376 		wil->scan_request = NULL;
377 	} else {
378 		/* listen */
379 		cfg80211_remain_on_channel_expired(wil->radio_wdev,
380 						   p2p->cookie,
381 						   &p2p->listen_chan,
382 						   GFP_KERNEL);
383 	}
384 
385 out:
386 	wil->radio_wdev = wil->wdev;
387 }
388