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