/* Extract additional MAC addresses if available */ if (mld->nvm_data->n_hw_addrs > 1)
num_addrs = min(mld->nvm_data->n_hw_addrs,
IWL_MLD_MAX_ADDRESSES);
for (int i = 1; i < num_addrs; i++) {
memcpy(mld->addresses[i].addr,
mld->addresses[i - 1].addr,
ETH_ALEN);
mld->addresses[i].addr[ETH_ALEN - 1]++;
wiphy->n_addresses++;
}
}
/* For fips_enabled, don't support WiFi7 due to WPA3/MFP requirements */ if (mld->nvm_data->sku_cap_11be_enable &&
!iwlwifi_mod_params.disable_11ax &&
!iwlwifi_mod_params.disable_11be &&
!fips_enabled)
wiphy->flags |= WIPHY_FLAG_SUPPORTS_MLO;
/* the firmware uses u8 for num of iterations, but 0xff is saved for * infinite loop, so the maximum number of iterations is actually 254.
*/
wiphy->max_sched_scan_plan_iterations = 254;
wiphy->max_sched_scan_ie_len = iwl_mld_scan_max_template_size();
wiphy->max_scan_ie_len = iwl_mld_scan_max_template_size();
wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX;
wiphy->max_scan_ssids = PROBE_OPTION_MAX;
wiphy->max_sched_scan_plans = IWL_MAX_SCHED_SCAN_PLANS;
wiphy->max_sched_scan_reqs = 1;
wiphy->max_sched_scan_plan_interval = U16_MAX;
wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES_V2;
if (ratecheck != 0 && ratecheck != 5) {
IWL_ERR(mld, "Firmware has inconsistent rates\n"); return -EINVAL;
}
/* 11ax is expected to be enabled for all supported devices */ if (WARN_ON(!mld->nvm_data->sku_cap_11ax_enable)) return -EINVAL;
/* LAR is expected to be enabled for all supported devices */ if (WARN_ON(!mld->nvm_data->lar_enabled)) return -EINVAL;
/* All supported devices are currently using version 3 of the cmd. * Since version 3, IWL_SCAN_MAX_PROFILES_V2 shall be used where * necessary.
*/ if (WARN_ON(iwl_fw_lookup_cmd_ver(mld->fw,
SCAN_OFFLOAD_UPDATE_PROFILES_CMD,
IWL_FW_CMD_VER_UNKNOWN) != 3)) return -EINVAL;
return 0;
}
int iwl_mld_register_hw(struct iwl_mld *mld)
{ /* verify once essential preconditions required for setting * the hw capabilities
*/ if (iwl_mld_hw_verify_preconditions(mld)) return -EINVAL;
/* In AP mode, mgmt frames are sent on the bcast station, * so the FW can't translate the MLD addr to the link addr. Do it here
*/ if (ieee80211_is_mgmt(hdr->frame_control) && sta &&
link_id != IEEE80211_LINK_UNSPECIFIED &&
!ieee80211_is_probe_resp(hdr->frame_control)) { /* translate MLD addresses to LINK addresses */ struct ieee80211_link_sta *link_sta =
rcu_dereference(sta->link[link_id]); struct ieee80211_bss_conf *link_conf =
rcu_dereference(info->control.vif->link_conf[link_id]); struct ieee80211_mgmt *mgmt;
if (WARN_ON(!link_sta || !link_conf)) {
ieee80211_free_txskb(hw, skb); return;
}
static int iwl_mld_mac80211_start(struct ieee80211_hw *hw)
{ struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); bool in_d3 = false; int ret = 0;
lockdep_assert_wiphy(mld->wiphy);
#ifdef CONFIG_PM_SLEEP /* Unless the host goes into hibernate the FW always stays on and * the d3_resume flow is used. When wowlan is configured, mac80211 * would call it's resume callback and the wowlan_resume flow * would be used.
*/
in_d3 = mld->fw_status.in_d3; if (in_d3) { /* mac80211 already cleaned up the state, no need for cleanup */
ret = iwl_mld_no_wowlan_resume(mld); if (ret) {
iwl_mld_stop_fw(mld); /* We're not really restarting in the sense of * in_hw_restart even if we got an error during * this. We'll just start again below and have * nothing to recover, mac80211 will do anyway.
*/
mld->fw_status.in_hw_restart = false;
}
} #endif/* CONFIG_PM_SLEEP */
if (mld->fw_status.in_hw_restart) {
iwl_mld_stop_fw(mld);
iwl_mld_restart_cleanup(mld);
}
if (!in_d3 || ret) {
ret = iwl_mld_start_fw(mld); if (ret) goto error;
}
error: /* If we failed to restart the hw, there is nothing useful * we can do but indicate we are no longer in restart.
*/
mld->fw_status.in_hw_restart = false;
/* if the suspend flow fails the fw is in error. Stop it here, and it * will be started upon wakeup
*/ if (!suspend ||
(IS_ENABLED(CONFIG_PM_SLEEP) && iwl_mld_no_wowlan_suspend(mld)))
iwl_mld_stop_fw(mld);
/* Clear in_hw_restart flag when stopping the hw, as mac80211 won't * execute the restart.
*/
mld->fw_status.in_hw_restart = false;
/* We shouldn't have any UIDs still set. Loop over all the UIDs to * make sure there's nothing left there and warn if any is found.
*/ for (int i = 0; i < ARRAY_SIZE(mld->scan.uid_status); i++) if (WARN_ONCE(mld->scan.uid_status[i], "UMAC scan UID %d status was not cleaned (0x%x 0x%x)\n",
i, mld->scan.uid_status[i], mld->scan.status))
mld->scan.uid_status[i] = 0;
}
static int iwl_mld_mac80211_config(struct ieee80211_hw *hw, int radio_idx,
u32 changed)
{ return 0;
}
static int iwl_mld_mac80211_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{ struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); int ret;
lockdep_assert_wiphy(mld->wiphy);
/* Construct mld_vif, add it to fw, and map its ID to ieee80211_vif */
ret = iwl_mld_add_vif(mld, vif); if (ret) return ret;
/* * Add the default link, but not if this is an MLD vif as that implies * the HW is restarting and it will be configured by change_vif_links.
*/ if (!ieee80211_vif_is_mld(vif))
ret = iwl_mld_add_link(mld, &vif->bss_conf); if (ret) goto err;
if (vif->type == NL80211_IFTYPE_STATION) {
vif->driver_flags |= IEEE80211_VIF_REMOVE_AP_AFTER_DISASSOC; if (!vif->p2p)
vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
IEEE80211_VIF_SUPPORTS_CQM_RSSI;
}
/* * For an MLD vif (in restart) we may not have a link; delay the call * the initial change_vif_links.
*/ if (vif->type == NL80211_IFTYPE_STATION &&
!ieee80211_vif_is_mld(vif))
iwl_mld_update_mac_power(mld, vif, false);
if (likely(mld_txq->status.allocated) || !txq->sta) {
iwl_mld_tx_from_txq(mld, txq); return;
}
/* We don't support TSPEC tids. %IEEE80211_NUM_TIDS is for mgmt */ if (txq->tid != IEEE80211_NUM_TIDS && txq->tid >= IWL_MAX_TID_COUNT) {
IWL_DEBUG_MAC80211(mld, "TID %d is not supported\n", txq->tid); return;
}
/* The worker will handle any packets we leave on the txq now */
spin_lock_bh(&mld->add_txqs_lock); /* The list is being deleted only after the queue is fully allocated. */ if (list_empty(&mld_txq->list) && /* recheck under lock, otherwise it can be added twice */
!mld_txq->status.allocated) {
list_add_tail(&mld_txq->list, &mld->txqs_to_add);
wiphy_work_queue(mld->wiphy, &mld->add_txqs_wk);
}
spin_unlock_bh(&mld->add_txqs_lock);
}
/* We don't care about these */ if (!(changed & ~(IEEE80211_CHANCTX_CHANGE_RX_CHAINS |
IEEE80211_CHANCTX_CHANGE_RADAR |
IEEE80211_CHANCTX_CHANGE_CHANNEL))) return;
/* Check if a FW update is required */
if (changed & IEEE80211_CHANCTX_CHANGE_AP) goto update;
if (chandef->chan == phy->chandef.chan &&
chandef->center_freq1 == phy->chandef.center_freq1 &&
chandef->punctured == phy->chandef.punctured) { /* Check if we are toggling between HT and non-HT, no-op */ if (phy->chandef.width == chandef->width ||
(phy->chandef.width <= NL80211_CHAN_WIDTH_20 &&
chandef->width <= NL80211_CHAN_WIDTH_20)) return;
}
update:
iwl_mld_update_phy_chandef(mld, ctx);
}
static u8
iwl_mld_chandef_get_primary_80(struct cfg80211_chan_def *chandef)
{ int data_start; int control_start; int bw;
/* data is bw wide so the start is half the width */
data_start = chandef->center_freq1 - bw / 2; /* control is 20Mhz width */
control_start = chandef->chan->center_freq - 10;
/* When switching links, we need to wait with the activation until the * STA was added to the FW. It'll be activated in * iwl_mld_update_link_stas
*/
link_sta = wiphy_dereference(mld->wiphy, mld_sta->link[link->link_id]);
/* In restart we can have a link_sta that doesn't exist in FW yet */ return link_sta && link_sta->in_fw;
}
/* if the assigned one was not counted yet, count it now */ if (!rcu_access_pointer(mld_link->chan_ctx)) {
n_active++;
/* Track addition of non-BSS link */ if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION) {
ret = iwl_mld_emlsr_check_non_bss_block(mld, 1); if (ret) return ret;
}
}
/* for AP, mac parameters such as HE support are updated at this stage. */ if (vif->type == NL80211_IFTYPE_AP) {
ret = iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_MODIFY);
if (ret) {
IWL_ERR(mld, "failed to update MAC %pM\n", vif->addr); return -EINVAL;
}
}
rcu_assign_pointer(mld_link->chan_ctx, ctx);
if (n_active > 1) { struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
/* Indicate to mac80211 that EML is enabled */
vif->driver_flags |= IEEE80211_VIF_EML_ACTIVE;
mld_vif->emlsr.last_entry_ts = jiffies;
/* First send the link command with the phy context ID. * Now that we have the phy, we know the band so also the rates
*/
ret = iwl_mld_change_link_in_fw(mld, link,
LINK_CONTEXT_MODIFY_RATES_INFO); if (ret) goto err;
/* TODO: Initialize rate control for the AP station, since we might be * doing a link switch here - we cannot initialize it before since * this needs the phy context assigned (and in FW?), and we cannot * do it later because it needs to be initialized as soon as we're * able to TX on the link, i.e. when active. (task=link-switch)
*/
/* Now activate the link */ if (iwl_mld_can_activate_link(mld, vif, link)) {
ret = iwl_mld_activate_link(mld, link); if (ret) goto err;
}
if (vif->type == NL80211_IFTYPE_STATION)
iwl_mld_send_ap_tx_power_constraint_cmd(mld, vif, link);
if (vif->type == NL80211_IFTYPE_MONITOR) {
ret = iwl_mld_add_mon_sta(mld, vif, link); if (ret) goto deactivate_link;
/* in the non-MLO case, remove/re-add the link to clean up FW state. * In MLO, it'll be done in drv_change_vif_link
*/ if (!ieee80211_vif_is_mld(vif) && !mld_vif->ap_sta &&
!WARN_ON_ONCE(vif->cfg.assoc) &&
vif->type != NL80211_IFTYPE_AP && !mld->fw_status.in_hw_restart) {
iwl_mld_remove_link(mld, link);
iwl_mld_add_link(mld, link);
}
}
static int iwl_mld_mac80211_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx,
u32 value)
{ return 0;
}
if (changes & (BSS_CHANGED_HT | BSS_CHANGED_ERP_CTS_PROT))
link_changes |= LINK_CONTEXT_MODIFY_PROTECT_FLAGS;
/* TODO: task=MLO check mac80211's HE flags and if command is needed * every time there's a link change. Currently used flags are * BSS_CHANGED_HE_OBSS_PD and BSS_CHANGED_HE_BSS_COLOR.
*/
has_he = link_conf->he_support && !iwlwifi_mod_params.disable_11ax;
has_eht = link_conf->eht_support && !iwlwifi_mod_params.disable_11be;
if (vif->cfg.assoc && (has_he || has_eht)) {
IWL_DEBUG_MAC80211(mld, "Associated in HE mode\n");
link_changes |= LINK_CONTEXT_MODIFY_HE_PARAMS;
}
if (link_changes)
iwl_mld_change_link_in_fw(mld, link_conf, link_changes);
if (changes & BSS_CHANGED_TPE)
iwl_mld_send_ap_tx_power_constraint_cmd(mld, vif, link_conf);
if (changes & BSS_CHANGED_BEACON_INFO)
iwl_mld_update_mac_power(mld, vif, false);
/* The firmware will wait quite a while after association before it * starts filtering the beacons. We can safely enable beacon filtering * upon CQM configuration, even if we didn't get a beacon yet.
*/ if (changes & (BSS_CHANGED_CQM | BSS_CHANGED_BEACON_INFO))
iwl_mld_enable_beacon_filter(mld, link_conf, false);
if (changes & BSS_CHANGED_BANDWIDTH)
iwl_mld_retry_emlsr(mld, vif);
}
switch (vif->type) { case NL80211_IFTYPE_STATION:
iwl_mld_mac80211_link_info_changed_sta(mld, vif, link_conf,
changes); break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_ADHOC:
iwl_mld_link_info_changed_ap_ibss(mld, vif, link_conf,
changes); break; case NL80211_IFTYPE_MONITOR: /* The firmware tracks this on its own in STATION mode, but * obviously not in sniffer mode.
*/ if (changes & BSS_CHANGED_MU_GROUPS)
iwl_mld_update_mu_groups(mld, link_conf); break; default: /* shouldn't happen */
WARN_ON_ONCE(1);
}
/* We now know our BSSID, we can configure the MAC context with * eht_support if needed.
*/ if (changes & BSS_CHANGED_BSSID)
iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_MODIFY);
if (changes & BSS_CHANGED_TXPOWER)
iwl_mld_set_tx_power(mld, link_conf, link_conf->txpower);
}
/* Send the device-level power commands since the * firmware checks the POWER_TABLE_CMD's POWER_SAVE_EN bit to * determine SMPS mode.
*/ if (mld_vif->ps_disabled == !enable) return;
if (changes & BSS_CHANGED_ASSOC) {
ret = iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_MODIFY); if (ret)
IWL_ERR(mld, "failed to update context\n");
if (vif->cfg.assoc) { /* Clear statistics to get clean beacon counter, and * ask for periodic statistics, as they are needed for * link selection and RX OMI decisions.
*/
iwl_mld_clear_stats_in_fw(mld);
iwl_mld_request_periodic_fw_stats(mld, true);
if (WARN_ON(!hw_req->req.n_channels ||
hw_req->req.n_channels >
mld->fw->ucode_capa.n_scan_channels)) return -EINVAL;
ret = iwl_mld_regular_scan_start(mld, vif, &hw_req->req, &hw_req->ies); if (!ret) { /* We will be busy with scanning, so the counters may not reflect the * reality. Stop checking the counters until the scan ends
*/
iwl_mld_start_ignoring_tpt_updates(mld);
}
/* Due to a race condition, it's possible that mac80211 asks * us to stop a hw_scan when it's already stopped. This can * happen, for instance, if we stopped the scan ourselves, * called ieee80211_scan_completed() and the userspace called * cancel scan before ieee80211_scan_work() could run. * To handle that, simply return if the scan is not running.
*/ if (mld->scan.status & IWL_MLD_SCAN_REGULAR) {
iwl_mld_scan_stop(mld, IWL_MLD_SCAN_REGULAR, true); /* Scan is over, we can check again the tpt counters */
iwl_mld_stop_ignoring_tpt_updates(mld);
}
}
/* Due to a race condition, it's possible that mac80211 asks * us to stop a sched_scan when it's already stopped. This * can happen, for instance, if we stopped the scan ourselves, * called ieee80211_sched_scan_stopped() and the userspace called * stop sched scan before ieee80211_sched_scan_stopped_work() * could run. To handle this, simply return if the scan is * not running.
*/ if (!(mld->scan.status & IWL_MLD_SCAN_SCHED)) return 0;
switch (reconfig_type) { case IEEE80211_RECONFIG_TYPE_RESTART:
mld->fw_status.in_hw_restart = false;
iwl_mld_send_recovery_cmd(mld, ERROR_RECOVERY_END_OF_RECOVERY);
iwl_trans_finish_sw_reset(mld->trans); /* no need to lock, adding in parallel would schedule too */ if (!list_empty(&mld->txqs_to_add))
wiphy_work_queue(mld->wiphy, &mld->add_txqs_wk);
IWL_INFO(mld, "restart completed\n"); break; case IEEE80211_RECONFIG_TYPE_SUSPEND: break;
}
}
/* After a successful association the connection is established * and we can rely on the quota to send the disassociation frame.
*/ if (info->was_assoc) return;
if (info->duration > duration)
duration = info->duration;
/* Successful authentication is the only case that requires to let * the session protection go. We'll need it for the upcoming * association. For all the other cases, we need to cancel the session * protection. * After successful association the connection is established and * further mgd tx can rely on the quota.
*/ if (info->success && info->subtype == IEEE80211_STYPE_AUTH) return;
/* The firmware will be on medium after we configure the vif as * associated. Removing the session protection allows the firmware * to stop being on medium. In order to ensure the continuity of our * presence on medium, we need first to configure the vif as associated * and only then, remove the session protection. * Currently, mac80211 calls vif_cfg_changed() first and then, * drv_mgd_complete_tx(). Ensure that this assumption stays true by * a warning.
*/
WARN_ON(info->success &&
(info->subtype == IEEE80211_STYPE_ASSOC_REQ ||
info->subtype == IEEE80211_STYPE_REASSOC_REQ) &&
!vif->cfg.assoc);
link = iwl_mld_link_dereference_check(mld_vif, link_id); if (!link) return -EINVAL;
link->queue_params[ac] = *params;
/* No need to update right away, we'll get BSS_CHANGED_QOS * The exception is P2P_DEVICE interface which needs immediate update.
*/ if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
iwl_mld_change_link_in_fw(mld, &vif->bss_conf,
LINK_CONTEXT_MODIFY_QOS_PARAMS);
/* If there is at least one AP on radar channel that cannot * tolerate 26-tone RU UL OFDMA transmissions using HE TB PPDU.
*/
mld_link->he_ru_2mhz_block = !tolerated;
}
if (old_state == IEEE80211_STA_NOTEXIST &&
new_state == IEEE80211_STA_NONE) { if (sta->tdls) { if (vif->p2p || hweight8(mld->used_phy_ids) != 1) return -EBUSY;
tdls_count = iwl_mld_tdls_sta_count(mld); if (tdls_count >= IWL_TDLS_STA_COUNT) return -EBUSY;
}
ret = iwl_mld_add_sta(mld, sta, vif, STATION_TYPE_PEER); if (ret) return ret;
/* just added first TDLS STA, so disable PM */ if (sta->tdls && tdls_count == 0)
iwl_mld_update_mac_power(mld, vif, false);
if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls)
mld_vif->ap_sta = sta;
/* Initialize TLC here already - this really tells * the firmware only what the supported legacy rates are * (may be) since it's initialized already from what the * AP advertised in the beacon/probe response. This will * allow the firmware to send auth/assoc frames with one * of the supported rates already, rather than having to * use a mandatory rate. * If we're the AP, we'll just assume mandatory rates at * this point, but we know nothing about the STA anyway.
*/
iwl_mld_config_tlc(mld, vif, sta);
if (vif->type == NL80211_IFTYPE_STATION)
iwl_mld_link_set_2mhz_block(mld, vif, sta); /* Now the link_sta's capabilities are set, update the FW */
iwl_mld_config_tlc(mld, vif, sta);
if (vif->type == NL80211_IFTYPE_AP) { /* Update MAC_CFG_FILTER_ACCEPT_BEACON if at least * one sta is associated
*/ if (++mld_vif->num_associated_stas == 1)
ret = iwl_mld_mac_fw_action(mld, vif,
FW_CTXT_ACTION_MODIFY);
}
/* Ensure any block due to a non-BSS link is synced */
iwl_mld_emlsr_check_non_bss_block(mld, 0);
/* Block EMLSR until a certain throughput it reached */ if (!mld->fw_status.in_hw_restart &&
IWL_MLD_ENTER_EMLSR_TPT_THRESH > 0)
iwl_mld_block_emlsr(mld_vif->mld, vif,
IWL_MLD_EMLSR_BLOCKED_TPT,
0);
/* clear COEX_HIGH_PRIORITY_ENABLE */
ret = iwl_mld_mac_fw_action(mld, vif,
FW_CTXT_ACTION_MODIFY); if (ret) return ret;
iwl_mld_smps_workaround(mld, vif, vif->cfg.ps);
}
/* MFP is set by default before the station is authorized. * Clear it here in case it's not used.
*/ if (!sta->mfp)
ret = iwl_mld_update_all_link_stations(mld, sta);
/* We can use wide bandwidth now, not only 20 MHz */
iwl_mld_config_tlc(mld, vif, sta);
switch (action) { case IEEE80211_AMPDU_RX_START: if (!iwl_enable_rx_ampdu()) {
ret = -EINVAL; break;
}
ret = iwl_mld_ampdu_rx_start(mld, sta, tid, ssn, buf_size,
timeout); break; case IEEE80211_AMPDU_RX_STOP:
ret = iwl_mld_ampdu_rx_stop(mld, sta, tid); break; default: /* The mac80211 TX_AMPDU_SETUP_IN_HW flag is set for all * devices, since all support TX A-MPDU offload in hardware. * Therefore, no TX action should be requested here.
*/
WARN_ON_ONCE(1); return -EINVAL;
}
/* For now don't aggregate IPv6 in AMSDU */ if (skb->protocol != htons(ETH_P_IP)) returnfalse;
/* Allow aggregation only if both frames have the same HW csum offload * capability, ensuring consistent HW or SW csum handling in A-MSDU.
*/ return iwl_mld_can_hw_csum(skb) == iwl_mld_can_hw_csum(head);
}
/* Returns 0 on success. 1 if failed to suspend with wowlan: * If the circumstances didn't satisfy the conditions for suspension * with wowlan, mac80211 would use the no_wowlan flow. * If an error had occurred we update the trans status and state here * and the result will be stopping the FW.
*/ staticint
iwl_mld_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
{ struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); int ret;
iwl_fw_runtime_suspend(&mld->fwrt);
ret = iwl_mld_wowlan_suspend(mld, wowlan); if (ret) { if (ret < 0) {
mld->trans->state = IWL_TRANS_NO_FW;
set_bit(STATUS_FW_ERROR, &mld->trans->status);
} return 1;
}
/* Will be set to 0 if added successfully */
key->hw_key_idx = STA_KEY_IDX_INVALID;
switch (key->cipher) { case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104:
IWL_DEBUG_MAC80211(mld, "Use SW encryption for WEP\n"); return -EOPNOTSUPP; case WLAN_CIPHER_SUITE_TKIP: if (vif->type == NL80211_IFTYPE_STATION) {
key->flags |= IEEE80211_KEY_FLAG_PUT_MIC_SPACE; break;
}
IWL_DEBUG_MAC80211(mld, "Use SW encryption for TKIP\n"); return -EOPNOTSUPP; case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: case WLAN_CIPHER_SUITE_AES_CMAC: case WLAN_CIPHER_SUITE_BIP_GMAC_128: case WLAN_CIPHER_SUITE_BIP_GMAC_256: break; default: return -EOPNOTSUPP;
}
/* After exiting from RFKILL, hostapd configures GTK/ITGK before the * AP is started, but those keys can't be sent to the FW before the * MCAST/BCAST STAs are added to it (which happens upon AP start). * Store it here to be sent later when the AP is started.
*/ if ((vif->type == NL80211_IFTYPE_ADHOC ||
vif->type == NL80211_IFTYPE_AP) && !sta &&
!mld_vif->ap_ibss_active) return iwl_mld_store_ap_early_key(mld, key, mld_vif);
/* if this key was stored to be added later to the FW - free it here */ if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
iwl_mld_free_ap_early_key(mld, key, mld_vif);
/* We already removed it */ if (key->hw_key_idx == STA_KEY_IDX_INVALID) return;
switch (cmd) { case SET_KEY:
ret = iwl_mld_set_key_add(mld, vif, sta, key); if (ret)
ret = -EOPNOTSUPP; break; case DISABLE_KEY:
iwl_mld_set_key_remove(mld, vif, sta, key);
ret = 0; break; default:
ret = -EINVAL; break;
}
IWL_DEBUG_MAC80211(mld, "pre CSA to freq %d\n",
chsw->chandef.center_freq1);
if (!iwl_mld_emlsr_active(vif)) return 0;
primary = iwl_mld_get_primary_link(vif);
/* stay on the primary link unless it is undergoing a CSA with quiet */ if (chsw->link_id == primary && chsw->block_tx)
selected = iwl_mld_get_other_link(vif, primary); else
selected = primary;
/* Remember to tell the firmware that this link can't tx * Note that this logic seems to be unrelated to emlsr, but it * really is needed only when emlsr is active. When we have a * single link, the firmware will handle all this on its own. * In multi-link scenarios, we can learn about the CSA from * another link and this logic is too complex for the firmware * to track. * Since we want to de-activate the link that got a CSA with mode=1, * we need to tell the firmware not to send any frame on that link * as the firmware may not be aware that link is under a CSA * with mode=1 (no Tx allowed).
*/
mld_link->silent_deactivation = chsw->block_tx;
iwl_mld_exit_emlsr(mld, vif, IWL_MLD_EMLSR_EXIT_CSA, selected);
/* By implementing this operation, we prevent mac80211 from * starting its own channel switch timer, so that we can call * ieee80211_chswitch_done() ourselves at the right time * (Upon receiving the channel_switch_start notification from the fw)
*/
IWL_DEBUG_MAC80211(mld, "dummy channel switch op\n");
}
ret = iwl_mld_add_chanctx(hw, vifs[0].new_ctx); if (ret) {
IWL_ERR(mld, "failed to add new_ctx during channel switch\n"); goto out_reassign;
}
ret = iwl_mld_assign_vif_chanctx(hw, vifs[0].vif, vifs[0].link_conf,
vifs[0].new_ctx); if (ret) {
IWL_ERR(mld, "failed to assign new_ctx during channel switch\n"); goto out_remove;
}
return 0;
out_remove:
iwl_mld_remove_chanctx(hw, vifs[0].new_ctx);
out_reassign: if (iwl_mld_add_chanctx(hw, vifs[0].old_ctx)) {
IWL_ERR(mld, "failed to add old_ctx after failure\n"); return ret;
}
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.26 Sekunden
(vorverarbeitet)
¤
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.