xref: /linux/drivers/net/wireless/mediatek/mt76/scan.c (revision 5ea5880764cbb164afb17a62e76ca75dc371409d)
1 // SPDX-License-Identifier: BSD-3-Clause-Clear
2 /*
3  * Copyright (C) 2024 Felix Fietkau <nbd@nbd.name>
4  */
5 #include "mt76.h"
6 
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 
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
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 
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 
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 
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 
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