/* Now we've got the basic rates as bitmaps in the ofdm and cck * variables. This isn't sufficient though, as there might not * be all the right rates in the bitmap. E.g. if the only basic * rates are 5.5 Mbps and 11 Mbps, we still need to add 1 Mbps * and 6 Mbps because the 802.11-2007 standard says in 9.6: * * [...] a STA responding to a received frame shall transmit * its Control Response frame [...] at the highest rate in the * BSSBasicRateSet parameter that is less than or equal to the * rate of the immediately previous frame in the frame exchange * sequence ([...]) and that is of the same modulation class * ([...]) as the received frame. If no rate contained in the * BSSBasicRateSet parameter meets these conditions, then the * control frame sent in response to a received frame shall be * transmitted at the highest mandatory rate of the PHY that is * less than or equal to the rate of the received frame, and * that is of the same modulation class as the received frame. * * As a consequence, we need to add all mandatory rates that are * lower than all of the basic rates to these bitmaps.
*/
if (lowest_present_ofdm > IWL_RATE_24M_INDEX)
ofdm |= IWL_RATE_BIT_MSK(24) >> IWL_FIRST_OFDM_RATE; if (lowest_present_ofdm > IWL_RATE_12M_INDEX)
ofdm |= IWL_RATE_BIT_MSK(12) >> IWL_FIRST_OFDM_RATE; /* 6M already there or needed so always add */
ofdm |= IWL_RATE_BIT_MSK(6) >> IWL_FIRST_OFDM_RATE;
/* CCK is a bit more complex with DSSS vs. HR/DSSS vs. ERP. * Note, however: * - if no CCK rates are basic, it must be ERP since there must * be some basic rates at all, so they're OFDM => ERP PHY * (or we're in 5 GHz, and the cck bitmap will never be used) * - if 11M is a basic rate, it must be ERP as well, so add 5.5M * - if 5.5M is basic, 1M and 2M are mandatory * - if 2M is basic, 1M is mandatory * - if 1M is basic, that's the only valid ACK rate. * As a consequence, it's not as complicated as it sounds, just add * any lower rates to the ACK rate bitmap.
*/ if (lowest_present_cck > IWL_RATE_11M_INDEX)
cck |= IWL_RATE_BIT_MSK(11) >> IWL_FIRST_CCK_RATE; if (lowest_present_cck > IWL_RATE_5M_INDEX)
cck |= IWL_RATE_BIT_MSK(5) >> IWL_FIRST_CCK_RATE; if (lowest_present_cck > IWL_RATE_2M_INDEX)
cck |= IWL_RATE_BIT_MSK(2) >> IWL_FIRST_CCK_RATE; /* 1M already there or needed so always add */
cck |= IWL_RATE_BIT_MSK(1) >> IWL_FIRST_CCK_RATE;
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. * Nongreenfield HT STAs Present is not supported.
*/ 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 * immediate quiet in EMLSR. Tell the firmware not to send any * 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 * the parameters are set in mac80211 (meaning after assoc)
*/ 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 * version 6 - it is sent there. For older versions of the PHY cmd, * puncturing is not needed at all.
*/ 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. In both cases, the CSA or Notice of Absence information is * now irrelevant. Remove the data here.
*/
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 * notifications for it. Cancel the ones that are already pending
*/
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 * adds a link to the fw
*/ 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. * Try to switch to a better link. EMLSR case is handled below.
*/ 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_THRESH beacons on boths links * OR more than IWL_MLD_BCN_LOSS_EXIT_ESR_THRESH on current link. * OR more than IWL_MLD_BCN_LOSS_EXIT_ESR_THRESH_BSS_PARAM_CHANGED * on current link and the link's bss_param_ch_count has changed on * the other link's beacon.
*/ 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, * but mark second link as invalid.
*/
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)) return 0;
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)) return 0;
link_rssi = MBM_TO_DBM(link_conf->bss->signal); /* * For 6 GHz the RSSI of the beacons is lower than * the RSSI of the data.
*/ if (band == NL80211_BAND_6GHZ && link_rssi)
link_rssi += 4;
rssi_idx = band == NL80211_BAND_2GHZ ? 0 : 1;
/* 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.