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 } 128 129 void qlink_chandef_cfg2q(const struct cfg80211_chan_def *chdef, 130 struct qlink_chandef *qch) 131 { 132 struct ieee80211_channel *chan = chdef->chan; 133 134 qch->chan.hw_value = cpu_to_le16(chan->hw_value); 135 qch->chan.center_freq = cpu_to_le16(chan->center_freq); 136 qch->chan.flags = cpu_to_le32(chan->flags); 137 138 qch->center_freq1 = cpu_to_le16(chdef->center_freq1); 139 qch->center_freq2 = cpu_to_le16(chdef->center_freq2); 140 qch->width = qlink_chanwidth_nl_to_qlink(chdef->width); 141 } 142 143 enum qlink_hidden_ssid qlink_hidden_ssid_nl2q(enum nl80211_hidden_ssid nl_val) 144 { 145 switch (nl_val) { 146 case NL80211_HIDDEN_SSID_ZERO_LEN: 147 return QLINK_HIDDEN_SSID_ZERO_LEN; 148 case NL80211_HIDDEN_SSID_ZERO_CONTENTS: 149 return QLINK_HIDDEN_SSID_ZERO_CONTENTS; 150 case NL80211_HIDDEN_SSID_NOT_IN_USE: 151 default: 152 return QLINK_HIDDEN_SSID_NOT_IN_USE; 153 } 154 } 155 156 bool qtnf_utils_is_bit_set(const u8 *arr, unsigned int bit, 157 unsigned int arr_max_len) 158 { 159 unsigned int idx = bit / BITS_PER_BYTE; 160 u8 mask = 1 << (bit - (idx * BITS_PER_BYTE)); 161 162 if (idx >= arr_max_len) 163 return false; 164 165 return arr[idx] & mask; 166 } 167 168 void qlink_acl_data_cfg2q(const struct cfg80211_acl_data *acl, 169 struct qlink_acl_data *qacl) 170 { 171 switch (acl->acl_policy) { 172 case NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED: 173 qacl->policy = 174 cpu_to_le32(QLINK_ACL_POLICY_ACCEPT_UNLESS_LISTED); 175 break; 176 case NL80211_ACL_POLICY_DENY_UNLESS_LISTED: 177 qacl->policy = cpu_to_le32(QLINK_ACL_POLICY_DENY_UNLESS_LISTED); 178 break; 179 } 180 181 qacl->num_entries = cpu_to_le32(acl->n_acl_entries); 182 memcpy(qacl->mac_addrs, acl->mac_addrs, 183 acl->n_acl_entries * sizeof(*qacl->mac_addrs)); 184 } 185 186 enum qlink_band qlink_utils_band_cfg2q(enum nl80211_band band) 187 { 188 switch (band) { 189 case NL80211_BAND_2GHZ: 190 return QLINK_BAND_2GHZ; 191 case NL80211_BAND_5GHZ: 192 return QLINK_BAND_5GHZ; 193 case NL80211_BAND_60GHZ: 194 return QLINK_BAND_60GHZ; 195 default: 196 return -EINVAL; 197 } 198 } 199 200 enum qlink_dfs_state qlink_utils_dfs_state_cfg2q(enum nl80211_dfs_state state) 201 { 202 switch (state) { 203 case NL80211_DFS_USABLE: 204 return QLINK_DFS_USABLE; 205 case NL80211_DFS_AVAILABLE: 206 return QLINK_DFS_AVAILABLE; 207 case NL80211_DFS_UNAVAILABLE: 208 default: 209 return QLINK_DFS_UNAVAILABLE; 210 } 211 } 212 213 u32 qlink_utils_chflags_cfg2q(u32 cfgflags) 214 { 215 u32 flags = 0; 216 217 if (cfgflags & IEEE80211_CHAN_DISABLED) 218 flags |= QLINK_CHAN_DISABLED; 219 220 if (cfgflags & IEEE80211_CHAN_NO_IR) 221 flags |= QLINK_CHAN_NO_IR; 222 223 if (cfgflags & IEEE80211_CHAN_RADAR) 224 flags |= QLINK_CHAN_RADAR; 225 226 if (cfgflags & IEEE80211_CHAN_NO_HT40PLUS) 227 flags |= QLINK_CHAN_NO_HT40PLUS; 228 229 if (cfgflags & IEEE80211_CHAN_NO_HT40MINUS) 230 flags |= QLINK_CHAN_NO_HT40MINUS; 231 232 if (cfgflags & IEEE80211_CHAN_NO_80MHZ) 233 flags |= QLINK_CHAN_NO_80MHZ; 234 235 if (cfgflags & IEEE80211_CHAN_NO_160MHZ) 236 flags |= QLINK_CHAN_NO_160MHZ; 237 238 return flags; 239 } 240 241 static u32 qtnf_reg_rule_flags_parse(u32 qflags) 242 { 243 u32 flags = 0; 244 245 if (qflags & QLINK_RRF_NO_OFDM) 246 flags |= NL80211_RRF_NO_OFDM; 247 248 if (qflags & QLINK_RRF_NO_CCK) 249 flags |= NL80211_RRF_NO_CCK; 250 251 if (qflags & QLINK_RRF_NO_INDOOR) 252 flags |= NL80211_RRF_NO_INDOOR; 253 254 if (qflags & QLINK_RRF_NO_OUTDOOR) 255 flags |= NL80211_RRF_NO_OUTDOOR; 256 257 if (qflags & QLINK_RRF_DFS) 258 flags |= NL80211_RRF_DFS; 259 260 if (qflags & QLINK_RRF_PTP_ONLY) 261 flags |= NL80211_RRF_PTP_ONLY; 262 263 if (qflags & QLINK_RRF_PTMP_ONLY) 264 flags |= NL80211_RRF_PTMP_ONLY; 265 266 if (qflags & QLINK_RRF_NO_IR) 267 flags |= NL80211_RRF_NO_IR; 268 269 if (qflags & QLINK_RRF_AUTO_BW) 270 flags |= NL80211_RRF_AUTO_BW; 271 272 if (qflags & QLINK_RRF_IR_CONCURRENT) 273 flags |= NL80211_RRF_IR_CONCURRENT; 274 275 if (qflags & QLINK_RRF_NO_HT40MINUS) 276 flags |= NL80211_RRF_NO_HT40MINUS; 277 278 if (qflags & QLINK_RRF_NO_HT40PLUS) 279 flags |= NL80211_RRF_NO_HT40PLUS; 280 281 if (qflags & QLINK_RRF_NO_80MHZ) 282 flags |= NL80211_RRF_NO_80MHZ; 283 284 if (qflags & QLINK_RRF_NO_160MHZ) 285 flags |= NL80211_RRF_NO_160MHZ; 286 287 return flags; 288 } 289 290 void qlink_utils_regrule_q2nl(struct ieee80211_reg_rule *rule, 291 const struct qlink_tlv_reg_rule *tlv) 292 { 293 rule->freq_range.start_freq_khz = le32_to_cpu(tlv->start_freq_khz); 294 rule->freq_range.end_freq_khz = le32_to_cpu(tlv->end_freq_khz); 295 rule->freq_range.max_bandwidth_khz = 296 le32_to_cpu(tlv->max_bandwidth_khz); 297 rule->power_rule.max_antenna_gain = le32_to_cpu(tlv->max_antenna_gain); 298 rule->power_rule.max_eirp = le32_to_cpu(tlv->max_eirp); 299 rule->dfs_cac_ms = le32_to_cpu(tlv->dfs_cac_ms); 300 rule->flags = qtnf_reg_rule_flags_parse(le32_to_cpu(tlv->flags)); 301 } 302