Skip to content

Commit 2f57f73

Browse files
Tamizh Chelvam Rajajeff-t-johnson
authored andcommitted
wifi: ath12k: Add support for 4-address mode
The current driver does not support enabling 4-address mode data traffic in WDS mode. Add the required functionality by introducing the sta_set_4addr() API, which is invoked when a 4-address AP/STA connects. This API sends the WMI_PEER_USE_4ADDR peer parameter to notify firmware about the 4-address peer, allowing firmware and hardware to transmit and receive frames in 4-address format for that peer. For 4-address multicast packet transmission, update the handling to set peer metadata values in HAL_TCL_DATA_CMD_INFO1_CMD_NUM instead of using vdev metadata values. Vdev metadata is used only for 3-address and 4-address unicast traffic and for 3-address multicast traffic. The peer metadata path embeds the correct peer_id, enabling proper multicast transmission in 4-address mode. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1 Signed-off-by: Tamizh Chelvam Raja <tamizh.raja@oss.qualcomm.com> Reviewed-by: Rameshkumar Sundaram <rameshkumar.sundaram@oss.qualcomm.com> Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com> Link: https://patch.msgid.link/20260525110942.2890212-3-tamizh.raja@oss.qualcomm.com Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
1 parent e1125b0 commit 2f57f73

8 files changed

Lines changed: 125 additions & 7 deletions

File tree

drivers/net/wireless/ath/ath12k/core.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,8 @@ struct ath12k_link_vif {
353353
u16 num_stations;
354354
bool is_csa_in_progress;
355355
struct wiphy_work bcn_tx_work;
356+
357+
bool set_wds_vdev_param;
356358
};
357359

358360
struct ath12k_vif {
@@ -492,6 +494,8 @@ struct ath12k_link_sta {
492494
/* link address similar to ieee80211_link_sta */
493495
u8 addr[ETH_ALEN];
494496

497+
u16 tcl_metadata;
498+
495499
/* the following are protected by ar->data_lock */
496500
u32 changed; /* IEEE80211_RC_* */
497501
u32 bw;
@@ -527,6 +531,8 @@ struct ath12k_sta {
527531
u16 free_logical_link_idx_map;
528532

529533
enum ieee80211_sta_state state;
534+
535+
bool enable_4addr;
530536
};
531537

532538
#define ATH12K_HALF_20MHZ_BW 10

drivers/net/wireless/ath/ath12k/mac.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6571,6 +6571,62 @@ static int ath12k_mac_station_disassoc(struct ath12k *ar,
65716571
return 0;
65726572
}
65736573

6574+
static int ath12k_mac_sta_set_4addr(struct wiphy *wiphy, struct ath12k_sta *ahsta)
6575+
{
6576+
struct ath12k_dp_link_peer *peer;
6577+
struct ath12k_link_vif *arvif;
6578+
struct ath12k_link_sta *arsta;
6579+
struct ath12k_dp *dp;
6580+
unsigned long links;
6581+
struct ath12k *ar;
6582+
u8 link_id;
6583+
int ret;
6584+
6585+
links = ahsta->links_map;
6586+
for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
6587+
arsta = wiphy_dereference(wiphy, ahsta->link[link_id]);
6588+
if (!arsta)
6589+
continue;
6590+
6591+
arvif = arsta->arvif;
6592+
ar = arvif->ar;
6593+
6594+
if (arvif->set_wds_vdev_param)
6595+
goto skip_use_4addr;
6596+
6597+
ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
6598+
"setting USE_4ADDR for peer %pM\n", arsta->addr);
6599+
6600+
ret = ath12k_wmi_set_peer_param(ar, arsta->addr,
6601+
arvif->vdev_id,
6602+
WMI_PEER_USE_4ADDR,
6603+
WMI_PEER_4ADDR_ALLOW_EAPOL_DATA_FRAME);
6604+
if (ret) {
6605+
ath12k_warn(ar->ab, "failed to set peer %pM 4addr capability: %d\n",
6606+
arsta->addr, ret);
6607+
return ret;
6608+
}
6609+
6610+
skip_use_4addr:
6611+
dp = ath12k_ab_to_dp(ar->ab);
6612+
spin_lock_bh(&dp->dp_lock);
6613+
peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, arvif->vdev_id,
6614+
arsta->addr);
6615+
if (peer && peer->dp_peer) {
6616+
peer->dp_peer->ucast_ra_only = true;
6617+
} else {
6618+
spin_unlock_bh(&dp->dp_lock);
6619+
ath12k_warn(ar->ab, "failed to find DP peer for %pM\n",
6620+
arsta->addr);
6621+
return -ENOENT;
6622+
}
6623+
6624+
spin_unlock_bh(&dp->dp_lock);
6625+
}
6626+
6627+
return 0;
6628+
}
6629+
65746630
static void ath12k_sta_rc_update_wk(struct wiphy *wiphy, struct wiphy_work *wk)
65756631
{
65766632
struct ieee80211_link_sta *link_sta;
@@ -7865,6 +7921,28 @@ int ath12k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw,
78657921
}
78667922
EXPORT_SYMBOL(ath12k_mac_op_sta_set_txpwr);
78677923

7924+
void ath12k_mac_op_sta_set_4addr(struct ieee80211_hw *hw,
7925+
struct ieee80211_vif *vif,
7926+
struct ieee80211_sta *sta, bool enabled)
7927+
{
7928+
struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta);
7929+
7930+
lockdep_assert_wiphy(hw->wiphy);
7931+
7932+
/*
7933+
* 4-address mode disabled option is available only for station
7934+
* interface from mac80211, and we have wds_vdev_param for station
7935+
* interface and target will not allow to disable the wds_vdev_param
7936+
* during run time. So, add support only for enable case, for
7937+
* disable case station interface needs to be reconnect.
7938+
*/
7939+
if (enabled && !ahsta->enable_4addr) {
7940+
if (!ath12k_mac_sta_set_4addr(hw->wiphy, ahsta))
7941+
ahsta->enable_4addr = true;
7942+
}
7943+
}
7944+
EXPORT_SYMBOL(ath12k_mac_op_sta_set_4addr);
7945+
78687946
void ath12k_mac_op_link_sta_rc_update(struct ieee80211_hw *hw,
78697947
struct ieee80211_vif *vif,
78707948
struct ieee80211_link_sta *link_sta,
@@ -10421,6 +10499,7 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif)
1042110499
ret);
1042210500
goto err_peer_del;
1042310501
}
10502+
arvif->set_wds_vdev_param = true;
1042410503
}
1042510504

1042610505
if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ab->wmi_ab.svc_map) &&

drivers/net/wireless/ath/ath12k/mac.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,9 @@ int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
255255
int ath12k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw,
256256
struct ieee80211_vif *vif,
257257
struct ieee80211_sta *sta);
258+
void ath12k_mac_op_sta_set_4addr(struct ieee80211_hw *hw,
259+
struct ieee80211_vif *vif,
260+
struct ieee80211_sta *sta, bool enabled);
258261
void ath12k_mac_op_link_sta_rc_update(struct ieee80211_hw *hw,
259262
struct ieee80211_vif *vif,
260263
struct ieee80211_link_sta *link_sta,

drivers/net/wireless/ath/ath12k/peer.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,12 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif,
218218
ahsta = ath12k_sta_to_ahsta(sta);
219219
arsta = wiphy_dereference(ath12k_ar_to_hw(ar)->wiphy,
220220
ahsta->link[link_id]);
221-
221+
/* TODO: Split DP related field usage to DP peer structure */
222+
arsta->tcl_metadata = u16_encode_bits(0, HTT_TCL_META_DATA_TYPE) |
223+
u16_encode_bits(peer->peer_id,
224+
HTT_TCL_META_DATA_PEER_ID) |
225+
u16_encode_bits(0,
226+
HTT_TCL_META_DATA_VALID_HTT);
222227
peer->link_id = arsta->link_id;
223228

224229
/* Fill ML info into created peer */

drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ static int ath12k_wifi7_dp_prepare_htt_metadata(struct sk_buff *skb)
5959

6060
/* TODO: Remove the export once this file is built with wifi7 ko */
6161
int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *arvif,
62-
struct sk_buff *skb, bool gsn_valid, int mcbc_gsn,
63-
bool is_mcast)
62+
struct ath12k_link_sta *arsta, struct sk_buff *skb,
63+
bool gsn_valid, int mcbc_gsn, bool is_mcast)
6464
{
6565
struct ath12k_dp *dp = dp_pdev->dp;
6666
struct ath12k_hal *hal = dp->hal;
@@ -125,6 +125,12 @@ int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *a
125125
ti.bank_id = dp_link_vif->bank_id;
126126
ti.meta_data_flags = dp_link_vif->tcl_metadata;
127127

128+
if (ieee80211_has_a4(hdr->frame_control) &&
129+
is_multicast_ether_addr(hdr->addr3) && arsta) {
130+
ti.meta_data_flags = arsta->tcl_metadata;
131+
ti.flags0 |= u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_TO_FW);
132+
}
133+
128134
if (dp_vif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW &&
129135
test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ab->dev_flags)) {
130136
if (skb_cb->flags & ATH12K_SKB_CIPHER_SET) {

drivers/net/wireless/ath/ath12k/wifi7/dp_tx.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
#define ATH12K_DP_TX_WIFI7_H
99

1010
int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *arvif,
11-
struct sk_buff *skb, bool gsn_valid, int mcbc_gsn,
12-
bool is_mcast);
11+
struct ath12k_link_sta *arsta, struct sk_buff *skb,
12+
bool gsn_valid, int mcbc_gsn, bool is_mcast);
1313
void ath12k_wifi7_dp_tx_completion_handler(struct ath12k_dp *dp, int ring_id);
1414
u32 ath12k_wifi7_dp_tx_get_vdev_bank_config(struct ath12k_base *ab,
1515
struct ath12k_link_vif *arvif);

drivers/net/wireless/ath/ath12k/wifi7/hw.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -889,7 +889,9 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
889889
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
890890
struct ieee80211_key_conf *key = info->control.hw_key;
891891
struct ieee80211_sta *sta = control->sta;
892+
struct ath12k_link_sta *arsta = NULL;
892893
struct ath12k_link_vif *tmp_arvif;
894+
struct ath12k_sta *ahsta = NULL;
893895
u32 info_flags = info->flags;
894896
struct sk_buff *msdu_copied;
895897
struct ath12k *ar, *tmp_ar;
@@ -971,6 +973,12 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
971973
if (!(info_flags & IEEE80211_TX_CTL_HW_80211_ENCAP))
972974
is_mcast = is_multicast_ether_addr(hdr->addr1);
973975

976+
if (sta) {
977+
ahsta = ath12k_sta_to_ahsta(control->sta);
978+
if (ahsta && ahsta->enable_4addr)
979+
arsta = rcu_dereference(ahsta->link[link_id]);
980+
}
981+
974982
/* This is case only for P2P_GO */
975983
if (vif->type == NL80211_IFTYPE_AP && vif->p2p)
976984
ath12k_mac_add_p2p_noa_ie(ar, vif, skb, is_prb_rsp);
@@ -991,7 +999,7 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
991999
if (!vif->valid_links || !is_mcast || is_dvlan ||
9921000
(skb_cb->flags & ATH12K_SKB_HW_80211_ENCAP) ||
9931001
test_bit(ATH12K_FLAG_RAW_MODE, &ar->ab->dev_flags)) {
994-
ret = ath12k_wifi7_dp_tx(dp_pdev, arvif, skb, false, 0, is_mcast);
1002+
ret = ath12k_wifi7_dp_tx(dp_pdev, arvif, arsta, skb, false, 0, is_mcast);
9951003
if (unlikely(ret)) {
9961004
ath12k_warn(ar->ab, "failed to transmit frame %d\n", ret);
9971005
ieee80211_free_txskb(ar->ah->hw, skb);
@@ -1029,6 +1037,11 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
10291037
skb_cb->vif = vif;
10301038
skb_cb->ar = tmp_ar;
10311039

1040+
if (ahsta && ahsta->enable_4addr)
1041+
arsta = rcu_dereference(ahsta->link[link_id]);
1042+
else
1043+
arsta = NULL;
1044+
10321045
/* For open mode, skip peer find logic */
10331046
if (unlikely(!ahvif->dp_vif.key_cipher))
10341047
goto skip_peer_find;
@@ -1060,7 +1073,7 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
10601073
spin_unlock_bh(&tmp_dp->dp_lock);
10611074

10621075
skip_peer_find:
1063-
ret = ath12k_wifi7_dp_tx(tmp_dp_pdev, tmp_arvif,
1076+
ret = ath12k_wifi7_dp_tx(tmp_dp_pdev, tmp_arvif, arsta,
10641077
msdu_copied, true, mcbc_gsn, is_mcast);
10651078
if (unlikely(ret)) {
10661079
if (ret == -ENOMEM) {
@@ -1105,6 +1118,7 @@ static const struct ieee80211_ops ath12k_ops_wifi7 = {
11051118
.sta_state = ath12k_mac_op_sta_state,
11061119
.sta_set_txpwr = ath12k_mac_op_sta_set_txpwr,
11071120
.link_sta_rc_update = ath12k_mac_op_link_sta_rc_update,
1121+
.sta_set_4addr = ath12k_mac_op_sta_set_4addr,
11081122
.conf_tx = ath12k_mac_op_conf_tx,
11091123
.set_antenna = ath12k_mac_op_set_antenna,
11101124
.get_antenna = ath12k_mac_op_get_antenna,

drivers/net/wireless/ath/ath12k/wmi.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2334,6 +2334,11 @@ enum wmi_preamble {
23342334
WMI_VDEV_PREAMBLE_SHORT = 2,
23352335
};
23362336

2337+
enum wmi_peer_4addr_allow_frame {
2338+
WMI_PEER_4ADDR_ALLOW_DATA_FRAME = 1,
2339+
WMI_PEER_4ADDR_ALLOW_EAPOL_DATA_FRAME = 2,
2340+
};
2341+
23372342
enum wmi_peer_smps_state {
23382343
WMI_PEER_SMPS_PS_NONE = 0,
23392344
WMI_PEER_SMPS_STATIC = 1,

0 commit comments

Comments
 (0)