1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* Copyright (c) 2015-2016 Quantenna Communications. All rights reserved. */ |
3 | |
4 | #include <linux/nl80211.h> |
5 | |
6 | #include "qlink_util.h" |
7 | |
8 | u16 qlink_iface_type_to_nl_mask(u16 qlink_type) |
9 | { |
10 | u16 result = 0; |
11 | |
12 | switch (qlink_type) { |
13 | case QLINK_IFTYPE_AP: |
14 | result |= BIT(NL80211_IFTYPE_AP); |
15 | break; |
16 | case QLINK_IFTYPE_STATION: |
17 | result |= BIT(NL80211_IFTYPE_STATION); |
18 | break; |
19 | case QLINK_IFTYPE_ADHOC: |
20 | result |= BIT(NL80211_IFTYPE_ADHOC); |
21 | break; |
22 | case QLINK_IFTYPE_MONITOR: |
23 | result |= BIT(NL80211_IFTYPE_MONITOR); |
24 | break; |
25 | case QLINK_IFTYPE_WDS: |
26 | result |= BIT(NL80211_IFTYPE_WDS); |
27 | break; |
28 | case QLINK_IFTYPE_AP_VLAN: |
29 | result |= BIT(NL80211_IFTYPE_AP_VLAN); |
30 | break; |
31 | } |
32 | |
33 | return result; |
34 | } |
35 | |
36 | u8 qlink_chan_width_mask_to_nl(u16 qlink_mask) |
37 | { |
38 | u8 result = 0; |
39 | |
40 | if (qlink_mask & BIT(QLINK_CHAN_WIDTH_5)) |
41 | result |= BIT(NL80211_CHAN_WIDTH_5); |
42 | |
43 | if (qlink_mask & BIT(QLINK_CHAN_WIDTH_10)) |
44 | result |= BIT(NL80211_CHAN_WIDTH_10); |
45 | |
46 | if (qlink_mask & BIT(QLINK_CHAN_WIDTH_20_NOHT)) |
47 | result |= BIT(NL80211_CHAN_WIDTH_20_NOHT); |
48 | |
49 | if (qlink_mask & BIT(QLINK_CHAN_WIDTH_20)) |
50 | result |= BIT(NL80211_CHAN_WIDTH_20); |
51 | |
52 | if (qlink_mask & BIT(QLINK_CHAN_WIDTH_40)) |
53 | result |= BIT(NL80211_CHAN_WIDTH_40); |
54 | |
55 | if (qlink_mask & BIT(QLINK_CHAN_WIDTH_80)) |
56 | result |= BIT(NL80211_CHAN_WIDTH_80); |
57 | |
58 | if (qlink_mask & BIT(QLINK_CHAN_WIDTH_80P80)) |
59 | result |= BIT(NL80211_CHAN_WIDTH_80P80); |
60 | |
61 | if (qlink_mask & BIT(QLINK_CHAN_WIDTH_160)) |
62 | result |= BIT(NL80211_CHAN_WIDTH_160); |
63 | |
64 | return result; |
65 | } |
66 | |
67 | static enum nl80211_chan_width qlink_chanwidth_to_nl(u8 qlw) |
68 | { |
69 | switch (qlw) { |
70 | case QLINK_CHAN_WIDTH_20_NOHT: |
71 | return NL80211_CHAN_WIDTH_20_NOHT; |
72 | case QLINK_CHAN_WIDTH_20: |
73 | return NL80211_CHAN_WIDTH_20; |
74 | case QLINK_CHAN_WIDTH_40: |
75 | return NL80211_CHAN_WIDTH_40; |
76 | case QLINK_CHAN_WIDTH_80: |
77 | return NL80211_CHAN_WIDTH_80; |
78 | case QLINK_CHAN_WIDTH_80P80: |
79 | return NL80211_CHAN_WIDTH_80P80; |
80 | case QLINK_CHAN_WIDTH_160: |
81 | return NL80211_CHAN_WIDTH_160; |
82 | case QLINK_CHAN_WIDTH_5: |
83 | return NL80211_CHAN_WIDTH_5; |
84 | case QLINK_CHAN_WIDTH_10: |
85 | return NL80211_CHAN_WIDTH_10; |
86 | default: |
87 | return -1; |
88 | } |
89 | } |
90 | |
91 | static u8 qlink_chanwidth_nl_to_qlink(enum nl80211_chan_width nlwidth) |
92 | { |
93 | switch (nlwidth) { |
94 | case NL80211_CHAN_WIDTH_20_NOHT: |
95 | return QLINK_CHAN_WIDTH_20_NOHT; |
96 | case NL80211_CHAN_WIDTH_20: |
97 | return QLINK_CHAN_WIDTH_20; |
98 | case NL80211_CHAN_WIDTH_40: |
99 | return QLINK_CHAN_WIDTH_40; |
100 | case NL80211_CHAN_WIDTH_80: |
101 | return QLINK_CHAN_WIDTH_80; |
102 | case NL80211_CHAN_WIDTH_80P80: |
103 | return QLINK_CHAN_WIDTH_80P80; |
104 | case NL80211_CHAN_WIDTH_160: |
105 | return QLINK_CHAN_WIDTH_160; |
106 | case NL80211_CHAN_WIDTH_5: |
107 | return QLINK_CHAN_WIDTH_5; |
108 | case NL80211_CHAN_WIDTH_10: |
109 | return QLINK_CHAN_WIDTH_10; |
110 | default: |
111 | return -1; |
112 | } |
113 | } |
114 | |
115 | void qlink_chandef_q2cfg(struct wiphy *wiphy, |
116 | const struct qlink_chandef *qch, |
117 | struct cfg80211_chan_def *chdef) |
118 | { |
119 | struct ieee80211_channel *chan; |
120 | |
121 | chan = ieee80211_get_channel(wiphy, le16_to_cpu(qch->chan.center_freq)); |
122 | |
123 | chdef->chan = chan; |
124 | chdef->center_freq1 = le16_to_cpu(qch->center_freq1); |
125 | chdef->center_freq2 = le16_to_cpu(qch->center_freq2); |
126 | chdef->width = qlink_chanwidth_to_nl(qlw: qch->width); |
127 | chdef->edmg.bw_config = 0; |
128 | chdef->edmg.channels = 0; |
129 | } |
130 | |
131 | void qlink_chandef_cfg2q(const struct cfg80211_chan_def *chdef, |
132 | struct qlink_chandef *qch) |
133 | { |
134 | struct ieee80211_channel *chan = chdef->chan; |
135 | |
136 | qch->chan.hw_value = cpu_to_le16(chan->hw_value); |
137 | qch->chan.center_freq = cpu_to_le16(chan->center_freq); |
138 | qch->chan.flags = cpu_to_le32(chan->flags); |
139 | |
140 | qch->center_freq1 = cpu_to_le16(chdef->center_freq1); |
141 | qch->center_freq2 = cpu_to_le16(chdef->center_freq2); |
142 | qch->width = qlink_chanwidth_nl_to_qlink(nlwidth: chdef->width); |
143 | } |
144 | |
145 | enum qlink_hidden_ssid qlink_hidden_ssid_nl2q(enum nl80211_hidden_ssid nl_val) |
146 | { |
147 | switch (nl_val) { |
148 | case NL80211_HIDDEN_SSID_ZERO_LEN: |
149 | return QLINK_HIDDEN_SSID_ZERO_LEN; |
150 | case NL80211_HIDDEN_SSID_ZERO_CONTENTS: |
151 | return QLINK_HIDDEN_SSID_ZERO_CONTENTS; |
152 | case NL80211_HIDDEN_SSID_NOT_IN_USE: |
153 | default: |
154 | return QLINK_HIDDEN_SSID_NOT_IN_USE; |
155 | } |
156 | } |
157 | |
158 | bool qtnf_utils_is_bit_set(const u8 *arr, unsigned int bit, |
159 | unsigned int arr_max_len) |
160 | { |
161 | unsigned int idx = bit / BITS_PER_BYTE; |
162 | u8 mask = 1 << (bit - (idx * BITS_PER_BYTE)); |
163 | |
164 | if (idx >= arr_max_len) |
165 | return false; |
166 | |
167 | return arr[idx] & mask; |
168 | } |
169 | |
170 | void qlink_acl_data_cfg2q(const struct cfg80211_acl_data *acl, |
171 | struct qlink_acl_data *qacl) |
172 | { |
173 | switch (acl->acl_policy) { |
174 | case NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED: |
175 | qacl->policy = |
176 | cpu_to_le32(QLINK_ACL_POLICY_ACCEPT_UNLESS_LISTED); |
177 | break; |
178 | case NL80211_ACL_POLICY_DENY_UNLESS_LISTED: |
179 | qacl->policy = cpu_to_le32(QLINK_ACL_POLICY_DENY_UNLESS_LISTED); |
180 | break; |
181 | } |
182 | |
183 | qacl->num_entries = cpu_to_le32(acl->n_acl_entries); |
184 | memcpy(qacl->mac_addrs, acl->mac_addrs, |
185 | acl->n_acl_entries * sizeof(*qacl->mac_addrs)); |
186 | } |
187 | |
188 | enum qlink_band qlink_utils_band_cfg2q(enum nl80211_band band) |
189 | { |
190 | switch (band) { |
191 | case NL80211_BAND_2GHZ: |
192 | return QLINK_BAND_2GHZ; |
193 | case NL80211_BAND_5GHZ: |
194 | return QLINK_BAND_5GHZ; |
195 | case NL80211_BAND_60GHZ: |
196 | return QLINK_BAND_60GHZ; |
197 | default: |
198 | return -EINVAL; |
199 | } |
200 | } |
201 | |
202 | enum qlink_dfs_state qlink_utils_dfs_state_cfg2q(enum nl80211_dfs_state state) |
203 | { |
204 | switch (state) { |
205 | case NL80211_DFS_USABLE: |
206 | return QLINK_DFS_USABLE; |
207 | case NL80211_DFS_AVAILABLE: |
208 | return QLINK_DFS_AVAILABLE; |
209 | case NL80211_DFS_UNAVAILABLE: |
210 | default: |
211 | return QLINK_DFS_UNAVAILABLE; |
212 | } |
213 | } |
214 | |
215 | u32 qlink_utils_chflags_cfg2q(u32 cfgflags) |
216 | { |
217 | u32 flags = 0; |
218 | |
219 | if (cfgflags & IEEE80211_CHAN_DISABLED) |
220 | flags |= QLINK_CHAN_DISABLED; |
221 | |
222 | if (cfgflags & IEEE80211_CHAN_NO_IR) |
223 | flags |= QLINK_CHAN_NO_IR; |
224 | |
225 | if (cfgflags & IEEE80211_CHAN_RADAR) |
226 | flags |= QLINK_CHAN_RADAR; |
227 | |
228 | if (cfgflags & IEEE80211_CHAN_NO_HT40PLUS) |
229 | flags |= QLINK_CHAN_NO_HT40PLUS; |
230 | |
231 | if (cfgflags & IEEE80211_CHAN_NO_HT40MINUS) |
232 | flags |= QLINK_CHAN_NO_HT40MINUS; |
233 | |
234 | if (cfgflags & IEEE80211_CHAN_NO_80MHZ) |
235 | flags |= QLINK_CHAN_NO_80MHZ; |
236 | |
237 | if (cfgflags & IEEE80211_CHAN_NO_160MHZ) |
238 | flags |= QLINK_CHAN_NO_160MHZ; |
239 | |
240 | return flags; |
241 | } |
242 | |
243 | static u32 qtnf_reg_rule_flags_parse(u32 qflags) |
244 | { |
245 | u32 flags = 0; |
246 | |
247 | if (qflags & QLINK_RRF_NO_OFDM) |
248 | flags |= NL80211_RRF_NO_OFDM; |
249 | |
250 | if (qflags & QLINK_RRF_NO_CCK) |
251 | flags |= NL80211_RRF_NO_CCK; |
252 | |
253 | if (qflags & QLINK_RRF_NO_INDOOR) |
254 | flags |= NL80211_RRF_NO_INDOOR; |
255 | |
256 | if (qflags & QLINK_RRF_NO_OUTDOOR) |
257 | flags |= NL80211_RRF_NO_OUTDOOR; |
258 | |
259 | if (qflags & QLINK_RRF_DFS) |
260 | flags |= NL80211_RRF_DFS; |
261 | |
262 | if (qflags & QLINK_RRF_PTP_ONLY) |
263 | flags |= NL80211_RRF_PTP_ONLY; |
264 | |
265 | if (qflags & QLINK_RRF_PTMP_ONLY) |
266 | flags |= NL80211_RRF_PTMP_ONLY; |
267 | |
268 | if (qflags & QLINK_RRF_NO_IR) |
269 | flags |= NL80211_RRF_NO_IR; |
270 | |
271 | if (qflags & QLINK_RRF_AUTO_BW) |
272 | flags |= NL80211_RRF_AUTO_BW; |
273 | |
274 | if (qflags & QLINK_RRF_IR_CONCURRENT) |
275 | flags |= NL80211_RRF_IR_CONCURRENT; |
276 | |
277 | if (qflags & QLINK_RRF_NO_HT40MINUS) |
278 | flags |= NL80211_RRF_NO_HT40MINUS; |
279 | |
280 | if (qflags & QLINK_RRF_NO_HT40PLUS) |
281 | flags |= NL80211_RRF_NO_HT40PLUS; |
282 | |
283 | if (qflags & QLINK_RRF_NO_80MHZ) |
284 | flags |= NL80211_RRF_NO_80MHZ; |
285 | |
286 | if (qflags & QLINK_RRF_NO_160MHZ) |
287 | flags |= NL80211_RRF_NO_160MHZ; |
288 | |
289 | return flags; |
290 | } |
291 | |
292 | void qlink_utils_regrule_q2nl(struct ieee80211_reg_rule *rule, |
293 | const struct qlink_tlv_reg_rule *tlv) |
294 | { |
295 | rule->freq_range.start_freq_khz = le32_to_cpu(tlv->start_freq_khz); |
296 | rule->freq_range.end_freq_khz = le32_to_cpu(tlv->end_freq_khz); |
297 | rule->freq_range.max_bandwidth_khz = |
298 | le32_to_cpu(tlv->max_bandwidth_khz); |
299 | rule->power_rule.max_antenna_gain = le32_to_cpu(tlv->max_antenna_gain); |
300 | rule->power_rule.max_eirp = le32_to_cpu(tlv->max_eirp); |
301 | rule->dfs_cac_ms = le32_to_cpu(tlv->dfs_cac_ms); |
302 | rule->flags = qtnf_reg_rule_flags_parse(le32_to_cpu(tlv->flags)); |
303 | } |
304 | |