Skip to content

Commit 57fa5e8

Browse files
committed
mac80211: determine chandef from HE 6 GHz operation
Support connecting to HE 6 GHz APs and mesh networks on 6 GHz, where the HT/VHT information is missing but instead the HE 6 GHz band capability is present, and the 6 GHz Operation information field is used to encode the channel configuration instead of the HT/VHT operation elements. Also add some other bits needed to connect to 6 GHz networks. Link: https://lore.kernel.org/r/[email protected] Co-developed-by: Rajkumar Manoharan <[email protected]> Signed-off-by: Rajkumar Manoharan <[email protected]> Link: https://lore.kernel.org/r/20200528213443.25687d2695bc.I3f9747c1147480f65445f13eda5c4a5ed4e86757@changeid Signed-off-by: Johannes Berg <[email protected]>
1 parent 2a333a0 commit 57fa5e8

File tree

4 files changed

+160
-19
lines changed

4 files changed

+160
-19
lines changed

net/mac80211/ieee80211_i.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2202,6 +2202,9 @@ bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw, u32 vht_cap_info,
22022202
const struct ieee80211_vht_operation *oper,
22032203
const struct ieee80211_ht_operation *htop,
22042204
struct cfg80211_chan_def *chandef);
2205+
bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
2206+
const struct ieee80211_he_operation *he_oper,
2207+
struct cfg80211_chan_def *chandef);
22052208
u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c);
22062209

22072210
int __must_check

net/mac80211/mesh.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
104104
ieee80211_chandef_vht_oper(&sdata->local->hw, vht_cap_info,
105105
ie->vht_operation, ie->ht_operation,
106106
&sta_chan_def);
107+
ieee80211_chandef_he_6ghz_oper(sdata, ie->he_operation, &sta_chan_def);
107108

108109
if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef,
109110
&sta_chan_def))

net/mac80211/mlme.c

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -156,15 +156,24 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
156156
struct ieee80211_sta_ht_cap sta_ht_cap;
157157
u32 ht_cfreq, ret;
158158

159-
memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap));
160-
ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap);
161-
162159
memset(chandef, 0, sizeof(struct cfg80211_chan_def));
163160
chandef->chan = channel;
164161
chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
165162
chandef->center_freq1 = channel->center_freq;
166163
chandef->freq1_offset = channel->freq_offset;
167164

165+
if (channel->band == NL80211_BAND_6GHZ) {
166+
if (!ieee80211_chandef_he_6ghz_oper(sdata, he_oper, chandef))
167+
ret = IEEE80211_STA_DISABLE_HT |
168+
IEEE80211_STA_DISABLE_VHT |
169+
IEEE80211_STA_DISABLE_HE;
170+
vht_chandef = *chandef;
171+
goto out;
172+
}
173+
174+
memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap));
175+
ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap);
176+
168177
if (!ht_oper || !sta_ht_cap.ht_supported) {
169178
ret = IEEE80211_STA_DISABLE_HT |
170179
IEEE80211_STA_DISABLE_VHT |
@@ -914,7 +923,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
914923
!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)))
915924
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
916925

917-
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT))
926+
if (sband->band != NL80211_BAND_6GHZ &&
927+
!(ifmgd->flags & IEEE80211_STA_DISABLE_HT))
918928
ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param,
919929
sband, chan, sdata->smps_mode);
920930

@@ -968,7 +978,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
968978
offset = noffset;
969979
}
970980

971-
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
981+
if (sband->band != NL80211_BAND_6GHZ &&
982+
!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
972983
ieee80211_add_vht_ie(sdata, skb, sband,
973984
&assoc_data->ap_vht_cap);
974985

@@ -3248,6 +3259,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
32483259
struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
32493260
const struct cfg80211_bss_ies *bss_ies = NULL;
32503261
struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
3262+
bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ;
32513263
u32 changed = 0;
32523264
int err;
32533265
bool ret;
@@ -3289,11 +3301,12 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
32893301
* 2G/3G/4G wifi routers, reported models include the "Onda PN51T",
32903302
* "Vodafone PocketWiFi 2", "ZTE MF60" and a similar T-Mobile device.
32913303
*/
3292-
if ((assoc_data->wmm && !elems->wmm_param) ||
3293-
(!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) &&
3294-
(!elems->ht_cap_elem || !elems->ht_operation)) ||
3295-
(!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) &&
3296-
(!elems->vht_cap_elem || !elems->vht_operation))) {
3304+
if (!is_6ghz &&
3305+
((assoc_data->wmm && !elems->wmm_param) ||
3306+
(!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) &&
3307+
(!elems->ht_cap_elem || !elems->ht_operation)) ||
3308+
(!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) &&
3309+
(!elems->vht_cap_elem || !elems->vht_operation)))) {
32973310
const struct cfg80211_bss_ies *ies;
32983311
struct ieee802_11_elems bss_elems;
32993312

@@ -3351,22 +3364,30 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
33513364
* We previously checked these in the beacon/probe response, so
33523365
* they should be present here. This is just a safety net.
33533366
*/
3354-
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) &&
3367+
if (!is_6ghz && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT) &&
33553368
(!elems->wmm_param || !elems->ht_cap_elem || !elems->ht_operation)) {
33563369
sdata_info(sdata,
33573370
"HT AP is missing WMM params or HT capability/operation\n");
33583371
ret = false;
33593372
goto out;
33603373
}
33613374

3362-
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) &&
3375+
if (!is_6ghz && !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) &&
33633376
(!elems->vht_cap_elem || !elems->vht_operation)) {
33643377
sdata_info(sdata,
33653378
"VHT AP is missing VHT capability/operation\n");
33663379
ret = false;
33673380
goto out;
33683381
}
33693382

3383+
if (is_6ghz && !(ifmgd->flags & IEEE80211_STA_DISABLE_HE) &&
3384+
!elems->he_6ghz_capa) {
3385+
sdata_info(sdata,
3386+
"HE 6 GHz AP is missing HE 6 GHz band capability\n");
3387+
ret = false;
3388+
goto out;
3389+
}
3390+
33703391
mutex_lock(&sdata->local->sta_mtx);
33713392
/*
33723393
* station info was already allocated and inserted before
@@ -4826,6 +4847,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
48264847
const struct ieee80211_he_operation *he_oper = NULL;
48274848
struct ieee80211_supported_band *sband;
48284849
struct cfg80211_chan_def chandef;
4850+
bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ;
48294851
struct ieee80211_bss *bss = (void *)cbss->priv;
48304852
int ret;
48314853
u32 i;
@@ -4838,21 +4860,23 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
48384860
IEEE80211_STA_DISABLE_160MHZ);
48394861

48404862
/* disable HT/VHT/HE if we don't support them */
4841-
if (!sband->ht_cap.ht_supported) {
4863+
if (!sband->ht_cap.ht_supported && !is_6ghz) {
48424864
ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
48434865
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
48444866
ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
48454867
}
48464868

4847-
if (!sband->vht_cap.vht_supported)
4869+
if (!sband->vht_cap.vht_supported && !is_6ghz) {
48484870
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
4871+
ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
4872+
}
48494873

48504874
if (!ieee80211_get_he_sta_cap(sband))
48514875
ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
48524876

48534877
rcu_read_lock();
48544878

4855-
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
4879+
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && !is_6ghz) {
48564880
const u8 *ht_oper_ie, *ht_cap_ie;
48574881

48584882
ht_oper_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_OPERATION);
@@ -4869,7 +4893,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
48694893
}
48704894
}
48714895

4872-
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) {
4896+
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && !is_6ghz) {
48734897
const u8 *vht_oper_ie, *vht_cap;
48744898

48754899
vht_oper_ie = ieee80211_bss_get_ie(cbss,
@@ -4934,6 +4958,11 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
49344958

49354959
rcu_read_unlock();
49364960

4961+
if (ifmgd->flags & IEEE80211_STA_DISABLE_HE && is_6ghz) {
4962+
sdata_info(sdata, "Rejecting non-HE 6/7 GHz connection");
4963+
return -EINVAL;
4964+
}
4965+
49374966
/* will change later if needed */
49384967
sdata->smps_mode = IEEE80211_SMPS_OFF;
49394968

@@ -5315,6 +5344,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
53155344
int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
53165345
struct cfg80211_assoc_request *req)
53175346
{
5347+
bool is_6ghz = req->bss->channel->band == NL80211_BAND_6GHZ;
53185348
struct ieee80211_local *local = sdata->local;
53195349
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
53205350
struct ieee80211_bss *bss = (void *)req->bss->priv;
@@ -5457,14 +5487,15 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
54575487
if (ht_ie && ht_ie[1] >= sizeof(struct ieee80211_ht_operation))
54585488
assoc_data->ap_ht_param =
54595489
((struct ieee80211_ht_operation *)(ht_ie + 2))->ht_param;
5460-
else
5490+
else if (!is_6ghz)
54615491
ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
54625492
vht_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_VHT_CAPABILITY);
54635493
if (vht_ie && vht_ie[1] >= sizeof(struct ieee80211_vht_cap))
54645494
memcpy(&assoc_data->ap_vht_cap, vht_ie + 2,
54655495
sizeof(struct ieee80211_vht_cap));
5466-
else
5467-
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
5496+
else if (!is_6ghz)
5497+
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT |
5498+
IEEE80211_STA_DISABLE_HE;
54685499
rcu_read_unlock();
54695500

54705501
if (WARN((sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_UAPSD) &&

net/mac80211/util.c

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3244,6 +3244,112 @@ bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw, u32 vht_cap_info,
32443244
return true;
32453245
}
32463246

3247+
bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
3248+
const struct ieee80211_he_operation *he_oper,
3249+
struct cfg80211_chan_def *chandef)
3250+
{
3251+
struct ieee80211_local *local = sdata->local;
3252+
struct ieee80211_supported_band *sband;
3253+
enum nl80211_iftype iftype = ieee80211_vif_type_p2p(&sdata->vif);
3254+
const struct ieee80211_sta_he_cap *he_cap;
3255+
struct cfg80211_chan_def he_chandef = *chandef;
3256+
const struct ieee80211_he_6ghz_oper *he_6ghz_oper;
3257+
bool support_80_80, support_160;
3258+
u8 he_phy_cap;
3259+
u32 freq;
3260+
3261+
if (chandef->chan->band != NL80211_BAND_6GHZ)
3262+
return true;
3263+
3264+
sband = local->hw.wiphy->bands[NL80211_BAND_6GHZ];
3265+
3266+
he_cap = ieee80211_get_he_iftype_cap(sband, iftype);
3267+
if (!he_cap) {
3268+
sdata_info(sdata, "Missing iftype sband data/HE cap");
3269+
return false;
3270+
}
3271+
3272+
he_phy_cap = he_cap->he_cap_elem.phy_cap_info[0];
3273+
support_160 =
3274+
he_phy_cap &
3275+
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
3276+
support_80_80 =
3277+
he_phy_cap &
3278+
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G;
3279+
3280+
if (!he_oper) {
3281+
sdata_info(sdata,
3282+
"HE is not advertised on (on %d MHz), expect issues\n",
3283+
chandef->chan->center_freq);
3284+
return false;
3285+
}
3286+
3287+
he_6ghz_oper = ieee80211_he_6ghz_oper(he_oper);
3288+
3289+
if (!he_6ghz_oper) {
3290+
sdata_info(sdata,
3291+
"HE 6GHz operation missing (on %d MHz), expect issues\n",
3292+
chandef->chan->center_freq);
3293+
return false;
3294+
}
3295+
3296+
freq = ieee80211_channel_to_frequency(he_6ghz_oper->primary,
3297+
NL80211_BAND_6GHZ);
3298+
he_chandef.chan = ieee80211_get_channel(sdata->local->hw.wiphy, freq);
3299+
3300+
switch (u8_get_bits(he_6ghz_oper->control,
3301+
IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH)) {
3302+
case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_20MHZ:
3303+
he_chandef.width = NL80211_CHAN_WIDTH_20;
3304+
break;
3305+
case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_40MHZ:
3306+
he_chandef.width = NL80211_CHAN_WIDTH_40;
3307+
break;
3308+
case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_80MHZ:
3309+
he_chandef.width = NL80211_CHAN_WIDTH_80;
3310+
break;
3311+
case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_160MHZ:
3312+
he_chandef.width = NL80211_CHAN_WIDTH_80;
3313+
if (!he_6ghz_oper->ccfs1)
3314+
break;
3315+
if (abs(he_6ghz_oper->ccfs1 - he_6ghz_oper->ccfs0) == 8) {
3316+
if (support_160)
3317+
he_chandef.width = NL80211_CHAN_WIDTH_160;
3318+
} else {
3319+
if (support_80_80)
3320+
he_chandef.width = NL80211_CHAN_WIDTH_80P80;
3321+
}
3322+
break;
3323+
}
3324+
3325+
if (he_chandef.width == NL80211_CHAN_WIDTH_160) {
3326+
he_chandef.center_freq1 =
3327+
ieee80211_channel_to_frequency(he_6ghz_oper->ccfs1,
3328+
NL80211_BAND_6GHZ);
3329+
} else {
3330+
he_chandef.center_freq1 =
3331+
ieee80211_channel_to_frequency(he_6ghz_oper->ccfs0,
3332+
NL80211_BAND_6GHZ);
3333+
he_chandef.center_freq2 =
3334+
ieee80211_channel_to_frequency(he_6ghz_oper->ccfs1,
3335+
NL80211_BAND_6GHZ);
3336+
}
3337+
3338+
if (!cfg80211_chandef_valid(&he_chandef)) {
3339+
sdata_info(sdata,
3340+
"HE 6GHz operation resulted in invalid chandef: %d MHz/%d/%d MHz/%d MHz\n",
3341+
he_chandef.chan ? he_chandef.chan->center_freq : 0,
3342+
he_chandef.width,
3343+
he_chandef.center_freq1,
3344+
he_chandef.center_freq2);
3345+
return false;
3346+
}
3347+
3348+
*chandef = he_chandef;
3349+
3350+
return true;
3351+
}
3352+
32473353
int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef,
32483354
const struct ieee80211_supported_band *sband,
32493355
const u8 *srates, int srates_len, u32 *rates)

0 commit comments

Comments
 (0)