static int __vlan_del(struct net_port_vlans *v, u16 vid) { if (!test_bit(vid, v->vlan_bitmap)) return -EINVAL; __vlan_delete_pvid(v, vid); clear_bit(vid, v->untagged_bitmap); if (v->port_idx && vid) { struct net_device *dev = v->parent.port->dev; const struct net_device_ops *ops = dev->netdev_ops; if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER) ops->ndo_vlan_rx_kill_vid(dev, htons(ETH_P_8021Q), vid); } clear_bit(vid, v->vlan_bitmap); v->num_vlans--; if (bitmap_empty(v->vlan_bitmap, BR_VLAN_BITMAP_LEN)) { if (v->port_idx) rcu_assign_pointer(v->parent.port->vlan_info, NULL); else rcu_assign_pointer(v->parent.br->vlan_info, NULL); kfree_rcu(v, rcu); } return 0; }
static int __vlan_del(struct net_port_vlans *v, u16 vid) { if (!test_bit(vid, v->vlan_bitmap)) return -EINVAL; __vlan_delete_pvid(v, vid); clear_bit(vid, v->untagged_bitmap); if (v->port_idx) vlan_vid_del(v->parent.port->dev, htons(ETH_P_8021Q), vid); clear_bit(vid, v->vlan_bitmap); v->num_vlans--; if (bitmap_empty(v->vlan_bitmap, VLAN_N_VID)) { if (v->port_idx) RCU_INIT_POINTER(v->parent.port->vlan_info, NULL); else RCU_INIT_POINTER(v->parent.br->vlan_info, NULL); kfree_rcu(v, rcu); } return 0; }
/* return true if anything changed, false otherwise */ static bool __vlan_add_flags(struct net_bridge_vlan *v, u16 flags) { struct net_bridge_vlan_group *vg; u16 old_flags = v->flags; bool ret; if (br_vlan_is_master(v)) vg = br_vlan_group(v->br); else vg = nbp_vlan_group(v->port); if (flags & BRIDGE_VLAN_INFO_PVID) ret = __vlan_add_pvid(vg, v->vid); else ret = __vlan_delete_pvid(vg, v->vid); if (flags & BRIDGE_VLAN_INFO_UNTAGGED) v->flags |= BRIDGE_VLAN_INFO_UNTAGGED; else v->flags &= ~BRIDGE_VLAN_INFO_UNTAGGED; return ret || !!(old_flags ^ v->flags); }