xref: /linux/drivers/net/wireless/mediatek/mt76/scan.c (revision a1d9d8e833781c44ab688708804ce35f20f3cbbd)
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 &&
20 	    !test_bit(MT76_MCU_RESET, &dev->phy.state))
21 		mt76_set_channel(phy, &phy->main_chandef, false);
22 	mt76_put_vif_phy_link(phy, dev->scan.vif, dev->scan.mlink);
23 	memset(&dev->scan, 0, sizeof(dev->scan));
24 	if (!test_bit(MT76_MCU_RESET, &dev->phy.state))
25 		ieee80211_scan_completed(phy->hw, &info);
26 }
27 
mt76_abort_scan(struct mt76_dev * dev)28 void mt76_abort_scan(struct mt76_dev *dev)
29 {
30 	cancel_delayed_work_sync(&dev->scan_work);
31 	mt76_scan_complete(dev, true);
32 }
33 EXPORT_SYMBOL_GPL(mt76_abort_scan);
34 
35 static void
mt76_scan_send_probe(struct mt76_dev * dev,struct cfg80211_ssid * ssid)36 mt76_scan_send_probe(struct mt76_dev *dev, struct cfg80211_ssid *ssid)
37 {
38 	struct cfg80211_scan_request *req = dev->scan.req;
39 	struct ieee80211_vif *vif = dev->scan.vif;
40 	struct mt76_vif_link *mvif = dev->scan.mlink;
41 	enum nl80211_band band = dev->scan.chan->band;
42 	struct mt76_phy *phy = dev->scan.phy;
43 	struct ieee80211_tx_info *info;
44 	struct sk_buff *skb;
45 
46 	skb = ieee80211_probereq_get(phy->hw, vif->addr, ssid->ssid,
47 				     ssid->ssid_len, req->ie_len);
48 	if (!skb)
49 		return;
50 
51 	if (is_unicast_ether_addr(req->bssid)) {
52 		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
53 
54 		ether_addr_copy(hdr->addr1, req->bssid);
55 		ether_addr_copy(hdr->addr3, req->bssid);
56 	}
57 
58 	if (req->ie_len)
59 		skb_put_data(skb, req->ie, req->ie_len);
60 
61 	skb->priority = 7;
62 	skb_set_queue_mapping(skb, IEEE80211_AC_VO);
63 
64 	rcu_read_lock();
65 
66 	if (!ieee80211_tx_prepare_skb(phy->hw, vif, skb, band, NULL))
67 		goto out;
68 
69 	info = IEEE80211_SKB_CB(skb);
70 	if (req->no_cck)
71 		info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
72 	info->control.flags |= IEEE80211_TX_CTRL_DONT_USE_RATE_MASK;
73 
74 	mt76_tx(phy, NULL, mvif->wcid, skb);
75 
76 out:
77 	rcu_read_unlock();
78 }
79 
mt76_scan_work(struct work_struct * work)80 void mt76_scan_work(struct work_struct *work)
81 {
82 	struct mt76_dev *dev = container_of(work, struct mt76_dev,
83 					    scan_work.work);
84 	struct cfg80211_scan_request *req = dev->scan.req;
85 	struct cfg80211_chan_def chandef = {};
86 	struct mt76_phy *phy = dev->scan.phy;
87 	int duration = HZ / 9; /* ~110 ms */
88 	int i;
89 
90 	if (dev->scan.chan_idx >= req->n_channels) {
91 		mt76_scan_complete(dev, false);
92 		return;
93 	}
94 
95 	if (dev->scan.chan && phy->num_sta) {
96 		dev->scan.chan = NULL;
97 		mt76_set_channel(phy, &phy->main_chandef, false);
98 		goto out;
99 	}
100 
101 	dev->scan.chan = req->channels[dev->scan.chan_idx++];
102 	cfg80211_chandef_create(&chandef, dev->scan.chan, NL80211_CHAN_HT20);
103 	mt76_set_channel(phy, &chandef, true);
104 
105 	if (!req->n_ssids ||
106 	    chandef.chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR))
107 		goto out;
108 
109 	duration = HZ / 16; /* ~60 ms */
110 	local_bh_disable();
111 	for (i = 0; i < req->n_ssids; i++)
112 		mt76_scan_send_probe(dev, &req->ssids[i]);
113 	local_bh_enable();
114 
115 out:
116 	if (dev->scan.chan)
117 		duration = max_t(int, duration,
118 			         msecs_to_jiffies(req->duration +
119 						  (req->duration >> 5)));
120 
121 	ieee80211_queue_delayed_work(dev->phy.hw, &dev->scan_work, duration);
122 }
123 
mt76_hw_scan(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_scan_request * req)124 int mt76_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
125 		 struct ieee80211_scan_request *req)
126 {
127 	struct mt76_phy *phy = hw->priv;
128 	struct mt76_dev *dev = phy->dev;
129 	struct mt76_vif_link *mlink;
130 	int ret = 0;
131 
132 	if (hw->wiphy->n_radio > 1) {
133 		phy = dev->band_phys[req->req.channels[0]->band];
134 		if (!phy)
135 			return -EINVAL;
136 	}
137 
138 	mutex_lock(&dev->mutex);
139 
140 	if (dev->scan.req || phy->roc_vif ||
141 	    test_bit(MT76_MCU_RESET, &dev->phy.state)) {
142 		ret = -EBUSY;
143 		goto out;
144 	}
145 
146 	mlink = mt76_get_vif_phy_link(phy, vif);
147 	if (IS_ERR(mlink)) {
148 		ret = PTR_ERR(mlink);
149 		goto out;
150 	}
151 
152 	memset(&dev->scan, 0, sizeof(dev->scan));
153 	dev->scan.req = &req->req;
154 	dev->scan.vif = vif;
155 	dev->scan.phy = phy;
156 	dev->scan.mlink = mlink;
157 	ieee80211_queue_delayed_work(dev->phy.hw, &dev->scan_work, 0);
158 
159 out:
160 	mutex_unlock(&dev->mutex);
161 
162 	return ret;
163 }
164 EXPORT_SYMBOL_GPL(mt76_hw_scan);
165 
mt76_cancel_hw_scan(struct ieee80211_hw * hw,struct ieee80211_vif * vif)166 void mt76_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
167 {
168 	struct mt76_phy *phy = hw->priv;
169 
170 	mt76_abort_scan(phy->dev);
171 }
172 EXPORT_SYMBOL_GPL(mt76_cancel_hw_scan);
173