diff options
author | Johannes Berg <johannes.berg@intel.com> | 2024-01-29 19:34:42 +0100 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2024-02-08 13:07:37 +0100 |
commit | 761748f001800d925c2ee8b04407e7aee12c3ffb (patch) | |
tree | c27f1469ed37f340073d9b8b6ccc48c6fb8cd3f5 /net/mac80211/mlme.c | |
parent | d1256c1546a0e03f103e2f0381103dc747ea7f81 (diff) |
wifi: mac80211: support wider bandwidth OFDMA config
EHT requires that stations are able to participate in
wider bandwidth OFDMA, i.e. parse downlink OFDMA and
uplink OFDMA triggers when they're not capable of (or
not connected at) the (wider) bandwidth that the AP
is using. This requires hardware configuration, since
the entity responsible for parsing (possibly hardware)
needs to know the AP bandwidth.
To support this, change the channel request to have
the AP's bandwidth for clients, and track that in the
channel context in mac80211. This means that the same
chandef might need to be split up into two different
contexts, if the APs are different. Interfaces other
than client are not participating in OFDMA the same
way, so they don't request any AP setting.
Note that this doesn't introduce any API to split a
channel context, so that there are cases where this
might lead to a disconnect, e.g. if there are two
client interfaces using the same channel context, e.g.
both 160 MHz connected to different 320 MHz APs, and
one of the APs switches to 160 MHz.
Note also there are possible cases where this can be
optimised, e.g. when using the upper or lower 160 Mhz,
but I haven't been able to really fully understand the
spec and/or hardware limitations.
If, for some reason, there are no hardware limits on
this because the OFDMA (downlink/trigger) parsing is
done in firmware and can take the transmitter into
account, then drivers can set the new flag
IEEE80211_VIF_IGNORE_OFDMA_WIDER_BW on interfaces to
not have them request any AP bandwidth in the channel
context and ignore this issue entirely. The bss_conf
still contains the AP configuration (if any, i.e. EHT)
in the chanreq.
Link: https://msgid.link/20240129194108.d3d5b35dd783.I939d04674f4ff06f39934b1591c8d36a30ce74c2@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 60 |
1 files changed, 35 insertions, 25 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e9d720f25ddf..31d6a5603582 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -665,7 +665,7 @@ static struct ieee802_11_elems * ieee80211_determine_chan_mode(struct ieee80211_sub_if_data *sdata, struct ieee80211_conn_settings *conn, struct cfg80211_bss *cbss, int link_id, - struct cfg80211_chan_def *chandef) + struct ieee80211_chan_req *chanreq) { struct ieee80211_local *local = sdata->local; const struct cfg80211_bss_ies *ies = rcu_dereference(cbss->ies); @@ -752,20 +752,27 @@ again: } conn->mode = ap_mode; - *chandef = ap_chandef; + chanreq->oper = ap_chandef; - while (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, + /* wider-bandwidth OFDMA is only done in EHT */ + if (conn->mode >= IEEE80211_CONN_MODE_EHT && + !(sdata->vif.driver_flags & IEEE80211_VIF_IGNORE_OFDMA_WIDER_BW)) + chanreq->ap = ap_chandef; + else + chanreq->ap.chan = NULL; + + while (!cfg80211_chandef_usable(sdata->local->hw.wiphy, &chanreq->oper, IEEE80211_CHAN_DISABLED)) { - if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) { + if (WARN_ON(chanreq->oper.width == NL80211_CHAN_WIDTH_20_NOHT)) { ret = -EINVAL; goto free; } - ieee80211_chandef_downgrade(chandef, conn); + ieee80211_chanreq_downgrade(chanreq, conn); } if (conn->mode >= IEEE80211_CONN_MODE_HE && - !cfg80211_chandef_usable(sdata->wdev.wiphy, chandef, + !cfg80211_chandef_usable(sdata->wdev.wiphy, &chanreq->oper, IEEE80211_CHAN_NO_HE)) { conn->mode = IEEE80211_CONN_MODE_VHT; conn->bw_limit = min_t(enum ieee80211_conn_bw_limit, @@ -774,7 +781,7 @@ again: } if (conn->mode >= IEEE80211_CONN_MODE_EHT && - !cfg80211_chandef_usable(sdata->wdev.wiphy, chandef, + !cfg80211_chandef_usable(sdata->wdev.wiphy, &chanreq->oper, IEEE80211_CHAN_NO_EHT)) { conn->mode = IEEE80211_CONN_MODE_HE; conn->bw_limit = min_t(enum ieee80211_conn_bw_limit, @@ -782,7 +789,7 @@ again: IEEE80211_CONN_BW_LIMIT_160); } - if (chandef->width != ap_chandef.width || ap_mode != conn->mode) + if (chanreq->oper.width != ap_chandef.width || ap_mode != conn->mode) sdata_info(sdata, "regulatory prevented using AP config, downgraded\n"); @@ -847,7 +854,7 @@ again: ieee80211_conn_mode_str(conn->mode), 20 * (1 << conn->bw_limit)); - if (WARN_ON_ONCE(!cfg80211_chandef_valid(chandef))) { + if (WARN_ON_ONCE(!cfg80211_chandef_valid(&chanreq->oper))) { ret = -EINVAL; goto free; } @@ -865,7 +872,6 @@ static int ieee80211_config_bw(struct ieee80211_link_data *link, struct ieee80211_channel *channel = link->conf->chanreq.oper.chan; struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_chan_req chanreq = {}; - struct cfg80211_chan_def ap_chandef; enum ieee80211_conn_mode ap_mode; u32 vht_cap_info = 0; u16 ht_opmode; @@ -881,7 +887,7 @@ static int ieee80211_config_bw(struct ieee80211_link_data *link, ap_mode = ieee80211_determine_ap_chan(sdata, channel, vht_cap_info, elems, true, &link->u.mgd.conn, - &ap_chandef); + &chanreq.ap); if (ap_mode != link->u.mgd.conn.mode) { link_info(link, @@ -891,6 +897,11 @@ static int ieee80211_config_bw(struct ieee80211_link_data *link, return -EINVAL; } + chanreq.oper = chanreq.ap; + if (link->u.mgd.conn.mode < IEEE80211_CONN_MODE_EHT || + sdata->vif.driver_flags & IEEE80211_VIF_IGNORE_OFDMA_WIDER_BW) + chanreq.ap.chan = NULL; + /* * if HT operation mode changed store the new one - * this may be applicable even if channel is identical @@ -911,20 +922,20 @@ static int ieee80211_config_bw(struct ieee80211_link_data *link, * won't do us any good -- we couldn't use it with the AP. */ while (link->u.mgd.conn.bw_limit < - ieee80211_min_bw_limit_from_chandef(&ap_chandef)) - ieee80211_chandef_downgrade(&ap_chandef, NULL); + ieee80211_min_bw_limit_from_chandef(&chanreq.oper)) + ieee80211_chandef_downgrade(&chanreq.oper, NULL); - if (cfg80211_chandef_identical(&ap_chandef, &link->conf->chanreq.oper)) + if (ieee80211_chanreq_identical(&chanreq, &link->conf->chanreq)) return 0; link_info(link, - "AP %pM changed bandwidth, new config is %d.%03d MHz, width %d (%d.%03d/%d MHz)\n", - link->u.mgd.bssid, ap_chandef.chan->center_freq, - ap_chandef.chan->freq_offset, ap_chandef.width, - ap_chandef.center_freq1, ap_chandef.freq1_offset, - ap_chandef.center_freq2); + "AP %pM changed bandwidth, new used config is %d.%03d MHz, width %d (%d.%03d/%d MHz)\n", + link->u.mgd.bssid, chanreq.oper.chan->center_freq, + chanreq.oper.chan->freq_offset, chanreq.oper.width, + chanreq.oper.center_freq1, chanreq.oper.freq1_offset, + chanreq.oper.center_freq2); - if (!cfg80211_chandef_valid(&ap_chandef)) { + if (!cfg80211_chandef_valid(&chanreq.oper)) { sdata_info(sdata, "AP %pM changed caps/bw in a way we can't support - disconnect\n", link->u.mgd.bssid); @@ -947,7 +958,6 @@ static int ieee80211_config_bw(struct ieee80211_link_data *link, * bandwidth changes where a this could happen, but those cases are * less common and wouldn't completely prevent using the AP. */ - chanreq.oper = ap_chandef; ret = ieee80211_link_change_chanreq(link, &chanreq, changed); if (ret) { @@ -2071,8 +2081,8 @@ static void ieee80211_chswitch_work(struct wiphy *wiphy, return; } - if (!cfg80211_chandef_identical(&link->conf->chanreq.oper, - &link->csa_chanreq.oper)) { + if (!ieee80211_chanreq_identical(&link->conf->chanreq, + &link->csa_chanreq)) { sdata_info(sdata, "failed to finalize channel switch, disconnecting\n"); wiphy_work_queue(sdata->local->hw.wiphy, @@ -5146,7 +5156,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, rcu_read_lock(); elems = ieee80211_determine_chan_mode(sdata, conn, cbss, link_id, - &chanreq.oper); + &chanreq); if (IS_ERR(elems)) { rcu_read_unlock(); @@ -5209,7 +5219,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, return ret; while (ret && chanreq.oper.width != NL80211_CHAN_WIDTH_20_NOHT) { - ieee80211_chandef_downgrade(&chanreq.oper, conn); + ieee80211_chanreq_downgrade(&chanreq, conn); ret = ieee80211_link_use_channel(link, &chanreq, IEEE80211_CHANCTX_SHARED); |