root/drivers/net/wireless/ath/wil6210/p2p.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. wil_p2p_start_listen
  2. wil_p2p_is_social_scan
  3. wil_p2p_search
  4. wil_p2p_listen
  5. wil_p2p_stop_discovery
  6. wil_p2p_cancel_listen
  7. wil_p2p_listen_expired
  8. wil_p2p_search_expired
  9. wil_p2p_delayed_listen_work
  10. wil_p2p_stop_radio_operations

   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 }

/* [<][>][^][v][top][bottom][index][help] */