* @IEEE80211_OFFLOAD_DECAP_ENABLED: rx encapsulation offload is enabled
* The driver supports passing received 802.11 frames as 802.3 frames to
* mac80211.
+ * @IEEE80211_OFFLOAD_ENCAP_MCAST: tx multicast encapsulation offload is enabled
+ * The driver supports sending multicast frames passed as 802.3 frames
+ * by mac80211.
*/
enum ieee80211_offload_flags {
IEEE80211_OFFLOAD_ENCAP_ENABLED = BIT(0),
IEEE80211_OFFLOAD_ENCAP_4ADDR = BIT(1),
IEEE80211_OFFLOAD_DECAP_ENABLED = BIT(2),
+ IEEE80211_OFFLOAD_ENCAP_MCAST = BIT(3),
};
#define IEEE80211_NAN_AVAIL_BLOB_MAX_LEN 54
kfree_skb(skb);
}
+static bool ieee80211_check_mcast_offload(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb)
+{
+ struct ethhdr *ehdr = (struct ethhdr *)skb->data;
+
+ if ((ieee80211_vif_is_mld(&sdata->vif) &&
+ (sdata->vif.type == NL80211_IFTYPE_AP &&
+ !ieee80211_hw_check(&sdata->local->hw, MLO_MCAST_MULTI_LINK_TX))) ||
+ (sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+ !sdata->wdev.use_4addr))
+ return false;
+
+ if (!is_multicast_ether_addr(skb->data) ||
+ !(sdata->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_MCAST) ||
+ sdata->control_port_protocol == ehdr->h_proto)
+ return false;
+
+ return true;
+}
+
static void __ieee80211_subif_start_xmit_8023(struct sk_buff *skb,
struct net_device *dev)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ethhdr *ehdr = (struct ethhdr *)skb->data;
+ struct ieee80211_link_data *link;
struct ieee80211_key *key;
struct sta_info *sta;
goto out;
}
- if (unlikely(IS_ERR_OR_NULL(sta) || !sta->uploaded ||
- !test_sta_flag(sta, WLAN_STA_AUTHORIZED) ||
- sdata->control_port_protocol == ehdr->h_proto))
+ /*
+ * If STA is invalid, use the multicast offload path when applicable.
+ * In AP mode, drop the frame if there are no associated stations;
+ * otherwise use the default link and multicast key for transmission.
+ */
+ if (unlikely(IS_ERR_OR_NULL(sta) &&
+ ieee80211_check_mcast_offload(sdata, skb))) {
+ sta = NULL;
+ if (ieee80211_vif_get_num_mcast_if(sdata) <= 0) {
+ /* No associated STAs - no need to send multicast frames. */
+ kfree_skb(skb);
+ goto out;
+ }
+ link = &sdata->deflink;
+ key = rcu_dereference(link->default_multicast_key);
+ } else if (unlikely(IS_ERR_OR_NULL(sta) || !sta->uploaded ||
+ !test_sta_flag(sta, WLAN_STA_AUTHORIZED) ||
+ sdata->control_port_protocol == ehdr->h_proto)) {
goto skip_offload;
-
- key = rcu_dereference(sta->ptk[sta->ptk_idx]);
- if (!key)
- key = rcu_dereference(sdata->default_unicast_key);
+ } else {
+ key = rcu_dereference(sta->ptk[sta->ptk_idx]);
+ if (!key)
+ key = rcu_dereference(sdata->default_unicast_key);
+ }
if (key && (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) ||
key->conf.cipher == WLAN_CIPHER_SUITE_TKIP))