p2p.c (8912B)
1// SPDX-License-Identifier: ISC 2/* 3 * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. 4 * Copyright (c) 2018, The Linux Foundation. All rights reserved. 5 */ 6 7#include "wil6210.h" 8#include "wmi.h" 9 10#define P2P_WILDCARD_SSID "DIRECT-" 11#define P2P_DMG_SOCIAL_CHANNEL 2 12#define P2P_SEARCH_DURATION_MS 500 13#define P2P_DEFAULT_BI 100 14 15static int wil_p2p_start_listen(struct wil6210_vif *vif) 16{ 17 struct wil6210_priv *wil = vif_to_wil(vif); 18 struct wil_p2p_info *p2p = &vif->p2p; 19 u8 channel = p2p->listen_chan.hw_value; 20 int rc; 21 22 lockdep_assert_held(&wil->mutex); 23 24 rc = wmi_p2p_cfg(vif, channel, P2P_DEFAULT_BI); 25 if (rc) { 26 wil_err(wil, "wmi_p2p_cfg failed\n"); 27 goto out; 28 } 29 30 rc = wmi_set_ssid(vif, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID); 31 if (rc) { 32 wil_err(wil, "wmi_set_ssid failed\n"); 33 goto out_stop; 34 } 35 36 rc = wmi_start_listen(vif); 37 if (rc) { 38 wil_err(wil, "wmi_start_listen failed\n"); 39 goto out_stop; 40 } 41 42 INIT_WORK(&p2p->discovery_expired_work, wil_p2p_listen_expired); 43 mod_timer(&p2p->discovery_timer, 44 jiffies + msecs_to_jiffies(p2p->listen_duration)); 45out_stop: 46 if (rc) 47 wmi_stop_discovery(vif); 48 49out: 50 return rc; 51} 52 53bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request) 54{ 55 return (request->n_channels == 1) && 56 (request->channels[0]->hw_value == P2P_DMG_SOCIAL_CHANNEL); 57} 58 59int wil_p2p_search(struct wil6210_vif *vif, 60 struct cfg80211_scan_request *request) 61{ 62 struct wil6210_priv *wil = vif_to_wil(vif); 63 int rc; 64 struct wil_p2p_info *p2p = &vif->p2p; 65 66 wil_dbg_misc(wil, "p2p_search: channel %d\n", P2P_DMG_SOCIAL_CHANNEL); 67 68 lockdep_assert_held(&wil->mutex); 69 70 if (p2p->discovery_started) { 71 wil_err(wil, "search failed. discovery already ongoing\n"); 72 rc = -EBUSY; 73 goto out; 74 } 75 76 rc = wmi_p2p_cfg(vif, P2P_DMG_SOCIAL_CHANNEL, P2P_DEFAULT_BI); 77 if (rc) { 78 wil_err(wil, "wmi_p2p_cfg failed\n"); 79 goto out; 80 } 81 82 rc = wmi_set_ssid(vif, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID); 83 if (rc) { 84 wil_err(wil, "wmi_set_ssid failed\n"); 85 goto out_stop; 86 } 87 88 /* Set application IE to probe request and probe response */ 89 rc = wmi_set_ie(vif, WMI_FRAME_PROBE_REQ, 90 request->ie_len, request->ie); 91 if (rc) { 92 wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_REQ) failed\n"); 93 goto out_stop; 94 } 95 96 /* supplicant doesn't provide Probe Response IEs. As a workaround - 97 * re-use Probe Request IEs 98 */ 99 rc = wmi_set_ie(vif, WMI_FRAME_PROBE_RESP, 100 request->ie_len, request->ie); 101 if (rc) { 102 wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_RESP) failed\n"); 103 goto out_stop; 104 } 105 106 rc = wmi_start_search(vif); 107 if (rc) { 108 wil_err(wil, "wmi_start_search failed\n"); 109 goto out_stop; 110 } 111 112 p2p->discovery_started = 1; 113 INIT_WORK(&p2p->discovery_expired_work, wil_p2p_search_expired); 114 mod_timer(&p2p->discovery_timer, 115 jiffies + msecs_to_jiffies(P2P_SEARCH_DURATION_MS)); 116 117out_stop: 118 if (rc) 119 wmi_stop_discovery(vif); 120 121out: 122 return rc; 123} 124 125int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev, 126 unsigned int duration, struct ieee80211_channel *chan, 127 u64 *cookie) 128{ 129 struct wil6210_vif *vif = wdev_to_vif(wil, wdev); 130 struct wil_p2p_info *p2p = &vif->p2p; 131 int rc; 132 133 if (!chan) 134 return -EINVAL; 135 136 wil_dbg_misc(wil, "p2p_listen: duration %d\n", duration); 137 138 mutex_lock(&wil->mutex); 139 140 if (p2p->discovery_started) { 141 wil_err(wil, "discovery already ongoing\n"); 142 rc = -EBUSY; 143 goto out; 144 } 145 146 memcpy(&p2p->listen_chan, chan, sizeof(*chan)); 147 *cookie = ++p2p->cookie; 148 p2p->listen_duration = duration; 149 150 mutex_lock(&wil->vif_mutex); 151 if (vif->scan_request) { 152 wil_dbg_misc(wil, "Delaying p2p listen until scan done\n"); 153 p2p->pending_listen_wdev = wdev; 154 p2p->discovery_started = 1; 155 rc = 0; 156 mutex_unlock(&wil->vif_mutex); 157 goto out; 158 } 159 mutex_unlock(&wil->vif_mutex); 160 161 rc = wil_p2p_start_listen(vif); 162 if (rc) 163 goto out; 164 165 p2p->discovery_started = 1; 166 if (vif->mid == 0) 167 wil->radio_wdev = wdev; 168 169 cfg80211_ready_on_channel(wdev, *cookie, chan, duration, 170 GFP_KERNEL); 171 172out: 173 mutex_unlock(&wil->mutex); 174 return rc; 175} 176 177u8 wil_p2p_stop_discovery(struct wil6210_vif *vif) 178{ 179 struct wil_p2p_info *p2p = &vif->p2p; 180 u8 started = p2p->discovery_started; 181 182 if (p2p->discovery_started) { 183 if (p2p->pending_listen_wdev) { 184 /* discovery not really started, only pending */ 185 p2p->pending_listen_wdev = NULL; 186 } else { 187 del_timer_sync(&p2p->discovery_timer); 188 wmi_stop_discovery(vif); 189 } 190 p2p->discovery_started = 0; 191 } 192 193 return started; 194} 195 196int wil_p2p_cancel_listen(struct wil6210_vif *vif, u64 cookie) 197{ 198 struct wil6210_priv *wil = vif_to_wil(vif); 199 struct wil_p2p_info *p2p = &vif->p2p; 200 u8 started; 201 202 mutex_lock(&wil->mutex); 203 204 if (cookie != p2p->cookie) { 205 wil_info(wil, "Cookie mismatch: 0x%016llx vs. 0x%016llx\n", 206 p2p->cookie, cookie); 207 mutex_unlock(&wil->mutex); 208 return -ENOENT; 209 } 210 211 started = wil_p2p_stop_discovery(vif); 212 213 mutex_unlock(&wil->mutex); 214 215 if (!started) { 216 wil_err(wil, "listen not started\n"); 217 return -ENOENT; 218 } 219 220 mutex_lock(&wil->vif_mutex); 221 cfg80211_remain_on_channel_expired(vif_to_radio_wdev(wil, vif), 222 p2p->cookie, 223 &p2p->listen_chan, 224 GFP_KERNEL); 225 if (vif->mid == 0) 226 wil->radio_wdev = wil->main_ndev->ieee80211_ptr; 227 mutex_unlock(&wil->vif_mutex); 228 return 0; 229} 230 231void wil_p2p_listen_expired(struct work_struct *work) 232{ 233 struct wil_p2p_info *p2p = container_of(work, 234 struct wil_p2p_info, discovery_expired_work); 235 struct wil6210_vif *vif = container_of(p2p, 236 struct wil6210_vif, p2p); 237 struct wil6210_priv *wil = vif_to_wil(vif); 238 u8 started; 239 240 wil_dbg_misc(wil, "p2p_listen_expired\n"); 241 242 mutex_lock(&wil->mutex); 243 started = wil_p2p_stop_discovery(vif); 244 mutex_unlock(&wil->mutex); 245 246 if (!started) 247 return; 248 249 mutex_lock(&wil->vif_mutex); 250 cfg80211_remain_on_channel_expired(vif_to_radio_wdev(wil, vif), 251 p2p->cookie, 252 &p2p->listen_chan, 253 GFP_KERNEL); 254 if (vif->mid == 0) 255 wil->radio_wdev = wil->main_ndev->ieee80211_ptr; 256 mutex_unlock(&wil->vif_mutex); 257} 258 259void wil_p2p_search_expired(struct work_struct *work) 260{ 261 struct wil_p2p_info *p2p = container_of(work, 262 struct wil_p2p_info, discovery_expired_work); 263 struct wil6210_vif *vif = container_of(p2p, 264 struct wil6210_vif, p2p); 265 struct wil6210_priv *wil = vif_to_wil(vif); 266 u8 started; 267 268 wil_dbg_misc(wil, "p2p_search_expired\n"); 269 270 mutex_lock(&wil->mutex); 271 started = wil_p2p_stop_discovery(vif); 272 mutex_unlock(&wil->mutex); 273 274 if (started) { 275 struct cfg80211_scan_info info = { 276 .aborted = false, 277 }; 278 279 mutex_lock(&wil->vif_mutex); 280 if (vif->scan_request) { 281 cfg80211_scan_done(vif->scan_request, &info); 282 vif->scan_request = NULL; 283 if (vif->mid == 0) 284 wil->radio_wdev = 285 wil->main_ndev->ieee80211_ptr; 286 } 287 mutex_unlock(&wil->vif_mutex); 288 } 289} 290 291void wil_p2p_delayed_listen_work(struct work_struct *work) 292{ 293 struct wil_p2p_info *p2p = container_of(work, 294 struct wil_p2p_info, delayed_listen_work); 295 struct wil6210_vif *vif = container_of(p2p, 296 struct wil6210_vif, p2p); 297 struct wil6210_priv *wil = vif_to_wil(vif); 298 int rc; 299 300 mutex_lock(&wil->mutex); 301 302 wil_dbg_misc(wil, "Checking delayed p2p listen\n"); 303 if (!p2p->discovery_started || !p2p->pending_listen_wdev) 304 goto out; 305 306 mutex_lock(&wil->vif_mutex); 307 if (vif->scan_request) { 308 /* another scan started, wait again... */ 309 mutex_unlock(&wil->vif_mutex); 310 goto out; 311 } 312 mutex_unlock(&wil->vif_mutex); 313 314 rc = wil_p2p_start_listen(vif); 315 316 mutex_lock(&wil->vif_mutex); 317 if (rc) { 318 cfg80211_remain_on_channel_expired(p2p->pending_listen_wdev, 319 p2p->cookie, 320 &p2p->listen_chan, 321 GFP_KERNEL); 322 if (vif->mid == 0) 323 wil->radio_wdev = wil->main_ndev->ieee80211_ptr; 324 } else { 325 cfg80211_ready_on_channel(p2p->pending_listen_wdev, p2p->cookie, 326 &p2p->listen_chan, 327 p2p->listen_duration, GFP_KERNEL); 328 if (vif->mid == 0) 329 wil->radio_wdev = p2p->pending_listen_wdev; 330 } 331 p2p->pending_listen_wdev = NULL; 332 mutex_unlock(&wil->vif_mutex); 333 334out: 335 mutex_unlock(&wil->mutex); 336} 337 338void wil_p2p_stop_radio_operations(struct wil6210_priv *wil) 339{ 340 struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); 341 struct wil_p2p_info *p2p = &vif->p2p; 342 struct cfg80211_scan_info info = { 343 .aborted = true, 344 }; 345 346 lockdep_assert_held(&wil->mutex); 347 lockdep_assert_held(&wil->vif_mutex); 348 349 if (wil->radio_wdev != wil->p2p_wdev) 350 goto out; 351 352 if (!p2p->discovery_started) { 353 /* Regular scan on the p2p device */ 354 if (vif->scan_request && 355 vif->scan_request->wdev == wil->p2p_wdev) 356 wil_abort_scan(vif, true); 357 goto out; 358 } 359 360 /* Search or listen on p2p device */ 361 mutex_unlock(&wil->vif_mutex); 362 wil_p2p_stop_discovery(vif); 363 mutex_lock(&wil->vif_mutex); 364 365 if (vif->scan_request) { 366 /* search */ 367 cfg80211_scan_done(vif->scan_request, &info); 368 vif->scan_request = NULL; 369 } else { 370 /* listen */ 371 cfg80211_remain_on_channel_expired(wil->radio_wdev, 372 p2p->cookie, 373 &p2p->listen_chan, 374 GFP_KERNEL); 375 } 376 377out: 378 wil->radio_wdev = wil->main_ndev->ieee80211_ptr; 379}