1 #include <linux/kernel.h> 2 #include <linux/netdevice.h> 3 #include <linux/rtnetlink.h> 4 #include <linux/slab.h> 5 6 #include "br_private.h" 7 8 static int __vlan_add(struct net_port_vlans *v, u16 vid) 9 { 10 int err; 11 12 if (test_bit(vid, v->vlan_bitmap)) 13 return -EEXIST; 14 15 if (v->port_idx && vid) { 16 struct net_device *dev = v->parent.port->dev; 17 18 /* Add VLAN to the device filter if it is supported. 19 * Stricly speaking, this is not necessary now, since devices 20 * are made promiscuous by the bridge, but if that ever changes 21 * this code will allow tagged traffic to enter the bridge. 22 */ 23 if (dev->features & NETIF_F_HW_VLAN_FILTER) { 24 err = dev->netdev_ops->ndo_vlan_rx_add_vid(dev, vid); 25 if (err) 26 return err; 27 } 28 } 29 30 set_bit(vid, v->vlan_bitmap); 31 return 0; 32 } 33 34 static int __vlan_del(struct net_port_vlans *v, u16 vid) 35 { 36 if (!test_bit(vid, v->vlan_bitmap)) 37 return -EINVAL; 38 39 if (v->port_idx && vid) { 40 struct net_device *dev = v->parent.port->dev; 41 42 if (dev->features & NETIF_F_HW_VLAN_FILTER) 43 dev->netdev_ops->ndo_vlan_rx_kill_vid(dev, vid); 44 } 45 46 clear_bit(vid, v->vlan_bitmap); 47 if (bitmap_empty(v->vlan_bitmap, BR_VLAN_BITMAP_LEN)) { 48 if (v->port_idx) 49 rcu_assign_pointer(v->parent.port->vlan_info, NULL); 50 else 51 rcu_assign_pointer(v->parent.br->vlan_info, NULL); 52 kfree_rcu(v, rcu); 53 } 54 return 0; 55 } 56 57 static void __vlan_flush(struct net_port_vlans *v) 58 { 59 bitmap_zero(v->vlan_bitmap, BR_VLAN_BITMAP_LEN); 60 if (v->port_idx) 61 rcu_assign_pointer(v->parent.port->vlan_info, NULL); 62 else 63 rcu_assign_pointer(v->parent.br->vlan_info, NULL); 64 kfree_rcu(v, rcu); 65 } 66 67 /* Must be protected by RTNL */ 68 int br_vlan_add(struct net_bridge *br, u16 vid) 69 { 70 struct net_port_vlans *pv = NULL; 71 int err; 72 73 ASSERT_RTNL(); 74 75 pv = rtnl_dereference(br->vlan_info); 76 if (pv) 77 return __vlan_add(pv, vid); 78 79 /* Create port vlan infomration 80 */ 81 pv = kzalloc(sizeof(*pv), GFP_KERNEL); 82 if (!pv) 83 return -ENOMEM; 84 85 pv->parent.br = br; 86 err = __vlan_add(pv, vid); 87 if (err) 88 goto out; 89 90 rcu_assign_pointer(br->vlan_info, pv); 91 return 0; 92 out: 93 kfree(pv); 94 return err; 95 } 96 97 /* Must be protected by RTNL */ 98 int br_vlan_delete(struct net_bridge *br, u16 vid) 99 { 100 struct net_port_vlans *pv; 101 102 ASSERT_RTNL(); 103 104 pv = rtnl_dereference(br->vlan_info); 105 if (!pv) 106 return -EINVAL; 107 108 __vlan_del(pv, vid); 109 return 0; 110 } 111 112 void br_vlan_flush(struct net_bridge *br) 113 { 114 struct net_port_vlans *pv; 115 116 ASSERT_RTNL(); 117 118 pv = rtnl_dereference(br->vlan_info); 119 if (!pv) 120 return; 121 122 __vlan_flush(pv); 123 } 124 125 int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val) 126 { 127 if (!rtnl_trylock()) 128 return restart_syscall(); 129 130 if (br->vlan_enabled == val) 131 goto unlock; 132 133 br->vlan_enabled = val; 134 135 unlock: 136 rtnl_unlock(); 137 return 0; 138 } 139 140 /* Must be protected by RTNL */ 141 int nbp_vlan_add(struct net_bridge_port *port, u16 vid) 142 { 143 struct net_port_vlans *pv = NULL; 144 int err; 145 146 ASSERT_RTNL(); 147 148 pv = rtnl_dereference(port->vlan_info); 149 if (pv) 150 return __vlan_add(pv, vid); 151 152 /* Create port vlan infomration 153 */ 154 pv = kzalloc(sizeof(*pv), GFP_KERNEL); 155 if (!pv) { 156 err = -ENOMEM; 157 goto clean_up; 158 } 159 160 pv->port_idx = port->port_no; 161 pv->parent.port = port; 162 err = __vlan_add(pv, vid); 163 if (err) 164 goto clean_up; 165 166 rcu_assign_pointer(port->vlan_info, pv); 167 return 0; 168 169 clean_up: 170 kfree(pv); 171 return err; 172 } 173 174 /* Must be protected by RTNL */ 175 int nbp_vlan_delete(struct net_bridge_port *port, u16 vid) 176 { 177 struct net_port_vlans *pv; 178 179 ASSERT_RTNL(); 180 181 pv = rtnl_dereference(port->vlan_info); 182 if (!pv) 183 return -EINVAL; 184 185 return __vlan_del(pv, vid); 186 } 187 188 void nbp_vlan_flush(struct net_bridge_port *port) 189 { 190 struct net_port_vlans *pv; 191 192 ASSERT_RTNL(); 193 194 pv = rtnl_dereference(port->vlan_info); 195 if (!pv) 196 return; 197 198 __vlan_flush(pv); 199 } 200