1 /* 2 * Copyright (c) 2014-2017 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(struct timer_list *t) 69 { 70 struct wil6210_priv *wil = from_timer(wil, t, p2p.discovery_timer); 71 72 wil_dbg_misc(wil, "p2p_discovery_timer_fn\n"); 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, "p2p_search: channel %d\n", P2P_DMG_SOCIAL_CHANNEL); 84 85 lockdep_assert_held(&wil->mutex); 86 87 if (p2p->discovery_started) { 88 wil_err(wil, "search failed. discovery already ongoing\n"); 89 rc = -EBUSY; 90 goto out; 91 } 92 93 rc = wmi_p2p_cfg(wil, P2P_DMG_SOCIAL_CHANNEL, P2P_DEFAULT_BI); 94 if (rc) { 95 wil_err(wil, "wmi_p2p_cfg failed\n"); 96 goto out; 97 } 98 99 rc = wmi_set_ssid(wil, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID); 100 if (rc) { 101 wil_err(wil, "wmi_set_ssid failed\n"); 102 goto out_stop; 103 } 104 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); 108 if (rc) { 109 wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_REQ) failed\n"); 110 goto out_stop; 111 } 112 113 /* supplicant doesn't provide Probe Response IEs. As a workaround - 114 * re-use Probe Request IEs 115 */ 116 rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, 117 request->ie_len, request->ie); 118 if (rc) { 119 wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_RESP) failed\n"); 120 goto out_stop; 121 } 122 123 rc = wmi_start_search(wil); 124 if (rc) { 125 wil_err(wil, "wmi_start_search failed\n"); 126 goto out_stop; 127 } 128 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)); 133 134 out_stop: 135 if (rc) 136 wmi_stop_discovery(wil); 137 138 out: 139 return rc; 140 } 141 142 int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev, 143 unsigned int duration, struct ieee80211_channel *chan, 144 u64 *cookie) 145 { 146 struct wil_p2p_info *p2p = &wil->p2p; 147 int rc; 148 149 if (!chan) 150 return -EINVAL; 151 152 wil_dbg_misc(wil, "p2p_listen: duration %d\n", duration); 153 154 mutex_lock(&wil->mutex); 155 156 if (p2p->discovery_started) { 157 wil_err(wil, "discovery already ongoing\n"); 158 rc = -EBUSY; 159 goto out; 160 } 161 162 memcpy(&p2p->listen_chan, chan, sizeof(*chan)); 163 *cookie = ++p2p->cookie; 164 p2p->listen_duration = duration; 165 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; 171 rc = 0; 172 mutex_unlock(&wil->p2p_wdev_mutex); 173 goto out; 174 } 175 mutex_unlock(&wil->p2p_wdev_mutex); 176 177 rc = wil_p2p_start_listen(wil); 178 if (rc) 179 goto out; 180 181 p2p->discovery_started = 1; 182 wil->radio_wdev = wdev; 183 184 cfg80211_ready_on_channel(wdev, *cookie, chan, duration, 185 GFP_KERNEL); 186 187 out: 188 mutex_unlock(&wil->mutex); 189 return rc; 190 } 191 192 u8 wil_p2p_stop_discovery(struct wil6210_priv *wil) 193 { 194 struct wil_p2p_info *p2p = &wil->p2p; 195 u8 started = p2p->discovery_started; 196 197 if (p2p->discovery_started) { 198 if (p2p->pending_listen_wdev) { 199 /* discovery not really started, only pending */ 200 p2p->pending_listen_wdev = NULL; 201 } else { 202 del_timer_sync(&p2p->discovery_timer); 203 wmi_stop_discovery(wil); 204 } 205 p2p->discovery_started = 0; 206 } 207 208 return started; 209 } 210 211 int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie) 212 { 213 struct wil_p2p_info *p2p = &wil->p2p; 214 u8 started; 215 216 mutex_lock(&wil->mutex); 217 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); 222 return -ENOENT; 223 } 224 225 started = wil_p2p_stop_discovery(wil); 226 227 mutex_unlock(&wil->mutex); 228 229 if (!started) { 230 wil_err(wil, "listen not started\n"); 231 return -ENOENT; 232 } 233 234 mutex_lock(&wil->p2p_wdev_mutex); 235 cfg80211_remain_on_channel_expired(wil->radio_wdev, 236 p2p->cookie, 237 &p2p->listen_chan, 238 GFP_KERNEL); 239 wil->radio_wdev = wil->wdev; 240 mutex_unlock(&wil->p2p_wdev_mutex); 241 return 0; 242 } 243 244 void wil_p2p_listen_expired(struct work_struct *work) 245 { 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); 250 u8 started; 251 252 wil_dbg_misc(wil, "p2p_listen_expired\n"); 253 254 mutex_lock(&wil->mutex); 255 started = wil_p2p_stop_discovery(wil); 256 mutex_unlock(&wil->mutex); 257 258 if (started) { 259 mutex_lock(&wil->p2p_wdev_mutex); 260 cfg80211_remain_on_channel_expired(wil->radio_wdev, 261 p2p->cookie, 262 &p2p->listen_chan, 263 GFP_KERNEL); 264 wil->radio_wdev = wil->wdev; 265 mutex_unlock(&wil->p2p_wdev_mutex); 266 } 267 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_priv *wil = container_of(p2p, 275 struct wil6210_priv, p2p); 276 u8 started; 277 278 wil_dbg_misc(wil, "p2p_search_expired\n"); 279 280 mutex_lock(&wil->mutex); 281 started = wil_p2p_stop_discovery(wil); 282 mutex_unlock(&wil->mutex); 283 284 if (started) { 285 struct cfg80211_scan_info info = { 286 .aborted = false, 287 }; 288 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; 294 } 295 mutex_unlock(&wil->p2p_wdev_mutex); 296 } 297 } 298 299 void wil_p2p_delayed_listen_work(struct work_struct *work) 300 { 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); 305 int rc; 306 307 mutex_lock(&wil->mutex); 308 309 wil_dbg_misc(wil, "Checking delayed p2p listen\n"); 310 if (!p2p->discovery_started || !p2p->pending_listen_wdev) 311 goto out; 312 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); 317 goto out; 318 } 319 mutex_unlock(&wil->p2p_wdev_mutex); 320 321 rc = wil_p2p_start_listen(wil); 322 323 mutex_lock(&wil->p2p_wdev_mutex); 324 if (rc) { 325 cfg80211_remain_on_channel_expired(p2p->pending_listen_wdev, 326 p2p->cookie, 327 &p2p->listen_chan, 328 GFP_KERNEL); 329 wil->radio_wdev = wil->wdev; 330 } else { 331 cfg80211_ready_on_channel(p2p->pending_listen_wdev, p2p->cookie, 332 &p2p->listen_chan, 333 p2p->listen_duration, GFP_KERNEL); 334 wil->radio_wdev = p2p->pending_listen_wdev; 335 } 336 p2p->pending_listen_wdev = NULL; 337 mutex_unlock(&wil->p2p_wdev_mutex); 338 339 out: 340 mutex_unlock(&wil->mutex); 341 } 342 343 void wil_p2p_stop_radio_operations(struct wil6210_priv *wil) 344 { 345 struct wil_p2p_info *p2p = &wil->p2p; 346 struct cfg80211_scan_info info = { 347 .aborted = true, 348 }; 349 350 lockdep_assert_held(&wil->mutex); 351 lockdep_assert_held(&wil->p2p_wdev_mutex); 352 353 if (wil->radio_wdev != wil->p2p_wdev) 354 goto out; 355 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); 361 goto out; 362 } 363 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); 368 369 if (wil->scan_request) { 370 /* search */ 371 cfg80211_scan_done(wil->scan_request, &info); 372 wil->scan_request = NULL; 373 } else { 374 /* listen */ 375 cfg80211_remain_on_channel_expired(wil->radio_wdev, 376 p2p->cookie, 377 &p2p->listen_chan, 378 GFP_KERNEL); 379 } 380 381 out: 382 wil->radio_wdev = wil->wdev; 383 } 384