mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-12-22 11:53:02 +00:00
530 lines
18 KiB
Diff
530 lines
18 KiB
Diff
From 369c67787c1106a176582913d1d211be2ac31877 Mon Sep 17 00:00:00 2001
|
|
From: Sathishkumar Muruganandam <quic_murugana@quicinc.com>
|
|
Date: Tue, 23 Nov 2021 18:19:03 +0530
|
|
Subject: [PATCH] mac80211: add EHT support for mesh
|
|
|
|
Add support for EHT capability, operation information element parsing
|
|
and advertisement in mesh beacon, probe responses, and peering action
|
|
frames.
|
|
|
|
Update EHT support configurations based on the parsed elements.
|
|
|
|
Filter capabilities reported by the firmware based on mesh needs
|
|
and remove the capabilities not required for mesh.
|
|
|
|
Signed-off-by: Sathishkumar Muruganandam <quic_murugana@quicinc.com>
|
|
Signed-off-by: Ramya Gnanasekar <quic_rgnanase@quicinc.com>
|
|
|
|
--- a/include/linux/ieee80211.h
|
|
+++ b/include/linux/ieee80211.h
|
|
@@ -4009,6 +4009,12 @@ struct ieee80211_multiple_bssid_configur
|
|
#define WLAN_OUI_TYPE_MICROSOFT_WPS 4
|
|
#define WLAN_OUI_TYPE_MICROSOFT_TPC 8
|
|
|
|
+#define IEEE80211_EHT_OPER_CTRL_CHANWIDTH_20MHZ 0
|
|
+#define IEEE80211_EHT_OPER_CTRL_CHANWIDTH_40MHZ 1
|
|
+#define IEEE80211_EHT_OPER_CTRL_CHANWIDTH_80MHZ 2
|
|
+#define IEEE80211_EHT_OPER_CTRL_CHANWIDTH_160MHZ 3
|
|
+#define IEEE80211_EHT_OPER_CTRL_CHANWIDTH_320MHZ 4
|
|
+
|
|
/*
|
|
* WMM/802.11e Tspec Element
|
|
*/
|
|
--- a/net/mac80211/ieee80211_i.h
|
|
+++ b/net/mac80211/ieee80211_i.h
|
|
@@ -2411,6 +2411,12 @@ u8 *ieee80211_ie_build_he_cap(ieee80211_
|
|
void ieee80211_ie_build_he_6ghz_cap(struct ieee80211_sub_if_data *sdata,
|
|
struct sk_buff *skb);
|
|
u8 *ieee80211_ie_build_he_oper(u8 *pos, struct cfg80211_chan_def *chandef);
|
|
+u8 ieee80211_ie_len_eht_cap(struct ieee80211_sub_if_data *sdata, u8 iftype);
|
|
+u8 *ieee80211_ie_build_eht_cap(u8 *pos,
|
|
+ const struct ieee80211_sta_he_cap *he_cap,
|
|
+ const struct ieee80211_sta_eht_cap *eht_cap,
|
|
+ u8 *end);
|
|
+u8 *ieee80211_ie_build_eht_oper(u8 *pos, struct cfg80211_chan_def *chandef);
|
|
int ieee80211_parse_bitrates(enum nl80211_chan_width width,
|
|
const struct ieee80211_supported_band *sband,
|
|
const u8 *srates, int srates_len, u32 *rates);
|
|
--- a/net/mac80211/mesh.c
|
|
+++ b/net/mac80211/mesh.c
|
|
@@ -104,7 +104,7 @@ bool mesh_matches_local(struct ieee80211
|
|
ieee80211_chandef_vht_oper(&sdata->local->hw, vht_cap_info,
|
|
ie->vht_operation, ie->ht_operation,
|
|
&sta_chan_def);
|
|
- ieee80211_chandef_he_6ghz_oper(sdata, ie->he_operation, NULL,
|
|
+ ieee80211_chandef_he_6ghz_oper(sdata, ie->he_operation, ie->eht_operation,
|
|
&sta_chan_def);
|
|
|
|
if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef,
|
|
@@ -644,6 +644,67 @@ int mesh_add_he_6ghz_cap_ie(struct ieee8
|
|
return 0;
|
|
}
|
|
|
|
+int mesh_add_eht_cap_ie(struct ieee80211_sub_if_data *sdata,
|
|
+ struct sk_buff *skb, u8 ie_len)
|
|
+{
|
|
+ const struct ieee80211_sta_he_cap *he_cap;
|
|
+ const struct ieee80211_sta_eht_cap *eht_cap;
|
|
+ struct ieee80211_supported_band *sband;
|
|
+ u8 *pos;
|
|
+
|
|
+ sband = ieee80211_get_sband(sdata);
|
|
+ if (!sband)
|
|
+ return -EINVAL;
|
|
+
|
|
+ he_cap = ieee80211_get_he_iftype_cap(sband, NL80211_IFTYPE_MESH_POINT);
|
|
+ eht_cap = ieee80211_get_eht_iftype_cap(sband, NL80211_IFTYPE_MESH_POINT);
|
|
+
|
|
+ if (!he_cap || !eht_cap ||
|
|
+ sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
|
|
+ sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 ||
|
|
+ sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10)
|
|
+ return 0;
|
|
+
|
|
+ if (skb_tailroom(skb) < ie_len)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ pos = skb_put(skb, ie_len);
|
|
+ ieee80211_ie_build_eht_cap(pos, he_cap, eht_cap, pos + ie_len);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int mesh_add_eht_oper_ie(struct ieee80211_sub_if_data *sdata,
|
|
+ struct sk_buff *skb)
|
|
+{
|
|
+ const struct ieee80211_sta_eht_cap *eht_cap;
|
|
+ struct ieee80211_supported_band *sband;
|
|
+ u32 len;
|
|
+ u8 *pos;
|
|
+
|
|
+ sband = ieee80211_get_sband(sdata);
|
|
+ if (!sband)
|
|
+ return -EINVAL;
|
|
+
|
|
+ eht_cap = ieee80211_get_eht_iftype_cap(sband, NL80211_IFTYPE_MESH_POINT);
|
|
+ if (!eht_cap ||
|
|
+ sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
|
|
+ sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 ||
|
|
+ sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10)
|
|
+ return 0;
|
|
+
|
|
+ len = 2 + 1 + sizeof(struct ieee80211_eht_operation) +
|
|
+ sizeof(struct ieee80211_eht_operation_info);
|
|
+
|
|
+ if (skb_tailroom(skb) < len)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ pos = skb_put(skb, len);
|
|
+ ieee80211_ie_build_eht_oper(pos, &sdata->vif.bss_conf.chandef);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static void ieee80211_mesh_path_timer(struct timer_list *t)
|
|
{
|
|
struct ieee80211_sub_if_data *sdata =
|
|
@@ -681,6 +742,7 @@ ieee80211_mesh_update_bss_params(struct
|
|
struct ieee80211_supported_band *sband;
|
|
const struct element *cap;
|
|
const struct ieee80211_he_operation *he_oper = NULL;
|
|
+ const struct ieee80211_eht_operation *eht_oper = NULL;
|
|
|
|
sband = ieee80211_get_sband(sdata);
|
|
if (!sband)
|
|
@@ -702,6 +764,18 @@ ieee80211_mesh_update_bss_params(struct
|
|
if (he_oper)
|
|
sdata->vif.bss_conf.he_oper.params =
|
|
__le32_to_cpu(he_oper->he_oper_params);
|
|
+
|
|
+ if (!ieee80211_get_eht_iftype_cap(sband, NL80211_IFTYPE_MESH_POINT))
|
|
+ return;
|
|
+
|
|
+ sdata->vif.bss_conf.eht_support = true;
|
|
+
|
|
+ cap = cfg80211_find_ext_elem(WLAN_EID_EXT_EHT_OPERATION, ie, ie_len);
|
|
+ if (cap && ieee80211_eht_oper_size_ok(cap, cap->datalen))
|
|
+ eht_oper = (void *)(cap->data + 1);
|
|
+
|
|
+ if (eht_oper)
|
|
+ ieee80211_eht_op_ie_to_bss_conf(&sdata->vif, eht_oper);
|
|
}
|
|
|
|
/**
|
|
@@ -821,7 +895,7 @@ ieee80211_mesh_build_beacon(struct ieee8
|
|
struct ieee80211_chanctx_conf *chanctx_conf;
|
|
struct mesh_csa_settings *csa;
|
|
enum nl80211_band band;
|
|
- u8 ie_len_he_cap;
|
|
+ u8 ie_len_he_cap, ie_len_eht_cap;
|
|
u8 *pos;
|
|
struct ieee80211_sub_if_data *sdata;
|
|
int hdr_len = offsetofend(struct ieee80211_mgmt, u.beacon);
|
|
@@ -834,6 +908,8 @@ ieee80211_mesh_build_beacon(struct ieee8
|
|
|
|
ie_len_he_cap = ieee80211_ie_len_he_cap(sdata,
|
|
NL80211_IFTYPE_MESH_POINT);
|
|
+ ie_len_eht_cap = ieee80211_ie_len_eht_cap(sdata,
|
|
+ NL80211_IFTYPE_MESH_POINT);
|
|
head_len = hdr_len +
|
|
2 + /* NULL SSID */
|
|
/* Channel Switch Announcement */
|
|
@@ -857,6 +933,9 @@ ieee80211_mesh_build_beacon(struct ieee8
|
|
2 + 1 + sizeof(struct ieee80211_he_operation) +
|
|
sizeof(struct ieee80211_he_6ghz_oper) +
|
|
2 + 1 + sizeof(struct ieee80211_he_6ghz_capa) +
|
|
+ ie_len_eht_cap +
|
|
+ 2 + 1 + sizeof(struct ieee80211_eht_operation) +
|
|
+ + sizeof(struct ieee80211_eht_operation_info) +
|
|
ifmsh->ie_len;
|
|
|
|
bcn = kzalloc(sizeof(*bcn) + head_len + tail_len, GFP_KERNEL);
|
|
@@ -978,6 +1057,8 @@ ieee80211_mesh_build_beacon(struct ieee8
|
|
mesh_add_he_cap_ie(sdata, skb, ie_len_he_cap) ||
|
|
mesh_add_he_oper_ie(sdata, skb) ||
|
|
mesh_add_he_6ghz_cap_ie(sdata, skb) ||
|
|
+ mesh_add_eht_cap_ie(sdata, skb, ie_len_eht_cap) ||
|
|
+ mesh_add_eht_oper_ie(sdata, skb) ||
|
|
mesh_add_vendor_ies(sdata, skb))
|
|
goto out_free;
|
|
|
|
--- a/net/mac80211/mesh.h
|
|
+++ b/net/mac80211/mesh.h
|
|
@@ -234,6 +234,10 @@ int mesh_add_he_oper_ie(struct ieee80211
|
|
struct sk_buff *skb);
|
|
int mesh_add_he_6ghz_cap_ie(struct ieee80211_sub_if_data *sdata,
|
|
struct sk_buff *skb);
|
|
+int mesh_add_eht_cap_ie(struct ieee80211_sub_if_data *sdata,
|
|
+ struct sk_buff *skb, u8 ie_len);
|
|
+int mesh_add_eht_oper_ie(struct ieee80211_sub_if_data *sdata,
|
|
+ struct sk_buff *skb);
|
|
void mesh_rmc_free(struct ieee80211_sub_if_data *sdata);
|
|
int mesh_rmc_init(struct ieee80211_sub_if_data *sdata);
|
|
void ieee80211s_init(void);
|
|
--- a/net/mac80211/mesh_plink.c
|
|
+++ b/net/mac80211/mesh_plink.c
|
|
@@ -219,12 +219,14 @@ static int mesh_plink_frame_tx(struct ie
|
|
bool include_plid = false;
|
|
u16 peering_proto = 0;
|
|
u8 *pos, ie_len = 4;
|
|
- u8 ie_len_he_cap;
|
|
+ u8 ie_len_he_cap, ie_len_eht_cap;
|
|
int hdr_len = offsetofend(struct ieee80211_mgmt, u.action.u.self_prot);
|
|
int err = -ENOMEM;
|
|
|
|
ie_len_he_cap = ieee80211_ie_len_he_cap(sdata,
|
|
NL80211_IFTYPE_MESH_POINT);
|
|
+ ie_len_eht_cap = ieee80211_ie_len_eht_cap(sdata,
|
|
+ NL80211_IFTYPE_MESH_POINT);
|
|
skb = dev_alloc_skb(local->tx_headroom +
|
|
hdr_len +
|
|
2 + /* capability info */
|
|
@@ -241,6 +243,9 @@ static int mesh_plink_frame_tx(struct ie
|
|
2 + 1 + sizeof(struct ieee80211_he_operation) +
|
|
sizeof(struct ieee80211_he_6ghz_oper) +
|
|
2 + 1 + sizeof(struct ieee80211_he_6ghz_capa) +
|
|
+ ie_len_eht_cap +
|
|
+ 2 + 1 + sizeof(struct ieee80211_eht_operation) +
|
|
+ sizeof(struct ieee80211_eht_operation_info) +
|
|
2 + 8 + /* peering IE */
|
|
sdata->u.mesh.ie_len);
|
|
if (!skb)
|
|
@@ -332,7 +337,9 @@ static int mesh_plink_frame_tx(struct ie
|
|
mesh_add_vht_oper_ie(sdata, skb) ||
|
|
mesh_add_he_cap_ie(sdata, skb, ie_len_he_cap) ||
|
|
mesh_add_he_oper_ie(sdata, skb) ||
|
|
- mesh_add_he_6ghz_cap_ie(sdata, skb))
|
|
+ mesh_add_he_6ghz_cap_ie(sdata, skb) ||
|
|
+ mesh_add_eht_cap_ie(sdata, skb, ie_len_eht_cap) ||
|
|
+ mesh_add_eht_oper_ie(sdata, skb))
|
|
goto free;
|
|
}
|
|
|
|
@@ -457,6 +464,11 @@ static void mesh_sta_info_init(struct ie
|
|
elems->he_6ghz_capa,
|
|
&sta->deflink);
|
|
|
|
+ ieee80211_eht_cap_ie_to_sta_eht_cap(sdata, sband, elems->he_cap,
|
|
+ elems->he_cap_len,
|
|
+ elems->eht_cap, elems->eht_cap_len,
|
|
+ &sta->deflink);
|
|
+
|
|
if (bw != sta->sta.deflink.bandwidth)
|
|
changed |= IEEE80211_RC_BW_CHANGED;
|
|
|
|
--- a/net/mac80211/util.c
|
|
+++ b/net/mac80211/util.c
|
|
@@ -3141,6 +3141,7 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos,
|
|
ht_oper->primary_chan = ieee80211_frequency_to_channel(
|
|
chandef->chan->center_freq);
|
|
switch (chandef->width) {
|
|
+ case NL80211_CHAN_WIDTH_320:
|
|
case NL80211_CHAN_WIDTH_160:
|
|
case NL80211_CHAN_WIDTH_80P80:
|
|
case NL80211_CHAN_WIDTH_80:
|
|
@@ -3150,10 +3151,6 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos,
|
|
else
|
|
ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
|
|
break;
|
|
- case NL80211_CHAN_WIDTH_320:
|
|
- /* HT information element should not be included on 6GHz */
|
|
- WARN_ON(1);
|
|
- return pos;
|
|
default:
|
|
ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE;
|
|
break;
|
|
@@ -3213,19 +3210,31 @@ u8 *ieee80211_ie_build_vht_oper(u8 *pos,
|
|
const struct cfg80211_chan_def *chandef)
|
|
{
|
|
struct ieee80211_vht_operation *vht_oper;
|
|
+ struct cfg80211_chan_def tmp_chandef;
|
|
+
|
|
+ cfg80211_chandef_create(&tmp_chandef, chandef->chan, NL80211_CHAN_NO_HT);
|
|
+ tmp_chandef.center_freq1 = chandef->center_freq1;
|
|
+ tmp_chandef.center_freq2 = chandef->center_freq2;
|
|
+ tmp_chandef.width = chandef->width;
|
|
|
|
*pos++ = WLAN_EID_VHT_OPERATION;
|
|
*pos++ = sizeof(struct ieee80211_vht_operation);
|
|
vht_oper = (struct ieee80211_vht_operation *)pos;
|
|
vht_oper->center_freq_seg0_idx = ieee80211_frequency_to_channel(
|
|
- chandef->center_freq1);
|
|
- if (chandef->center_freq2)
|
|
+ tmp_chandef.center_freq1);
|
|
+ if (tmp_chandef.center_freq2)
|
|
vht_oper->center_freq_seg1_idx =
|
|
- ieee80211_frequency_to_channel(chandef->center_freq2);
|
|
+ ieee80211_frequency_to_channel(tmp_chandef.center_freq2);
|
|
else
|
|
vht_oper->center_freq_seg1_idx = 0x00;
|
|
|
|
- switch (chandef->width) {
|
|
+ switch (tmp_chandef.width) {
|
|
+ case NL80211_CHAN_WIDTH_320:
|
|
+ /* Downgrade EHT 320 MHz BW to 160 MHz for VHT & set new center_freq1 */
|
|
+ ieee80211_chandef_downgrade(&tmp_chandef);
|
|
+ vht_oper->center_freq_seg0_idx =
|
|
+ ieee80211_frequency_to_channel(tmp_chandef.center_freq1);
|
|
+ fallthrough;
|
|
case NL80211_CHAN_WIDTH_160:
|
|
/*
|
|
* Convert 160 MHz channel width to new style as interop
|
|
@@ -3233,7 +3242,7 @@ u8 *ieee80211_ie_build_vht_oper(u8 *pos,
|
|
*/
|
|
vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
|
|
vht_oper->center_freq_seg1_idx = vht_oper->center_freq_seg0_idx;
|
|
- if (chandef->chan->center_freq < chandef->center_freq1)
|
|
+ if (tmp_chandef.chan->center_freq < tmp_chandef.center_freq1)
|
|
vht_oper->center_freq_seg0_idx -= 8;
|
|
else
|
|
vht_oper->center_freq_seg0_idx += 8;
|
|
@@ -3248,10 +3257,6 @@ u8 *ieee80211_ie_build_vht_oper(u8 *pos,
|
|
case NL80211_CHAN_WIDTH_80:
|
|
vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
|
|
break;
|
|
- case NL80211_CHAN_WIDTH_320:
|
|
- /* VHT information element should not be included on 6GHz */
|
|
- WARN_ON(1);
|
|
- return pos;
|
|
default:
|
|
vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_USE_HT;
|
|
break;
|
|
@@ -3269,6 +3274,7 @@ u8 *ieee80211_ie_build_he_oper(u8 *pos,
|
|
struct ieee80211_he_6ghz_oper *he_6ghz_op;
|
|
u32 he_oper_params;
|
|
u8 ie_len = 1 + sizeof(struct ieee80211_he_operation);
|
|
+ struct cfg80211_chan_def tmp_chandef;
|
|
|
|
if (chandef->chan->band == NL80211_BAND_6GHZ)
|
|
ie_len += sizeof(struct ieee80211_he_6ghz_oper);
|
|
@@ -3298,27 +3304,30 @@ u8 *ieee80211_ie_build_he_oper(u8 *pos,
|
|
if (chandef->chan->band != NL80211_BAND_6GHZ)
|
|
goto out;
|
|
|
|
+ cfg80211_chandef_create(&tmp_chandef, chandef->chan, NL80211_CHAN_NO_HT);
|
|
+ tmp_chandef.center_freq1 = chandef->center_freq1;
|
|
+ tmp_chandef.center_freq2 = chandef->center_freq2;
|
|
+ tmp_chandef.width = chandef->width;
|
|
/* TODO add VHT operational */
|
|
he_6ghz_op = (struct ieee80211_he_6ghz_oper *)pos;
|
|
he_6ghz_op->minrate = 6; /* 6 Mbps */
|
|
he_6ghz_op->primary =
|
|
- ieee80211_frequency_to_channel(chandef->chan->center_freq);
|
|
+ ieee80211_frequency_to_channel(tmp_chandef.chan->center_freq);
|
|
he_6ghz_op->ccfs0 =
|
|
- ieee80211_frequency_to_channel(chandef->center_freq1);
|
|
- if (chandef->center_freq2)
|
|
+ ieee80211_frequency_to_channel(tmp_chandef.center_freq1);
|
|
+ if (tmp_chandef.center_freq2)
|
|
he_6ghz_op->ccfs1 =
|
|
- ieee80211_frequency_to_channel(chandef->center_freq2);
|
|
+ ieee80211_frequency_to_channel(tmp_chandef.center_freq2);
|
|
else
|
|
he_6ghz_op->ccfs1 = 0;
|
|
|
|
- switch (chandef->width) {
|
|
+ switch (tmp_chandef.width) {
|
|
case NL80211_CHAN_WIDTH_320:
|
|
- /*
|
|
- * TODO: mesh operation is not defined over 6GHz 320 MHz
|
|
- * channels.
|
|
- */
|
|
- WARN_ON(1);
|
|
- break;
|
|
+ /* Downgrade EHT 320 MHz BW to 160 MHz for HE & set new center_freq1 */
|
|
+ ieee80211_chandef_downgrade(&tmp_chandef);
|
|
+ he_6ghz_op->ccfs0 =
|
|
+ ieee80211_frequency_to_channel(tmp_chandef.center_freq1);
|
|
+ fallthrough;
|
|
case NL80211_CHAN_WIDTH_160:
|
|
/* Convert 160 MHz channel width to new style as interop
|
|
* workaround.
|
|
@@ -3326,7 +3335,7 @@ u8 *ieee80211_ie_build_he_oper(u8 *pos,
|
|
he_6ghz_op->control =
|
|
IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_160MHZ;
|
|
he_6ghz_op->ccfs1 = he_6ghz_op->ccfs0;
|
|
- if (chandef->chan->center_freq < chandef->center_freq1)
|
|
+ if (tmp_chandef.chan->center_freq < tmp_chandef.center_freq1)
|
|
he_6ghz_op->ccfs0 -= 8;
|
|
else
|
|
he_6ghz_op->ccfs0 += 8;
|
|
@@ -3355,6 +3364,59 @@ out:
|
|
return pos;
|
|
}
|
|
|
|
+u8 *ieee80211_ie_build_eht_oper(u8 *pos, struct cfg80211_chan_def *chandef)
|
|
+{
|
|
+ struct ieee80211_eht_operation *eht_oper;
|
|
+ struct ieee80211_eht_operation_info *eht_oper_info;
|
|
+ u8 ie_len = 1 + sizeof(struct ieee80211_eht_operation) +
|
|
+ sizeof(struct ieee80211_eht_operation_info);
|
|
+ u8 chwidth = 0;
|
|
+
|
|
+ *pos++ = WLAN_EID_EXTENSION;
|
|
+ *pos++ = ie_len;
|
|
+ *pos++ = WLAN_EID_EXT_EHT_OPERATION;
|
|
+
|
|
+ eht_oper = (struct ieee80211_eht_operation *)pos;
|
|
+ pos += sizeof(struct ieee80211_eht_operation);
|
|
+
|
|
+ eht_oper_info = (struct ieee80211_eht_operation_info *)pos;
|
|
+ pos += sizeof(struct ieee80211_eht_operation_info);
|
|
+
|
|
+ switch (chandef->width) {
|
|
+ case NL80211_CHAN_WIDTH_320:
|
|
+ chwidth = IEEE80211_EHT_OPER_CTRL_CHANWIDTH_320MHZ;
|
|
+ break;
|
|
+ case NL80211_CHAN_WIDTH_160:
|
|
+ chwidth = IEEE80211_EHT_OPER_CTRL_CHANWIDTH_160MHZ;
|
|
+ break;
|
|
+ case NL80211_CHAN_WIDTH_80P80:
|
|
+ chwidth = IEEE80211_EHT_OPER_CTRL_CHANWIDTH_160MHZ;
|
|
+ break;
|
|
+ case NL80211_CHAN_WIDTH_80:
|
|
+ chwidth = IEEE80211_EHT_OPER_CTRL_CHANWIDTH_80MHZ;
|
|
+ break;
|
|
+ case NL80211_CHAN_WIDTH_40:
|
|
+ chwidth = IEEE80211_EHT_OPER_CTRL_CHANWIDTH_40MHZ;
|
|
+ break;
|
|
+ default:
|
|
+ chwidth = IEEE80211_EHT_OPER_CTRL_CHANWIDTH_20MHZ;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ eht_oper->params |= IEEE80211_EHT_OPER_INFO_PRESENT;
|
|
+
|
|
+ eht_oper_info->control = chwidth;
|
|
+ eht_oper_info->ccfs0 =
|
|
+ ieee80211_frequency_to_channel(chandef->center_freq1);
|
|
+ eht_oper_info->ccfs1 = 0; /* How to get this? */
|
|
+
|
|
+ eht_oper->optional[0] = eht_oper_info->control;
|
|
+ eht_oper->optional[1] = eht_oper_info->ccfs0;
|
|
+ eht_oper->optional[2] = eht_oper_info->ccfs1;
|
|
+
|
|
+ return pos;
|
|
+}
|
|
+
|
|
bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,
|
|
struct cfg80211_chan_def *chandef)
|
|
{
|
|
@@ -4869,7 +4931,7 @@ u8 ieee80211_ie_len_eht_cap(struct ieee8
|
|
n = ieee80211_eht_mcs_nss_size(&he_cap->he_cap_elem,
|
|
&eht_cap->eht_cap_elem);
|
|
return 2 + 1 +
|
|
- sizeof(he_cap->he_cap_elem) + n +
|
|
+ sizeof(eht_cap->eht_cap_elem) + n +
|
|
ieee80211_eht_ppe_size(eht_cap->eht_ppe_thres[0],
|
|
eht_cap->eht_cap_elem.phy_cap_info);
|
|
return 0;
|
|
--- a/drivers/net/wireless/ath/ath12k/mac.c
|
|
+++ b/drivers/net/wireless/ath/ath12k/mac.c
|
|
@@ -5803,6 +5803,47 @@ static void ath12k_gen_eht_mcs_nss(struc
|
|
sizeof(struct ieee80211_eht_mcs_nss_supp_bw));
|
|
}
|
|
|
|
+static void
|
|
+ath12k_mac_filter_eht_cap_mesh(struct ieee80211_eht_cap_elem_fixed *eht_cap_elem)
|
|
+{
|
|
+ u8 m;
|
|
+
|
|
+ m = IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS;
|
|
+ eht_cap_elem->mac_cap_info[0] &= ~m;
|
|
+
|
|
+ m = IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO;
|
|
+ eht_cap_elem->phy_cap_info[0] &= ~m;
|
|
+
|
|
+ m = IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK |
|
|
+ IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK |
|
|
+ IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK |
|
|
+ IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK;
|
|
+ eht_cap_elem->phy_cap_info[3] &= ~m;
|
|
+
|
|
+ m = IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO |
|
|
+ IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP |
|
|
+ IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP |
|
|
+ IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI;
|
|
+ eht_cap_elem->phy_cap_info[4] &= ~m;
|
|
+
|
|
+ m = IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK |
|
|
+ IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP |
|
|
+ IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP |
|
|
+ IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK;
|
|
+ eht_cap_elem->phy_cap_info[5] &= ~m;
|
|
+
|
|
+ m = IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK;
|
|
+ eht_cap_elem->phy_cap_info[6] &= ~m;
|
|
+
|
|
+ m = IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ |
|
|
+ IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ |
|
|
+ IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_320MHZ |
|
|
+ IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ |
|
|
+ IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ |
|
|
+ IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_320MHZ;
|
|
+ eht_cap_elem->phy_cap_info[7] &= ~m;
|
|
+}
|
|
+
|
|
static void ath12k_mac_copy_eht_cap(struct ath12k *ar,
|
|
struct ath12k_band_cap *band_cap,
|
|
struct ieee80211_he_cap_elem *he_cap_elem,
|
|
@@ -5837,6 +5878,9 @@ static void ath12k_mac_copy_eht_cap(stru
|
|
IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ |
|
|
IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_320MHZ);
|
|
break;
|
|
+ case NL80211_IFTYPE_MESH_POINT:
|
|
+ ath12k_mac_filter_eht_cap_mesh(eht_cap_elem);
|
|
+ break;
|
|
default:
|
|
break;
|
|
}
|
|
--- a/net/mac80211/ht.c
|
|
+++ b/net/mac80211/ht.c
|
|
@@ -269,6 +269,7 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(s
|
|
case NL80211_CHAN_WIDTH_80:
|
|
case NL80211_CHAN_WIDTH_80P80:
|
|
case NL80211_CHAN_WIDTH_160:
|
|
+ case NL80211_CHAN_WIDTH_320:
|
|
bw = ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
|
|
IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20;
|
|
break;
|