static void enic_set_multicast_list(struct net_device *netdev) { struct enic *enic = netdev_priv(netdev); struct dev_mc_list *list = netdev->mc_list; int directed = 1; int multicast = (netdev->flags & IFF_MULTICAST) ? 1 : 0; int broadcast = (netdev->flags & IFF_BROADCAST) ? 1 : 0; int promisc = (netdev->flags & IFF_PROMISC) ? 1 : 0; int allmulti = (netdev->flags & IFF_ALLMULTI) || (netdev->mc_count > ENIC_MULTICAST_PERFECT_FILTERS); u8 mc_addr[ENIC_MULTICAST_PERFECT_FILTERS][ETH_ALEN]; unsigned int mc_count = netdev->mc_count; unsigned int i, j; if (mc_count > ENIC_MULTICAST_PERFECT_FILTERS) mc_count = ENIC_MULTICAST_PERFECT_FILTERS; spin_lock(&enic->devcmd_lock); vnic_dev_packet_filter(enic->vdev, directed, multicast, broadcast, promisc, allmulti); for (i = 0; list && i < mc_count; i++) { memcpy(mc_addr[i], list->dmi_addr, ETH_ALEN); list = list->next; } for (i = 0; i < enic->mc_count; i++) { for (j = 0; j < mc_count; j++) if (compare_ether_addr(enic->mc_addr[i], mc_addr[j]) == 0) break; if (j == mc_count) enic_del_multicast_addr(enic, enic->mc_addr[i]); } for (i = 0; i < mc_count; i++) { for (j = 0; j < enic->mc_count; j++) if (compare_ether_addr(mc_addr[i], enic->mc_addr[j]) == 0) break; if (j == enic->mc_count) enic_add_multicast_addr(enic, mc_addr[i]); } for (i = 0; i < mc_count; i++) memcpy(enic->mc_addr[i], mc_addr[i], ETH_ALEN); enic->mc_count = mc_count; spin_unlock(&enic->devcmd_lock); }
/* netif_tx_lock held, BHs disabled */ static void enic_set_multicast_list(struct net_device *netdev) { struct enic *enic = netdev_priv(netdev); struct dev_mc_list *list = netdev->mc_list; int directed = 1; int multicast = (netdev->flags & IFF_MULTICAST) ? 1 : 0; int broadcast = (netdev->flags & IFF_BROADCAST) ? 1 : 0; int promisc = (netdev->flags & IFF_PROMISC) ? 1 : 0; int allmulti = (netdev->flags & IFF_ALLMULTI) || (netdev->mc_count > ENIC_MULTICAST_PERFECT_FILTERS); u8 mc_addr[ENIC_MULTICAST_PERFECT_FILTERS][ETH_ALEN]; unsigned int mc_count = netdev->mc_count; unsigned int i, j; if (mc_count > ENIC_MULTICAST_PERFECT_FILTERS) mc_count = ENIC_MULTICAST_PERFECT_FILTERS; spin_lock(&enic->devcmd_lock); vnic_dev_packet_filter(enic->vdev, directed, multicast, broadcast, promisc, allmulti); /* Is there an easier way? Trying to minimize to * calls to add/del multicast addrs. We keep the * addrs from the last call in enic->mc_addr and * look for changes to add/del. */ for (i = 0; list && i < mc_count; i++) { memcpy(mc_addr[i], list->dmi_addr, ETH_ALEN); list = list->next; } for (i = 0; i < enic->mc_count; i++) { for (j = 0; j < mc_count; j++) if (compare_ether_addr(enic->mc_addr[i], mc_addr[j]) == 0) break; if (j == mc_count) enic_del_multicast_addr(enic, enic->mc_addr[i]); } for (i = 0; i < mc_count; i++) { for (j = 0; j < enic->mc_count; j++) if (compare_ether_addr(mc_addr[i], enic->mc_addr[j]) == 0) break; if (j == enic->mc_count) enic_add_multicast_addr(enic, mc_addr[i]); } /* Save the list to compare against next time */ for (i = 0; i < mc_count; i++) memcpy(enic->mc_addr[i], mc_addr[i], ETH_ALEN); enic->mc_count = mc_count; spin_unlock(&enic->devcmd_lock); }