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.
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
;
31 lockdep_assert_held(&wil
->mutex
);
33 rc
= wmi_p2p_cfg(wil
, channel
, P2P_DEFAULT_BI
);
35 wil_err(wil
, "wmi_p2p_cfg failed\n");
39 rc
= wmi_set_ssid(wil
, strlen(P2P_WILDCARD_SSID
), P2P_WILDCARD_SSID
);
41 wil_err(wil
, "wmi_set_ssid failed\n");
45 rc
= wmi_start_listen(wil
);
47 wil_err(wil
, "wmi_start_listen failed\n");
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
));
56 wmi_stop_discovery(wil
);
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
)
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");
93 rc
= wmi_p2p_cfg(wil
, P2P_DMG_SOCIAL_CHANNEL
, P2P_DEFAULT_BI
);
95 wil_err(wil
, "wmi_p2p_cfg failed\n");
99 rc
= wmi_set_ssid(wil
, strlen(P2P_WILDCARD_SSID
), P2P_WILDCARD_SSID
);
101 wil_err(wil
, "wmi_set_ssid failed\n");
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
);
109 wil_err(wil
, "wmi_set_ie(WMI_FRAME_PROBE_REQ) failed\n");
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
);
119 wil_err(wil
, "wmi_set_ie(WMI_FRAME_PROBE_RESP) failed\n");
123 rc
= wmi_start_search(wil
);
125 wil_err(wil
, "wmi_start_search failed\n");
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
));
136 wmi_stop_discovery(wil
);
142 int wil_p2p_listen(struct wil6210_priv
*wil
, struct wireless_dev
*wdev
,
143 unsigned int duration
, struct ieee80211_channel
*chan
,
146 struct wil_p2p_info
*p2p
= &wil
->p2p
;
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");
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;
172 mutex_unlock(&wil
->p2p_wdev_mutex
);
175 mutex_unlock(&wil
->p2p_wdev_mutex
);
177 rc
= wil_p2p_start_listen(wil
);
181 p2p
->discovery_started
= 1;
182 wil
->radio_wdev
= wdev
;
184 cfg80211_ready_on_channel(wdev
, *cookie
, chan
, duration
,
188 mutex_unlock(&wil
->mutex
);
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
;
202 del_timer_sync(&p2p
->discovery_timer
);
203 wmi_stop_discovery(wil
);
205 p2p
->discovery_started
= 0;
211 int wil_p2p_cancel_listen(struct wil6210_priv
*wil
, u64 cookie
)
213 struct wil_p2p_info
*p2p
= &wil
->p2p
;
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
);
225 started
= wil_p2p_stop_discovery(wil
);
227 mutex_unlock(&wil
->mutex
);
230 wil_err(wil
, "listen not started\n");
234 mutex_lock(&wil
->p2p_wdev_mutex
);
235 cfg80211_remain_on_channel_expired(wil
->radio_wdev
,
239 wil
->radio_wdev
= wil
->wdev
;
240 mutex_unlock(&wil
->p2p_wdev_mutex
);
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
);
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
);
259 mutex_lock(&wil
->p2p_wdev_mutex
);
260 cfg80211_remain_on_channel_expired(wil
->radio_wdev
,
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
);
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
);
285 struct cfg80211_scan_info info
= {
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
);
307 mutex_lock(&wil
->mutex
);
309 wil_dbg_misc(wil
, "Checking delayed p2p listen\n");
310 if (!p2p
->discovery_started
|| !p2p
->pending_listen_wdev
)
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
);
319 mutex_unlock(&wil
->p2p_wdev_mutex
);
321 rc
= wil_p2p_start_listen(wil
);
323 mutex_lock(&wil
->p2p_wdev_mutex
);
325 cfg80211_remain_on_channel_expired(p2p
->pending_listen_wdev
,
329 wil
->radio_wdev
= wil
->wdev
;
331 cfg80211_ready_on_channel(p2p
->pending_listen_wdev
, p2p
->cookie
,
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
);
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
= {
350 lockdep_assert_held(&wil
->mutex
);
351 lockdep_assert_held(&wil
->p2p_wdev_mutex
);
353 if (wil
->radio_wdev
!= wil
->p2p_wdev
)
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);
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
) {
371 cfg80211_scan_done(wil
->scan_request
, &info
);
372 wil
->scan_request
= NULL
;
375 cfg80211_remain_on_channel_expired(wil
->radio_wdev
,
382 wil
->radio_wdev
= wil
->wdev
;