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(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(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