u16 num_stations;
bool is_csa_in_progress;
struct wiphy_work bcn_tx_work;
+
+ bool set_wds_vdev_param;
};
struct ath12k_vif {
/* link address similar to ieee80211_link_sta */
u8 addr[ETH_ALEN];
+ u16 tcl_metadata;
+
/* the following are protected by ar->data_lock */
u32 changed; /* IEEE80211_RC_* */
u32 bw;
u16 free_logical_link_idx_map;
enum ieee80211_sta_state state;
+
+ bool enable_4addr;
};
#define ATH12K_HALF_20MHZ_BW 10
return 0;
}
+static int ath12k_mac_sta_set_4addr(struct wiphy *wiphy, struct ath12k_sta *ahsta)
+{
+ struct ath12k_dp_link_peer *peer;
+ struct ath12k_link_vif *arvif;
+ struct ath12k_link_sta *arsta;
+ struct ath12k_dp *dp;
+ unsigned long links;
+ struct ath12k *ar;
+ u8 link_id;
+ int ret;
+
+ links = ahsta->links_map;
+ for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
+ arsta = wiphy_dereference(wiphy, ahsta->link[link_id]);
+ if (!arsta)
+ continue;
+
+ arvif = arsta->arvif;
+ ar = arvif->ar;
+
+ if (arvif->set_wds_vdev_param)
+ goto skip_use_4addr;
+
+ ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
+ "setting USE_4ADDR for peer %pM\n", arsta->addr);
+
+ ret = ath12k_wmi_set_peer_param(ar, arsta->addr,
+ arvif->vdev_id,
+ WMI_PEER_USE_4ADDR,
+ WMI_PEER_4ADDR_ALLOW_EAPOL_DATA_FRAME);
+ if (ret) {
+ ath12k_warn(ar->ab, "failed to set peer %pM 4addr capability: %d\n",
+ arsta->addr, ret);
+ return ret;
+ }
+
+skip_use_4addr:
+ dp = ath12k_ab_to_dp(ar->ab);
+ spin_lock_bh(&dp->dp_lock);
+ peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, arvif->vdev_id,
+ arsta->addr);
+ if (peer && peer->dp_peer) {
+ peer->dp_peer->ucast_ra_only = true;
+ } else {
+ spin_unlock_bh(&dp->dp_lock);
+ ath12k_warn(ar->ab, "failed to find DP peer for %pM\n",
+ arsta->addr);
+ return -ENOENT;
+ }
+
+ spin_unlock_bh(&dp->dp_lock);
+ }
+
+ return 0;
+}
+
static void ath12k_sta_rc_update_wk(struct wiphy *wiphy, struct wiphy_work *wk)
{
struct ieee80211_link_sta *link_sta;
}
EXPORT_SYMBOL(ath12k_mac_op_sta_set_txpwr);
+void ath12k_mac_op_sta_set_4addr(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, bool enabled)
+{
+ struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta);
+
+ lockdep_assert_wiphy(hw->wiphy);
+
+ /*
+ * 4-address mode disabled option is available only for station
+ * interface from mac80211, and we have wds_vdev_param for station
+ * interface and target will not allow to disable the wds_vdev_param
+ * during run time. So, add support only for enable case, for
+ * disable case station interface needs to be reconnect.
+ */
+ if (enabled && !ahsta->enable_4addr) {
+ if (!ath12k_mac_sta_set_4addr(hw->wiphy, ahsta))
+ ahsta->enable_4addr = true;
+ }
+}
+EXPORT_SYMBOL(ath12k_mac_op_sta_set_4addr);
+
void ath12k_mac_op_link_sta_rc_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_link_sta *link_sta,
ret);
goto err_peer_del;
}
+ arvif->set_wds_vdev_param = true;
}
if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ab->wmi_ab.svc_map) &&
int ath12k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
+void ath12k_mac_op_sta_set_4addr(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, bool enabled);
void ath12k_mac_op_link_sta_rc_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_link_sta *link_sta,
ahsta = ath12k_sta_to_ahsta(sta);
arsta = wiphy_dereference(ath12k_ar_to_hw(ar)->wiphy,
ahsta->link[link_id]);
-
+ /* TODO: Split DP related field usage to DP peer structure */
+ arsta->tcl_metadata = u16_encode_bits(0, HTT_TCL_META_DATA_TYPE) |
+ u16_encode_bits(peer->peer_id,
+ HTT_TCL_META_DATA_PEER_ID) |
+ u16_encode_bits(0,
+ HTT_TCL_META_DATA_VALID_HTT);
peer->link_id = arsta->link_id;
/* Fill ML info into created peer */
/* TODO: Remove the export once this file is built with wifi7 ko */
int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *arvif,
- struct sk_buff *skb, bool gsn_valid, int mcbc_gsn,
- bool is_mcast)
+ struct ath12k_link_sta *arsta, struct sk_buff *skb,
+ bool gsn_valid, int mcbc_gsn, bool is_mcast)
{
struct ath12k_dp *dp = dp_pdev->dp;
struct ath12k_hal *hal = dp->hal;
ti.bank_id = dp_link_vif->bank_id;
ti.meta_data_flags = dp_link_vif->tcl_metadata;
+ if (ieee80211_has_a4(hdr->frame_control) &&
+ is_multicast_ether_addr(hdr->addr3) && arsta) {
+ ti.meta_data_flags = arsta->tcl_metadata;
+ ti.flags0 |= u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_TO_FW);
+ }
+
if (dp_vif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW &&
test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ab->dev_flags)) {
if (skb_cb->flags & ATH12K_SKB_CIPHER_SET) {
#define ATH12K_DP_TX_WIFI7_H
int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *arvif,
- struct sk_buff *skb, bool gsn_valid, int mcbc_gsn,
- bool is_mcast);
+ struct ath12k_link_sta *arsta, struct sk_buff *skb,
+ bool gsn_valid, int mcbc_gsn, bool is_mcast);
void ath12k_wifi7_dp_tx_completion_handler(struct ath12k_dp *dp, int ring_id);
u32 ath12k_wifi7_dp_tx_get_vdev_bank_config(struct ath12k_base *ab,
struct ath12k_link_vif *arvif);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_key_conf *key = info->control.hw_key;
struct ieee80211_sta *sta = control->sta;
+ struct ath12k_link_sta *arsta = NULL;
struct ath12k_link_vif *tmp_arvif;
+ struct ath12k_sta *ahsta = NULL;
u32 info_flags = info->flags;
struct sk_buff *msdu_copied;
struct ath12k *ar, *tmp_ar;
if (!(info_flags & IEEE80211_TX_CTL_HW_80211_ENCAP))
is_mcast = is_multicast_ether_addr(hdr->addr1);
+ if (sta) {
+ ahsta = ath12k_sta_to_ahsta(control->sta);
+ if (ahsta && ahsta->enable_4addr)
+ arsta = rcu_dereference(ahsta->link[link_id]);
+ }
+
/* This is case only for P2P_GO */
if (vif->type == NL80211_IFTYPE_AP && vif->p2p)
ath12k_mac_add_p2p_noa_ie(ar, vif, skb, is_prb_rsp);
if (!vif->valid_links || !is_mcast || is_dvlan ||
(skb_cb->flags & ATH12K_SKB_HW_80211_ENCAP) ||
test_bit(ATH12K_FLAG_RAW_MODE, &ar->ab->dev_flags)) {
- ret = ath12k_wifi7_dp_tx(dp_pdev, arvif, skb, false, 0, is_mcast);
+ ret = ath12k_wifi7_dp_tx(dp_pdev, arvif, arsta, skb, false, 0, is_mcast);
if (unlikely(ret)) {
ath12k_warn(ar->ab, "failed to transmit frame %d\n", ret);
ieee80211_free_txskb(ar->ah->hw, skb);
skb_cb->vif = vif;
skb_cb->ar = tmp_ar;
+ if (ahsta && ahsta->enable_4addr)
+ arsta = rcu_dereference(ahsta->link[link_id]);
+ else
+ arsta = NULL;
+
/* For open mode, skip peer find logic */
if (unlikely(!ahvif->dp_vif.key_cipher))
goto skip_peer_find;
spin_unlock_bh(&tmp_dp->dp_lock);
skip_peer_find:
- ret = ath12k_wifi7_dp_tx(tmp_dp_pdev, tmp_arvif,
+ ret = ath12k_wifi7_dp_tx(tmp_dp_pdev, tmp_arvif, arsta,
msdu_copied, true, mcbc_gsn, is_mcast);
if (unlikely(ret)) {
if (ret == -ENOMEM) {
.sta_state = ath12k_mac_op_sta_state,
.sta_set_txpwr = ath12k_mac_op_sta_set_txpwr,
.link_sta_rc_update = ath12k_mac_op_link_sta_rc_update,
+ .sta_set_4addr = ath12k_mac_op_sta_set_4addr,
.conf_tx = ath12k_mac_op_conf_tx,
.set_antenna = ath12k_mac_op_set_antenna,
.get_antenna = ath12k_mac_op_get_antenna,
WMI_VDEV_PREAMBLE_SHORT = 2,
};
+enum wmi_peer_4addr_allow_frame {
+ WMI_PEER_4ADDR_ALLOW_DATA_FRAME = 1,
+ WMI_PEER_4ADDR_ALLOW_EAPOL_DATA_FRAME = 2,
+};
+
enum wmi_peer_smps_state {
WMI_PEER_SMPS_PS_NONE = 0,
WMI_PEER_SMPS_STATIC = 1,