304 lines · c
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 8u16 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 36u8 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 67static 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 91static 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 115void 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 131void 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 145enum 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 158bool 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 170void 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 188enum 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 202enum 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 215u32 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 243static 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 292void 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