2 * Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
3 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
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.
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.
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
26 static int wil_p2p_start_listen(struct wil6210_vif *vif)
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;
33 lockdep_assert_held(&wil->mutex);
35 rc = wmi_p2p_cfg(vif, channel, P2P_DEFAULT_BI);
37 wil_err(wil, "wmi_p2p_cfg failed\n");
41 rc = wmi_set_ssid(vif, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
43 wil_err(wil, "wmi_set_ssid failed\n");
47 rc = wmi_start_listen(vif);
49 wil_err(wil, "wmi_start_listen failed\n");
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));
58 wmi_stop_discovery(vif);
64 bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request)
66 return (request->n_channels == 1) &&
67 (request->channels[0]->hw_value == P2P_DMG_SOCIAL_CHANNEL);
70 int wil_p2p_search(struct wil6210_vif *vif,
71 struct cfg80211_scan_request *request)
73 struct wil6210_priv *wil = vif_to_wil(vif);
75 struct wil_p2p_info *p2p = &vif->p2p;
77 wil_dbg_misc(wil, "p2p_search: channel %d\n", P2P_DMG_SOCIAL_CHANNEL);
79 lockdep_assert_held(&wil->mutex);
81 if (p2p->discovery_started) {
82 wil_err(wil, "search failed. discovery already ongoing\n");
87 rc = wmi_p2p_cfg(vif, P2P_DMG_SOCIAL_CHANNEL, P2P_DEFAULT_BI);
89 wil_err(wil, "wmi_p2p_cfg failed\n");
93 rc = wmi_set_ssid(vif, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
95 wil_err(wil, "wmi_set_ssid failed\n");
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);
103 wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_REQ) failed\n");
107 /* supplicant doesn't provide Probe Response IEs. As a workaround -
108 * re-use Probe Request IEs
110 rc = wmi_set_ie(vif, WMI_FRAME_PROBE_RESP,
111 request->ie_len, request->ie);
113 wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_RESP) failed\n");
117 rc = wmi_start_search(vif);
119 wil_err(wil, "wmi_start_search failed\n");
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));
130 wmi_stop_discovery(vif);
136 int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
137 unsigned int duration, struct ieee80211_channel *chan,
140 struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
141 struct wil_p2p_info *p2p = &vif->p2p;
147 wil_dbg_misc(wil, "p2p_listen: duration %d\n", duration);
149 mutex_lock(&wil->mutex);
151 if (p2p->discovery_started) {
152 wil_err(wil, "discovery already ongoing\n");
157 memcpy(&p2p->listen_chan, chan, sizeof(*chan));
158 *cookie = ++p2p->cookie;
159 p2p->listen_duration = duration;
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;
167 mutex_unlock(&wil->vif_mutex);
170 mutex_unlock(&wil->vif_mutex);
172 rc = wil_p2p_start_listen(vif);
176 p2p->discovery_started = 1;
178 wil->radio_wdev = wdev;
180 cfg80211_ready_on_channel(wdev, *cookie, chan, duration,
184 mutex_unlock(&wil->mutex);
188 u8 wil_p2p_stop_discovery(struct wil6210_vif *vif)
190 struct wil_p2p_info *p2p = &vif->p2p;
191 u8 started = p2p->discovery_started;
193 if (p2p->discovery_started) {
194 if (p2p->pending_listen_wdev) {
195 /* discovery not really started, only pending */
196 p2p->pending_listen_wdev = NULL;
198 del_timer_sync(&p2p->discovery_timer);
199 wmi_stop_discovery(vif);
201 p2p->discovery_started = 0;
207 int wil_p2p_cancel_listen(struct wil6210_vif *vif, u64 cookie)
209 struct wil6210_priv *wil = vif_to_wil(vif);
210 struct wil_p2p_info *p2p = &vif->p2p;
213 mutex_lock(&wil->mutex);
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);
222 started = wil_p2p_stop_discovery(vif);
224 mutex_unlock(&wil->mutex);
227 wil_err(wil, "listen not started\n");
231 mutex_lock(&wil->vif_mutex);
232 cfg80211_remain_on_channel_expired(vif_to_radio_wdev(wil, vif),
237 wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
238 mutex_unlock(&wil->vif_mutex);
242 void wil_p2p_listen_expired(struct work_struct *work)
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);
251 wil_dbg_misc(wil, "p2p_listen_expired\n");
253 mutex_lock(&wil->mutex);
254 started = wil_p2p_stop_discovery(vif);
255 mutex_unlock(&wil->mutex);
260 mutex_lock(&wil->vif_mutex);
261 cfg80211_remain_on_channel_expired(vif_to_radio_wdev(wil, vif),
266 wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
267 mutex_unlock(&wil->vif_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_vif *vif = container_of(p2p,
275 struct wil6210_vif, p2p);
276 struct wil6210_priv *wil = vif_to_wil(vif);
279 wil_dbg_misc(wil, "p2p_search_expired\n");
281 mutex_lock(&wil->mutex);
282 started = wil_p2p_stop_discovery(vif);
283 mutex_unlock(&wil->mutex);
286 struct cfg80211_scan_info info = {
290 mutex_lock(&wil->vif_mutex);
291 if (vif->scan_request) {
292 cfg80211_scan_done(vif->scan_request, &info);
293 vif->scan_request = NULL;
296 wil->main_ndev->ieee80211_ptr;
298 mutex_unlock(&wil->vif_mutex);
302 void wil_p2p_delayed_listen_work(struct work_struct *work)
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);
311 mutex_lock(&wil->mutex);
313 wil_dbg_misc(wil, "Checking delayed p2p listen\n");
314 if (!p2p->discovery_started || !p2p->pending_listen_wdev)
317 mutex_lock(&wil->vif_mutex);
318 if (vif->scan_request) {
319 /* another scan started, wait again... */
320 mutex_unlock(&wil->vif_mutex);
323 mutex_unlock(&wil->vif_mutex);
325 rc = wil_p2p_start_listen(vif);
327 mutex_lock(&wil->vif_mutex);
329 cfg80211_remain_on_channel_expired(p2p->pending_listen_wdev,
334 wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
336 cfg80211_ready_on_channel(p2p->pending_listen_wdev, p2p->cookie,
338 p2p->listen_duration, GFP_KERNEL);
340 wil->radio_wdev = p2p->pending_listen_wdev;
342 p2p->pending_listen_wdev = NULL;
343 mutex_unlock(&wil->vif_mutex);
346 mutex_unlock(&wil->mutex);
349 void wil_p2p_stop_radio_operations(struct wil6210_priv *wil)
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 = {
357 lockdep_assert_held(&wil->mutex);
358 lockdep_assert_held(&wil->vif_mutex);
360 if (wil->radio_wdev != wil->p2p_wdev)
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);
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);
376 if (vif->scan_request) {
378 cfg80211_scan_done(vif->scan_request, &info);
379 vif->scan_request = NULL;
382 cfg80211_remain_on_channel_expired(wil->radio_wdev,
389 wil->radio_wdev = wil->main_ndev->ieee80211_ptr;