scan.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Scan related functions.
  4. *
  5. * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
  6. * Copyright (c) 2010, ST-Ericsson
  7. */
  8. #include <net/mac80211.h>
  9. #include "scan.h"
  10. #include "wfx.h"
  11. #include "sta.h"
  12. #include "hif_tx_mib.h"
  13. static void __ieee80211_scan_completed_compat(struct ieee80211_hw *hw,
  14. bool aborted)
  15. {
  16. struct cfg80211_scan_info info = {
  17. .aborted = aborted,
  18. };
  19. ieee80211_scan_completed(hw, &info);
  20. }
  21. static int update_probe_tmpl(struct wfx_vif *wvif,
  22. struct cfg80211_scan_request *req)
  23. {
  24. struct sk_buff *skb;
  25. skb = ieee80211_probereq_get(wvif->wdev->hw, wvif->vif->addr,
  26. NULL, 0, req->ie_len);
  27. if (!skb)
  28. return -ENOMEM;
  29. skb_put_data(skb, req->ie, req->ie_len);
  30. hif_set_template_frame(wvif, skb, HIF_TMPLT_PRBREQ, 0);
  31. dev_kfree_skb(skb);
  32. return 0;
  33. }
  34. static int send_scan_req(struct wfx_vif *wvif,
  35. struct cfg80211_scan_request *req, int start_idx)
  36. {
  37. int i, ret, timeout;
  38. struct ieee80211_channel *ch_start, *ch_cur;
  39. for (i = start_idx; i < req->n_channels; i++) {
  40. ch_start = req->channels[start_idx];
  41. ch_cur = req->channels[i];
  42. WARN(ch_cur->band != NL80211_BAND_2GHZ, "band not supported");
  43. if (ch_cur->max_power != ch_start->max_power)
  44. break;
  45. if ((ch_cur->flags ^ ch_start->flags) & IEEE80211_CHAN_NO_IR)
  46. break;
  47. }
  48. wfx_tx_lock_flush(wvif->wdev);
  49. wvif->scan_abort = false;
  50. reinit_completion(&wvif->scan_complete);
  51. ret = hif_scan(wvif, req, start_idx, i - start_idx, &timeout);
  52. if (ret) {
  53. wfx_tx_unlock(wvif->wdev);
  54. return -EIO;
  55. }
  56. ret = wait_for_completion_timeout(&wvif->scan_complete, timeout);
  57. if (req->channels[start_idx]->max_power != wvif->vif->bss_conf.txpower)
  58. hif_set_output_power(wvif, wvif->vif->bss_conf.txpower);
  59. wfx_tx_unlock(wvif->wdev);
  60. if (!ret) {
  61. dev_notice(wvif->wdev->dev, "scan timeout\n");
  62. hif_stop_scan(wvif);
  63. return -ETIMEDOUT;
  64. }
  65. if (wvif->scan_abort) {
  66. dev_notice(wvif->wdev->dev, "scan abort\n");
  67. return -ECONNABORTED;
  68. }
  69. return i - start_idx;
  70. }
  71. /*
  72. * It is not really necessary to run scan request asynchronously. However,
  73. * there is a bug in "iw scan" when ieee80211_scan_completed() is called before
  74. * wfx_hw_scan() return
  75. */
  76. void wfx_hw_scan_work(struct work_struct *work)
  77. {
  78. struct wfx_vif *wvif = container_of(work, struct wfx_vif, scan_work);
  79. struct ieee80211_scan_request *hw_req = wvif->scan_req;
  80. int chan_cur, ret;
  81. mutex_lock(&wvif->wdev->conf_mutex);
  82. mutex_lock(&wvif->scan_lock);
  83. if (wvif->join_in_progress) {
  84. dev_info(wvif->wdev->dev, "%s: abort in-progress REQ_JOIN",
  85. __func__);
  86. wfx_reset(wvif);
  87. }
  88. update_probe_tmpl(wvif, &hw_req->req);
  89. chan_cur = 0;
  90. do {
  91. ret = send_scan_req(wvif, &hw_req->req, chan_cur);
  92. if (ret > 0)
  93. chan_cur += ret;
  94. } while (ret > 0 && chan_cur < hw_req->req.n_channels);
  95. mutex_unlock(&wvif->scan_lock);
  96. mutex_unlock(&wvif->wdev->conf_mutex);
  97. __ieee80211_scan_completed_compat(wvif->wdev->hw, ret < 0);
  98. }
  99. int wfx_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
  100. struct ieee80211_scan_request *hw_req)
  101. {
  102. struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
  103. WARN_ON(hw_req->req.n_channels > HIF_API_MAX_NB_CHANNELS);
  104. wvif->scan_req = hw_req;
  105. schedule_work(&wvif->scan_work);
  106. return 0;
  107. }
  108. void wfx_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
  109. {
  110. struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
  111. wvif->scan_abort = true;
  112. hif_stop_scan(wvif);
  113. }
  114. void wfx_scan_complete(struct wfx_vif *wvif)
  115. {
  116. complete(&wvif->scan_complete);
  117. }