v->pvid = 0;
}
+static void __vlan_add_flags(struct net_port_vlans *v, u16 vid, u16 flags)
+{
+ if (flags & BRIDGE_VLAN_INFO_PVID)
+ __vlan_add_pvid(v, vid);
+
+ if (flags & BRIDGE_VLAN_INFO_UNTAGGED)
+ set_bit(vid, v->untagged_bitmap);
+}
+
static int __vlan_add(struct net_port_vlans *v, u16 vid, u16 flags)
{
+ struct net_bridge_port *p = NULL;
+ struct net_bridge *br;
+ struct net_device *dev;
int err;
if (test_bit(vid, v->vlan_bitmap)) {
- if (flags & BRIDGE_VLAN_INFO_PVID)
- __vlan_add_pvid(v, vid);
+ __vlan_add_flags(v, vid, flags);
return 0;
}
- if (v->port_idx && vid) {
- struct net_device *dev = v->parent.port->dev;
+ if (vid) {
+ if (v->port_idx) {
+ p = v->parent.port;
+ br = p->br;
+ dev = p->dev;
+ } else {
+ br = v->parent.br;
+ dev = br->dev;
+ }
- /* Add VLAN to the device filter if it is supported.
- * Stricly speaking, this is not necessary now, since devices
- * are made promiscuous by the bridge, but if that ever changes
- * this code will allow tagged traffic to enter the bridge.
- */
- if (dev->features & NETIF_F_HW_VLAN_FILTER) {
+ if (p && (dev->features & NETIF_F_HW_VLAN_FILTER)) {
+ /* Add VLAN to the device filter if it is supported.
+ * Stricly speaking, this is not necessary now, since
+ * devices are made promiscuous by the bridge, but if
+ * that ever changes this code will allow tagged
+ * traffic to enter the bridge.
+ */
err = dev->netdev_ops->ndo_vlan_rx_add_vid(dev, vid);
if (err)
return err;
}
+
+ err = br_fdb_insert(br, p, dev->dev_addr, vid);
+ if (err) {
+ br_err(br, "failed insert local address into bridge "
+ "forwarding table\n");
+ goto out_filt;
+ }
+
}
set_bit(vid, v->vlan_bitmap);
v->num_vlans++;
- if (flags & BRIDGE_VLAN_INFO_PVID)
- __vlan_add_pvid(v, vid);
+ __vlan_add_flags(v, vid, flags);
return 0;
+
+out_filt:
+ if (p && (dev->features & NETIF_F_HW_VLAN_FILTER))
+ dev->netdev_ops->ndo_vlan_rx_kill_vid(dev, vid);
+ return err;
}
static int __vlan_del(struct net_port_vlans *v, u16 vid)
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;
goto out;
/* At this point, we know that the frame was filtered and contains
- * a valid vlan id. If the vlan id matches the pvid of current port
+ * a valid vlan id. If the vlan id is set in the untagged bitmap,
* send untagged; otherwise, send taged.
*/
br_vlan_get_tag(skb, &vid);
- if (vid == br_get_pvid(pv))
+ if (test_bit(vid, pv->untagged_bitmap))
skb = br_vlan_untag(skb);
else {
/* Egress policy says "send tagged". If output device
if (!pv)
return -EINVAL;
+ if (vid) {
+ /* If the VID !=0 remove fdb for this vid. VID 0 is special
+ * in that it's the default and is always there in the fdb.
+ */
+ spin_lock_bh(&br->hash_lock);
+ fdb_delete_by_addr(br, br->dev->dev_addr, vid);
+ spin_unlock_bh(&br->hash_lock);
+ }
+
__vlan_del(pv, vid);
return 0;
}
if (!pv)
return -EINVAL;
+ if (vid) {
+ /* If the VID !=0 remove fdb for this vid. VID 0 is special
+ * in that it's the default and is always there in the fdb.
+ */
+ spin_lock_bh(&port->br->hash_lock);
+ fdb_delete_by_addr(port->br, port->dev->dev_addr, vid);
+ spin_unlock_bh(&port->br->hash_lock);
+ }
+
return __vlan_del(pv, vid);
}
__vlan_flush(pv);
}
+
+bool nbp_vlan_find(struct net_bridge_port *port, u16 vid)
+{
+ struct net_port_vlans *pv;
+ bool found = false;
+
+ rcu_read_lock();
+ pv = rcu_dereference(port->vlan_info);
+
+ if (!pv)
+ goto out;
+
+ if (test_bit(vid, pv->vlan_bitmap))
+ found = true;
+
+out:
+ rcu_read_unlock();
+ return found;
+}