Commit 9f051db5 authored by Dmitry Bogdanov's avatar Dmitry Bogdanov Committed by David S. Miller

net: aquantia: correctly handle macvlan and multicast coexistence

macvlan and multicast handling is now mixed up.
The explicit issue is that macvlan interface gets broken (no traffic)
after clearing MULTICAST flag on the real interface.

We now do separate logic and consider both ALLMULTI and MULTICAST
flags on the device.

Fixes: 11ba961c ("net: aquantia: Fix IFF_ALLMULTI flag functionality")
Signed-off-by: default avatarDmitry Bogdanov <dmitry.bogdanov@aquantia.com>
Signed-off-by: default avatarIgor Russkikh <igor.russkikh@aquantia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d08b9a0a
......@@ -194,9 +194,7 @@ static void aq_ndev_set_multicast_settings(struct net_device *ndev)
{
struct aq_nic_s *aq_nic = netdev_priv(ndev);
aq_nic_set_packet_filter(aq_nic, ndev->flags);
aq_nic_set_multicast_list(aq_nic, ndev);
(void)aq_nic_set_multicast_list(aq_nic, ndev);
}
static int aq_ndo_vlan_rx_add_vid(struct net_device *ndev, __be16 proto,
......
......@@ -631,9 +631,12 @@ int aq_nic_set_packet_filter(struct aq_nic_s *self, unsigned int flags)
int aq_nic_set_multicast_list(struct aq_nic_s *self, struct net_device *ndev)
{
unsigned int packet_filter = self->packet_filter;
const struct aq_hw_ops *hw_ops = self->aq_hw_ops;
struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg;
unsigned int packet_filter = ndev->flags;
struct netdev_hw_addr *ha = NULL;
unsigned int i = 0U;
int err = 0;
self->mc_list.count = 0;
if (netdev_uc_count(ndev) > AQ_HW_MULTICAST_ADDRESS_MAX) {
......@@ -641,29 +644,26 @@ int aq_nic_set_multicast_list(struct aq_nic_s *self, struct net_device *ndev)
} else {
netdev_for_each_uc_addr(ha, ndev) {
ether_addr_copy(self->mc_list.ar[i++], ha->addr);
if (i >= AQ_HW_MULTICAST_ADDRESS_MAX)
break;
}
}
if (i + netdev_mc_count(ndev) > AQ_HW_MULTICAST_ADDRESS_MAX) {
packet_filter |= IFF_ALLMULTI;
} else {
netdev_for_each_mc_addr(ha, ndev) {
ether_addr_copy(self->mc_list.ar[i++], ha->addr);
if (i >= AQ_HW_MULTICAST_ADDRESS_MAX)
break;
cfg->is_mc_list_enabled = !!(packet_filter & IFF_MULTICAST);
if (cfg->is_mc_list_enabled) {
if (i + netdev_mc_count(ndev) > AQ_HW_MULTICAST_ADDRESS_MAX) {
packet_filter |= IFF_ALLMULTI;
} else {
netdev_for_each_mc_addr(ha, ndev) {
ether_addr_copy(self->mc_list.ar[i++],
ha->addr);
}
}
}
if (i > 0 && i <= AQ_HW_MULTICAST_ADDRESS_MAX) {
packet_filter |= IFF_MULTICAST;
self->mc_list.count = i;
self->aq_hw_ops->hw_multicast_list_set(self->aq_hw,
self->mc_list.ar,
self->mc_list.count);
err = hw_ops->hw_multicast_list_set(self->aq_hw,
self->mc_list.ar,
self->mc_list.count);
}
return aq_nic_set_packet_filter(self, packet_filter);
}
......
......@@ -818,14 +818,15 @@ static int hw_atl_b0_hw_packet_filter_set(struct aq_hw_s *self,
cfg->is_vlan_force_promisc);
hw_atl_rpfl2multicast_flr_en_set(self,
IS_FILTER_ENABLED(IFF_ALLMULTI), 0);
IS_FILTER_ENABLED(IFF_ALLMULTI) &&
IS_FILTER_ENABLED(IFF_MULTICAST), 0);
hw_atl_rpfl2_accept_all_mc_packets_set(self,
IS_FILTER_ENABLED(IFF_ALLMULTI));
IS_FILTER_ENABLED(IFF_ALLMULTI) &&
IS_FILTER_ENABLED(IFF_MULTICAST));
hw_atl_rpfl2broadcast_en_set(self, IS_FILTER_ENABLED(IFF_BROADCAST));
cfg->is_mc_list_enabled = IS_FILTER_ENABLED(IFF_MULTICAST);
for (i = HW_ATL_B0_MAC_MIN; i < HW_ATL_B0_MAC_MAX; ++i)
hw_atl_rpfl2_uc_flr_en_set(self,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment