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