Commit 310c8387 authored by Johannes Berg's avatar Johannes Berg

wifi: mac80211: clean up connection process

Rewrite the station-side connection handling. The connection
flags (IEEE80211_DISABLE_*) are rather confusing, and they're
not always maintained well. Additionally, for wider-bandwidth
OFDMA support we need to know the precise bandwidth of the AP,
which is currently somewhat difficult.

Rewrite this to have a 'mode' (S1G/legacy/HT/...) and a limit
on the bandwidth. This is not entirely clean because some of
those modes aren't completely sequenced (as this assumes in
some places), e.g. VHT doesn't exist on 2.4 GHz, but HE does.
However, it still simplifies things and gives us a good idea
what we're operating as, so we can parse elements accordingly
etc.

This leaves a FIXME for puncturing, this is addressed in a
later patch.
Reviewed-by: default avatarIlan Peer <ilan.peer@intel.com>
Reviewed-by: default avatarMiriam Rachel Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://msgid.link/20240129194108.9451722c0110.I3e61f4cfe9da89008e1854160093c76a1e69dc2a@changeidSigned-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 61f02611
......@@ -382,7 +382,7 @@ _ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
/* downgrade chandef up to max_bw */
min_def = ctx->conf.def;
while (min_def.width > max_bw)
ieee80211_chandef_downgrade(&min_def);
ieee80211_chandef_downgrade(&min_def, NULL);
if (cfg80211_chandef_identical(&ctx->conf.min_def, &min_def))
return 0;
......
......@@ -152,16 +152,17 @@ do { \
else \
_sdata_err((link)->sdata, fmt, ##__VA_ARGS__); \
} while (0)
#define link_dbg(link, fmt, ...) \
#define _link_id_dbg(print, sdata, link_id, fmt, ...) \
do { \
if (ieee80211_vif_is_mld(&(link)->sdata->vif)) \
_sdata_dbg(1, (link)->sdata, "[link %d] " fmt, \
(link)->link_id, \
##__VA_ARGS__); \
if (ieee80211_vif_is_mld(&(sdata)->vif)) \
_sdata_dbg(print, sdata, "[link %d] " fmt, \
link_id, ##__VA_ARGS__); \
else \
_sdata_dbg(1, (link)->sdata, fmt, \
##__VA_ARGS__); \
_sdata_dbg(1, sdata, fmt, ##__VA_ARGS__); \
} while (0)
#define link_dbg(link, fmt, ...) \
_link_id_dbg(1, (link)->sdata, (link)->link_id, \
fmt, ##__VA_ARGS__)
#define ht_dbg(sdata, fmt, ...) \
_sdata_dbg(MAC80211_HT_DEBUG, \
......@@ -226,6 +227,9 @@ do { \
#define mlme_dbg(sdata, fmt, ...) \
_sdata_dbg(MAC80211_MLME_DEBUG, \
sdata, fmt, ##__VA_ARGS__)
#define mlme_link_id_dbg(sdata, link_id, fmt, ...) \
_link_id_dbg(MAC80211_MLME_DEBUG, sdata, link_id, \
fmt, ##__VA_ARGS__)
#define mlme_dbg_ratelimited(sdata, fmt, ...) \
_sdata_dbg(MAC80211_MLME_DEBUG && net_ratelimit(), \
......
......@@ -757,21 +757,22 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
enum nl80211_channel_type ch_type;
int err;
ieee80211_conn_flags_t conn_flags;
struct ieee80211_conn_settings conn = {
.mode = IEEE80211_CONN_MODE_HT,
.bw_limit = IEEE80211_CONN_BW_LIMIT_40,
};
u32 vht_cap_info = 0;
lockdep_assert_wiphy(sdata->local->hw.wiphy);
conn_flags = IEEE80211_CONN_DISABLE_VHT;
switch (ifibss->chandef.width) {
case NL80211_CHAN_WIDTH_5:
case NL80211_CHAN_WIDTH_10:
case NL80211_CHAN_WIDTH_20_NOHT:
conn_flags |= IEEE80211_CONN_DISABLE_HT;
conn.mode = IEEE80211_CONN_MODE_LEGACY;
fallthrough;
case NL80211_CHAN_WIDTH_20:
conn_flags |= IEEE80211_CONN_DISABLE_40MHZ;
conn.bw_limit = IEEE80211_CONN_BW_LIMIT_20;
break;
default:
break;
......@@ -783,8 +784,8 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
memset(&params, 0, sizeof(params));
err = ieee80211_parse_ch_switch_ie(sdata, elems,
ifibss->chandef.chan->band,
vht_cap_info,
conn_flags, ifibss->bssid, &csa_ie);
vht_cap_info, &conn,
ifibss->bssid, &csa_ie);
/* can't switch to destination channel, fail */
if (err < 0)
goto disconnect;
......
......@@ -370,19 +370,32 @@ enum ieee80211_sta_flags {
IEEE80211_STA_ENABLE_RRM = BIT(15),
};
typedef u32 __bitwise ieee80211_conn_flags_t;
enum ieee80211_conn_flags {
IEEE80211_CONN_DISABLE_HT = (__force ieee80211_conn_flags_t)BIT(0),
IEEE80211_CONN_DISABLE_40MHZ = (__force ieee80211_conn_flags_t)BIT(1),
IEEE80211_CONN_DISABLE_VHT = (__force ieee80211_conn_flags_t)BIT(2),
IEEE80211_CONN_DISABLE_80P80MHZ = (__force ieee80211_conn_flags_t)BIT(3),
IEEE80211_CONN_DISABLE_160MHZ = (__force ieee80211_conn_flags_t)BIT(4),
IEEE80211_CONN_DISABLE_HE = (__force ieee80211_conn_flags_t)BIT(5),
IEEE80211_CONN_DISABLE_EHT = (__force ieee80211_conn_flags_t)BIT(6),
IEEE80211_CONN_DISABLE_320MHZ = (__force ieee80211_conn_flags_t)BIT(7),
enum ieee80211_conn_mode {
IEEE80211_CONN_MODE_S1G,
IEEE80211_CONN_MODE_LEGACY,
IEEE80211_CONN_MODE_HT,
IEEE80211_CONN_MODE_VHT,
IEEE80211_CONN_MODE_HE,
IEEE80211_CONN_MODE_EHT,
};
#define IEEE80211_CONN_MODE_HIGHEST IEEE80211_CONN_MODE_EHT
enum ieee80211_conn_bw_limit {
IEEE80211_CONN_BW_LIMIT_20,
IEEE80211_CONN_BW_LIMIT_40,
IEEE80211_CONN_BW_LIMIT_80,
IEEE80211_CONN_BW_LIMIT_160, /* also 80+80 */
IEEE80211_CONN_BW_LIMIT_320,
};
struct ieee80211_conn_settings {
enum ieee80211_conn_mode mode;
enum ieee80211_conn_bw_limit bw_limit;
};
extern const struct ieee80211_conn_settings ieee80211_conn_settings_unlimited;
struct ieee80211_mgd_auth_data {
struct cfg80211_bss *bss;
unsigned long timeout;
......@@ -416,7 +429,7 @@ struct ieee80211_mgd_assoc_data {
size_t elems_len;
u8 *elems; /* pointing to inside ie[] below */
ieee80211_conn_flags_t conn_flags;
struct ieee80211_conn_settings conn;
u16 status;
......@@ -943,7 +956,7 @@ struct ieee80211_link_data_managed {
enum ieee80211_smps_mode req_smps, /* requested smps mode */
driver_smps_mode; /* smps mode request */
ieee80211_conn_flags_t conn_flags;
struct ieee80211_conn_settings conn;
s16 p2p_noa_index;
......@@ -2171,9 +2184,8 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
* @elems: parsed 802.11 elements received with the frame
* @current_band: indicates the current band
* @vht_cap_info: VHT capabilities of the transmitter
* @conn_flags: contains information about own capabilities and restrictions
* to decide which channel switch announcements can be accepted, using
* flags from &enum ieee80211_conn_flags.
* @conn: contains information about own capabilities and restrictions
* to decide which channel switch announcements can be accepted
* @bssid: the currently connected bssid (for reporting)
* @csa_ie: parsed 802.11 csa elements on count, mode, chandef and mesh ttl.
* All of them will be filled with if success only.
......@@ -2183,7 +2195,8 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
struct ieee802_11_elems *elems,
enum nl80211_band current_band,
u32 vht_cap_info,
ieee80211_conn_flags_t conn_flags, u8 *bssid,
struct ieee80211_conn_settings *conn,
u8 *bssid,
struct ieee80211_csa_ie *csa_ie);
/* Suspend/resume and hw reconfiguration */
......@@ -2207,6 +2220,9 @@ static inline int __ieee80211_resume(struct ieee80211_hw *hw)
/* utility functions/constants */
extern const void *const mac80211_wiphy_privid; /* for wiphy privid */
const char *ieee80211_conn_mode_str(enum ieee80211_conn_mode mode);
enum ieee80211_conn_bw_limit
ieee80211_min_bw_limit_from_chandef(struct cfg80211_chan_def *chandef);
int ieee80211_frame_duration(enum nl80211_band band, size_t len,
int rate, int erp, int short_preamble);
void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata,
......@@ -2248,6 +2264,7 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata,
/**
* struct ieee80211_elems_parse_params - element parsing parameters
* @mode: connection mode for parsing
* @start: pointer to the elements
* @len: length of the elements
* @action: %true if the elements came from an action frame
......@@ -2265,6 +2282,7 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata,
* for EHT capabilities parsing)
*/
struct ieee80211_elems_parse_params {
enum ieee80211_conn_mode mode;
const u8 *start;
size_t len;
bool action;
......@@ -2284,6 +2302,7 @@ ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
struct cfg80211_bss *bss)
{
struct ieee80211_elems_parse_params params = {
.mode = IEEE80211_CONN_MODE_HIGHEST,
.start = start,
.len = len,
.action = action,
......@@ -2459,9 +2478,9 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
const struct cfg80211_chan_def *chandef);
u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_data *sdata, u8 iftype);
u8 *ieee80211_ie_build_he_cap(ieee80211_conn_flags_t disable_flags, u8 *pos,
u8 *ieee80211_ie_build_he_cap(const struct ieee80211_conn_settings *conn,
const struct ieee80211_sta_he_cap *he_cap,
u8 *end);
u8 *pos, u8 *end);
void ieee80211_ie_build_he_6ghz_cap(struct ieee80211_sub_if_data *sdata,
enum ieee80211_smps_mode smps_mode,
struct sk_buff *skb);
......@@ -2501,7 +2520,8 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
struct cfg80211_chan_def *chandef);
bool ieee80211_chandef_s1g_oper(const struct ieee80211_s1g_oper_ie *oper,
struct cfg80211_chan_def *chandef);
ieee80211_conn_flags_t ieee80211_chandef_downgrade(struct cfg80211_chan_def *c);
void ieee80211_chandef_downgrade(struct cfg80211_chan_def *chandef,
struct ieee80211_conn_settings *conn);
int __must_check
ieee80211_link_use_channel(struct ieee80211_link_data *link,
......
......@@ -586,7 +586,7 @@ int mesh_add_he_cap_ie(struct ieee80211_sub_if_data *sdata,
return -ENOMEM;
pos = skb_put(skb, ie_len);
ieee80211_ie_build_he_cap(0, pos, he_cap, pos + ie_len);
ieee80211_ie_build_he_cap(NULL, he_cap, pos, pos + ie_len);
return 0;
}
......@@ -1292,7 +1292,7 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct ieee80211_supported_band *sband;
int err;
ieee80211_conn_flags_t conn_flags = 0;
struct ieee80211_conn_settings conn = ieee80211_conn_settings_unlimited;
u32 vht_cap_info = 0;
lockdep_assert_wiphy(sdata->local->hw.wiphy);
......@@ -1303,13 +1303,16 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
switch (sdata->vif.bss_conf.chandef.width) {
case NL80211_CHAN_WIDTH_20_NOHT:
conn_flags |= IEEE80211_CONN_DISABLE_HT;
fallthrough;
conn.mode = IEEE80211_CONN_MODE_LEGACY;
conn.bw_limit = IEEE80211_CONN_BW_LIMIT_20;
break;
case NL80211_CHAN_WIDTH_20:
conn_flags |= IEEE80211_CONN_DISABLE_40MHZ;
fallthrough;
conn.mode = IEEE80211_CONN_MODE_HT;
conn.bw_limit = IEEE80211_CONN_BW_LIMIT_20;
break;
case NL80211_CHAN_WIDTH_40:
conn_flags |= IEEE80211_CONN_DISABLE_VHT;
conn.mode = IEEE80211_CONN_MODE_HT;
conn.bw_limit = IEEE80211_CONN_BW_LIMIT_40;
break;
default:
break;
......@@ -1321,8 +1324,8 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
memset(&params, 0, sizeof(params));
err = ieee80211_parse_ch_switch_ie(sdata, elems, sband->band,
vht_cap_info,
conn_flags, sdata->vif.addr,
vht_cap_info, &conn,
sdata->vif.addr,
&csa_ie);
if (err < 0)
return false;
......
This diff is collapsed.
......@@ -23,7 +23,8 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
struct ieee802_11_elems *elems,
enum nl80211_band current_band,
u32 vht_cap_info,
ieee80211_conn_flags_t conn_flags, u8 *bssid,
struct ieee80211_conn_settings *conn,
u8 *bssid,
struct ieee80211_csa_ie *csa_ie)
{
enum nl80211_band new_band = current_band;
......@@ -42,13 +43,13 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
wide_bw_chansw_ie = elems->wide_bw_chansw_ie;
bwi = elems->bandwidth_indication;
if (conn_flags & (IEEE80211_CONN_DISABLE_HT |
IEEE80211_CONN_DISABLE_40MHZ)) {
if (conn->mode < IEEE80211_CONN_MODE_HT ||
conn->bw_limit < IEEE80211_CONN_BW_LIMIT_40) {
sec_chan_offs = NULL;
wide_bw_chansw_ie = NULL;
}
if (conn_flags & IEEE80211_CONN_DISABLE_VHT)
if (conn->mode < IEEE80211_CONN_MODE_VHT)
wide_bw_chansw_ie = NULL;
if (elems->ext_chansw_ie) {
......@@ -95,7 +96,7 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
if (sec_chan_offs) {
secondary_channel_offset = sec_chan_offs->sec_chan_offs;
} else if (!(conn_flags & IEEE80211_CONN_DISABLE_HT)) {
} else if (conn->mode >= IEEE80211_CONN_MODE_HT) {
/* If the secondary channel offset IE is not present,
* we can't know what's the post-CSA offset, so the
* best we can do is use 20MHz.
......@@ -169,12 +170,10 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
&new_vht_chandef))
new_vht_chandef.chan = NULL;
if (conn_flags & IEEE80211_CONN_DISABLE_80P80MHZ &&
new_vht_chandef.width == NL80211_CHAN_WIDTH_80P80)
ieee80211_chandef_downgrade(&new_vht_chandef);
if (conn_flags & IEEE80211_CONN_DISABLE_160MHZ &&
new_vht_chandef.width == NL80211_CHAN_WIDTH_160)
ieee80211_chandef_downgrade(&new_vht_chandef);
if (conn->bw_limit < IEEE80211_CONN_BW_LIMIT_160 &&
(new_vht_chandef.width == NL80211_CHAN_WIDTH_80P80 ||
new_vht_chandef.width == NL80211_CHAN_WIDTH_160))
ieee80211_chandef_downgrade(&new_vht_chandef, NULL);
}
/* if VHT data is there validate & use it */
......
......@@ -347,7 +347,7 @@ ieee80211_tdls_chandef_vht_upgrade(struct ieee80211_sub_if_data *sdata,
(uc.width > sta->tdls_chandef.width &&
!cfg80211_reg_can_beacon_relax(sdata->local->hw.wiphy, &uc,
sdata->wdev.iftype)))
ieee80211_chandef_downgrade(&uc);
ieee80211_chandef_downgrade(&uc, NULL);
if (!cfg80211_chandef_identical(&uc, &sta->tdls_chandef)) {
tdls_dbg(sdata, "TDLS ch width upgraded %d -> %d\n",
......@@ -561,7 +561,7 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_link_data *link,
ieee80211_he_ppe_size(he_cap->ppe_thres[0],
he_cap->he_cap_elem.phy_cap_info);
pos = skb_put(skb, cap_size);
pos = ieee80211_ie_build_he_cap(0, pos, he_cap, pos + cap_size);
pos = ieee80211_ie_build_he_cap(NULL, he_cap, pos, pos + cap_size);
/* Build HE 6Ghz capa IE from sband */
if (sband->band == NL80211_BAND_6GHZ) {
......@@ -1413,8 +1413,8 @@ iee80211_tdls_recalc_ht_protection(struct ieee80211_sub_if_data *sdata,
IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT;
u16 opmode;
/* Nothing to do if the BSS connection uses HT */
if (!(sdata->deflink.u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT))
/* Nothing to do if the BSS connection uses (at least) HT */
if (sdata->deflink.u.mgd.conn.mode >= IEEE80211_CONN_MODE_HT)
return;
tdls_ht = (sta && sta->sta.deflink.ht_cap.ht_supported) ||
......
......@@ -14,6 +14,7 @@ static void mle_defrag(struct kunit *test)
struct ieee80211_elems_parse_params parse_params = {
.link_id = 12,
.from_ap = true,
.mode = IEEE80211_CONN_MODE_EHT,
};
struct ieee802_11_elems *parsed;
struct sk_buff *skb;
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment