if (link->use_cts_prot)
*protection_flags |= cpu_to_le32(LINK_PROT_FLG_TGG_PROTECT);
/* See section 9.23.3.1 of IEEE 80211-2012. *NongreenfieldHTSTAsPresentisnotsupported.
*/ switch (protection_mode) { case IEEE80211_HT_OP_MODE_PROTECTION_NONE: break; case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
*protection_flags |= cpu_to_le32(ht_flag); break; case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: /* Protect when channel wider than 20MHz */ if (link->chanreq.oper.width > NL80211_CHAN_WIDTH_20)
*protection_flags |= cpu_to_le32(ht_flag); break;
}
}
if ((changes & LINK_CONTEXT_MODIFY_ACTIVE) && !mld_link->active &&
mld_link->silent_deactivation) { /* We are de-activating a link that is having CSA with *immediatequietinEMLSR.Tellthefirmwarenottosendany *frame.
*/
cmd.block_tx = 1;
mld_link->silent_deactivation = false;
}
if (vif->type == NL80211_IFTYPE_ADHOC && link->bssid)
ether_addr_copy(cmd.ibss_bssid_addr, link->bssid);
/* Channel context is needed to get the rates */ if (chan_ctx)
iwl_mld_fill_rates(mld, link, chan_ctx, &cmd.cck_rates,
&cmd.ofdm_rates);
/* Configure HE parameters only if HE is supported, and only after *theparametersaresetinmac80211(meaningafterassoc)
*/ if (!link->he_support || iwlwifi_mod_params.disable_11ax ||
(vif->type == NL80211_IFTYPE_STATION && !vif->cfg.assoc)) {
changes &= ~LINK_CONTEXT_MODIFY_HE_PARAMS; goto send_cmd;
}
/* ap_sta may be NULL if we're disconnecting */ if (mld_vif->ap_sta) { struct ieee80211_link_sta *link_sta =
link_sta_dereference_check(mld_vif->ap_sta,
link->link_id);
if (link->nontransmitted) {
ether_addr_copy(cmd.ref_bssid_addr, link->transmitter_bssid);
cmd.bssid_index = link->bssid_index;
}
/* The only EHT parameter is puncturing, and starting from PHY cmd *version6-itissentthere.ForolderversionsofthePHYcmd, *puncturingisnotneededatall.
*/ if (WARN_ON(changes & LINK_CONTEXT_MODIFY_EHT_PARAMS))
changes &= ~LINK_CONTEXT_MODIFY_EHT_PARAMS;
/* If we deactivate the link, we will probably remove it, or switch *channel.Inbothcases,theCSAorNoticeofAbsenceinformationis *nowirrelevant.Removethedatahere.
*/
probe_data = wiphy_dereference(mld->wiphy, mld_link->probe_resp_data);
RCU_INIT_POINTER(mld_link->probe_resp_data, NULL); if (probe_data)
kfree_rcu(probe_data, rcu_head);
/* Now that the link is not active in FW, we don't expect any new *notificationsforit.Canceltheonesthatarealreadypending
*/
iwl_mld_cancel_notifications_of_object(mld, IWL_MLD_OBJECT_TYPE_LINK,
mld_link->fw_id);
}
/* Initializes the link structure, maps fw id to the ieee80211_bss_conf, and *addsalinktothefw
*/ int iwl_mld_add_link(struct iwl_mld *mld, struct ieee80211_bss_conf *bss_conf)
{ struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(bss_conf->vif); struct iwl_mld_link *link = iwl_mld_link_from_mac80211(bss_conf); bool is_deflink = bss_conf == &bss_conf->vif->bss_conf; int ret;
if (!link) { if (is_deflink)
link = &mld_vif->deflink; else
link = kzalloc(sizeof(*link), GFP_KERNEL);
} else {
WARN_ON(!mld->fw_status.in_hw_restart);
}
ret = iwl_mld_init_link(mld, bss_conf, link); if (ret) goto free;
if (missed_bcon >= IWL_MLD_MISSED_BEACONS_THRESHOLD_LONG) { if (missed_bcon_since_rx >=
IWL_MLD_MISSED_BEACONS_SINCE_RX_THOLD) {
ieee80211_connection_loss(vif); return;
}
IWL_WARN(mld, "missed beacons exceeds threshold, but receiving data. Stay connected, Expect bugs.\n"); return;
}
if (missed_bcon_since_rx > IWL_MLD_MISSED_BEACONS_THRESHOLD) {
ieee80211_cqm_beacon_loss_notify(vif, GFP_ATOMIC);
/* Not in EMLSR and we can't hear the link. *Trytoswitchtoabetterlink.EMLSRcaseishandledbelow.
*/ if (!iwl_mld_emlsr_active(vif))
iwl_mld_int_mlo_scan(mld, vif);
}
/* no more logic if we're not in EMLSR */ if (hweight16(vif->active_links) <= 1) return;
/* We are processing a notification before link activation */ if (le32_to_cpu(notif->other_link_id) == FW_CTXT_ID_INVALID) return;
/* Exit EMLSR if we lost more than *IWL_MLD_MISSED_BEACONS_EXIT_ESR_THRESHbeaconsonbothslinks *ORmorethanIWL_MLD_BCN_LOSS_EXIT_ESR_THRESHoncurrentlink. *ORmorethanIWL_MLD_BCN_LOSS_EXIT_ESR_THRESH_BSS_PARAM_CHANGED *oncurrentlinkandthelink'sbss_param_ch_counthaschangedon *theotherlink'sbeacon.
*/ if ((missed_bcon >= IWL_MLD_BCN_LOSS_EXIT_ESR_THRESH_2_LINKS &&
scnd_lnk_bcn_lost >= IWL_MLD_BCN_LOSS_EXIT_ESR_THRESH_2_LINKS) ||
missed_bcon >= IWL_MLD_BCN_LOSS_EXIT_ESR_THRESH ||
(bss_param_ch_cnt_link_id != link_id &&
missed_bcon >=
IWL_MLD_BCN_LOSS_EXIT_ESR_THRESH_BSS_PARAM_CHANGED)) {
iwl_mld_exit_emlsr(mld, vif, IWL_MLD_EMLSR_EXIT_MISSED_BEACON,
iwl_mld_get_primary_link(vif));
}
}
EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mld_handle_missed_beacon_notif);
if (le32_to_cpu(notif->other_link_id) == removed_link_id) { /* Second link is being removed. Don't cancel the notification, *butmarksecondlinkasinvalid.
*/
notif->other_link_id = cpu_to_le32(FW_CTXT_ID_INVALID);
}
/* If the primary link is removed, cancel the notification */ return le32_to_cpu(notif->link_id) == removed_link_id;
}
/* Returns error if the channel utilization element is invalid/unavailable */ int iwl_mld_get_chan_load_by_others(struct iwl_mld *mld, struct ieee80211_bss_conf *link_conf, bool expect_active_link)
{ int chan_load; unsignedint chan_load_by_us;
/* get overall load */
chan_load = iwl_mld_get_chan_load_from_element(mld, link_conf); if (chan_load < 0) return chan_load;
/* This function calculates the grade of a link. Returns 0 in error case */ unsignedint iwl_mld_get_link_grade(struct iwl_mld *mld, struct ieee80211_bss_conf *link_conf)
{ enum nl80211_band band; int rssi_idx;
s32 link_rssi; unsignedint grade = MAX_GRADE;
if (WARN_ON_ONCE(!link_conf)) return0;
band = link_conf->chanreq.oper.chan->band; if (WARN_ONCE(band != NL80211_BAND_2GHZ &&
band != NL80211_BAND_5GHZ &&
band != NL80211_BAND_6GHZ, "Invalid band (%u)\n", band)) return0;
/* No valid RSSI - take the lowest grade */ if (!link_rssi)
link_rssi = rssi_to_grade_map[0].rssi[rssi_idx];
IWL_DEBUG_EHT(mld, "Calculating grade of link %d: band = %d, bandwidth = %d, punctured subchannels =0x%x RSSI = %d\n",
link_conf->link_id, band,
link_conf->chanreq.oper.width,
link_conf->chanreq.oper.punctured, link_rssi);
/* Get grade based on RSSI */ for (int i = 0; i < ARRAY_SIZE(rssi_to_grade_map); i++) { conststruct iwl_mld_rssi_to_grade *line =
&rssi_to_grade_map[i];
if (link_rssi > line->rssi[rssi_idx]) continue;
grade = line->grade; break;
}
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.