xref: /openbmc/linux/net/bridge/br_vlan.c (revision 243a2e63)
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