1 // SPDX-License-Identifier: BSD-3-Clause-Clear
2 /*
3 * Copyright (C) 2024 Felix Fietkau <nbd@nbd.name>
4 */
5 #include "mt76.h"
6
mt76_scan_complete(struct mt76_dev * dev,bool abort)7 static void mt76_scan_complete(struct mt76_dev *dev, bool abort)
8 {
9 struct mt76_phy *phy = dev->scan.phy;
10 struct cfg80211_scan_info info = {
11 .aborted = abort,
12 };
13
14 if (!phy)
15 return;
16
17 clear_bit(MT76_SCANNING, &phy->state);
18
19 if (dev->scan.chan && phy->main_chandef.chan && phy->offchannel &&
20 !test_bit(MT76_MCU_RESET, &dev->phy.state)) {
21 mt76_set_channel(phy, &phy->main_chandef, false);
22 mt76_offchannel_notify(phy, false);
23 }
24 mt76_put_vif_phy_link(phy, dev->scan.vif, dev->scan.mlink);
25 memset(&dev->scan, 0, sizeof(dev->scan));
26 if (!test_bit(MT76_MCU_RESET, &dev->phy.state))
27 ieee80211_scan_completed(phy->hw, &info);
28 }
29
mt76_abort_scan(struct mt76_dev * dev)30 void mt76_abort_scan(struct mt76_dev *dev)
31 {
32 spin_lock_bh(&dev->scan_lock);
33 dev->scan.beacon_wait = false;
34 spin_unlock_bh(&dev->scan_lock);
35
36 cancel_delayed_work_sync(&dev->scan_work);
37 mt76_scan_complete(dev, true);
38 }
39 EXPORT_SYMBOL_GPL(mt76_abort_scan);
40
41 static void
mt76_scan_send_probe(struct mt76_dev * dev,struct cfg80211_ssid * ssid)42 mt76_scan_send_probe(struct mt76_dev *dev, struct cfg80211_ssid *ssid)
43 {
44 struct cfg80211_scan_request *req = dev->scan.req;
45 struct ieee80211_vif *vif = dev->scan.vif;
46 struct mt76_vif_link *mvif = dev->scan.mlink;
47 enum nl80211_band band = dev->scan.chan->band;
48 struct mt76_phy *phy = dev->scan.phy;
49 struct ieee80211_tx_info *info;
50 struct sk_buff *skb;
51
52 skb = ieee80211_probereq_get(phy->hw, vif->addr, ssid->ssid,
53 ssid->ssid_len, req->ie_len);
54 if (!skb)
55 return;
56
57 if (is_unicast_ether_addr(req->bssid)) {
58 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
59
60 ether_addr_copy(hdr->addr1, req->bssid);
61 ether_addr_copy(hdr->addr3, req->bssid);
62 }
63
64 if (req->ie_len)
65 skb_put_data(skb, req->ie, req->ie_len);
66
67 skb->priority = 7;
68 skb_set_queue_mapping(skb, IEEE80211_AC_VO);
69
70 rcu_read_lock();
71
72 if (!ieee80211_tx_prepare_skb(phy->hw, vif, skb, band, NULL))
73 goto out;
74
75 info = IEEE80211_SKB_CB(skb);
76 if (req->no_cck)
77 info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
78 info->control.flags |= IEEE80211_TX_CTRL_DONT_USE_RATE_MASK;
79
80 mt76_tx(phy, NULL, mvif->wcid, skb);
81
82 out:
83 rcu_read_unlock();
84 }
85
mt76_scan_rx_beacon(struct mt76_dev * dev,struct ieee80211_channel * chan)86 void mt76_scan_rx_beacon(struct mt76_dev *dev, struct ieee80211_channel *chan)
87 {
88 struct mt76_phy *phy;
89
90 spin_lock(&dev->scan_lock);
91
92 if (!dev->scan.beacon_wait || dev->scan.beacon_received ||
93 dev->scan.chan != chan)
94 goto out;
95
96 phy = dev->scan.phy;
97 if (!phy)
98 goto out;
99
100 dev->scan.beacon_received = true;
101 ieee80211_queue_delayed_work(phy->hw, &dev->scan_work, 0);
102
103 out:
104 spin_unlock(&dev->scan_lock);
105 }
106
mt76_scan_work(struct work_struct * work)107 void mt76_scan_work(struct work_struct *work)
108 {
109 struct mt76_dev *dev = container_of(work, struct mt76_dev,
110 scan_work.work);
111 struct cfg80211_scan_request *req = dev->scan.req;
112 struct cfg80211_chan_def chandef = {};
113 struct mt76_phy *phy = dev->scan.phy;
114 int duration = HZ / 9; /* ~110 ms */
115 bool beacon_rx, offchannel = true;
116 int i;
117
118 if (!phy || !req)
119 return;
120
121 spin_lock_bh(&dev->scan_lock);
122 beacon_rx = dev->scan.beacon_wait && dev->scan.beacon_received;
123 dev->scan.beacon_wait = false;
124 spin_unlock_bh(&dev->scan_lock);
125
126 if (beacon_rx)
127 goto probe;
128
129 if (dev->scan.chan_idx >= req->n_channels) {
130 mt76_scan_complete(dev, false);
131 return;
132 }
133
134 if (dev->scan.chan && phy->num_sta && phy->offchannel) {
135 dev->scan.chan = NULL;
136 mt76_set_channel(phy, &phy->main_chandef, false);
137 mt76_offchannel_notify(phy, false);
138 goto out;
139 }
140
141 dev->scan.chan = req->channels[dev->scan.chan_idx++];
142 offchannel = mt76_offchannel_chandef(phy, dev->scan.chan, &chandef);
143
144 if (offchannel)
145 mt76_offchannel_notify(phy, true);
146 mt76_set_channel(phy, &chandef, offchannel);
147
148 if (!req->n_ssids)
149 goto out;
150
151 if (chandef.chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) {
152 spin_lock_bh(&dev->scan_lock);
153 dev->scan.beacon_received = false;
154 dev->scan.beacon_wait = true;
155 spin_unlock_bh(&dev->scan_lock);
156 goto out;
157 }
158
159 probe:
160 if (phy->offchannel)
161 duration = HZ / 16; /* ~60 ms */
162 local_bh_disable();
163 for (i = 0; i < req->n_ssids; i++)
164 mt76_scan_send_probe(dev, &req->ssids[i]);
165 local_bh_enable();
166
167 out:
168 if (dev->scan.chan && phy->offchannel)
169 duration = max_t(int, duration,
170 msecs_to_jiffies(req->duration +
171 (req->duration >> 5)));
172
173 ieee80211_queue_delayed_work(dev->phy.hw, &dev->scan_work, duration);
174 }
175
mt76_hw_scan(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_scan_request * req)176 int mt76_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
177 struct ieee80211_scan_request *req)
178 {
179 struct mt76_phy *phy = hw->priv;
180 struct mt76_dev *dev = phy->dev;
181 struct mt76_vif_link *mlink;
182 int ret = 0;
183
184 if (hw->wiphy->n_radio > 1) {
185 phy = dev->band_phys[req->req.channels[0]->band];
186 if (!phy)
187 return -EINVAL;
188 }
189
190 mutex_lock(&dev->mutex);
191
192 if (dev->scan.req || phy->roc_vif ||
193 test_bit(MT76_MCU_RESET, &dev->phy.state)) {
194 ret = -EBUSY;
195 goto out;
196 }
197
198 mlink = mt76_get_vif_phy_link(phy, vif);
199 if (IS_ERR(mlink)) {
200 ret = PTR_ERR(mlink);
201 goto out;
202 }
203
204 memset(&dev->scan, 0, sizeof(dev->scan));
205 dev->scan.req = &req->req;
206 dev->scan.vif = vif;
207 dev->scan.phy = phy;
208 dev->scan.mlink = mlink;
209 ieee80211_queue_delayed_work(dev->phy.hw, &dev->scan_work, 0);
210
211 out:
212 mutex_unlock(&dev->mutex);
213
214 return ret;
215 }
216 EXPORT_SYMBOL_GPL(mt76_hw_scan);
217
mt76_cancel_hw_scan(struct ieee80211_hw * hw,struct ieee80211_vif * vif)218 void mt76_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
219 {
220 struct mt76_phy *phy = hw->priv;
221
222 mt76_abort_scan(phy->dev);
223 }
224 EXPORT_SYMBOL_GPL(mt76_cancel_hw_scan);
225