/* force it also for scanning, since drivers might config differently */ if (offchannel_flag || local->scanning || local->in_reconfig ||
!cfg80211_chandef_identical(&local->hw.conf.chandef, &chandef)) {
local->hw.conf.chandef = chandef;
changed |= IEEE80211_CONF_CHANGE_CHANNEL;
}
if (!conf_is_ht(&local->hw.conf)) { /* * mac80211.h documents that this is only valid * when the channel is set to an HT type, and * that otherwise STATIC is used.
*/
local->hw.conf.smps_mode = IEEE80211_SMPS_STATIC;
} elseif (local->hw.conf.smps_mode != smps_mode) {
local->hw.conf.smps_mode = smps_mode;
changed |= IEEE80211_CONF_CHANGE_SMPS;
}
power = ieee80211_chandef_max_power(&chandef); if (local->user_power_level != IEEE80211_UNSET_POWER_LEVEL)
power = min(local->user_power_level, power);
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) { if (!rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf)) continue; if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) continue; if (sdata->vif.bss_conf.txpower == INT_MIN) continue;
power = min(power, sdata->vif.bss_conf.txpower);
}
rcu_read_unlock();
if (changed && local->open_count) {
ret = drv_config(local, radio_idx, changed); /* * Goal: * HW reconfiguration should never fail, the driver has told * us what it can support so it should live up to that promise. * * Current status: * rfkill is not integrated with mac80211 and a * configuration command can thus fail if hardware rfkill * is enabled * * FIXME: integrate rfkill with mac80211 and then add this * WARN_ON() back *
*/ /* WARN_ON(ret); */
}
return ret;
}
/* for scanning, offchannel and chanctx emulation only */ staticint _ieee80211_hw_conf_chan(struct ieee80211_local *local, struct ieee80211_chanctx_conf *ctx)
{
u32 changed;
if (!local->open_count) return 0;
changed = ieee80211_calc_hw_conf_chan(local, ctx); if (!changed) return 0;
return drv_config(local, -1, changed);
}
int ieee80211_hw_conf_chan(struct ieee80211_local *local)
{ struct ieee80211_chanctx *ctx;
rtnl_lock(); /* we might do interface manipulations, so need both */
wiphy_lock(local->hw.wiphy);
wiphy_work_flush(local->hw.wiphy, NULL);
WARN(test_bit(SCAN_HW_SCANNING, &local->scanning), "%s called with hardware scan in progress\n", __func__);
list_for_each_entry(sdata, &local->interfaces, list) { /* * XXX: there may be more work for other vif types and even * for station mode: a good thing would be to run most of * the iface type's dependent _stop (ieee80211_mg_stop, * ieee80211_ibss_stop) etc... * For now, fix only the specific bug that was seen: race * between csa_connection_drop_work and us.
*/ if (sdata->vif.type == NL80211_IFTYPE_STATION) { /* * This worker is scheduled from the iface worker that * runs on mac80211's workqueue, so we can't be * scheduling this worker after the cancel right here. * The exception is ieee80211_chswitch_done. * Then we can have a race...
*/
wiphy_work_cancel(local->hw.wiphy,
&sdata->u.mgd.csa_connection_drop_work); if (sdata->vif.bss_conf.csa_active)
ieee80211_sta_connection_lost(sdata,
WLAN_REASON_UNSPECIFIED, false);
}
wiphy_delayed_work_flush(local->hw.wiphy,
&sdata->dec_tailroom_needed_wk);
}
ieee80211_scan_cancel(local);
/* make sure any new ROC will consider local->in_reconfig */
wiphy_delayed_work_flush(local->hw.wiphy, &local->roc_work);
wiphy_work_flush(local->hw.wiphy, &local->hw_roc_done);
/* wait for all packet processing to be done */
synchronize_net();
ret = ieee80211_reconfig(local);
wiphy_unlock(local->hw.wiphy);
if (ret)
cfg80211_shutdown_all_interfaces(local->hw.wiphy);
wiphy_info(hw->wiphy, "Hardware restart was requested\n");
/* use this reason, ieee80211_reconfig will unblock it */
ieee80211_stop_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_SUSPEND, false);
/* * Stop all Rx during the reconfig. We don't want state changes * or driver callbacks while this is in progress.
*/
local->in_reconfig = true;
barrier();
/* ARP filtering is only supported in managed mode */ if (sdata->vif.type != NL80211_IFTYPE_STATION) return NOTIFY_DONE;
idev = __in_dev_get_rtnl(sdata->dev); if (!idev) return NOTIFY_DONE;
ifmgd = &sdata->u.mgd;
/* * The nested here is needed to convince lockdep that this is * all OK. Yes, we lock the wiphy mutex here while we already * hold the notifier rwsem, that's the normal case. And yes, * we also acquire the notifier rwsem again when unregistering * a netdev while we already hold the wiphy mutex, so it does * look like a typical ABBA deadlock. * * However, both of these things happen with the RTNL held * already. Therefore, they can't actually happen, since the * lock orders really are ABC and ACB, which is fine due to * the RTNL (A). * * We still need to prevent recursion, which is accomplished * by the !wdev->registered check above.
*/
mutex_lock_nested(&local->hw.wiphy->mtx, 1);
__acquire(&local->hw.wiphy->mtx);
/* Copy the addresses to the vif config list */
ifa = rtnl_dereference(idev->ifa_list); while (ifa) { if (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN)
vif_cfg->arp_addr_list[c] = ifa->ifa_address;
ifa = rtnl_dereference(ifa->ifa_next);
c++;
}
vif_cfg->arp_addr_cnt = c;
/* Configure driver only if associated (which also implies it is up) */ if (ifmgd->associated)
ieee80211_vif_cfg_change_notify(sdata, BSS_CHANGED_ARP_FILTER);
/* Make sure it's our interface that got changed */ if (!wdev || wdev->wiphy != local->hw.wiphy) return NOTIFY_DONE;
sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
/* * For now only support station mode. This is mostly because * doing AP would have to handle AP_VLAN in some way ...
*/ if (sdata->vif.type != NL80211_IFTYPE_STATION) return NOTIFY_DONE;
drv_ipv6_addr_change(local, sdata, idev);
return NOTIFY_OK;
} #endif
/* There isn't a lot of sense in it, but you can transmit anything you like */ staticconststruct ieee80211_txrx_stypes
ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
[NL80211_IFTYPE_ADHOC] = {
.tx = 0xffff,
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
BIT(IEEE80211_STYPE_AUTH >> 4) |
BIT(IEEE80211_STYPE_DEAUTH >> 4) |
BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
},
[NL80211_IFTYPE_STATION] = {
.tx = 0xffff, /* * To support Pre Association Security Negotiation (PASN) while * already associated to one AP, allow user space to register to * Rx authentication frames, so that the user space logic would * be able to receive/handle authentication frames from a * different AP as part of PASN. * It is expected that user space would intelligently register * for Rx authentication frames, i.e., only when PASN is used * and configure a match filter only for PASN authentication * algorithm, as otherwise the MLME functionality of mac80211 * would be broken.
*/
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
BIT(IEEE80211_STYPE_AUTH >> 4) |
BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
},
[NL80211_IFTYPE_AP] = {
.tx = 0xffff,
.rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
BIT(IEEE80211_STYPE_DISASSOC >> 4) |
BIT(IEEE80211_STYPE_AUTH >> 4) |
BIT(IEEE80211_STYPE_DEAUTH >> 4) |
BIT(IEEE80211_STYPE_ACTION >> 4),
},
[NL80211_IFTYPE_AP_VLAN] = { /* copy AP */
.tx = 0xffff,
.rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
BIT(IEEE80211_STYPE_DISASSOC >> 4) |
BIT(IEEE80211_STYPE_AUTH >> 4) |
BIT(IEEE80211_STYPE_DEAUTH >> 4) |
BIT(IEEE80211_STYPE_ACTION >> 4),
},
[NL80211_IFTYPE_P2P_CLIENT] = {
.tx = 0xffff,
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
},
[NL80211_IFTYPE_P2P_GO] = {
.tx = 0xffff,
.rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
BIT(IEEE80211_STYPE_DISASSOC >> 4) |
BIT(IEEE80211_STYPE_AUTH >> 4) |
BIT(IEEE80211_STYPE_DEAUTH >> 4) |
BIT(IEEE80211_STYPE_ACTION >> 4),
},
[NL80211_IFTYPE_MESH_POINT] = {
.tx = 0xffff,
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
BIT(IEEE80211_STYPE_AUTH >> 4) |
BIT(IEEE80211_STYPE_DEAUTH >> 4),
},
[NL80211_IFTYPE_P2P_DEVICE] = {
.tx = 0xffff, /* * To support P2P PASN pairing let user space register to rx * also AUTH frames on P2P device interface.
*/
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
BIT(IEEE80211_STYPE_AUTH >> 4),
},
};
if (WARN_ON(ops->sta_state && (ops->sta_add || ops->sta_remove))) return NULL;
if (WARN_ON(!!ops->link_info_changed != !!ops->vif_cfg_changed ||
(ops->link_info_changed && ops->bss_info_changed))) return NULL;
/* check all or no channel context operations exist */ if (ops->add_chanctx == ieee80211_emulate_add_chanctx &&
ops->remove_chanctx == ieee80211_emulate_remove_chanctx &&
ops->change_chanctx == ieee80211_emulate_change_chanctx) { if (WARN_ON(ops->assign_vif_chanctx ||
ops->unassign_vif_chanctx)) return NULL;
emulate_chanctx = true;
} else { if (WARN_ON(ops->add_chanctx == ieee80211_emulate_add_chanctx ||
ops->remove_chanctx == ieee80211_emulate_remove_chanctx ||
ops->change_chanctx == ieee80211_emulate_change_chanctx)) return NULL; if (WARN_ON(!ops->add_chanctx ||
!ops->remove_chanctx ||
!ops->change_chanctx ||
!ops->assign_vif_chanctx ||
!ops->unassign_vif_chanctx)) return NULL;
emulate_chanctx = false;
}
/* Ensure 32-byte alignment of our private data and hw private data. * We use the wiphy priv data for both our ieee80211_local and for * the driver's private data * * In memory it'll be like this: * * +-------------------------+ * | struct wiphy | * +-------------------------+ * | struct ieee80211_local | * +-------------------------+ * | driver's private data | * +-------------------------+ *
*/
priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len;
if (!ops->hw_scan) {
wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN |
NL80211_FEATURE_AP_SCAN; /* * if the driver behaves correctly using the probe request * (template) from mac80211, then both of these should be * supported even with hw scan - but let drivers opt in.
*/
wiphy_ext_feature_set(wiphy,
NL80211_EXT_FEATURE_SCAN_RANDOM_SN);
wiphy_ext_feature_set(wiphy,
NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT);
}
if (!ops->set_key) {
wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
wiphy_ext_feature_set(wiphy,
NL80211_EXT_FEATURE_SPP_AMSDU_SUPPORT);
}
if (emulate_chanctx)
ieee80211_hw_set(&local->hw, CHANCTX_STA_CSA);
/* * We need a bit of data queued to build aggregates properly, so * instruct the TCP stack to allow more than a single ms of data * to be queued in the stack. The value is a bit-shift of 1 * second, so 7 is ~8ms of queued data. Only affects local TCP * sockets. * This is the default, anyhow - drivers may need to override it * for local reasons (longer buffers, longer completion time, or * similar).
*/
local->hw.tx_sk_pacing_shift = 7;
staticint ieee80211_init_cipher_suites(struct ieee80211_local *local)
{ bool have_mfp = ieee80211_hw_check(&local->hw, MFP_CAPABLE); staticconst u32 cipher_suites[] = { /* keep WEP and TKIP first, they may be removed below */
WLAN_CIPHER_SUITE_WEP40,
WLAN_CIPHER_SUITE_WEP104,
WLAN_CIPHER_SUITE_TKIP,
WLAN_CIPHER_SUITE_CCMP,
WLAN_CIPHER_SUITE_CCMP_256,
WLAN_CIPHER_SUITE_GCMP,
WLAN_CIPHER_SUITE_GCMP_256,
/* keep last -- depends on hw flags! */
WLAN_CIPHER_SUITE_AES_CMAC,
WLAN_CIPHER_SUITE_BIP_CMAC_256,
WLAN_CIPHER_SUITE_BIP_GMAC_128,
WLAN_CIPHER_SUITE_BIP_GMAC_256,
};
if (ieee80211_hw_check(&local->hw, SW_CRYPTO_CONTROL) && fips_enabled) {
dev_err(local->hw.wiphy->dev.parent, "Drivers with SW_CRYPTO_CONTROL cannot work with FIPS\n"); return -EINVAL;
}
if (WARN_ON(ieee80211_hw_check(&local->hw, SW_CRYPTO_CONTROL) &&
!local->hw.wiphy->cipher_suites)) return -EINVAL;
if (fips_enabled || !local->hw.wiphy->cipher_suites) { /* assign the (software supported and perhaps offloaded) * cipher suites
*/
local->hw.wiphy->cipher_suites = cipher_suites;
local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
if (!have_mfp)
local->hw.wiphy->n_cipher_suites -= 4;
/* FIPS does not permit the use of RC4 */ if (fips_enabled) {
local->hw.wiphy->cipher_suites += 3;
local->hw.wiphy->n_cipher_suites -= 3;
}
}
return 0;
}
staticbool
ieee80211_ifcomb_check(conststruct ieee80211_iface_combination *c, int n_comb)
{ int i, j;
for (i = 0; i < n_comb; i++, c++) { /* DFS is not supported with multi-channel combinations yet */ if (c->radar_detect_widths &&
c->num_different_channels > 1) returnfalse;
/* mac80211 doesn't support more than one IBSS interface */ for (j = 0; j < c->n_limits; j++) if ((c->limits[j].types & BIT(NL80211_IFTYPE_ADHOC)) &&
c->limits[j].max > 1) returnfalse;
}
returntrue;
}
int ieee80211_register_hw(struct ieee80211_hw *hw)
{ struct ieee80211_local *local = hw_to_local(hw); int result, i; enum nl80211_band band; int channels, max_bitrates; bool supp_ht, supp_vht, supp_he, supp_eht, supp_s1g; struct cfg80211_chan_def dflt_chandef = {};
if (WARN_ON(ieee80211_hw_check(hw, SUPPORTS_TX_FRAG) &&
!local->ops->set_frag_threshold)) return -EINVAL;
if (WARN_ON(local->hw.wiphy->interface_modes &
BIT(NL80211_IFTYPE_NAN) &&
(!local->ops->start_nan || !local->ops->stop_nan))) return -EINVAL;
if (hw->wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO) { /* * For drivers capable of doing MLO, assume modern driver * or firmware facilities, so software doesn't have to do * as much, e.g. monitoring beacons would be hard if we * might not even know which link is active at which time.
*/ if (WARN_ON(local->emulate_chanctx)) return -EINVAL;
if (WARN_ON(!local->ops->link_info_changed)) return -EINVAL;
if (WARN_ON(!ieee80211_hw_check(hw, HAS_RATE_CONTROL))) return -EINVAL;
if (WARN_ON(!ieee80211_hw_check(hw, AMPDU_AGGREGATION))) return -EINVAL;
if (WARN_ON(ieee80211_hw_check(hw, HOST_BROADCAST_PS_BUFFERING))) return -EINVAL;
if (local->emulate_chanctx) { for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) { conststruct ieee80211_iface_combination *comb;
comb = &local->hw.wiphy->iface_combinations[i];
if (comb->num_different_channels > 1) return -EINVAL;
}
}
if (hw->wiphy->n_radio) { for (i = 0; i < hw->wiphy->n_radio; i++) { conststruct wiphy_radio *radio = &hw->wiphy->radio[i];
if (!ieee80211_ifcomb_check(radio->iface_combinations,
radio->n_iface_combinations)) return -EINVAL;
}
} else { if (!ieee80211_ifcomb_check(hw->wiphy->iface_combinations,
hw->wiphy->n_iface_combinations)) return -EINVAL;
}
/* Only HW csum features are currently compatible with mac80211 */ if (WARN_ON(hw->netdev_features & ~MAC80211_SUPPORTED_FEATURES)) return -EINVAL;
if (hw->max_report_rates == 0)
hw->max_report_rates = hw->max_rates;
local->rx_chains = 1;
/* * generic code guarantees at least one band, * set this very early because much code assumes * that hw.conf.channel is assigned
*/
channels = 0;
max_bitrates = 0;
supp_ht = false;
supp_vht = false;
supp_he = false;
supp_eht = false;
supp_s1g = false; for (band = 0; band < NUM_NL80211_BANDS; band++) { conststruct ieee80211_sband_iftype_data *iftd; struct ieee80211_supported_band *sband;
sband = local->hw.wiphy->bands[band]; if (!sband) continue;
if (!dflt_chandef.chan) { /* * Assign the first enabled channel to dflt_chandef * from the list of channels
*/ for (i = 0; i < sband->n_channels; i++) if (!(sband->channels[i].flags &
IEEE80211_CHAN_DISABLED)) break; /* if none found then use the first anyway */ if (i == sband->n_channels)
i = 0;
cfg80211_chandef_create(&dflt_chandef,
&sband->channels[i],
NL80211_CHAN_NO_HT); /* init channel we're on */
local->monitor_chanreq.oper = dflt_chandef; if (local->emulate_chanctx) {
local->dflt_chandef = dflt_chandef;
local->hw.conf.chandef = dflt_chandef;
}
}
channels += sband->n_channels;
/* * Due to the way the aggregation code handles this and it * being an HT capability, we can't really support delayed * BA in MLO (yet).
*/ if (WARN_ON(sband->ht_cap.ht_supported &&
(sband->ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA) &&
hw->wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO)) return -EINVAL;
/* currently no support for HE client where HT has 40 MHz but not HT */ if (iftd->he_cap.has_he &&
iftd->types_mask & (BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_P2P_CLIENT)) &&
sband->ht_cap.ht_supported &&
sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 &&
!(iftd->he_cap.he_cap_elem.phy_cap_info[0] & he_40_mhz_cap)) return -EINVAL;
/* no support for per-band vendor elems with MLO */ if (WARN_ON(iftd->vendor_elems.len &&
hw->wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO)) return -EINVAL;
}
/* EHT requires HE support */ if (WARN_ON(supp_eht && !supp_he)) return -EINVAL;
if (!sband->ht_cap.ht_supported) continue;
/* TODO: consider VHT for RX chains, hopefully it's the same */
local->rx_chains =
max(ieee80211_mcs_to_chains(&sband->ht_cap.mcs),
local->rx_chains);
/* no need to mask, SM_PS_DISABLED has all bits set */
sband->ht_cap.cap |= WLAN_HT_CAP_SM_PS_DISABLED <<
IEEE80211_HT_CAP_SM_PS_SHIFT;
}
/* if low-level driver supports AP, we also support VLAN. * drivers advertising SW_CRYPTO_CONTROL should enable AP_VLAN * based on their support to transmit SW encrypted packets.
*/ if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP) &&
!ieee80211_hw_check(&local->hw, SW_CRYPTO_CONTROL)) {
hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN);
hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_AP_VLAN);
}
local->int_scan_req = kzalloc(struct_size(local->int_scan_req,
channels, channels),
GFP_KERNEL); if (!local->int_scan_req) return -ENOMEM;
eth_broadcast_addr(local->int_scan_req->bssid);
for (band = 0; band < NUM_NL80211_BANDS; band++) { if (!local->hw.wiphy->bands[band]) continue;
local->int_scan_req->rates[band] = (u32) -1;
}
#ifndef CONFIG_MAC80211_MESH /* mesh depends on Kconfig, but drivers should set it if they want */
local->hw.wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MESH_POINT); #endif
/* if the underlying driver supports mesh, mac80211 will (at least)
* provide routing of mesh authentication frames to userspace */ if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_MESH_POINT))
local->hw.wiphy->flags |= WIPHY_FLAG_MESH_AUTH;
/* mac80211 supports control port protocol changing */
local->hw.wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL;
if (ieee80211_hw_check(&local->hw, SIGNAL_DBM)) {
local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
} elseif (ieee80211_hw_check(&local->hw, SIGNAL_UNSPEC)) {
local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; if (hw->max_signal <= 0) {
result = -EINVAL; goto fail_workqueue;
}
}
/* Mac80211 and therefore all drivers using SW crypto only * are able to handle PTK rekeys and Extended Key ID.
*/ if (!local->ops->set_key) {
wiphy_ext_feature_set(local->hw.wiphy,
NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
wiphy_ext_feature_set(local->hw.wiphy,
NL80211_EXT_FEATURE_EXT_KEY_ID);
}
if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_ADHOC))
wiphy_ext_feature_set(local->hw.wiphy,
NL80211_EXT_FEATURE_DEL_IBSS_STA);
/* * Calculate scan IE length -- we need this to alloc * memory and to subtract from the driver limit. It * includes the DS Params, (extended) supported rates, and HT * information -- SSID is the driver's responsibility.
*/
local->scan_ies_len = 4 + max_bitrates /* (ext) supp rates */ +
3 /* DS Params */; if (supp_ht)
local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap);
if (supp_vht)
local->scan_ies_len +=
2 + sizeof(struct ieee80211_vht_cap);
if (supp_s1g)
local->scan_ies_len += 2 + sizeof(struct ieee80211_s1g_cap);
/*
* HE cap element is variable in size - set len to allow max size */ if (supp_he) {
local->scan_ies_len +=
3 + sizeof(struct ieee80211_he_cap_elem) + sizeof(struct ieee80211_he_mcs_nss_supp) +
IEEE80211_HE_PPE_THRES_MAX_LEN;
if (!local->ops->hw_scan) { /* For hw_scan, driver needs to set these up. */
local->hw.wiphy->max_scan_ssids = 4;
local->hw.wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
}
/* * If the driver supports any scan IEs, then assume the * limit includes the IEs mac80211 will add, otherwise * leave it at zero and let the driver sort it out; we * still pass our IEs to the driver but userspace will * not be allowed to in that case.
*/ if (local->hw.wiphy->max_scan_ie_len)
local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len;
result = ieee80211_init_cipher_suites(local); if (result < 0) goto fail_workqueue;
if (!local->ops->remain_on_channel)
local->hw.wiphy->max_remain_on_channel_duration = 5000;
/* mac80211 based drivers don't support internal TDLS setup */ if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)
local->hw.wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP;
/* mac80211 supports eCSA, if the driver supports STA CSA at all */ if (ieee80211_hw_check(&local->hw, CHANCTX_STA_CSA))
local->ext_capa[0] |= WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING;
/* mac80211 supports multi BSSID, if the driver supports it */ if (ieee80211_hw_check(&local->hw, SUPPORTS_MULTI_BSSID)) {
local->hw.wiphy->support_mbssid = true; if (ieee80211_hw_check(&local->hw,
SUPPORTS_ONLY_HE_MULTI_BSSID))
local->hw.wiphy->support_only_he_mbssid = true; else
local->ext_capa[2] |=
WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT;
}
/* * We use the number of queues for feature tests (QoS, HT) internally * so restrict them appropriately.
*/ if (hw->queues > IEEE80211_MAX_QUEUES)
hw->queues = IEEE80211_MAX_QUEUES;
local->workqueue =
alloc_ordered_workqueue("%s", 0, wiphy_name(local->hw.wiphy)); if (!local->workqueue) {
result = -ENOMEM; goto fail_workqueue;
}
/* * The hardware needs headroom for sending the frame, * and we need some headroom for passing the frame to monitor * interfaces, but never both at the same time.
*/
local->tx_headroom = max_t(unsignedint , local->hw.extra_tx_headroom,
IEEE80211_TX_STATUS_HEADROOM);
/* * if the driver doesn't specify a max listen interval we * use 5 which should be a safe default
*/ if (local->hw.max_listen_interval == 0)
local->hw.max_listen_interval = 5;
if (!local->hw.max_nan_de_entries)
local->hw.max_nan_de_entries = IEEE80211_MAX_NAN_INSTANCE_ID;
if (!local->hw.weight_multiplier)
local->hw.weight_multiplier = 1;
ieee80211_wep_init(local);
local->hw.conf.flags = IEEE80211_CONF_IDLE;
ieee80211_led_init(local);
result = ieee80211_txq_setup_flows(local); if (result) goto fail_flows;
rtnl_lock();
result = ieee80211_init_rate_ctrl_alg(local,
hw->rate_control_algorithm);
rtnl_unlock(); if (result < 0) {
wiphy_debug(local->hw.wiphy, "Failed to initialize rate control algorithm\n"); goto fail_rate;
}
if (local->rate_ctrl) {
clear_bit(IEEE80211_HW_SUPPORTS_VHT_EXT_NSS_BW, hw->flags); if (local->rate_ctrl->ops->capa & RATE_CTRL_CAPA_VHT_EXT_NSS_BW)
ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW);
}
/* * If the VHT capabilities don't have IEEE80211_VHT_EXT_NSS_BW_CAPABLE, * or have it when we don't, copy the sband structure and set/clear it. * This is necessary because rate scaling algorithms could be switched * and have different support values. * Print a message so that in the common case the reallocation can be * avoided.
*/
BUILD_BUG_ON(NUM_NL80211_BANDS > 8 * sizeof(local->sband_allocated)); for (band = 0; band < NUM_NL80211_BANDS; band++) { struct ieee80211_supported_band *sband; bool local_cap, ie_cap;
/* * At this point, interface list manipulations are fine * because the driver cannot be handing us frames any * more and the tasklet is killed.
*/
ieee80211_remove_interfaces(local);
if (skb_queue_len(&local->skb_queue) ||
skb_queue_len(&local->skb_queue_unreliable))
wiphy_warn(local->hw.wiphy, "skb_queue not empty\n");
skb_queue_purge(&local->skb_queue);
skb_queue_purge(&local->skb_queue_unreliable);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.