static int cfg80211_wext_siwtxpower(struct net_device *dev, struct iw_request_info *info, union iwreq_data *data, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); enum nl80211_tx_power_setting type; int dbm = 0; if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) return -EINVAL; if (data->txpower.flags & IW_TXPOW_RANGE) return -EINVAL; if (!rdev->ops->set_tx_power) return -EOPNOTSUPP; /* only change when not disabling */ if (!data->txpower.disabled) { rfkill_set_sw_state(rdev->rfkill, false); if (data->txpower.fixed) { /* * wext doesn't support negative values, see * below where it's for automatic */ if (data->txpower.value < 0) return -EINVAL; dbm = data->txpower.value; type = NL80211_TX_POWER_FIXED; /* TODO: do regulatory check! */ } else { /* * Automatic power level setting, max being the value * passed in from userland. */ if (data->txpower.value < 0) { type = NL80211_TX_POWER_AUTOMATIC; } else { dbm = data->txpower.value; type = NL80211_TX_POWER_LIMITED; } } } else { rfkill_set_sw_state(rdev->rfkill, true); schedule_work(&rdev->rfkill_sync); return 0; } return rdev->ops->set_tx_power(wdev->wiphy, type, DBM_TO_MBM(dbm)); }
static int cfg80211_wext_siwtxpower(struct net_device *dev, struct iw_request_info *info, union iwreq_data *data, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); enum nl80211_tx_power_setting type; int dbm = 0; if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) return -EINVAL; if (data->txpower.flags & IW_TXPOW_RANGE) return -EINVAL; if (!rdev->ops->set_tx_power) return -EOPNOTSUPP; /* */ if (!data->txpower.disabled) { rfkill_set_sw_state(rdev->rfkill, false); if (data->txpower.fixed) { /* */ if (data->txpower.value < 0) return -EINVAL; dbm = data->txpower.value; type = NL80211_TX_POWER_FIXED; /* */ } else { /* */ if (data->txpower.value < 0) { type = NL80211_TX_POWER_AUTOMATIC; } else { dbm = data->txpower.value; type = NL80211_TX_POWER_LIMITED; } } } else { rfkill_set_sw_state(rdev->rfkill, true); schedule_work(&rdev->rfkill_sync); return 0; } return rdev->ops->set_tx_power(wdev->wiphy, type, DBM_TO_MBM(dbm)); }
struct ieee80211_regdomain * iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, int num_of_ch, __le32 *channels, u16 fw_mcc) { int ch_idx; u16 ch_flags, prev_ch_flags = 0; const u8 *nvm_chan = cfg->device_family == IWL_DEVICE_FAMILY_8000 ? iwl_nvm_channels_family_8000 : iwl_nvm_channels; struct ieee80211_regdomain *regd; int size_of_regd; struct ieee80211_reg_rule *rule; enum nl80211_band band; int center_freq, prev_center_freq = 0; int valid_rules = 0; bool new_rule; int max_num_ch = cfg->device_family == IWL_DEVICE_FAMILY_8000 ? IWL_NUM_CHANNELS_FAMILY_8000 : IWL_NUM_CHANNELS; if (WARN_ON_ONCE(num_of_ch > NL80211_MAX_SUPP_REG_RULES)) return ERR_PTR(-EINVAL); if (WARN_ON(num_of_ch > max_num_ch)) num_of_ch = max_num_ch; IWL_DEBUG_DEV(dev, IWL_DL_LAR, "building regdom for %d channels\n", num_of_ch); /* build a regdomain rule for every valid channel */ size_of_regd = sizeof(struct ieee80211_regdomain) + num_of_ch * sizeof(struct ieee80211_reg_rule); regd = kzalloc(size_of_regd, GFP_KERNEL); if (!regd) return ERR_PTR(-ENOMEM); for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) { ch_flags = (u16)__le32_to_cpup(channels + ch_idx); band = (ch_idx < NUM_2GHZ_CHANNELS) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ; center_freq = ieee80211_channel_to_frequency(nvm_chan[ch_idx], band); new_rule = false; if (!(ch_flags & NVM_CHANNEL_VALID)) { IWL_DEBUG_DEV(dev, IWL_DL_LAR, "Ch. %d Flags %x [%sGHz] - No traffic\n", nvm_chan[ch_idx], ch_flags, (ch_idx >= NUM_2GHZ_CHANNELS) ? "5.2" : "2.4"); continue; } /* we can't continue the same rule */ if (ch_idx == 0 || prev_ch_flags != ch_flags || center_freq - prev_center_freq > 20) { valid_rules++; new_rule = true; } rule = ®d->reg_rules[valid_rules - 1]; if (new_rule) rule->freq_range.start_freq_khz = MHZ_TO_KHZ(center_freq - 10); rule->freq_range.end_freq_khz = MHZ_TO_KHZ(center_freq + 10); /* this doesn't matter - not used by FW */ rule->power_rule.max_antenna_gain = DBI_TO_MBI(6); rule->power_rule.max_eirp = DBM_TO_MBM(IWL_DEFAULT_MAX_TX_POWER); rule->flags = iwl_nvm_get_regdom_bw_flags(nvm_chan, ch_idx, ch_flags, cfg); /* rely on auto-calculation to merge BW of contiguous chans */ rule->flags |= NL80211_RRF_AUTO_BW; rule->freq_range.max_bandwidth_khz = 0; prev_ch_flags = ch_flags; prev_center_freq = center_freq; IWL_DEBUG_DEV(dev, IWL_DL_LAR, "Ch. %d [%sGHz] %s%s%s%s%s%s%s%s%s(0x%02x): Ad-Hoc %ssupported\n", center_freq, band == NL80211_BAND_5GHZ ? "5.2" : "2.4", CHECK_AND_PRINT_I(VALID), CHECK_AND_PRINT_I(ACTIVE), CHECK_AND_PRINT_I(RADAR), CHECK_AND_PRINT_I(WIDE), CHECK_AND_PRINT_I(40MHZ), CHECK_AND_PRINT_I(80MHZ), CHECK_AND_PRINT_I(160MHZ), CHECK_AND_PRINT_I(INDOOR_ONLY), CHECK_AND_PRINT_I(GO_CONCURRENT), ch_flags, ((ch_flags & NVM_CHANNEL_ACTIVE) && !(ch_flags & NVM_CHANNEL_RADAR)) ? "" : "not "); } regd->n_reg_rules = valid_rules; /* set alpha2 from FW. */ regd->alpha2[0] = fw_mcc >> 8; regd->alpha2[1] = fw_mcc & 0xff; return regd; }
static struct ieee80211_regdomain * mwifiex_create_custom_regdomain(struct mwifiex_private *priv, u8 *buf, u16 buf_len) { u16 num_chan = buf_len / 2; struct ieee80211_regdomain *regd; struct ieee80211_reg_rule *rule; bool new_rule; int regd_size, idx, freq, prev_freq = 0; u32 bw, prev_bw = 0; u8 chflags, prev_chflags = 0, valid_rules = 0; if (WARN_ON_ONCE(num_chan > NL80211_MAX_SUPP_REG_RULES)) return ERR_PTR(-EINVAL); regd_size = sizeof(struct ieee80211_regdomain) + num_chan * sizeof(struct ieee80211_reg_rule); regd = kzalloc(regd_size, GFP_KERNEL); if (!regd) return ERR_PTR(-ENOMEM); for (idx = 0; idx < num_chan; idx++) { u8 chan; enum nl80211_band band; chan = *buf++; if (!chan) { kfree(regd); return NULL; } chflags = *buf++; band = (chan <= 14) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ; freq = ieee80211_channel_to_frequency(chan, band); new_rule = false; if (chflags & MWIFIEX_CHANNEL_DISABLED) continue; if (band == NL80211_BAND_5GHZ) { if (!(chflags & MWIFIEX_CHANNEL_NOHT80)) bw = MHZ_TO_KHZ(80); else if (!(chflags & MWIFIEX_CHANNEL_NOHT40)) bw = MHZ_TO_KHZ(40); else bw = MHZ_TO_KHZ(20); } else { if (!(chflags & MWIFIEX_CHANNEL_NOHT40)) bw = MHZ_TO_KHZ(40); else bw = MHZ_TO_KHZ(20); } if (idx == 0 || prev_chflags != chflags || prev_bw != bw || freq - prev_freq > 20) { valid_rules++; new_rule = true; } rule = ®d->reg_rules[valid_rules - 1]; rule->freq_range.end_freq_khz = MHZ_TO_KHZ(freq + 10); prev_chflags = chflags; prev_freq = freq; prev_bw = bw; if (!new_rule) continue; rule->freq_range.start_freq_khz = MHZ_TO_KHZ(freq - 10); rule->power_rule.max_eirp = DBM_TO_MBM(19); if (chflags & MWIFIEX_CHANNEL_PASSIVE) rule->flags = NL80211_RRF_NO_IR; if (chflags & MWIFIEX_CHANNEL_DFS) rule->flags = NL80211_RRF_DFS; rule->freq_range.max_bandwidth_khz = bw; } regd->n_reg_rules = valid_rules; regd->alpha2[0] = '9'; regd->alpha2[1] = '9'; return regd; }
static int qtnf_event_handle_scan_results(struct qtnf_vif *vif, const struct qlink_event_scan_result *sr, u16 len) { struct cfg80211_bss *bss; struct ieee80211_channel *channel; struct wiphy *wiphy = priv_to_wiphy(vif->mac); enum cfg80211_bss_frame_type frame_type = CFG80211_BSS_FTYPE_UNKNOWN; size_t payload_len; u16 tlv_type; u16 tlv_value_len; size_t tlv_full_len; const struct qlink_tlv_hdr *tlv; const u8 *ies = NULL; size_t ies_len = 0; if (len < sizeof(*sr)) { pr_err("VIF%u.%u: payload is too short\n", vif->mac->macid, vif->vifid); return -EINVAL; } channel = ieee80211_get_channel(wiphy, le16_to_cpu(sr->freq)); if (!channel) { pr_err("VIF%u.%u: channel at %u MHz not found\n", vif->mac->macid, vif->vifid, le16_to_cpu(sr->freq)); return -EINVAL; } payload_len = len - sizeof(*sr); tlv = (struct qlink_tlv_hdr *)sr->payload; while (payload_len >= sizeof(struct qlink_tlv_hdr)) { tlv_type = le16_to_cpu(tlv->type); tlv_value_len = le16_to_cpu(tlv->len); tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr); if (tlv_full_len > payload_len) return -EINVAL; if (tlv_type == QTN_TLV_ID_IE_SET) { const struct qlink_tlv_ie_set *ie_set; unsigned int ie_len; if (payload_len < sizeof(*ie_set)) return -EINVAL; ie_set = (const struct qlink_tlv_ie_set *)tlv; ie_len = tlv_value_len - (sizeof(*ie_set) - sizeof(ie_set->hdr)); switch (ie_set->type) { case QLINK_IE_SET_BEACON_IES: frame_type = CFG80211_BSS_FTYPE_BEACON; break; case QLINK_IE_SET_PROBE_RESP_IES: frame_type = CFG80211_BSS_FTYPE_PRESP; break; default: frame_type = CFG80211_BSS_FTYPE_UNKNOWN; } if (ie_len) { ies = ie_set->ie_data; ies_len = ie_len; } } payload_len -= tlv_full_len; tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len); } if (payload_len) return -EINVAL; bss = cfg80211_inform_bss(wiphy, channel, frame_type, sr->bssid, get_unaligned_le64(&sr->tsf), le16_to_cpu(sr->capab), le16_to_cpu(sr->bintval), ies, ies_len, DBM_TO_MBM(sr->sig_dbm), GFP_KERNEL); if (!bss) return -ENOMEM; cfg80211_put_bss(wiphy, bss); return 0; }