提交 5e5f069c 编写于 作者: A Ahmad Masri 提交者: Kalle Valo

wil6210: support set_multicast_to_unicast cfg80211 operation

Wil6210 AP has a separate ring for transmitting multicast packets,
multicast packets are transmitted without an ack from the receiver side.
Therefore, 802.11 spec defines some low MCS rates for multicat packets.
However, there is no guarantee that these packets were really received
and handled on the client side.

Some applications that rely on multicast packets, may prefer to
transmit these packets as a unicast to ensure reliability, and also
to ensure better performance with high MCS rates.
multicast to unicast is done by duplicating multicast packets to all
clients and changing the DA (multicast) to the MAC address of the
client.
see NL80211_CMD_SET_MULTICAST_TO_UNICAST for more info.
Signed-off-by: NAhmad Masri <amasri@codeaurora.org>
Signed-off-by: NMaya Erez <merez@codeaurora.org>
Signed-off-by: NKalle Valo <kvalo@codeaurora.org>
上级 18beb61d
......@@ -2579,6 +2579,21 @@ wil_cfg80211_update_ft_ies(struct wiphy *wiphy, struct net_device *dev,
return rc;
}
static int wil_cfg80211_set_multicast_to_unicast(struct wiphy *wiphy,
struct net_device *dev,
const bool enabled)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
if (wil->multicast_to_unicast == enabled)
return 0;
wil_info(wil, "set multicast to unicast, enabled=%d\n", enabled);
wil->multicast_to_unicast = enabled;
return 0;
}
static const struct cfg80211_ops wil_cfg80211_ops = {
.add_virtual_intf = wil_cfg80211_add_iface,
.del_virtual_intf = wil_cfg80211_del_iface,
......@@ -2615,6 +2630,7 @@ static const struct cfg80211_ops wil_cfg80211_ops = {
.sched_scan_start = wil_cfg80211_sched_scan_start,
.sched_scan_stop = wil_cfg80211_sched_scan_stop,
.update_ft_ies = wil_cfg80211_update_ft_ies,
.set_multicast_to_unicast = wil_cfg80211_set_multicast_to_unicast,
};
static void wil_wiphy_init(struct wiphy *wiphy)
......
......@@ -10,6 +10,7 @@
#include <linux/moduleparam.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/if_vlan.h>
#include <net/ipv6.h>
#include <linux/prefetch.h>
......@@ -1529,6 +1530,35 @@ static struct wil_ring *wil_find_tx_bcast_1(struct wil6210_priv *wil,
return v;
}
/* apply multicast to unicast only for ARP and IP packets
* (see NL80211_CMD_SET_MULTICAST_TO_UNICAST for more info)
*/
static bool wil_check_multicast_to_unicast(struct wil6210_priv *wil,
struct sk_buff *skb)
{
const struct ethhdr *eth = (void *)skb->data;
const struct vlan_ethhdr *ethvlan = (void *)skb->data;
__be16 ethertype;
if (!wil->multicast_to_unicast)
return false;
/* multicast to unicast conversion only for some payload */
ethertype = eth->h_proto;
if (ethertype == htons(ETH_P_8021Q) && skb->len >= VLAN_ETH_HLEN)
ethertype = ethvlan->h_vlan_encapsulated_proto;
switch (ethertype) {
case htons(ETH_P_ARP):
case htons(ETH_P_IP):
case htons(ETH_P_IPV6):
break;
default:
return false;
}
return true;
}
static void wil_set_da_for_vring(struct wil6210_priv *wil,
struct sk_buff *skb, int vring_index)
{
......@@ -2336,7 +2366,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
/* in STA mode (ESS), all to same VRING (to AP) */
ring = wil_find_tx_ring_sta(wil, vif, skb);
} else if (bcast) {
if (vif->pbss)
if (vif->pbss || wil_check_multicast_to_unicast(wil, skb))
/* in pbss, no bcast VRING - duplicate skb in
* all stations VRINGs
*/
......
......@@ -1059,6 +1059,7 @@ struct wil6210_priv {
u32 max_agg_wsize;
u32 max_ampdu_size;
u8 multicast_to_unicast;
};
#define wil_to_wiphy(i) (i->wiphy)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册