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 }
391