scan.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  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 wfx_ieee80211_scan_completed_compat(struct ieee80211_hw *hw, bool aborted)
  14. {
  15. struct cfg80211_scan_info info = {
  16. .aborted = aborted,
  17. };
  18. ieee80211_scan_completed(hw, &info);
  19. }
  20. static int update_probe_tmpl(struct wfx_vif *wvif, struct cfg80211_scan_request *req)
  21. {
  22. struct ieee80211_vif *vif = wvif_to_vif(wvif);
  23. struct sk_buff *skb;
  24. skb = ieee80211_probereq_get(wvif->wdev->hw, vif->addr, NULL, 0,
  25. req->ie_len);
  26. if (!skb)
  27. return -ENOMEM;
  28. skb_put_data(skb, req->ie, req->ie_len);
  29. wfx_hif_set_template_frame(wvif, skb, HIF_TMPLT_PRBREQ, 0);
  30. dev_kfree_skb(skb);
  31. return 0;
  32. }
  33. static int send_scan_req(struct wfx_vif *wvif, struct cfg80211_scan_request *req, int start_idx)
  34. {
  35. struct ieee80211_vif *vif = wvif_to_vif(wvif);
  36. struct ieee80211_channel *ch_start, *ch_cur;
  37. int i, ret;
  38. for (i = start_idx; i < req->n_channels; i++) {
  39. ch_start = req->channels[start_idx];
  40. ch_cur = req->channels[i];
  41. WARN(ch_cur->band != NL80211_BAND_2GHZ, "band not supported");
  42. if (ch_cur->max_power != ch_start->max_power)
  43. break;
  44. if ((ch_cur->flags ^ ch_start->flags) & IEEE80211_CHAN_NO_IR)
  45. break;
  46. }
  47. wfx_tx_lock_flush(wvif->wdev);
  48. wvif->scan_abort = false;
  49. reinit_completion(&wvif->scan_complete);
  50. ret = wfx_hif_scan(wvif, req, start_idx, i - start_idx);
  51. if (ret) {
  52. wfx_tx_unlock(wvif->wdev);
  53. return -EIO;
  54. }
  55. ret = wait_for_completion_timeout(&wvif->scan_complete, 1 * HZ);
  56. if (!ret) {
  57. wfx_hif_stop_scan(wvif);
  58. ret = wait_for_completion_timeout(&wvif->scan_complete, 1 * HZ);
  59. dev_dbg(wvif->wdev->dev, "scan timeout (%d channels done)\n",
  60. wvif->scan_nb_chan_done);
  61. }
  62. if (!ret) {
  63. dev_err(wvif->wdev->dev, "scan didn't stop\n");
  64. ret = -ETIMEDOUT;
  65. } else if (wvif->scan_abort) {
  66. dev_notice(wvif->wdev->dev, "scan abort\n");
  67. ret = -ECONNABORTED;
  68. } else if (wvif->scan_nb_chan_done > i - start_idx) {
  69. ret = -EIO;
  70. } else {
  71. ret = wvif->scan_nb_chan_done;
  72. }
  73. if (req->channels[start_idx]->max_power != vif->bss_conf.txpower)
  74. wfx_hif_set_output_power(wvif, vif->bss_conf.txpower);
  75. wfx_tx_unlock(wvif->wdev);
  76. return ret;
  77. }
  78. /* It is not really necessary to run scan request asynchronously. However,
  79. * there is a bug in "iw scan" when ieee80211_scan_completed() is called before
  80. * wfx_hw_scan() return
  81. */
  82. void wfx_hw_scan_work(struct work_struct *work)
  83. {
  84. struct wfx_vif *wvif = container_of(work, struct wfx_vif, scan_work);
  85. struct ieee80211_scan_request *hw_req = wvif->scan_req;
  86. int chan_cur, ret, err;
  87. mutex_lock(&wvif->wdev->conf_mutex);
  88. mutex_lock(&wvif->scan_lock);
  89. if (wvif->join_in_progress) {
  90. dev_info(wvif->wdev->dev, "abort in-progress REQ_JOIN");
  91. wfx_reset(wvif);
  92. }
  93. update_probe_tmpl(wvif, &hw_req->req);
  94. chan_cur = 0;
  95. err = 0;
  96. do {
  97. ret = send_scan_req(wvif, &hw_req->req, chan_cur);
  98. if (ret > 0) {
  99. chan_cur += ret;
  100. err = 0;
  101. }
  102. if (!ret)
  103. err++;
  104. if (err > 2) {
  105. dev_err(wvif->wdev->dev, "scan has not been able to start\n");
  106. ret = -ETIMEDOUT;
  107. }
  108. } while (ret >= 0 && chan_cur < hw_req->req.n_channels);
  109. mutex_unlock(&wvif->scan_lock);
  110. mutex_unlock(&wvif->wdev->conf_mutex);
  111. wfx_ieee80211_scan_completed_compat(wvif->wdev->hw, ret < 0);
  112. }
  113. int wfx_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
  114. struct ieee80211_scan_request *hw_req)
  115. {
  116. struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
  117. WARN_ON(hw_req->req.n_channels > HIF_API_MAX_NB_CHANNELS);
  118. wvif->scan_req = hw_req;
  119. schedule_work(&wvif->scan_work);
  120. return 0;
  121. }
  122. void wfx_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
  123. {
  124. struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
  125. wvif->scan_abort = true;
  126. wfx_hif_stop_scan(wvif);
  127. }
  128. void wfx_scan_complete(struct wfx_vif *wvif, int nb_chan_done)
  129. {
  130. wvif->scan_nb_chan_done = nb_chan_done;
  131. complete(&wvif->scan_complete);
  132. }