xref: /openbmc/linux/net/bridge/br_vlan.c (revision 83f6d600)
1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2243a2e63SVlad Yasevich #include <linux/kernel.h>
3243a2e63SVlad Yasevich #include <linux/netdevice.h>
4243a2e63SVlad Yasevich #include <linux/rtnetlink.h>
5243a2e63SVlad Yasevich #include <linux/slab.h>
67f109539SScott Feldman #include <net/switchdev.h>
7243a2e63SVlad Yasevich 
8243a2e63SVlad Yasevich #include "br_private.h"
9efa5356bSRoopa Prabhu #include "br_private_tunnel.h"
10243a2e63SVlad Yasevich 
1180900acdSMike Manning static void nbp_vlan_set_vlan_dev_state(struct net_bridge_port *p, u16 vid);
1280900acdSMike Manning 
br_vlan_cmp(struct rhashtable_compare_arg * arg,const void * ptr)132594e906SNikolay Aleksandrov static inline int br_vlan_cmp(struct rhashtable_compare_arg *arg,
142594e906SNikolay Aleksandrov 			      const void *ptr)
15552406c4SVlad Yasevich {
162594e906SNikolay Aleksandrov 	const struct net_bridge_vlan *vle = ptr;
172594e906SNikolay Aleksandrov 	u16 vid = *(u16 *)arg->key;
182594e906SNikolay Aleksandrov 
192594e906SNikolay Aleksandrov 	return vle->vid != vid;
202594e906SNikolay Aleksandrov }
212594e906SNikolay Aleksandrov 
222594e906SNikolay Aleksandrov static const struct rhashtable_params br_vlan_rht_params = {
232594e906SNikolay Aleksandrov 	.head_offset = offsetof(struct net_bridge_vlan, vnode),
242594e906SNikolay Aleksandrov 	.key_offset = offsetof(struct net_bridge_vlan, vid),
252594e906SNikolay Aleksandrov 	.key_len = sizeof(u16),
268af78b64SNikolay Aleksandrov 	.nelem_hint = 3,
272594e906SNikolay Aleksandrov 	.max_size = VLAN_N_VID,
282594e906SNikolay Aleksandrov 	.obj_cmpfn = br_vlan_cmp,
292594e906SNikolay Aleksandrov 	.automatic_shrinking = true,
302594e906SNikolay Aleksandrov };
312594e906SNikolay Aleksandrov 
br_vlan_lookup(struct rhashtable * tbl,u16 vid)322594e906SNikolay Aleksandrov static struct net_bridge_vlan *br_vlan_lookup(struct rhashtable *tbl, u16 vid)
332594e906SNikolay Aleksandrov {
342594e906SNikolay Aleksandrov 	return rhashtable_lookup_fast(tbl, &vid, br_vlan_rht_params);
352594e906SNikolay Aleksandrov }
362594e906SNikolay Aleksandrov 
__vlan_add_pvid(struct net_bridge_vlan_group * vg,const struct net_bridge_vlan * v)3727c5f74cSVladimir Oltean static void __vlan_add_pvid(struct net_bridge_vlan_group *vg,
38a580c76dSNikolay Aleksandrov 			    const struct net_bridge_vlan *v)
392594e906SNikolay Aleksandrov {
40a580c76dSNikolay Aleksandrov 	if (vg->pvid == v->vid)
4127c5f74cSVladimir Oltean 		return;
42552406c4SVlad Yasevich 
43552406c4SVlad Yasevich 	smp_wmb();
44a580c76dSNikolay Aleksandrov 	br_vlan_set_pvid_state(vg, v->state);
45a580c76dSNikolay Aleksandrov 	vg->pvid = v->vid;
46552406c4SVlad Yasevich }
47552406c4SVlad Yasevich 
__vlan_delete_pvid(struct net_bridge_vlan_group * vg,u16 vid)4827c5f74cSVladimir Oltean static void __vlan_delete_pvid(struct net_bridge_vlan_group *vg, u16 vid)
49552406c4SVlad Yasevich {
5077751ee8SNikolay Aleksandrov 	if (vg->pvid != vid)
5127c5f74cSVladimir Oltean 		return;
52552406c4SVlad Yasevich 
53552406c4SVlad Yasevich 	smp_wmb();
5477751ee8SNikolay Aleksandrov 	vg->pvid = 0;
55552406c4SVlad Yasevich }
56552406c4SVlad Yasevich 
5727c5f74cSVladimir Oltean /* Update the BRIDGE_VLAN_INFO_PVID and BRIDGE_VLAN_INFO_UNTAGGED flags of @v.
5827c5f74cSVladimir Oltean  * If @commit is false, return just whether the BRIDGE_VLAN_INFO_PVID and
5927c5f74cSVladimir Oltean  * BRIDGE_VLAN_INFO_UNTAGGED bits of @flags would produce any change onto @v.
60cab2cd77SVladimir Oltean  */
__vlan_flags_update(struct net_bridge_vlan * v,u16 flags,bool commit)6127c5f74cSVladimir Oltean static bool __vlan_flags_update(struct net_bridge_vlan *v, u16 flags,
6227c5f74cSVladimir Oltean 				bool commit)
6335e03f3aSVlad Yasevich {
6477751ee8SNikolay Aleksandrov 	struct net_bridge_vlan_group *vg;
6527c5f74cSVladimir Oltean 	bool change;
6677751ee8SNikolay Aleksandrov 
672594e906SNikolay Aleksandrov 	if (br_vlan_is_master(v))
68907b1e6eSNikolay Aleksandrov 		vg = br_vlan_group(v->br);
69635126b7SVlad Yasevich 	else
70907b1e6eSNikolay Aleksandrov 		vg = nbp_vlan_group(v->port);
7177751ee8SNikolay Aleksandrov 
7227c5f74cSVladimir Oltean 	/* check if anything would be changed on commit */
7327c5f74cSVladimir Oltean 	change = !!(flags & BRIDGE_VLAN_INFO_PVID) == !!(vg->pvid != v->vid) ||
7427c5f74cSVladimir Oltean 		 ((flags ^ v->flags) & BRIDGE_VLAN_INFO_UNTAGGED);
7527c5f74cSVladimir Oltean 
7627c5f74cSVladimir Oltean 	if (!commit)
7727c5f74cSVladimir Oltean 		goto out;
7827c5f74cSVladimir Oltean 
7977751ee8SNikolay Aleksandrov 	if (flags & BRIDGE_VLAN_INFO_PVID)
8027c5f74cSVladimir Oltean 		__vlan_add_pvid(vg, v);
812594e906SNikolay Aleksandrov 	else
8227c5f74cSVladimir Oltean 		__vlan_delete_pvid(vg, v->vid);
8335e03f3aSVlad Yasevich 
8435e03f3aSVlad Yasevich 	if (flags & BRIDGE_VLAN_INFO_UNTAGGED)
852594e906SNikolay Aleksandrov 		v->flags |= BRIDGE_VLAN_INFO_UNTAGGED;
86635126b7SVlad Yasevich 	else
872594e906SNikolay Aleksandrov 		v->flags &= ~BRIDGE_VLAN_INFO_UNTAGGED;
88f418af63SNikolay Aleksandrov 
8927c5f74cSVladimir Oltean out:
9027c5f74cSVladimir Oltean 	return change;
9127c5f74cSVladimir Oltean }
9227c5f74cSVladimir Oltean 
__vlan_flags_would_change(struct net_bridge_vlan * v,u16 flags)9327c5f74cSVladimir Oltean static bool __vlan_flags_would_change(struct net_bridge_vlan *v, u16 flags)
9427c5f74cSVladimir Oltean {
9527c5f74cSVladimir Oltean 	return __vlan_flags_update(v, flags, false);
9627c5f74cSVladimir Oltean }
9727c5f74cSVladimir Oltean 
__vlan_flags_commit(struct net_bridge_vlan * v,u16 flags)9827c5f74cSVladimir Oltean static void __vlan_flags_commit(struct net_bridge_vlan *v, u16 flags)
9927c5f74cSVladimir Oltean {
10027c5f74cSVladimir Oltean 	__vlan_flags_update(v, flags, true);
10135e03f3aSVlad Yasevich }
10235e03f3aSVlad Yasevich 
__vlan_vid_add(struct net_device * dev,struct net_bridge * br,struct net_bridge_vlan * v,u16 flags,struct netlink_ext_ack * extack)1037f109539SScott Feldman static int __vlan_vid_add(struct net_device *dev, struct net_bridge *br,
10427973793SIdo Schimmel 			  struct net_bridge_vlan *v, u16 flags,
10527973793SIdo Schimmel 			  struct netlink_ext_ack *extack)
1067f109539SScott Feldman {
1070944d6b5SJiri Pirko 	int err;
1087f109539SScott Feldman 
1090944d6b5SJiri Pirko 	/* Try switchdev op first. In case it is not supported, fallback to
1100944d6b5SJiri Pirko 	 * 8021q add.
1110944d6b5SJiri Pirko 	 */
1128d23a54fSVladimir Oltean 	err = br_switchdev_port_vlan_add(dev, v->vid, flags, false, extack);
1137f109539SScott Feldman 	if (err == -EOPNOTSUPP)
11427973793SIdo Schimmel 		return vlan_vid_add(dev, br->vlan_proto, v->vid);
11527973793SIdo Schimmel 	v->priv_flags |= BR_VLFLAG_ADDED_BY_SWITCHDEV;
1167f109539SScott Feldman 	return err;
1177f109539SScott Feldman }
1187f109539SScott Feldman 
__vlan_add_list(struct net_bridge_vlan * v)1192594e906SNikolay Aleksandrov static void __vlan_add_list(struct net_bridge_vlan *v)
120243a2e63SVlad Yasevich {
121907b1e6eSNikolay Aleksandrov 	struct net_bridge_vlan_group *vg;
1222594e906SNikolay Aleksandrov 	struct list_head *headp, *hpos;
1232594e906SNikolay Aleksandrov 	struct net_bridge_vlan *vent;
124243a2e63SVlad Yasevich 
125907b1e6eSNikolay Aleksandrov 	if (br_vlan_is_master(v))
126907b1e6eSNikolay Aleksandrov 		vg = br_vlan_group(v->br);
127907b1e6eSNikolay Aleksandrov 	else
128907b1e6eSNikolay Aleksandrov 		vg = nbp_vlan_group(v->port);
129907b1e6eSNikolay Aleksandrov 
130907b1e6eSNikolay Aleksandrov 	headp = &vg->vlan_list;
1312594e906SNikolay Aleksandrov 	list_for_each_prev(hpos, headp) {
1322594e906SNikolay Aleksandrov 		vent = list_entry(hpos, struct net_bridge_vlan, vlist);
133040c1257SColin Ian King 		if (v->vid >= vent->vid)
1342594e906SNikolay Aleksandrov 			break;
1352594e906SNikolay Aleksandrov 	}
136586c2b57SNikolay Aleksandrov 	list_add_rcu(&v->vlist, hpos);
137552406c4SVlad Yasevich }
138243a2e63SVlad Yasevich 
__vlan_del_list(struct net_bridge_vlan * v)1392594e906SNikolay Aleksandrov static void __vlan_del_list(struct net_bridge_vlan *v)
1402594e906SNikolay Aleksandrov {
141586c2b57SNikolay Aleksandrov 	list_del_rcu(&v->vlist);
142243a2e63SVlad Yasevich }
143243a2e63SVlad Yasevich 
__vlan_vid_del(struct net_device * dev,struct net_bridge * br,const struct net_bridge_vlan * v)144bf361ad3SVivien Didelot static int __vlan_vid_del(struct net_device *dev, struct net_bridge *br,
14527973793SIdo Schimmel 			  const struct net_bridge_vlan *v)
1467f109539SScott Feldman {
1470944d6b5SJiri Pirko 	int err;
1487f109539SScott Feldman 
1490944d6b5SJiri Pirko 	/* Try switchdev op first. In case it is not supported, fallback to
1500944d6b5SJiri Pirko 	 * 8021q del.
1510944d6b5SJiri Pirko 	 */
15227973793SIdo Schimmel 	err = br_switchdev_port_vlan_del(dev, v->vid);
15327973793SIdo Schimmel 	if (!(v->priv_flags & BR_VLFLAG_ADDED_BY_SWITCHDEV))
15427973793SIdo Schimmel 		vlan_vid_del(dev, br->vlan_proto, v->vid);
15527973793SIdo Schimmel 	return err == -EOPNOTSUPP ? 0 : err;
1567f109539SScott Feldman }
1577f109539SScott Feldman 
1584bbd026cSRandy Dunlap /* Returns a master vlan, if it didn't exist it gets created. In all cases
159f8ed289fSNikolay Aleksandrov  * a reference is taken to the master vlan before returning.
160f8ed289fSNikolay Aleksandrov  */
161169327d5SPetr Machata static struct net_bridge_vlan *
br_vlan_get_master(struct net_bridge * br,u16 vid,struct netlink_ext_ack * extack)162169327d5SPetr Machata br_vlan_get_master(struct net_bridge *br, u16 vid,
163169327d5SPetr Machata 		   struct netlink_ext_ack *extack)
164f8ed289fSNikolay Aleksandrov {
165907b1e6eSNikolay Aleksandrov 	struct net_bridge_vlan_group *vg;
166f8ed289fSNikolay Aleksandrov 	struct net_bridge_vlan *masterv;
167f8ed289fSNikolay Aleksandrov 
168907b1e6eSNikolay Aleksandrov 	vg = br_vlan_group(br);
169907b1e6eSNikolay Aleksandrov 	masterv = br_vlan_find(vg, vid);
170f8ed289fSNikolay Aleksandrov 	if (!masterv) {
171f418af63SNikolay Aleksandrov 		bool changed;
172f418af63SNikolay Aleksandrov 
173f8ed289fSNikolay Aleksandrov 		/* missing global ctx, create it now */
174169327d5SPetr Machata 		if (br_vlan_add(br, vid, 0, &changed, extack))
175f8ed289fSNikolay Aleksandrov 			return NULL;
176907b1e6eSNikolay Aleksandrov 		masterv = br_vlan_find(vg, vid);
177f8ed289fSNikolay Aleksandrov 		if (WARN_ON(!masterv))
178f8ed289fSNikolay Aleksandrov 			return NULL;
1790e5a82efSIdo Schimmel 		refcount_set(&masterv->refcnt, 1);
1800e5a82efSIdo Schimmel 		return masterv;
181f8ed289fSNikolay Aleksandrov 	}
18225127759SReshetova, Elena 	refcount_inc(&masterv->refcnt);
183f8ed289fSNikolay Aleksandrov 
184f8ed289fSNikolay Aleksandrov 	return masterv;
185f8ed289fSNikolay Aleksandrov }
186f8ed289fSNikolay Aleksandrov 
br_master_vlan_rcu_free(struct rcu_head * rcu)1876dada9b1SNikolay Aleksandrov static void br_master_vlan_rcu_free(struct rcu_head *rcu)
1886dada9b1SNikolay Aleksandrov {
1896dada9b1SNikolay Aleksandrov 	struct net_bridge_vlan *v;
1906dada9b1SNikolay Aleksandrov 
1916dada9b1SNikolay Aleksandrov 	v = container_of(rcu, struct net_bridge_vlan, rcu);
1926dada9b1SNikolay Aleksandrov 	WARN_ON(!br_vlan_is_master(v));
1936dada9b1SNikolay Aleksandrov 	free_percpu(v->stats);
1946dada9b1SNikolay Aleksandrov 	v->stats = NULL;
1956dada9b1SNikolay Aleksandrov 	kfree(v);
1966dada9b1SNikolay Aleksandrov }
1976dada9b1SNikolay Aleksandrov 
br_vlan_put_master(struct net_bridge_vlan * masterv)198f8ed289fSNikolay Aleksandrov static void br_vlan_put_master(struct net_bridge_vlan *masterv)
199f8ed289fSNikolay Aleksandrov {
200907b1e6eSNikolay Aleksandrov 	struct net_bridge_vlan_group *vg;
201907b1e6eSNikolay Aleksandrov 
202f8ed289fSNikolay Aleksandrov 	if (!br_vlan_is_master(masterv))
203f8ed289fSNikolay Aleksandrov 		return;
204f8ed289fSNikolay Aleksandrov 
205907b1e6eSNikolay Aleksandrov 	vg = br_vlan_group(masterv->br);
20625127759SReshetova, Elena 	if (refcount_dec_and_test(&masterv->refcnt)) {
207907b1e6eSNikolay Aleksandrov 		rhashtable_remove_fast(&vg->vlan_hash,
208f8ed289fSNikolay Aleksandrov 				       &masterv->vnode, br_vlan_rht_params);
209f8ed289fSNikolay Aleksandrov 		__vlan_del_list(masterv);
2107b54aaafSNikolay Aleksandrov 		br_multicast_toggle_one_vlan(masterv, false);
211613d61dbSNikolay Aleksandrov 		br_multicast_ctx_deinit(&masterv->br_mcast_ctx);
2126dada9b1SNikolay Aleksandrov 		call_rcu(&masterv->rcu, br_master_vlan_rcu_free);
213f8ed289fSNikolay Aleksandrov 	}
214f8ed289fSNikolay Aleksandrov }
215f8ed289fSNikolay Aleksandrov 
nbp_vlan_rcu_free(struct rcu_head * rcu)2169163a0fcSNikolay Aleksandrov static void nbp_vlan_rcu_free(struct rcu_head *rcu)
2179163a0fcSNikolay Aleksandrov {
2189163a0fcSNikolay Aleksandrov 	struct net_bridge_vlan *v;
2199163a0fcSNikolay Aleksandrov 
2209163a0fcSNikolay Aleksandrov 	v = container_of(rcu, struct net_bridge_vlan, rcu);
2219163a0fcSNikolay Aleksandrov 	WARN_ON(br_vlan_is_master(v));
2229163a0fcSNikolay Aleksandrov 	/* if we had per-port stats configured then free them here */
2239d332e69SNikolay Aleksandrov 	if (v->priv_flags & BR_VLFLAG_PER_PORT_STATS)
2249163a0fcSNikolay Aleksandrov 		free_percpu(v->stats);
2259163a0fcSNikolay Aleksandrov 	v->stats = NULL;
2269163a0fcSNikolay Aleksandrov 	kfree(v);
2279163a0fcSNikolay Aleksandrov }
2289163a0fcSNikolay Aleksandrov 
br_vlan_init_state(struct net_bridge_vlan * v)229ec7328b5STobias Waldekranz static void br_vlan_init_state(struct net_bridge_vlan *v)
230ec7328b5STobias Waldekranz {
231ec7328b5STobias Waldekranz 	struct net_bridge *br;
232ec7328b5STobias Waldekranz 
233ec7328b5STobias Waldekranz 	if (br_vlan_is_master(v))
234ec7328b5STobias Waldekranz 		br = v->br;
235ec7328b5STobias Waldekranz 	else
236ec7328b5STobias Waldekranz 		br = v->port->br;
237ec7328b5STobias Waldekranz 
238ec7328b5STobias Waldekranz 	if (br_opt_get(br, BROPT_MST_ENABLED)) {
239ec7328b5STobias Waldekranz 		br_mst_vlan_init_state(v);
240ec7328b5STobias Waldekranz 		return;
241ec7328b5STobias Waldekranz 	}
242ec7328b5STobias Waldekranz 
243ec7328b5STobias Waldekranz 	v->state = BR_STATE_FORWARDING;
244ec7328b5STobias Waldekranz 	v->msti = 0;
245ec7328b5STobias Waldekranz }
246ec7328b5STobias Waldekranz 
2472594e906SNikolay Aleksandrov /* This is the shared VLAN add function which works for both ports and bridge
2482594e906SNikolay Aleksandrov  * devices. There are four possible calls to this function in terms of the
2492594e906SNikolay Aleksandrov  * vlan entry type:
2502594e906SNikolay Aleksandrov  * 1. vlan is being added on a port (no master flags, global entry exists)
251ddd611d3SIdo Schimmel  * 2. vlan is being added on a bridge (both master and brentry flags)
2522594e906SNikolay Aleksandrov  * 3. vlan is being added on a port, but a global entry didn't exist which
253ddd611d3SIdo Schimmel  *    is being created right now (master flag set, brentry flag unset), the
2542594e906SNikolay Aleksandrov  *    global entry is used for global per-vlan features, but not for filtering
255ddd611d3SIdo Schimmel  * 4. same as 3 but with both master and brentry flags set so the entry
2562594e906SNikolay Aleksandrov  *    will be used for filtering in both the port and the bridge
2572594e906SNikolay Aleksandrov  */
__vlan_add(struct net_bridge_vlan * v,u16 flags,struct netlink_ext_ack * extack)258169327d5SPetr Machata static int __vlan_add(struct net_bridge_vlan *v, u16 flags,
259169327d5SPetr Machata 		      struct netlink_ext_ack *extack)
260243a2e63SVlad Yasevich {
2612594e906SNikolay Aleksandrov 	struct net_bridge_vlan *masterv = NULL;
2622594e906SNikolay Aleksandrov 	struct net_bridge_port *p = NULL;
2636be144f6SNikolay Aleksandrov 	struct net_bridge_vlan_group *vg;
2642594e906SNikolay Aleksandrov 	struct net_device *dev;
2652594e906SNikolay Aleksandrov 	struct net_bridge *br;
266bf361ad3SVivien Didelot 	int err;
267bf361ad3SVivien Didelot 
2682594e906SNikolay Aleksandrov 	if (br_vlan_is_master(v)) {
2692594e906SNikolay Aleksandrov 		br = v->br;
2702594e906SNikolay Aleksandrov 		dev = br->dev;
271907b1e6eSNikolay Aleksandrov 		vg = br_vlan_group(br);
2722594e906SNikolay Aleksandrov 	} else {
2732594e906SNikolay Aleksandrov 		p = v->port;
2742594e906SNikolay Aleksandrov 		br = p->br;
2752594e906SNikolay Aleksandrov 		dev = p->dev;
276907b1e6eSNikolay Aleksandrov 		vg = nbp_vlan_group(p);
2772594e906SNikolay Aleksandrov 	}
2782594e906SNikolay Aleksandrov 
2792594e906SNikolay Aleksandrov 	if (p) {
2802594e906SNikolay Aleksandrov 		/* Add VLAN to the device filter if it is supported.
2812594e906SNikolay Aleksandrov 		 * This ensures tagged traffic enters the bridge when
2822594e906SNikolay Aleksandrov 		 * promiscuous mode is disabled by br_manage_promisc().
2832594e906SNikolay Aleksandrov 		 */
28427973793SIdo Schimmel 		err = __vlan_vid_add(dev, br, v, flags, extack);
285bf361ad3SVivien Didelot 		if (err)
2862594e906SNikolay Aleksandrov 			goto out;
2872594e906SNikolay Aleksandrov 
2882594e906SNikolay Aleksandrov 		/* need to work on the master vlan too */
2892594e906SNikolay Aleksandrov 		if (flags & BRIDGE_VLAN_INFO_MASTER) {
290f418af63SNikolay Aleksandrov 			bool changed;
291f418af63SNikolay Aleksandrov 
292f418af63SNikolay Aleksandrov 			err = br_vlan_add(br, v->vid,
293f418af63SNikolay Aleksandrov 					  flags | BRIDGE_VLAN_INFO_BRENTRY,
294169327d5SPetr Machata 					  &changed, extack);
2952594e906SNikolay Aleksandrov 			if (err)
2962594e906SNikolay Aleksandrov 				goto out_filt;
297f545923bSNikolay Aleksandrov 
298f545923bSNikolay Aleksandrov 			if (changed)
299f545923bSNikolay Aleksandrov 				br_vlan_notify(br, NULL, v->vid, 0,
300f545923bSNikolay Aleksandrov 					       RTM_NEWVLAN);
3012594e906SNikolay Aleksandrov 		}
3022594e906SNikolay Aleksandrov 
303169327d5SPetr Machata 		masterv = br_vlan_get_master(br, v->vid, extack);
304ee4f52a8SZhang Changzhong 		if (!masterv) {
305ee4f52a8SZhang Changzhong 			err = -ENOMEM;
3062594e906SNikolay Aleksandrov 			goto out_filt;
307ee4f52a8SZhang Changzhong 		}
3082594e906SNikolay Aleksandrov 		v->brvlan = masterv;
3099163a0fcSNikolay Aleksandrov 		if (br_opt_get(br, BROPT_VLAN_STATS_PER_PORT)) {
310281cc284SHeiner Kallweit 			v->stats =
311281cc284SHeiner Kallweit 			     netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
3129163a0fcSNikolay Aleksandrov 			if (!v->stats) {
3139163a0fcSNikolay Aleksandrov 				err = -ENOMEM;
3149163a0fcSNikolay Aleksandrov 				goto out_filt;
3159163a0fcSNikolay Aleksandrov 			}
3169d332e69SNikolay Aleksandrov 			v->priv_flags |= BR_VLFLAG_PER_PORT_STATS;
3179163a0fcSNikolay Aleksandrov 		} else {
3186dada9b1SNikolay Aleksandrov 			v->stats = masterv->stats;
3199163a0fcSNikolay Aleksandrov 		}
320613d61dbSNikolay Aleksandrov 		br_multicast_port_ctx_init(p, v, &v->port_mcast_ctx);
3219c86ce2cSPetr Machata 	} else {
3223116ad06SVladimir Oltean 		if (br_vlan_should_use(v)) {
3233116ad06SVladimir Oltean 			err = br_switchdev_port_vlan_add(dev, v->vid, flags,
3248d23a54fSVladimir Oltean 							 false, extack);
3259c86ce2cSPetr Machata 			if (err && err != -EOPNOTSUPP)
3269c86ce2cSPetr Machata 				goto out;
3273116ad06SVladimir Oltean 		}
328613d61dbSNikolay Aleksandrov 		br_multicast_ctx_init(br, v, &v->br_mcast_ctx);
3297b54aaafSNikolay Aleksandrov 		v->priv_flags |= BR_VLFLAG_GLOBAL_MCAST_ENABLED;
3302594e906SNikolay Aleksandrov 	}
3312594e906SNikolay Aleksandrov 
3326be144f6SNikolay Aleksandrov 	/* Add the dev mac and count the vlan only if it's usable */
3332594e906SNikolay Aleksandrov 	if (br_vlan_should_use(v)) {
334f6814fdcSVladimir Oltean 		err = br_fdb_add_local(br, p, dev->dev_addr, v->vid);
3352594e906SNikolay Aleksandrov 		if (err) {
3362594e906SNikolay Aleksandrov 			br_err(br, "failed insert local address into bridge forwarding table\n");
3372594e906SNikolay Aleksandrov 			goto out_filt;
3382594e906SNikolay Aleksandrov 		}
3396be144f6SNikolay Aleksandrov 		vg->num_vlans++;
3402594e906SNikolay Aleksandrov 	}
3412594e906SNikolay Aleksandrov 
342a580c76dSNikolay Aleksandrov 	/* set the state before publishing */
343ec7328b5STobias Waldekranz 	br_vlan_init_state(v);
344a580c76dSNikolay Aleksandrov 
3456be144f6SNikolay Aleksandrov 	err = rhashtable_lookup_insert_fast(&vg->vlan_hash, &v->vnode,
3466be144f6SNikolay Aleksandrov 					    br_vlan_rht_params);
3472594e906SNikolay Aleksandrov 	if (err)
3482594e906SNikolay Aleksandrov 		goto out_fdb_insert;
3492594e906SNikolay Aleksandrov 
3502594e906SNikolay Aleksandrov 	__vlan_add_list(v);
35127c5f74cSVladimir Oltean 	__vlan_flags_commit(v, flags);
3527b54aaafSNikolay Aleksandrov 	br_multicast_toggle_one_vlan(v, true);
35380900acdSMike Manning 
35480900acdSMike Manning 	if (p)
35580900acdSMike Manning 		nbp_vlan_set_vlan_dev_state(p, v->vid);
3562594e906SNikolay Aleksandrov out:
3572594e906SNikolay Aleksandrov 	return err;
3582594e906SNikolay Aleksandrov 
3592594e906SNikolay Aleksandrov out_fdb_insert:
3606be144f6SNikolay Aleksandrov 	if (br_vlan_should_use(v)) {
3616be144f6SNikolay Aleksandrov 		br_fdb_find_delete_local(br, p, dev->dev_addr, v->vid);
3626be144f6SNikolay Aleksandrov 		vg->num_vlans--;
3636be144f6SNikolay Aleksandrov 	}
3642594e906SNikolay Aleksandrov 
3652594e906SNikolay Aleksandrov out_filt:
3662594e906SNikolay Aleksandrov 	if (p) {
36727973793SIdo Schimmel 		__vlan_vid_del(dev, br, v);
3682594e906SNikolay Aleksandrov 		if (masterv) {
3691a3aea25SLi RongQing 			if (v->stats && masterv->stats != v->stats)
3701a3aea25SLi RongQing 				free_percpu(v->stats);
3711a3aea25SLi RongQing 			v->stats = NULL;
3721a3aea25SLi RongQing 
373f8ed289fSNikolay Aleksandrov 			br_vlan_put_master(masterv);
3742594e906SNikolay Aleksandrov 			v->brvlan = NULL;
3752594e906SNikolay Aleksandrov 		}
3769c86ce2cSPetr Machata 	} else {
3779c86ce2cSPetr Machata 		br_switchdev_port_vlan_del(dev, v->vid);
3782594e906SNikolay Aleksandrov 	}
3792594e906SNikolay Aleksandrov 
3802594e906SNikolay Aleksandrov 	goto out;
3812594e906SNikolay Aleksandrov }
3822594e906SNikolay Aleksandrov 
__vlan_del(struct net_bridge_vlan * v)3832594e906SNikolay Aleksandrov static int __vlan_del(struct net_bridge_vlan *v)
3842594e906SNikolay Aleksandrov {
3852594e906SNikolay Aleksandrov 	struct net_bridge_vlan *masterv = v;
38677751ee8SNikolay Aleksandrov 	struct net_bridge_vlan_group *vg;
3872594e906SNikolay Aleksandrov 	struct net_bridge_port *p = NULL;
3882594e906SNikolay Aleksandrov 	int err = 0;
3892594e906SNikolay Aleksandrov 
3902594e906SNikolay Aleksandrov 	if (br_vlan_is_master(v)) {
391907b1e6eSNikolay Aleksandrov 		vg = br_vlan_group(v->br);
3922594e906SNikolay Aleksandrov 	} else {
3932594e906SNikolay Aleksandrov 		p = v->port;
394907b1e6eSNikolay Aleksandrov 		vg = nbp_vlan_group(v->port);
3952594e906SNikolay Aleksandrov 		masterv = v->brvlan;
3962594e906SNikolay Aleksandrov 	}
3972594e906SNikolay Aleksandrov 
39877751ee8SNikolay Aleksandrov 	__vlan_delete_pvid(vg, v->vid);
3992594e906SNikolay Aleksandrov 	if (p) {
40027973793SIdo Schimmel 		err = __vlan_vid_del(p->dev, p->br, v);
4012594e906SNikolay Aleksandrov 		if (err)
4022594e906SNikolay Aleksandrov 			goto out;
4039c86ce2cSPetr Machata 	} else {
4049c86ce2cSPetr Machata 		err = br_switchdev_port_vlan_del(v->br->dev, v->vid);
4059c86ce2cSPetr Machata 		if (err && err != -EOPNOTSUPP)
4069c86ce2cSPetr Machata 			goto out;
4079c86ce2cSPetr Machata 		err = 0;
4082594e906SNikolay Aleksandrov 	}
4092594e906SNikolay Aleksandrov 
4106be144f6SNikolay Aleksandrov 	if (br_vlan_should_use(v)) {
4112594e906SNikolay Aleksandrov 		v->flags &= ~BRIDGE_VLAN_INFO_BRENTRY;
4126be144f6SNikolay Aleksandrov 		vg->num_vlans--;
4132594e906SNikolay Aleksandrov 	}
4142594e906SNikolay Aleksandrov 
4152594e906SNikolay Aleksandrov 	if (masterv != v) {
416efa5356bSRoopa Prabhu 		vlan_tunnel_info_del(vg, v);
41777751ee8SNikolay Aleksandrov 		rhashtable_remove_fast(&vg->vlan_hash, &v->vnode,
41877751ee8SNikolay Aleksandrov 				       br_vlan_rht_params);
4192594e906SNikolay Aleksandrov 		__vlan_del_list(v);
42080900acdSMike Manning 		nbp_vlan_set_vlan_dev_state(p, v->vid);
4217b54aaafSNikolay Aleksandrov 		br_multicast_toggle_one_vlan(v, false);
422613d61dbSNikolay Aleksandrov 		br_multicast_port_ctx_deinit(&v->port_mcast_ctx);
4239163a0fcSNikolay Aleksandrov 		call_rcu(&v->rcu, nbp_vlan_rcu_free);
4242594e906SNikolay Aleksandrov 	}
4252594e906SNikolay Aleksandrov 
426f8ed289fSNikolay Aleksandrov 	br_vlan_put_master(masterv);
4272594e906SNikolay Aleksandrov out:
428bf361ad3SVivien Didelot 	return err;
4298580e211SToshiaki Makita }
430243a2e63SVlad Yasevich 
__vlan_group_free(struct net_bridge_vlan_group * vg)431f409d0edSNikolay Aleksandrov static void __vlan_group_free(struct net_bridge_vlan_group *vg)
432f409d0edSNikolay Aleksandrov {
433f409d0edSNikolay Aleksandrov 	WARN_ON(!list_empty(&vg->vlan_list));
434f409d0edSNikolay Aleksandrov 	rhashtable_destroy(&vg->vlan_hash);
435efa5356bSRoopa Prabhu 	vlan_tunnel_deinit(vg);
436f409d0edSNikolay Aleksandrov 	kfree(vg);
437f409d0edSNikolay Aleksandrov }
438f409d0edSNikolay Aleksandrov 
__vlan_flush(const struct net_bridge * br,const struct net_bridge_port * p,struct net_bridge_vlan_group * vg)439f545923bSNikolay Aleksandrov static void __vlan_flush(const struct net_bridge *br,
440f545923bSNikolay Aleksandrov 			 const struct net_bridge_port *p,
441f545923bSNikolay Aleksandrov 			 struct net_bridge_vlan_group *vg)
442243a2e63SVlad Yasevich {
4432594e906SNikolay Aleksandrov 	struct net_bridge_vlan *vlan, *tmp;
444f545923bSNikolay Aleksandrov 	u16 v_start = 0, v_end = 0;
4455454f5c2SVladimir Oltean 	int err;
4462594e906SNikolay Aleksandrov 
447f409d0edSNikolay Aleksandrov 	__vlan_delete_pvid(vg, vg->pvid);
448f545923bSNikolay Aleksandrov 	list_for_each_entry_safe(vlan, tmp, &vg->vlan_list, vlist) {
449f545923bSNikolay Aleksandrov 		/* take care of disjoint ranges */
450f545923bSNikolay Aleksandrov 		if (!v_start) {
451f545923bSNikolay Aleksandrov 			v_start = vlan->vid;
452f545923bSNikolay Aleksandrov 		} else if (vlan->vid - v_end != 1) {
453f545923bSNikolay Aleksandrov 			/* found range end, notify and start next one */
454f545923bSNikolay Aleksandrov 			br_vlan_notify(br, p, v_start, v_end, RTM_DELVLAN);
455f545923bSNikolay Aleksandrov 			v_start = vlan->vid;
456f545923bSNikolay Aleksandrov 		}
457f545923bSNikolay Aleksandrov 		v_end = vlan->vid;
458f545923bSNikolay Aleksandrov 
4595454f5c2SVladimir Oltean 		err = __vlan_del(vlan);
4605454f5c2SVladimir Oltean 		if (err) {
4615454f5c2SVladimir Oltean 			br_err(br,
4625454f5c2SVladimir Oltean 			       "port %u(%s) failed to delete vlan %d: %pe\n",
4635454f5c2SVladimir Oltean 			       (unsigned int) p->port_no, p->dev->name,
4645454f5c2SVladimir Oltean 			       vlan->vid, ERR_PTR(err));
4655454f5c2SVladimir Oltean 		}
466243a2e63SVlad Yasevich 	}
467243a2e63SVlad Yasevich 
468f545923bSNikolay Aleksandrov 	/* notify about the last/whole vlan range */
469f545923bSNikolay Aleksandrov 	if (v_start)
470f545923bSNikolay Aleksandrov 		br_vlan_notify(br, p, v_start, v_end, RTM_DELVLAN);
471f545923bSNikolay Aleksandrov }
472f545923bSNikolay Aleksandrov 
br_handle_vlan(struct net_bridge * br,const struct net_bridge_port * p,struct net_bridge_vlan_group * vg,struct sk_buff * skb)47378851988SVlad Yasevich struct sk_buff *br_handle_vlan(struct net_bridge *br,
47411538d03SRoopa Prabhu 			       const struct net_bridge_port *p,
4752594e906SNikolay Aleksandrov 			       struct net_bridge_vlan_group *vg,
476a37b85c9SVlad Yasevich 			       struct sk_buff *skb)
477a37b85c9SVlad Yasevich {
478281cc284SHeiner Kallweit 	struct pcpu_sw_netstats *stats;
4792594e906SNikolay Aleksandrov 	struct net_bridge_vlan *v;
480a37b85c9SVlad Yasevich 	u16 vid;
481a37b85c9SVlad Yasevich 
48220adfa1aSVlad Yasevich 	/* If this packet was not filtered at input, let it pass */
48320adfa1aSVlad Yasevich 	if (!BR_INPUT_SKB_CB(skb)->vlan_filtered)
48478851988SVlad Yasevich 		goto out;
48578851988SVlad Yasevich 
4862594e906SNikolay Aleksandrov 	/* At this point, we know that the frame was filtered and contains
4872594e906SNikolay Aleksandrov 	 * a valid vlan id.  If the vlan id has untagged flag set,
4882594e906SNikolay Aleksandrov 	 * send untagged; otherwise, send tagged.
4892594e906SNikolay Aleksandrov 	 */
4902594e906SNikolay Aleksandrov 	br_vlan_get_tag(skb, &vid);
4912594e906SNikolay Aleksandrov 	v = br_vlan_find(vg, vid);
4922594e906SNikolay Aleksandrov 	/* Vlan entry must be configured at this point.  The
493fc92f745SVlad Yasevich 	 * only exception is the bridge is set in promisc mode and the
494fc92f745SVlad Yasevich 	 * packet is destined for the bridge device.  In this case
495fc92f745SVlad Yasevich 	 * pass the packet as is.
496fc92f745SVlad Yasevich 	 */
4972594e906SNikolay Aleksandrov 	if (!v || !br_vlan_should_use(v)) {
498fc92f745SVlad Yasevich 		if ((br->dev->flags & IFF_PROMISC) && skb->dev == br->dev) {
499fc92f745SVlad Yasevich 			goto out;
500fc92f745SVlad Yasevich 		} else {
501fc92f745SVlad Yasevich 			kfree_skb(skb);
502fc92f745SVlad Yasevich 			return NULL;
503fc92f745SVlad Yasevich 		}
504fc92f745SVlad Yasevich 	}
505ae75767eSNikolay Aleksandrov 	if (br_opt_get(br, BROPT_VLAN_STATS_ENABLED)) {
5066dada9b1SNikolay Aleksandrov 		stats = this_cpu_ptr(v->stats);
5076dada9b1SNikolay Aleksandrov 		u64_stats_update_begin(&stats->syncp);
5089962acefSEric Dumazet 		u64_stats_add(&stats->tx_bytes, skb->len);
5099962acefSEric Dumazet 		u64_stats_inc(&stats->tx_packets);
5106dada9b1SNikolay Aleksandrov 		u64_stats_update_end(&stats->syncp);
5116dada9b1SNikolay Aleksandrov 	}
5126dada9b1SNikolay Aleksandrov 
51347211192STobias Waldekranz 	/* If the skb will be sent using forwarding offload, the assumption is
51447211192STobias Waldekranz 	 * that the switchdev will inject the packet into hardware together
51547211192STobias Waldekranz 	 * with the bridge VLAN, so that it can be forwarded according to that
51647211192STobias Waldekranz 	 * VLAN. The switchdev should deal with popping the VLAN header in
51747211192STobias Waldekranz 	 * hardware on each egress port as appropriate. So only strip the VLAN
51847211192STobias Waldekranz 	 * header if forwarding offload is not being used.
51947211192STobias Waldekranz 	 */
52047211192STobias Waldekranz 	if (v->flags & BRIDGE_VLAN_INFO_UNTAGGED &&
52147211192STobias Waldekranz 	    !br_switchdev_frame_uses_tx_fwd_offload(skb))
5225978f8a9SMichał Mirosław 		__vlan_hwaccel_clear_tag(skb);
52311538d03SRoopa Prabhu 
52411538d03SRoopa Prabhu 	if (p && (p->flags & BR_VLAN_TUNNEL) &&
52511538d03SRoopa Prabhu 	    br_handle_egress_vlan_tunnel(skb, v)) {
52611538d03SRoopa Prabhu 		kfree_skb(skb);
52711538d03SRoopa Prabhu 		return NULL;
52811538d03SRoopa Prabhu 	}
52978851988SVlad Yasevich out:
53078851988SVlad Yasevich 	return skb;
53178851988SVlad Yasevich }
53278851988SVlad Yasevich 
53378851988SVlad Yasevich /* Called under RCU */
__allowed_ingress(const struct net_bridge * br,struct net_bridge_vlan_group * vg,struct sk_buff * skb,u16 * vid,u8 * state,struct net_bridge_vlan ** vlan)5346dada9b1SNikolay Aleksandrov static bool __allowed_ingress(const struct net_bridge *br,
5356dada9b1SNikolay Aleksandrov 			      struct net_bridge_vlan_group *vg,
536a580c76dSNikolay Aleksandrov 			      struct sk_buff *skb, u16 *vid,
537f4b7002aSNikolay Aleksandrov 			      u8 *state,
538f4b7002aSNikolay Aleksandrov 			      struct net_bridge_vlan **vlan)
53978851988SVlad Yasevich {
540281cc284SHeiner Kallweit 	struct pcpu_sw_netstats *stats;
5416dada9b1SNikolay Aleksandrov 	struct net_bridge_vlan *v;
5428580e211SToshiaki Makita 	bool tagged;
543a37b85c9SVlad Yasevich 
54420adfa1aSVlad Yasevich 	BR_INPUT_SKB_CB(skb)->vlan_filtered = true;
54512464bb8SToshiaki Makita 	/* If vlan tx offload is disabled on bridge device and frame was
54612464bb8SToshiaki Makita 	 * sent from vlan device on the bridge device, it does not have
54712464bb8SToshiaki Makita 	 * HW accelerated vlan tag.
54812464bb8SToshiaki Makita 	 */
549df8a39deSJiri Pirko 	if (unlikely(!skb_vlan_tag_present(skb) &&
5506dada9b1SNikolay Aleksandrov 		     skb->protocol == br->vlan_proto)) {
5510d5501c1SVlad Yasevich 		skb = skb_vlan_untag(skb);
55212464bb8SToshiaki Makita 		if (unlikely(!skb))
55312464bb8SToshiaki Makita 			return false;
55412464bb8SToshiaki Makita 	}
55512464bb8SToshiaki Makita 
5568580e211SToshiaki Makita 	if (!br_vlan_get_tag(skb, vid)) {
5578580e211SToshiaki Makita 		/* Tagged frame */
5586dada9b1SNikolay Aleksandrov 		if (skb->vlan_proto != br->vlan_proto) {
5598580e211SToshiaki Makita 			/* Protocol-mismatch, empty out vlan_tci for new tag */
5608580e211SToshiaki Makita 			skb_push(skb, ETH_HLEN);
56162749e2cSJiri Pirko 			skb = vlan_insert_tag_set_proto(skb, skb->vlan_proto,
562df8a39deSJiri Pirko 							skb_vlan_tag_get(skb));
5638580e211SToshiaki Makita 			if (unlikely(!skb))
5648580e211SToshiaki Makita 				return false;
5658580e211SToshiaki Makita 
5668580e211SToshiaki Makita 			skb_pull(skb, ETH_HLEN);
5678580e211SToshiaki Makita 			skb_reset_mac_len(skb);
5688580e211SToshiaki Makita 			*vid = 0;
5698580e211SToshiaki Makita 			tagged = false;
5708580e211SToshiaki Makita 		} else {
5718580e211SToshiaki Makita 			tagged = true;
5728580e211SToshiaki Makita 		}
5738580e211SToshiaki Makita 	} else {
5748580e211SToshiaki Makita 		/* Untagged frame */
5758580e211SToshiaki Makita 		tagged = false;
5768580e211SToshiaki Makita 	}
5778580e211SToshiaki Makita 
578b90356ceSToshiaki Makita 	if (!*vid) {
57977751ee8SNikolay Aleksandrov 		u16 pvid = br_get_pvid(vg);
58077751ee8SNikolay Aleksandrov 
581b90356ceSToshiaki Makita 		/* Frame had a tag with VID 0 or did not have a tag.
582b90356ceSToshiaki Makita 		 * See if pvid is set on this port.  That tells us which
583b90356ceSToshiaki Makita 		 * vlan untagged or priority-tagged traffic belongs to.
58478851988SVlad Yasevich 		 */
5853df6bf45SVlad Yasevich 		if (!pvid)
586eb707618SToshiaki Makita 			goto drop;
58778851988SVlad Yasevich 
588b90356ceSToshiaki Makita 		/* PVID is set on this port.  Any untagged or priority-tagged
589b90356ceSToshiaki Makita 		 * ingress frame is considered to belong to this vlan.
59078851988SVlad Yasevich 		 */
591dfb5fa32SToshiaki Makita 		*vid = pvid;
5928580e211SToshiaki Makita 		if (likely(!tagged))
593b90356ceSToshiaki Makita 			/* Untagged Frame. */
5946dada9b1SNikolay Aleksandrov 			__vlan_hwaccel_put_tag(skb, br->vlan_proto, pvid);
595b90356ceSToshiaki Makita 		else
596b90356ceSToshiaki Makita 			/* Priority-tagged Frame.
5975978f8a9SMichał Mirosław 			 * At this point, we know that skb->vlan_tci VID
5985978f8a9SMichał Mirosław 			 * field was 0.
599b90356ceSToshiaki Makita 			 * We update only VID field and preserve PCP field.
600b90356ceSToshiaki Makita 			 */
601b90356ceSToshiaki Makita 			skb->vlan_tci |= pvid;
602b90356ceSToshiaki Makita 
603f4b7002aSNikolay Aleksandrov 		/* if snooping and stats are disabled we can avoid the lookup */
604f4b7002aSNikolay Aleksandrov 		if (!br_opt_get(br, BROPT_MCAST_VLAN_SNOOPING_ENABLED) &&
605f4b7002aSNikolay Aleksandrov 		    !br_opt_get(br, BROPT_VLAN_STATS_ENABLED)) {
606a580c76dSNikolay Aleksandrov 			if (*state == BR_STATE_FORWARDING) {
607a580c76dSNikolay Aleksandrov 				*state = br_vlan_get_pvid_state(vg);
608fd20d973STim Yi 				if (!br_vlan_state_allowed(*state, true))
609fd20d973STim Yi 					goto drop;
61078851988SVlad Yasevich 			}
611fd20d973STim Yi 			return true;
612a580c76dSNikolay Aleksandrov 		}
613a580c76dSNikolay Aleksandrov 	}
61477751ee8SNikolay Aleksandrov 	v = br_vlan_find(vg, *vid);
6156dada9b1SNikolay Aleksandrov 	if (!v || !br_vlan_should_use(v))
6166dada9b1SNikolay Aleksandrov 		goto drop;
6176dada9b1SNikolay Aleksandrov 
618a580c76dSNikolay Aleksandrov 	if (*state == BR_STATE_FORWARDING) {
619a580c76dSNikolay Aleksandrov 		*state = br_vlan_get_state(v);
620a580c76dSNikolay Aleksandrov 		if (!br_vlan_state_allowed(*state, true))
621a580c76dSNikolay Aleksandrov 			goto drop;
622a580c76dSNikolay Aleksandrov 	}
623a580c76dSNikolay Aleksandrov 
624ae75767eSNikolay Aleksandrov 	if (br_opt_get(br, BROPT_VLAN_STATS_ENABLED)) {
6256dada9b1SNikolay Aleksandrov 		stats = this_cpu_ptr(v->stats);
6266dada9b1SNikolay Aleksandrov 		u64_stats_update_begin(&stats->syncp);
6279962acefSEric Dumazet 		u64_stats_add(&stats->rx_bytes, skb->len);
6289962acefSEric Dumazet 		u64_stats_inc(&stats->rx_packets);
6296dada9b1SNikolay Aleksandrov 		u64_stats_update_end(&stats->syncp);
6306dada9b1SNikolay Aleksandrov 	}
6316dada9b1SNikolay Aleksandrov 
632f4b7002aSNikolay Aleksandrov 	*vlan = v;
633f4b7002aSNikolay Aleksandrov 
634a37b85c9SVlad Yasevich 	return true;
6356dada9b1SNikolay Aleksandrov 
636eb707618SToshiaki Makita drop:
637eb707618SToshiaki Makita 	kfree_skb(skb);
638a37b85c9SVlad Yasevich 	return false;
639a37b85c9SVlad Yasevich }
640a37b85c9SVlad Yasevich 
br_allowed_ingress(const struct net_bridge * br,struct net_bridge_vlan_group * vg,struct sk_buff * skb,u16 * vid,u8 * state,struct net_bridge_vlan ** vlan)64177751ee8SNikolay Aleksandrov bool br_allowed_ingress(const struct net_bridge *br,
64277751ee8SNikolay Aleksandrov 			struct net_bridge_vlan_group *vg, struct sk_buff *skb,
643f4b7002aSNikolay Aleksandrov 			u16 *vid, u8 *state,
644f4b7002aSNikolay Aleksandrov 			struct net_bridge_vlan **vlan)
6452594e906SNikolay Aleksandrov {
6462594e906SNikolay Aleksandrov 	/* If VLAN filtering is disabled on the bridge, all packets are
6472594e906SNikolay Aleksandrov 	 * permitted.
6482594e906SNikolay Aleksandrov 	 */
649f4b7002aSNikolay Aleksandrov 	*vlan = NULL;
650ae75767eSNikolay Aleksandrov 	if (!br_opt_get(br, BROPT_VLAN_ENABLED)) {
6512594e906SNikolay Aleksandrov 		BR_INPUT_SKB_CB(skb)->vlan_filtered = false;
6522594e906SNikolay Aleksandrov 		return true;
6532594e906SNikolay Aleksandrov 	}
6542594e906SNikolay Aleksandrov 
655f4b7002aSNikolay Aleksandrov 	return __allowed_ingress(br, vg, skb, vid, state, vlan);
6562594e906SNikolay Aleksandrov }
6572594e906SNikolay Aleksandrov 
65885f46c6bSVlad Yasevich /* Called under RCU. */
br_allowed_egress(struct net_bridge_vlan_group * vg,const struct sk_buff * skb)6592594e906SNikolay Aleksandrov bool br_allowed_egress(struct net_bridge_vlan_group *vg,
66085f46c6bSVlad Yasevich 		       const struct sk_buff *skb)
66185f46c6bSVlad Yasevich {
6622594e906SNikolay Aleksandrov 	const struct net_bridge_vlan *v;
66385f46c6bSVlad Yasevich 	u16 vid;
66485f46c6bSVlad Yasevich 
66520adfa1aSVlad Yasevich 	/* If this packet was not filtered at input, let it pass */
66620adfa1aSVlad Yasevich 	if (!BR_INPUT_SKB_CB(skb)->vlan_filtered)
66785f46c6bSVlad Yasevich 		return true;
66885f46c6bSVlad Yasevich 
66985f46c6bSVlad Yasevich 	br_vlan_get_tag(skb, &vid);
6702594e906SNikolay Aleksandrov 	v = br_vlan_find(vg, vid);
671a580c76dSNikolay Aleksandrov 	if (v && br_vlan_should_use(v) &&
672a580c76dSNikolay Aleksandrov 	    br_vlan_state_allowed(br_vlan_get_state(v), false))
67385f46c6bSVlad Yasevich 		return true;
67485f46c6bSVlad Yasevich 
67585f46c6bSVlad Yasevich 	return false;
67685f46c6bSVlad Yasevich }
67785f46c6bSVlad Yasevich 
678e0d7968aSToshiaki Makita /* Called under RCU */
br_should_learn(struct net_bridge_port * p,struct sk_buff * skb,u16 * vid)679e0d7968aSToshiaki Makita bool br_should_learn(struct net_bridge_port *p, struct sk_buff *skb, u16 *vid)
680e0d7968aSToshiaki Makita {
681468e7944SNikolay Aleksandrov 	struct net_bridge_vlan_group *vg;
682e0d7968aSToshiaki Makita 	struct net_bridge *br = p->br;
683a580c76dSNikolay Aleksandrov 	struct net_bridge_vlan *v;
684e0d7968aSToshiaki Makita 
68520adfa1aSVlad Yasevich 	/* If filtering was disabled at input, let it pass. */
686ae75767eSNikolay Aleksandrov 	if (!br_opt_get(br, BROPT_VLAN_ENABLED))
687e0d7968aSToshiaki Makita 		return true;
688e0d7968aSToshiaki Makita 
689eca1e006SIdo Schimmel 	vg = nbp_vlan_group_rcu(p);
690468e7944SNikolay Aleksandrov 	if (!vg || !vg->num_vlans)
691e0d7968aSToshiaki Makita 		return false;
692e0d7968aSToshiaki Makita 
6938580e211SToshiaki Makita 	if (!br_vlan_get_tag(skb, vid) && skb->vlan_proto != br->vlan_proto)
6948580e211SToshiaki Makita 		*vid = 0;
6958580e211SToshiaki Makita 
696e0d7968aSToshiaki Makita 	if (!*vid) {
69777751ee8SNikolay Aleksandrov 		*vid = br_get_pvid(vg);
698a580c76dSNikolay Aleksandrov 		if (!*vid ||
699a580c76dSNikolay Aleksandrov 		    !br_vlan_state_allowed(br_vlan_get_pvid_state(vg), true))
700e0d7968aSToshiaki Makita 			return false;
701e0d7968aSToshiaki Makita 
702e0d7968aSToshiaki Makita 		return true;
703e0d7968aSToshiaki Makita 	}
704e0d7968aSToshiaki Makita 
705a580c76dSNikolay Aleksandrov 	v = br_vlan_find(vg, *vid);
706a580c76dSNikolay Aleksandrov 	if (v && br_vlan_state_allowed(br_vlan_get_state(v), true))
707e0d7968aSToshiaki Makita 		return true;
708e0d7968aSToshiaki Makita 
709e0d7968aSToshiaki Makita 	return false;
710e0d7968aSToshiaki Makita }
711e0d7968aSToshiaki Makita 
br_vlan_add_existing(struct net_bridge * br,struct net_bridge_vlan_group * vg,struct net_bridge_vlan * vlan,u16 flags,bool * changed,struct netlink_ext_ack * extack)712dbd6dc75SPetr Machata static int br_vlan_add_existing(struct net_bridge *br,
713dbd6dc75SPetr Machata 				struct net_bridge_vlan_group *vg,
714dbd6dc75SPetr Machata 				struct net_bridge_vlan *vlan,
715169327d5SPetr Machata 				u16 flags, bool *changed,
716169327d5SPetr Machata 				struct netlink_ext_ack *extack)
717dbd6dc75SPetr Machata {
71827c5f74cSVladimir Oltean 	bool would_change = __vlan_flags_would_change(vlan, flags);
71927c5f74cSVladimir Oltean 	bool becomes_brentry = false;
720dbd6dc75SPetr Machata 	int err;
721dbd6dc75SPetr Machata 
72227c5f74cSVladimir Oltean 	if (!br_vlan_is_brentry(vlan)) {
723b2bc58d4SVladimir Oltean 		/* Trying to change flags of non-existent bridge vlan */
72427c5f74cSVladimir Oltean 		if (!(flags & BRIDGE_VLAN_INFO_BRENTRY))
725b2bc58d4SVladimir Oltean 			return -EINVAL;
726b2bc58d4SVladimir Oltean 
72727c5f74cSVladimir Oltean 		becomes_brentry = true;
72827c5f74cSVladimir Oltean 	}
72927c5f74cSVladimir Oltean 
73027c5f74cSVladimir Oltean 	/* Master VLANs that aren't brentries weren't notified before,
73127c5f74cSVladimir Oltean 	 * time to notify them now.
73227c5f74cSVladimir Oltean 	 */
73327c5f74cSVladimir Oltean 	if (becomes_brentry || would_change) {
73427c5f74cSVladimir Oltean 		err = br_switchdev_port_vlan_add(br->dev, vlan->vid, flags,
7358d23a54fSVladimir Oltean 						 would_change, extack);
7369c86ce2cSPetr Machata 		if (err && err != -EOPNOTSUPP)
7379c86ce2cSPetr Machata 			return err;
73827c5f74cSVladimir Oltean 	}
7399c86ce2cSPetr Machata 
74027c5f74cSVladimir Oltean 	if (becomes_brentry) {
741dbd6dc75SPetr Machata 		/* It was only kept for port vlans, now make it real */
742f6814fdcSVladimir Oltean 		err = br_fdb_add_local(br, NULL, br->dev->dev_addr, vlan->vid);
743dbd6dc75SPetr Machata 		if (err) {
744dbd6dc75SPetr Machata 			br_err(br, "failed to insert local address into bridge forwarding table\n");
7459c86ce2cSPetr Machata 			goto err_fdb_insert;
746dbd6dc75SPetr Machata 		}
747dbd6dc75SPetr Machata 
748dbd6dc75SPetr Machata 		refcount_inc(&vlan->refcnt);
749dbd6dc75SPetr Machata 		vlan->flags |= BRIDGE_VLAN_INFO_BRENTRY;
750dbd6dc75SPetr Machata 		vg->num_vlans++;
751dbd6dc75SPetr Machata 		*changed = true;
752b92dace3SNikolay Aleksandrov 		br_multicast_toggle_one_vlan(vlan, true);
753dbd6dc75SPetr Machata 	}
754dbd6dc75SPetr Machata 
75527c5f74cSVladimir Oltean 	__vlan_flags_commit(vlan, flags);
75627c5f74cSVladimir Oltean 	if (would_change)
757dbd6dc75SPetr Machata 		*changed = true;
758dbd6dc75SPetr Machata 
759dbd6dc75SPetr Machata 	return 0;
7609c86ce2cSPetr Machata 
7619c86ce2cSPetr Machata err_fdb_insert:
7629c86ce2cSPetr Machata 	br_switchdev_port_vlan_del(br->dev, vlan->vid);
7639c86ce2cSPetr Machata 	return err;
764dbd6dc75SPetr Machata }
765dbd6dc75SPetr Machata 
7668adff41cSToshiaki Makita /* Must be protected by RTNL.
7678adff41cSToshiaki Makita  * Must be called with vid in range from 1 to 4094 inclusive.
768f418af63SNikolay Aleksandrov  * changed must be true only if the vlan was created or updated
7698adff41cSToshiaki Makita  */
br_vlan_add(struct net_bridge * br,u16 vid,u16 flags,bool * changed,struct netlink_ext_ack * extack)770169327d5SPetr Machata int br_vlan_add(struct net_bridge *br, u16 vid, u16 flags, bool *changed,
771169327d5SPetr Machata 		struct netlink_ext_ack *extack)
772243a2e63SVlad Yasevich {
773907b1e6eSNikolay Aleksandrov 	struct net_bridge_vlan_group *vg;
7742594e906SNikolay Aleksandrov 	struct net_bridge_vlan *vlan;
7752594e906SNikolay Aleksandrov 	int ret;
776243a2e63SVlad Yasevich 
777243a2e63SVlad Yasevich 	ASSERT_RTNL();
778243a2e63SVlad Yasevich 
779f418af63SNikolay Aleksandrov 	*changed = false;
780907b1e6eSNikolay Aleksandrov 	vg = br_vlan_group(br);
781907b1e6eSNikolay Aleksandrov 	vlan = br_vlan_find(vg, vid);
782dbd6dc75SPetr Machata 	if (vlan)
783169327d5SPetr Machata 		return br_vlan_add_existing(br, vg, vlan, flags, changed,
784169327d5SPetr Machata 					    extack);
785243a2e63SVlad Yasevich 
7862594e906SNikolay Aleksandrov 	vlan = kzalloc(sizeof(*vlan), GFP_KERNEL);
7872594e906SNikolay Aleksandrov 	if (!vlan)
788243a2e63SVlad Yasevich 		return -ENOMEM;
789243a2e63SVlad Yasevich 
790281cc284SHeiner Kallweit 	vlan->stats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
7916dada9b1SNikolay Aleksandrov 	if (!vlan->stats) {
7926dada9b1SNikolay Aleksandrov 		kfree(vlan);
7936dada9b1SNikolay Aleksandrov 		return -ENOMEM;
7946dada9b1SNikolay Aleksandrov 	}
7952594e906SNikolay Aleksandrov 	vlan->vid = vid;
7962594e906SNikolay Aleksandrov 	vlan->flags = flags | BRIDGE_VLAN_INFO_MASTER;
7972594e906SNikolay Aleksandrov 	vlan->flags &= ~BRIDGE_VLAN_INFO_PVID;
7982594e906SNikolay Aleksandrov 	vlan->br = br;
7992594e906SNikolay Aleksandrov 	if (flags & BRIDGE_VLAN_INFO_BRENTRY)
80025127759SReshetova, Elena 		refcount_set(&vlan->refcnt, 1);
801169327d5SPetr Machata 	ret = __vlan_add(vlan, flags, extack);
8026dada9b1SNikolay Aleksandrov 	if (ret) {
8036dada9b1SNikolay Aleksandrov 		free_percpu(vlan->stats);
8042594e906SNikolay Aleksandrov 		kfree(vlan);
805f418af63SNikolay Aleksandrov 	} else {
806f418af63SNikolay Aleksandrov 		*changed = true;
8076dada9b1SNikolay Aleksandrov 	}
808243a2e63SVlad Yasevich 
8092594e906SNikolay Aleksandrov 	return ret;
810243a2e63SVlad Yasevich }
811243a2e63SVlad Yasevich 
8128adff41cSToshiaki Makita /* Must be protected by RTNL.
8138adff41cSToshiaki Makita  * Must be called with vid in range from 1 to 4094 inclusive.
8148adff41cSToshiaki Makita  */
br_vlan_delete(struct net_bridge * br,u16 vid)815243a2e63SVlad Yasevich int br_vlan_delete(struct net_bridge *br, u16 vid)
816243a2e63SVlad Yasevich {
817907b1e6eSNikolay Aleksandrov 	struct net_bridge_vlan_group *vg;
8182594e906SNikolay Aleksandrov 	struct net_bridge_vlan *v;
819243a2e63SVlad Yasevich 
820243a2e63SVlad Yasevich 	ASSERT_RTNL();
821243a2e63SVlad Yasevich 
822907b1e6eSNikolay Aleksandrov 	vg = br_vlan_group(br);
823907b1e6eSNikolay Aleksandrov 	v = br_vlan_find(vg, vid);
8242594e906SNikolay Aleksandrov 	if (!v || !br_vlan_is_brentry(v))
8252594e906SNikolay Aleksandrov 		return -ENOENT;
826243a2e63SVlad Yasevich 
827424bb9c9SToshiaki Makita 	br_fdb_find_delete_local(br, NULL, br->dev->dev_addr, vid);
8283741873bSRoopa Prabhu 	br_fdb_delete_by_port(br, NULL, vid, 0);
829bc9a25d2SVlad Yasevich 
830efa5356bSRoopa Prabhu 	vlan_tunnel_info_del(vg, v);
831efa5356bSRoopa Prabhu 
8322594e906SNikolay Aleksandrov 	return __vlan_del(v);
833243a2e63SVlad Yasevich }
834243a2e63SVlad Yasevich 
br_vlan_flush(struct net_bridge * br)835243a2e63SVlad Yasevich void br_vlan_flush(struct net_bridge *br)
836243a2e63SVlad Yasevich {
837f409d0edSNikolay Aleksandrov 	struct net_bridge_vlan_group *vg;
838f409d0edSNikolay Aleksandrov 
839243a2e63SVlad Yasevich 	ASSERT_RTNL();
840243a2e63SVlad Yasevich 
841f409d0edSNikolay Aleksandrov 	vg = br_vlan_group(br);
842f545923bSNikolay Aleksandrov 	__vlan_flush(br, NULL, vg);
843f409d0edSNikolay Aleksandrov 	RCU_INIT_POINTER(br->vlgrp, NULL);
844f409d0edSNikolay Aleksandrov 	synchronize_rcu();
845f409d0edSNikolay Aleksandrov 	__vlan_group_free(vg);
846243a2e63SVlad Yasevich }
847243a2e63SVlad Yasevich 
br_vlan_find(struct net_bridge_vlan_group * vg,u16 vid)8482594e906SNikolay Aleksandrov struct net_bridge_vlan *br_vlan_find(struct net_bridge_vlan_group *vg, u16 vid)
8492b292fb4SToshiaki Makita {
8502594e906SNikolay Aleksandrov 	if (!vg)
8512594e906SNikolay Aleksandrov 		return NULL;
8522b292fb4SToshiaki Makita 
8532594e906SNikolay Aleksandrov 	return br_vlan_lookup(&vg->vlan_hash, vid);
8542b292fb4SToshiaki Makita }
8552b292fb4SToshiaki Makita 
856204177f3SToshiaki Makita /* Must be protected by RTNL. */
recalculate_group_addr(struct net_bridge * br)857204177f3SToshiaki Makita static void recalculate_group_addr(struct net_bridge *br)
858204177f3SToshiaki Makita {
859be3664a0SNikolay Aleksandrov 	if (br_opt_get(br, BROPT_GROUP_ADDR_SET))
860204177f3SToshiaki Makita 		return;
861204177f3SToshiaki Makita 
862204177f3SToshiaki Makita 	spin_lock_bh(&br->lock);
863ae75767eSNikolay Aleksandrov 	if (!br_opt_get(br, BROPT_VLAN_ENABLED) ||
864ae75767eSNikolay Aleksandrov 	    br->vlan_proto == htons(ETH_P_8021Q)) {
865204177f3SToshiaki Makita 		/* Bridge Group Address */
866204177f3SToshiaki Makita 		br->group_addr[5] = 0x00;
867204177f3SToshiaki Makita 	} else { /* vlan_enabled && ETH_P_8021AD */
868204177f3SToshiaki Makita 		/* Provider Bridge Group Address */
869204177f3SToshiaki Makita 		br->group_addr[5] = 0x08;
870204177f3SToshiaki Makita 	}
871204177f3SToshiaki Makita 	spin_unlock_bh(&br->lock);
872204177f3SToshiaki Makita }
873204177f3SToshiaki Makita 
874204177f3SToshiaki Makita /* Must be protected by RTNL. */
br_recalculate_fwd_mask(struct net_bridge * br)875204177f3SToshiaki Makita void br_recalculate_fwd_mask(struct net_bridge *br)
876204177f3SToshiaki Makita {
877ae75767eSNikolay Aleksandrov 	if (!br_opt_get(br, BROPT_VLAN_ENABLED) ||
878ae75767eSNikolay Aleksandrov 	    br->vlan_proto == htons(ETH_P_8021Q))
879204177f3SToshiaki Makita 		br->group_fwd_mask_required = BR_GROUPFWD_DEFAULT;
880204177f3SToshiaki Makita 	else /* vlan_enabled && ETH_P_8021AD */
881204177f3SToshiaki Makita 		br->group_fwd_mask_required = BR_GROUPFWD_8021AD &
882204177f3SToshiaki Makita 					      ~(1u << br->group_addr[5]);
883204177f3SToshiaki Makita }
884204177f3SToshiaki Makita 
br_vlan_filter_toggle(struct net_bridge * br,unsigned long val,struct netlink_ext_ack * extack)8859e781401SVladimir Oltean int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val,
8869e781401SVladimir Oltean 			  struct netlink_ext_ack *extack)
887243a2e63SVlad Yasevich {
8886b72a770SElad Raz 	struct switchdev_attr attr = {
8896b72a770SElad Raz 		.orig_dev = br->dev,
8906b72a770SElad Raz 		.id = SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING,
8916b72a770SElad Raz 		.flags = SWITCHDEV_F_SKIP_EOPNOTSUPP,
8926b72a770SElad Raz 		.u.vlan_filtering = val,
8936b72a770SElad Raz 	};
8946b72a770SElad Raz 	int err;
8956b72a770SElad Raz 
896ae75767eSNikolay Aleksandrov 	if (br_opt_get(br, BROPT_VLAN_ENABLED) == !!val)
897a7854037SNikolay Aleksandrov 		return 0;
898243a2e63SVlad Yasevich 
899ae75767eSNikolay Aleksandrov 	br_opt_toggle(br, BROPT_VLAN_ENABLED, !!val);
900f7cdb3ecSVladimir Oltean 
901f7cdb3ecSVladimir Oltean 	err = switchdev_port_attr_set(br->dev, &attr, extack);
902f7cdb3ecSVladimir Oltean 	if (err && err != -EOPNOTSUPP) {
903f7cdb3ecSVladimir Oltean 		br_opt_toggle(br, BROPT_VLAN_ENABLED, !val);
904f7cdb3ecSVladimir Oltean 		return err;
905f7cdb3ecSVladimir Oltean 	}
906f7cdb3ecSVladimir Oltean 
9072796d0c6SVlad Yasevich 	br_manage_promisc(br);
908204177f3SToshiaki Makita 	recalculate_group_addr(br);
909204177f3SToshiaki Makita 	br_recalculate_fwd_mask(br);
910f4b7002aSNikolay Aleksandrov 	if (!val && br_opt_get(br, BROPT_MCAST_VLAN_SNOOPING_ENABLED)) {
911f4b7002aSNikolay Aleksandrov 		br_info(br, "vlan filtering disabled, automatically disabling multicast vlan snooping\n");
912f4b7002aSNikolay Aleksandrov 		br_multicast_toggle_vlan_snooping(br, false, NULL);
913f4b7002aSNikolay Aleksandrov 	}
914243a2e63SVlad Yasevich 
915a7854037SNikolay Aleksandrov 	return 0;
916a7854037SNikolay Aleksandrov }
917a7854037SNikolay Aleksandrov 
br_vlan_enabled(const struct net_device * dev)9181f51445aSIdo Schimmel bool br_vlan_enabled(const struct net_device *dev)
9191f51445aSIdo Schimmel {
9201f51445aSIdo Schimmel 	struct net_bridge *br = netdev_priv(dev);
9211f51445aSIdo Schimmel 
922ae75767eSNikolay Aleksandrov 	return br_opt_get(br, BROPT_VLAN_ENABLED);
9231f51445aSIdo Schimmel }
9241f51445aSIdo Schimmel EXPORT_SYMBOL_GPL(br_vlan_enabled);
9251f51445aSIdo Schimmel 
br_vlan_get_proto(const struct net_device * dev,u16 * p_proto)92631aed46fSwenxu int br_vlan_get_proto(const struct net_device *dev, u16 *p_proto)
92731aed46fSwenxu {
92831aed46fSwenxu 	struct net_bridge *br = netdev_priv(dev);
92931aed46fSwenxu 
93031aed46fSwenxu 	*p_proto = ntohs(br->vlan_proto);
93131aed46fSwenxu 
93231aed46fSwenxu 	return 0;
93331aed46fSwenxu }
93431aed46fSwenxu EXPORT_SYMBOL_GPL(br_vlan_get_proto);
93531aed46fSwenxu 
__br_vlan_set_proto(struct net_bridge * br,__be16 proto,struct netlink_ext_ack * extack)936dcbdf135SVladimir Oltean int __br_vlan_set_proto(struct net_bridge *br, __be16 proto,
937dcbdf135SVladimir Oltean 			struct netlink_ext_ack *extack)
938204177f3SToshiaki Makita {
93922ec19f3SDanielle Ratson 	struct switchdev_attr attr = {
94022ec19f3SDanielle Ratson 		.orig_dev = br->dev,
94122ec19f3SDanielle Ratson 		.id = SWITCHDEV_ATTR_ID_BRIDGE_VLAN_PROTOCOL,
94222ec19f3SDanielle Ratson 		.flags = SWITCHDEV_F_SKIP_EOPNOTSUPP,
94322ec19f3SDanielle Ratson 		.u.vlan_protocol = ntohs(proto),
94422ec19f3SDanielle Ratson 	};
945204177f3SToshiaki Makita 	int err = 0;
946204177f3SToshiaki Makita 	struct net_bridge_port *p;
9472594e906SNikolay Aleksandrov 	struct net_bridge_vlan *vlan;
948907b1e6eSNikolay Aleksandrov 	struct net_bridge_vlan_group *vg;
94922ec19f3SDanielle Ratson 	__be16 oldproto = br->vlan_proto;
950204177f3SToshiaki Makita 
951204177f3SToshiaki Makita 	if (br->vlan_proto == proto)
952d2d427b3SToshiaki Makita 		return 0;
953204177f3SToshiaki Makita 
954dcbdf135SVladimir Oltean 	err = switchdev_port_attr_set(br->dev, &attr, extack);
95522ec19f3SDanielle Ratson 	if (err && err != -EOPNOTSUPP)
95622ec19f3SDanielle Ratson 		return err;
95722ec19f3SDanielle Ratson 
958204177f3SToshiaki Makita 	/* Add VLANs for the new proto to the device filter. */
959204177f3SToshiaki Makita 	list_for_each_entry(p, &br->port_list, list) {
960907b1e6eSNikolay Aleksandrov 		vg = nbp_vlan_group(p);
961907b1e6eSNikolay Aleksandrov 		list_for_each_entry(vlan, &vg->vlan_list, vlist) {
9629d45921eSIdo Schimmel 			if (vlan->priv_flags & BR_VLFLAG_ADDED_BY_SWITCHDEV)
9639d45921eSIdo Schimmel 				continue;
9642594e906SNikolay Aleksandrov 			err = vlan_vid_add(p->dev, proto, vlan->vid);
965204177f3SToshiaki Makita 			if (err)
966204177f3SToshiaki Makita 				goto err_filt;
967204177f3SToshiaki Makita 		}
968204177f3SToshiaki Makita 	}
969204177f3SToshiaki Makita 
970204177f3SToshiaki Makita 	br->vlan_proto = proto;
971204177f3SToshiaki Makita 
972204177f3SToshiaki Makita 	recalculate_group_addr(br);
973204177f3SToshiaki Makita 	br_recalculate_fwd_mask(br);
974204177f3SToshiaki Makita 
975204177f3SToshiaki Makita 	/* Delete VLANs for the old proto from the device filter. */
976907b1e6eSNikolay Aleksandrov 	list_for_each_entry(p, &br->port_list, list) {
977907b1e6eSNikolay Aleksandrov 		vg = nbp_vlan_group(p);
9789d45921eSIdo Schimmel 		list_for_each_entry(vlan, &vg->vlan_list, vlist) {
9799d45921eSIdo Schimmel 			if (vlan->priv_flags & BR_VLFLAG_ADDED_BY_SWITCHDEV)
9809d45921eSIdo Schimmel 				continue;
9812594e906SNikolay Aleksandrov 			vlan_vid_del(p->dev, oldproto, vlan->vid);
982907b1e6eSNikolay Aleksandrov 		}
9839d45921eSIdo Schimmel 	}
984204177f3SToshiaki Makita 
985d2d427b3SToshiaki Makita 	return 0;
986204177f3SToshiaki Makita 
987204177f3SToshiaki Makita err_filt:
98822ec19f3SDanielle Ratson 	attr.u.vlan_protocol = ntohs(oldproto);
989dcbdf135SVladimir Oltean 	switchdev_port_attr_set(br->dev, &attr, NULL);
99022ec19f3SDanielle Ratson 
9919d45921eSIdo Schimmel 	list_for_each_entry_continue_reverse(vlan, &vg->vlan_list, vlist) {
9929d45921eSIdo Schimmel 		if (vlan->priv_flags & BR_VLFLAG_ADDED_BY_SWITCHDEV)
9939d45921eSIdo Schimmel 			continue;
9942594e906SNikolay Aleksandrov 		vlan_vid_del(p->dev, proto, vlan->vid);
9959d45921eSIdo Schimmel 	}
996204177f3SToshiaki Makita 
997907b1e6eSNikolay Aleksandrov 	list_for_each_entry_continue_reverse(p, &br->port_list, list) {
998907b1e6eSNikolay Aleksandrov 		vg = nbp_vlan_group(p);
9999d45921eSIdo Schimmel 		list_for_each_entry(vlan, &vg->vlan_list, vlist) {
10009d45921eSIdo Schimmel 			if (vlan->priv_flags & BR_VLFLAG_ADDED_BY_SWITCHDEV)
10019d45921eSIdo Schimmel 				continue;
10022594e906SNikolay Aleksandrov 			vlan_vid_del(p->dev, proto, vlan->vid);
1003907b1e6eSNikolay Aleksandrov 		}
10049d45921eSIdo Schimmel 	}
1005204177f3SToshiaki Makita 
1006d2d427b3SToshiaki Makita 	return err;
1007d2d427b3SToshiaki Makita }
1008d2d427b3SToshiaki Makita 
br_vlan_set_proto(struct net_bridge * br,unsigned long val,struct netlink_ext_ack * extack)10099e781401SVladimir Oltean int br_vlan_set_proto(struct net_bridge *br, unsigned long val,
10109e781401SVladimir Oltean 		      struct netlink_ext_ack *extack)
1011d2d427b3SToshiaki Makita {
1012a98c0c47SMenglong Dong 	if (!eth_type_vlan(htons(val)))
1013d2d427b3SToshiaki Makita 		return -EPROTONOSUPPORT;
1014d2d427b3SToshiaki Makita 
1015dcbdf135SVladimir Oltean 	return __br_vlan_set_proto(br, htons(val), extack);
1016204177f3SToshiaki Makita }
1017204177f3SToshiaki Makita 
br_vlan_set_stats(struct net_bridge * br,unsigned long val)10186dada9b1SNikolay Aleksandrov int br_vlan_set_stats(struct net_bridge *br, unsigned long val)
10196dada9b1SNikolay Aleksandrov {
10206dada9b1SNikolay Aleksandrov 	switch (val) {
10216dada9b1SNikolay Aleksandrov 	case 0:
10226dada9b1SNikolay Aleksandrov 	case 1:
1023ae75767eSNikolay Aleksandrov 		br_opt_toggle(br, BROPT_VLAN_STATS_ENABLED, !!val);
10246dada9b1SNikolay Aleksandrov 		break;
10256dada9b1SNikolay Aleksandrov 	default:
10266dada9b1SNikolay Aleksandrov 		return -EINVAL;
10276dada9b1SNikolay Aleksandrov 	}
10286dada9b1SNikolay Aleksandrov 
10296dada9b1SNikolay Aleksandrov 	return 0;
10306dada9b1SNikolay Aleksandrov }
10316dada9b1SNikolay Aleksandrov 
br_vlan_set_stats_per_port(struct net_bridge * br,unsigned long val)10329163a0fcSNikolay Aleksandrov int br_vlan_set_stats_per_port(struct net_bridge *br, unsigned long val)
10339163a0fcSNikolay Aleksandrov {
10349163a0fcSNikolay Aleksandrov 	struct net_bridge_port *p;
10359163a0fcSNikolay Aleksandrov 
10369163a0fcSNikolay Aleksandrov 	/* allow to change the option if there are no port vlans configured */
10379163a0fcSNikolay Aleksandrov 	list_for_each_entry(p, &br->port_list, list) {
10389163a0fcSNikolay Aleksandrov 		struct net_bridge_vlan_group *vg = nbp_vlan_group(p);
10399163a0fcSNikolay Aleksandrov 
10409163a0fcSNikolay Aleksandrov 		if (vg->num_vlans)
10419163a0fcSNikolay Aleksandrov 			return -EBUSY;
10429163a0fcSNikolay Aleksandrov 	}
10439163a0fcSNikolay Aleksandrov 
10449163a0fcSNikolay Aleksandrov 	switch (val) {
10459163a0fcSNikolay Aleksandrov 	case 0:
10469163a0fcSNikolay Aleksandrov 	case 1:
10479163a0fcSNikolay Aleksandrov 		br_opt_toggle(br, BROPT_VLAN_STATS_PER_PORT, !!val);
10489163a0fcSNikolay Aleksandrov 		break;
10499163a0fcSNikolay Aleksandrov 	default:
10509163a0fcSNikolay Aleksandrov 		return -EINVAL;
10519163a0fcSNikolay Aleksandrov 	}
10529163a0fcSNikolay Aleksandrov 
10539163a0fcSNikolay Aleksandrov 	return 0;
10549163a0fcSNikolay Aleksandrov }
10559163a0fcSNikolay Aleksandrov 
vlan_default_pvid(struct net_bridge_vlan_group * vg,u16 vid)105677751ee8SNikolay Aleksandrov static bool vlan_default_pvid(struct net_bridge_vlan_group *vg, u16 vid)
10575be5a2dfSVlad Yasevich {
10582594e906SNikolay Aleksandrov 	struct net_bridge_vlan *v;
10592594e906SNikolay Aleksandrov 
106077751ee8SNikolay Aleksandrov 	if (vid != vg->pvid)
10612594e906SNikolay Aleksandrov 		return false;
10622594e906SNikolay Aleksandrov 
10632594e906SNikolay Aleksandrov 	v = br_vlan_lookup(&vg->vlan_hash, vid);
10642594e906SNikolay Aleksandrov 	if (v && br_vlan_should_use(v) &&
10652594e906SNikolay Aleksandrov 	    (v->flags & BRIDGE_VLAN_INFO_UNTAGGED))
10662594e906SNikolay Aleksandrov 		return true;
10672594e906SNikolay Aleksandrov 
10682594e906SNikolay Aleksandrov 	return false;
10695be5a2dfSVlad Yasevich }
10705be5a2dfSVlad Yasevich 
br_vlan_disable_default_pvid(struct net_bridge * br)10715be5a2dfSVlad Yasevich static void br_vlan_disable_default_pvid(struct net_bridge *br)
10725be5a2dfSVlad Yasevich {
10735be5a2dfSVlad Yasevich 	struct net_bridge_port *p;
10745be5a2dfSVlad Yasevich 	u16 pvid = br->default_pvid;
10755be5a2dfSVlad Yasevich 
10765be5a2dfSVlad Yasevich 	/* Disable default_pvid on all ports where it is still
10775be5a2dfSVlad Yasevich 	 * configured.
10785be5a2dfSVlad Yasevich 	 */
1079f545923bSNikolay Aleksandrov 	if (vlan_default_pvid(br_vlan_group(br), pvid)) {
1080f545923bSNikolay Aleksandrov 		if (!br_vlan_delete(br, pvid))
1081f545923bSNikolay Aleksandrov 			br_vlan_notify(br, NULL, pvid, 0, RTM_DELVLAN);
1082f545923bSNikolay Aleksandrov 	}
10835be5a2dfSVlad Yasevich 
10845be5a2dfSVlad Yasevich 	list_for_each_entry(p, &br->port_list, list) {
1085f545923bSNikolay Aleksandrov 		if (vlan_default_pvid(nbp_vlan_group(p), pvid) &&
1086f545923bSNikolay Aleksandrov 		    !nbp_vlan_delete(p, pvid))
1087f545923bSNikolay Aleksandrov 			br_vlan_notify(br, p, pvid, 0, RTM_DELVLAN);
10885be5a2dfSVlad Yasevich 	}
10895be5a2dfSVlad Yasevich 
10905be5a2dfSVlad Yasevich 	br->default_pvid = 0;
10915be5a2dfSVlad Yasevich }
10925be5a2dfSVlad Yasevich 
__br_vlan_set_default_pvid(struct net_bridge * br,u16 pvid,struct netlink_ext_ack * extack)1093169327d5SPetr Machata int __br_vlan_set_default_pvid(struct net_bridge *br, u16 pvid,
1094169327d5SPetr Machata 			       struct netlink_ext_ack *extack)
10955be5a2dfSVlad Yasevich {
10962594e906SNikolay Aleksandrov 	const struct net_bridge_vlan *pvent;
1097907b1e6eSNikolay Aleksandrov 	struct net_bridge_vlan_group *vg;
10985be5a2dfSVlad Yasevich 	struct net_bridge_port *p;
1099f418af63SNikolay Aleksandrov 	unsigned long *changed;
1100f418af63SNikolay Aleksandrov 	bool vlchange;
11015be5a2dfSVlad Yasevich 	u16 old_pvid;
11025be5a2dfSVlad Yasevich 	int err = 0;
11035be5a2dfSVlad Yasevich 
11040f963b75SNikolay Aleksandrov 	if (!pvid) {
11050f963b75SNikolay Aleksandrov 		br_vlan_disable_default_pvid(br);
11060f963b75SNikolay Aleksandrov 		return 0;
11070f963b75SNikolay Aleksandrov 	}
11080f963b75SNikolay Aleksandrov 
1109459479daSAndy Shevchenko 	changed = bitmap_zalloc(BR_MAX_PORTS, GFP_KERNEL);
11105be5a2dfSVlad Yasevich 	if (!changed)
11115be5a2dfSVlad Yasevich 		return -ENOMEM;
11125be5a2dfSVlad Yasevich 
11135be5a2dfSVlad Yasevich 	old_pvid = br->default_pvid;
11145be5a2dfSVlad Yasevich 
11155be5a2dfSVlad Yasevich 	/* Update default_pvid config only if we do not conflict with
11165be5a2dfSVlad Yasevich 	 * user configuration.
11175be5a2dfSVlad Yasevich 	 */
1118907b1e6eSNikolay Aleksandrov 	vg = br_vlan_group(br);
1119907b1e6eSNikolay Aleksandrov 	pvent = br_vlan_find(vg, pvid);
1120907b1e6eSNikolay Aleksandrov 	if ((!old_pvid || vlan_default_pvid(vg, old_pvid)) &&
11212594e906SNikolay Aleksandrov 	    (!pvent || !br_vlan_should_use(pvent))) {
11225be5a2dfSVlad Yasevich 		err = br_vlan_add(br, pvid,
11235be5a2dfSVlad Yasevich 				  BRIDGE_VLAN_INFO_PVID |
11242594e906SNikolay Aleksandrov 				  BRIDGE_VLAN_INFO_UNTAGGED |
1125f418af63SNikolay Aleksandrov 				  BRIDGE_VLAN_INFO_BRENTRY,
1126169327d5SPetr Machata 				  &vlchange, extack);
11275be5a2dfSVlad Yasevich 		if (err)
11285be5a2dfSVlad Yasevich 			goto out;
1129f545923bSNikolay Aleksandrov 
1130f545923bSNikolay Aleksandrov 		if (br_vlan_delete(br, old_pvid))
1131f545923bSNikolay Aleksandrov 			br_vlan_notify(br, NULL, old_pvid, 0, RTM_DELVLAN);
1132f545923bSNikolay Aleksandrov 		br_vlan_notify(br, NULL, pvid, 0, RTM_NEWVLAN);
1133442b03c3SXin Long 		__set_bit(0, changed);
11345be5a2dfSVlad Yasevich 	}
11355be5a2dfSVlad Yasevich 
11365be5a2dfSVlad Yasevich 	list_for_each_entry(p, &br->port_list, list) {
11375be5a2dfSVlad Yasevich 		/* Update default_pvid config only if we do not conflict with
11385be5a2dfSVlad Yasevich 		 * user configuration.
11395be5a2dfSVlad Yasevich 		 */
1140907b1e6eSNikolay Aleksandrov 		vg = nbp_vlan_group(p);
11415be5a2dfSVlad Yasevich 		if ((old_pvid &&
1142907b1e6eSNikolay Aleksandrov 		     !vlan_default_pvid(vg, old_pvid)) ||
1143907b1e6eSNikolay Aleksandrov 		    br_vlan_find(vg, pvid))
11445be5a2dfSVlad Yasevich 			continue;
11455be5a2dfSVlad Yasevich 
11465be5a2dfSVlad Yasevich 		err = nbp_vlan_add(p, pvid,
11475be5a2dfSVlad Yasevich 				   BRIDGE_VLAN_INFO_PVID |
1148f418af63SNikolay Aleksandrov 				   BRIDGE_VLAN_INFO_UNTAGGED,
1149169327d5SPetr Machata 				   &vlchange, extack);
11505be5a2dfSVlad Yasevich 		if (err)
11515be5a2dfSVlad Yasevich 			goto err_port;
1152f545923bSNikolay Aleksandrov 		if (nbp_vlan_delete(p, old_pvid))
1153f545923bSNikolay Aleksandrov 			br_vlan_notify(br, p, old_pvid, 0, RTM_DELVLAN);
1154f545923bSNikolay Aleksandrov 		br_vlan_notify(p->br, p, pvid, 0, RTM_NEWVLAN);
1155442b03c3SXin Long 		__set_bit(p->port_no, changed);
11565be5a2dfSVlad Yasevich 	}
11575be5a2dfSVlad Yasevich 
11585be5a2dfSVlad Yasevich 	br->default_pvid = pvid;
11595be5a2dfSVlad Yasevich 
11605be5a2dfSVlad Yasevich out:
1161459479daSAndy Shevchenko 	bitmap_free(changed);
11625be5a2dfSVlad Yasevich 	return err;
11635be5a2dfSVlad Yasevich 
11645be5a2dfSVlad Yasevich err_port:
11655be5a2dfSVlad Yasevich 	list_for_each_entry_continue_reverse(p, &br->port_list, list) {
11665be5a2dfSVlad Yasevich 		if (!test_bit(p->port_no, changed))
11675be5a2dfSVlad Yasevich 			continue;
11685be5a2dfSVlad Yasevich 
1169f545923bSNikolay Aleksandrov 		if (old_pvid) {
11705be5a2dfSVlad Yasevich 			nbp_vlan_add(p, old_pvid,
11715be5a2dfSVlad Yasevich 				     BRIDGE_VLAN_INFO_PVID |
1172f418af63SNikolay Aleksandrov 				     BRIDGE_VLAN_INFO_UNTAGGED,
1173169327d5SPetr Machata 				     &vlchange, NULL);
1174f545923bSNikolay Aleksandrov 			br_vlan_notify(p->br, p, old_pvid, 0, RTM_NEWVLAN);
1175f545923bSNikolay Aleksandrov 		}
11765be5a2dfSVlad Yasevich 		nbp_vlan_delete(p, pvid);
1177f545923bSNikolay Aleksandrov 		br_vlan_notify(br, p, pvid, 0, RTM_DELVLAN);
11785be5a2dfSVlad Yasevich 	}
11795be5a2dfSVlad Yasevich 
11805be5a2dfSVlad Yasevich 	if (test_bit(0, changed)) {
1181f545923bSNikolay Aleksandrov 		if (old_pvid) {
11825be5a2dfSVlad Yasevich 			br_vlan_add(br, old_pvid,
11835be5a2dfSVlad Yasevich 				    BRIDGE_VLAN_INFO_PVID |
11842594e906SNikolay Aleksandrov 				    BRIDGE_VLAN_INFO_UNTAGGED |
1185f418af63SNikolay Aleksandrov 				    BRIDGE_VLAN_INFO_BRENTRY,
1186169327d5SPetr Machata 				    &vlchange, NULL);
1187f545923bSNikolay Aleksandrov 			br_vlan_notify(br, NULL, old_pvid, 0, RTM_NEWVLAN);
1188f545923bSNikolay Aleksandrov 		}
11895be5a2dfSVlad Yasevich 		br_vlan_delete(br, pvid);
1190f545923bSNikolay Aleksandrov 		br_vlan_notify(br, NULL, pvid, 0, RTM_DELVLAN);
11915be5a2dfSVlad Yasevich 	}
11925be5a2dfSVlad Yasevich 	goto out;
11935be5a2dfSVlad Yasevich }
11945be5a2dfSVlad Yasevich 
br_vlan_set_default_pvid(struct net_bridge * br,unsigned long val,struct netlink_ext_ack * extack)11959e781401SVladimir Oltean int br_vlan_set_default_pvid(struct net_bridge *br, unsigned long val,
11969e781401SVladimir Oltean 			     struct netlink_ext_ack *extack)
119796a20d9dSVlad Yasevich {
119896a20d9dSVlad Yasevich 	u16 pvid = val;
119996a20d9dSVlad Yasevich 	int err = 0;
120096a20d9dSVlad Yasevich 
12015be5a2dfSVlad Yasevich 	if (val >= VLAN_VID_MASK)
120296a20d9dSVlad Yasevich 		return -EINVAL;
120396a20d9dSVlad Yasevich 
120496a20d9dSVlad Yasevich 	if (pvid == br->default_pvid)
1205047831a9SXin Long 		goto out;
120696a20d9dSVlad Yasevich 
120796a20d9dSVlad Yasevich 	/* Only allow default pvid change when filtering is disabled */
1208ae75767eSNikolay Aleksandrov 	if (br_opt_get(br, BROPT_VLAN_ENABLED)) {
120996a20d9dSVlad Yasevich 		pr_info_once("Please disable vlan filtering to change default_pvid\n");
121096a20d9dSVlad Yasevich 		err = -EPERM;
1211047831a9SXin Long 		goto out;
121296a20d9dSVlad Yasevich 	}
12139e781401SVladimir Oltean 	err = __br_vlan_set_default_pvid(br, pvid, extack);
1214047831a9SXin Long out:
121596a20d9dSVlad Yasevich 	return err;
121696a20d9dSVlad Yasevich }
121796a20d9dSVlad Yasevich 
br_vlan_init(struct net_bridge * br)12185be5a2dfSVlad Yasevich int br_vlan_init(struct net_bridge *br)
12198580e211SToshiaki Makita {
1220907b1e6eSNikolay Aleksandrov 	struct net_bridge_vlan_group *vg;
12212594e906SNikolay Aleksandrov 	int ret = -ENOMEM;
12222594e906SNikolay Aleksandrov 
1223907b1e6eSNikolay Aleksandrov 	vg = kzalloc(sizeof(*vg), GFP_KERNEL);
1224907b1e6eSNikolay Aleksandrov 	if (!vg)
12252594e906SNikolay Aleksandrov 		goto out;
1226907b1e6eSNikolay Aleksandrov 	ret = rhashtable_init(&vg->vlan_hash, &br_vlan_rht_params);
12272594e906SNikolay Aleksandrov 	if (ret)
12282594e906SNikolay Aleksandrov 		goto err_rhtbl;
1229efa5356bSRoopa Prabhu 	ret = vlan_tunnel_init(vg);
1230efa5356bSRoopa Prabhu 	if (ret)
1231efa5356bSRoopa Prabhu 		goto err_tunnel_init;
1232907b1e6eSNikolay Aleksandrov 	INIT_LIST_HEAD(&vg->vlan_list);
12338580e211SToshiaki Makita 	br->vlan_proto = htons(ETH_P_8021Q);
123496a20d9dSVlad Yasevich 	br->default_pvid = 1;
1235907b1e6eSNikolay Aleksandrov 	rcu_assign_pointer(br->vlgrp, vg);
12362594e906SNikolay Aleksandrov 
12372594e906SNikolay Aleksandrov out:
12382594e906SNikolay Aleksandrov 	return ret;
12392594e906SNikolay Aleksandrov 
1240efa5356bSRoopa Prabhu err_tunnel_init:
1241907b1e6eSNikolay Aleksandrov 	rhashtable_destroy(&vg->vlan_hash);
12422594e906SNikolay Aleksandrov err_rhtbl:
1243907b1e6eSNikolay Aleksandrov 	kfree(vg);
12442594e906SNikolay Aleksandrov 
12452594e906SNikolay Aleksandrov 	goto out;
12462594e906SNikolay Aleksandrov }
12472594e906SNikolay Aleksandrov 
nbp_vlan_init(struct net_bridge_port * p,struct netlink_ext_ack * extack)1248169327d5SPetr Machata int nbp_vlan_init(struct net_bridge_port *p, struct netlink_ext_ack *extack)
12492594e906SNikolay Aleksandrov {
1250404cdbf0SElad Raz 	struct switchdev_attr attr = {
1251404cdbf0SElad Raz 		.orig_dev = p->br->dev,
1252404cdbf0SElad Raz 		.id = SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING,
1253404cdbf0SElad Raz 		.flags = SWITCHDEV_F_SKIP_EOPNOTSUPP,
1254ae75767eSNikolay Aleksandrov 		.u.vlan_filtering = br_opt_get(p->br, BROPT_VLAN_ENABLED),
1255404cdbf0SElad Raz 	};
1256263344e6SNikolay Aleksandrov 	struct net_bridge_vlan_group *vg;
12572594e906SNikolay Aleksandrov 	int ret = -ENOMEM;
12582594e906SNikolay Aleksandrov 
1259263344e6SNikolay Aleksandrov 	vg = kzalloc(sizeof(struct net_bridge_vlan_group), GFP_KERNEL);
1260263344e6SNikolay Aleksandrov 	if (!vg)
12612594e906SNikolay Aleksandrov 		goto out;
12622594e906SNikolay Aleksandrov 
1263dcbdf135SVladimir Oltean 	ret = switchdev_port_attr_set(p->dev, &attr, extack);
1264404cdbf0SElad Raz 	if (ret && ret != -EOPNOTSUPP)
1265404cdbf0SElad Raz 		goto err_vlan_enabled;
1266404cdbf0SElad Raz 
1267263344e6SNikolay Aleksandrov 	ret = rhashtable_init(&vg->vlan_hash, &br_vlan_rht_params);
12682594e906SNikolay Aleksandrov 	if (ret)
12692594e906SNikolay Aleksandrov 		goto err_rhtbl;
1270efa5356bSRoopa Prabhu 	ret = vlan_tunnel_init(vg);
1271efa5356bSRoopa Prabhu 	if (ret)
1272efa5356bSRoopa Prabhu 		goto err_tunnel_init;
1273263344e6SNikolay Aleksandrov 	INIT_LIST_HEAD(&vg->vlan_list);
1274907b1e6eSNikolay Aleksandrov 	rcu_assign_pointer(p->vlgrp, vg);
12752594e906SNikolay Aleksandrov 	if (p->br->default_pvid) {
1276f418af63SNikolay Aleksandrov 		bool changed;
1277f418af63SNikolay Aleksandrov 
12782594e906SNikolay Aleksandrov 		ret = nbp_vlan_add(p, p->br->default_pvid,
12792594e906SNikolay Aleksandrov 				   BRIDGE_VLAN_INFO_PVID |
1280f418af63SNikolay Aleksandrov 				   BRIDGE_VLAN_INFO_UNTAGGED,
1281169327d5SPetr Machata 				   &changed, extack);
12822594e906SNikolay Aleksandrov 		if (ret)
12832594e906SNikolay Aleksandrov 			goto err_vlan_add;
1284f545923bSNikolay Aleksandrov 		br_vlan_notify(p->br, p, p->br->default_pvid, 0, RTM_NEWVLAN);
12852594e906SNikolay Aleksandrov 	}
12862594e906SNikolay Aleksandrov out:
12872594e906SNikolay Aleksandrov 	return ret;
12882594e906SNikolay Aleksandrov 
12892594e906SNikolay Aleksandrov err_vlan_add:
129007bc588fSIdo Schimmel 	RCU_INIT_POINTER(p->vlgrp, NULL);
129107bc588fSIdo Schimmel 	synchronize_rcu();
1292efa5356bSRoopa Prabhu 	vlan_tunnel_deinit(vg);
1293efa5356bSRoopa Prabhu err_tunnel_init:
1294efa5356bSRoopa Prabhu 	rhashtable_destroy(&vg->vlan_hash);
12952594e906SNikolay Aleksandrov err_rhtbl:
1296df2c4334SYotam Gigi err_vlan_enabled:
1297263344e6SNikolay Aleksandrov 	kfree(vg);
12982594e906SNikolay Aleksandrov 
12992594e906SNikolay Aleksandrov 	goto out;
13008580e211SToshiaki Makita }
13018580e211SToshiaki Makita 
13028adff41cSToshiaki Makita /* Must be protected by RTNL.
13038adff41cSToshiaki Makita  * Must be called with vid in range from 1 to 4094 inclusive.
1304f418af63SNikolay Aleksandrov  * changed must be true only if the vlan was created or updated
13058adff41cSToshiaki Makita  */
nbp_vlan_add(struct net_bridge_port * port,u16 vid,u16 flags,bool * changed,struct netlink_ext_ack * extack)1306f418af63SNikolay Aleksandrov int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags,
1307169327d5SPetr Machata 		 bool *changed, struct netlink_ext_ack *extack)
1308243a2e63SVlad Yasevich {
13092594e906SNikolay Aleksandrov 	struct net_bridge_vlan *vlan;
13102594e906SNikolay Aleksandrov 	int ret;
1311243a2e63SVlad Yasevich 
1312243a2e63SVlad Yasevich 	ASSERT_RTNL();
1313243a2e63SVlad Yasevich 
1314f418af63SNikolay Aleksandrov 	*changed = false;
1315907b1e6eSNikolay Aleksandrov 	vlan = br_vlan_find(nbp_vlan_group(port), vid);
13162594e906SNikolay Aleksandrov 	if (vlan) {
131727c5f74cSVladimir Oltean 		bool would_change = __vlan_flags_would_change(vlan, flags);
131827c5f74cSVladimir Oltean 
131927c5f74cSVladimir Oltean 		if (would_change) {
13207fbac984SIdo Schimmel 			/* Pass the flags to the hardware bridge */
13218d23a54fSVladimir Oltean 			ret = br_switchdev_port_vlan_add(port->dev, vid, flags,
13228d23a54fSVladimir Oltean 							 true, extack);
13237fbac984SIdo Schimmel 			if (ret && ret != -EOPNOTSUPP)
13247fbac984SIdo Schimmel 				return ret;
132527c5f74cSVladimir Oltean 		}
132627c5f74cSVladimir Oltean 
132727c5f74cSVladimir Oltean 		__vlan_flags_commit(vlan, flags);
132827c5f74cSVladimir Oltean 		*changed = would_change;
1329f418af63SNikolay Aleksandrov 
13302594e906SNikolay Aleksandrov 		return 0;
1331243a2e63SVlad Yasevich 	}
1332243a2e63SVlad Yasevich 
13332594e906SNikolay Aleksandrov 	vlan = kzalloc(sizeof(*vlan), GFP_KERNEL);
13342594e906SNikolay Aleksandrov 	if (!vlan)
13352594e906SNikolay Aleksandrov 		return -ENOMEM;
1336243a2e63SVlad Yasevich 
13372594e906SNikolay Aleksandrov 	vlan->vid = vid;
13382594e906SNikolay Aleksandrov 	vlan->port = port;
1339169327d5SPetr Machata 	ret = __vlan_add(vlan, flags, extack);
13402594e906SNikolay Aleksandrov 	if (ret)
13412594e906SNikolay Aleksandrov 		kfree(vlan);
1342f418af63SNikolay Aleksandrov 	else
1343f418af63SNikolay Aleksandrov 		*changed = true;
1344243a2e63SVlad Yasevich 
13452594e906SNikolay Aleksandrov 	return ret;
1346243a2e63SVlad Yasevich }
1347243a2e63SVlad Yasevich 
13488adff41cSToshiaki Makita /* Must be protected by RTNL.
13498adff41cSToshiaki Makita  * Must be called with vid in range from 1 to 4094 inclusive.
13508adff41cSToshiaki Makita  */
nbp_vlan_delete(struct net_bridge_port * port,u16 vid)1351243a2e63SVlad Yasevich int nbp_vlan_delete(struct net_bridge_port *port, u16 vid)
1352243a2e63SVlad Yasevich {
13532594e906SNikolay Aleksandrov 	struct net_bridge_vlan *v;
1354243a2e63SVlad Yasevich 
1355243a2e63SVlad Yasevich 	ASSERT_RTNL();
1356243a2e63SVlad Yasevich 
1357907b1e6eSNikolay Aleksandrov 	v = br_vlan_find(nbp_vlan_group(port), vid);
13582594e906SNikolay Aleksandrov 	if (!v)
13592594e906SNikolay Aleksandrov 		return -ENOENT;
1360424bb9c9SToshiaki Makita 	br_fdb_find_delete_local(port->br, port, port->dev->dev_addr, vid);
13611ea2d020SNikolay Aleksandrov 	br_fdb_delete_by_port(port->br, port, vid, 0);
1362bc9a25d2SVlad Yasevich 
13632594e906SNikolay Aleksandrov 	return __vlan_del(v);
1364243a2e63SVlad Yasevich }
1365243a2e63SVlad Yasevich 
nbp_vlan_flush(struct net_bridge_port * port)1366243a2e63SVlad Yasevich void nbp_vlan_flush(struct net_bridge_port *port)
1367243a2e63SVlad Yasevich {
1368f409d0edSNikolay Aleksandrov 	struct net_bridge_vlan_group *vg;
1369f409d0edSNikolay Aleksandrov 
1370243a2e63SVlad Yasevich 	ASSERT_RTNL();
1371243a2e63SVlad Yasevich 
1372f409d0edSNikolay Aleksandrov 	vg = nbp_vlan_group(port);
1373f545923bSNikolay Aleksandrov 	__vlan_flush(port->br, port, vg);
1374f409d0edSNikolay Aleksandrov 	RCU_INIT_POINTER(port->vlgrp, NULL);
1375f409d0edSNikolay Aleksandrov 	synchronize_rcu();
1376f409d0edSNikolay Aleksandrov 	__vlan_group_free(vg);
13775be5a2dfSVlad Yasevich }
1378a60c0903SNikolay Aleksandrov 
br_vlan_get_stats(const struct net_bridge_vlan * v,struct pcpu_sw_netstats * stats)1379a60c0903SNikolay Aleksandrov void br_vlan_get_stats(const struct net_bridge_vlan *v,
1380281cc284SHeiner Kallweit 		       struct pcpu_sw_netstats *stats)
1381a60c0903SNikolay Aleksandrov {
1382a60c0903SNikolay Aleksandrov 	int i;
1383a60c0903SNikolay Aleksandrov 
1384a60c0903SNikolay Aleksandrov 	memset(stats, 0, sizeof(*stats));
1385a60c0903SNikolay Aleksandrov 	for_each_possible_cpu(i) {
1386a60c0903SNikolay Aleksandrov 		u64 rxpackets, rxbytes, txpackets, txbytes;
1387281cc284SHeiner Kallweit 		struct pcpu_sw_netstats *cpu_stats;
1388a60c0903SNikolay Aleksandrov 		unsigned int start;
1389a60c0903SNikolay Aleksandrov 
1390a60c0903SNikolay Aleksandrov 		cpu_stats = per_cpu_ptr(v->stats, i);
1391a60c0903SNikolay Aleksandrov 		do {
1392d120d1a6SThomas Gleixner 			start = u64_stats_fetch_begin(&cpu_stats->syncp);
13939962acefSEric Dumazet 			rxpackets = u64_stats_read(&cpu_stats->rx_packets);
13949962acefSEric Dumazet 			rxbytes = u64_stats_read(&cpu_stats->rx_bytes);
13959962acefSEric Dumazet 			txbytes = u64_stats_read(&cpu_stats->tx_bytes);
13969962acefSEric Dumazet 			txpackets = u64_stats_read(&cpu_stats->tx_packets);
1397d120d1a6SThomas Gleixner 		} while (u64_stats_fetch_retry(&cpu_stats->syncp, start));
1398a60c0903SNikolay Aleksandrov 
13999962acefSEric Dumazet 		u64_stats_add(&stats->rx_packets, rxpackets);
14009962acefSEric Dumazet 		u64_stats_add(&stats->rx_bytes, rxbytes);
14019962acefSEric Dumazet 		u64_stats_add(&stats->tx_bytes, txbytes);
14029962acefSEric Dumazet 		u64_stats_add(&stats->tx_packets, txpackets);
1403a60c0903SNikolay Aleksandrov 	}
1404a60c0903SNikolay Aleksandrov }
14054d4fd361SPetr Machata 
br_vlan_get_pvid(const struct net_device * dev,u16 * p_pvid)140699f62a74SVladimir Oltean int br_vlan_get_pvid(const struct net_device *dev, u16 *p_pvid)
14074d4fd361SPetr Machata {
14084d4fd361SPetr Machata 	struct net_bridge_vlan_group *vg;
140999f62a74SVladimir Oltean 	struct net_bridge_port *p;
14104d4fd361SPetr Machata 
141199f62a74SVladimir Oltean 	ASSERT_RTNL();
141299f62a74SVladimir Oltean 	p = br_port_get_check_rtnl(dev);
14135a6db04cSIdo Schimmel 	if (p)
14145a6db04cSIdo Schimmel 		vg = nbp_vlan_group(p);
14155a6db04cSIdo Schimmel 	else if (netif_is_bridge_master(dev))
14164d4fd361SPetr Machata 		vg = br_vlan_group(netdev_priv(dev));
14174d4fd361SPetr Machata 	else
14184d4fd361SPetr Machata 		return -EINVAL;
14194d4fd361SPetr Machata 
14204d4fd361SPetr Machata 	*p_pvid = br_get_pvid(vg);
14214d4fd361SPetr Machata 	return 0;
14224d4fd361SPetr Machata }
14234d4fd361SPetr Machata EXPORT_SYMBOL_GPL(br_vlan_get_pvid);
14244d4fd361SPetr Machata 
br_vlan_get_pvid_rcu(const struct net_device * dev,u16 * p_pvid)14257582f5b7SPablo Neira Ayuso int br_vlan_get_pvid_rcu(const struct net_device *dev, u16 *p_pvid)
14267582f5b7SPablo Neira Ayuso {
142799f62a74SVladimir Oltean 	struct net_bridge_vlan_group *vg;
142899f62a74SVladimir Oltean 	struct net_bridge_port *p;
142999f62a74SVladimir Oltean 
143099f62a74SVladimir Oltean 	p = br_port_get_check_rcu(dev);
143199f62a74SVladimir Oltean 	if (p)
143299f62a74SVladimir Oltean 		vg = nbp_vlan_group_rcu(p);
143399f62a74SVladimir Oltean 	else if (netif_is_bridge_master(dev))
143499f62a74SVladimir Oltean 		vg = br_vlan_group_rcu(netdev_priv(dev));
143599f62a74SVladimir Oltean 	else
143699f62a74SVladimir Oltean 		return -EINVAL;
143799f62a74SVladimir Oltean 
143899f62a74SVladimir Oltean 	*p_pvid = br_get_pvid(vg);
143999f62a74SVladimir Oltean 	return 0;
14407582f5b7SPablo Neira Ayuso }
14417582f5b7SPablo Neira Ayuso EXPORT_SYMBOL_GPL(br_vlan_get_pvid_rcu);
14427582f5b7SPablo Neira Ayuso 
br_vlan_fill_forward_path_pvid(struct net_bridge * br,struct net_device_path_ctx * ctx,struct net_device_path * path)1443bcf2766bSFelix Fietkau void br_vlan_fill_forward_path_pvid(struct net_bridge *br,
1444bcf2766bSFelix Fietkau 				    struct net_device_path_ctx *ctx,
1445bcf2766bSFelix Fietkau 				    struct net_device_path *path)
1446bcf2766bSFelix Fietkau {
1447bcf2766bSFelix Fietkau 	struct net_bridge_vlan_group *vg;
1448bcf2766bSFelix Fietkau 	int idx = ctx->num_vlans - 1;
1449bcf2766bSFelix Fietkau 	u16 vid;
1450bcf2766bSFelix Fietkau 
1451bcf2766bSFelix Fietkau 	path->bridge.vlan_mode = DEV_PATH_BR_VLAN_KEEP;
1452bcf2766bSFelix Fietkau 
1453bcf2766bSFelix Fietkau 	if (!br_opt_get(br, BROPT_VLAN_ENABLED))
1454bcf2766bSFelix Fietkau 		return;
1455bcf2766bSFelix Fietkau 
1456bcf2766bSFelix Fietkau 	vg = br_vlan_group(br);
1457bcf2766bSFelix Fietkau 
1458bcf2766bSFelix Fietkau 	if (idx >= 0 &&
1459bcf2766bSFelix Fietkau 	    ctx->vlan[idx].proto == br->vlan_proto) {
1460bcf2766bSFelix Fietkau 		vid = ctx->vlan[idx].id;
1461bcf2766bSFelix Fietkau 	} else {
1462bcf2766bSFelix Fietkau 		path->bridge.vlan_mode = DEV_PATH_BR_VLAN_TAG;
1463bcf2766bSFelix Fietkau 		vid = br_get_pvid(vg);
1464bcf2766bSFelix Fietkau 	}
1465bcf2766bSFelix Fietkau 
1466bcf2766bSFelix Fietkau 	path->bridge.vlan_id = vid;
1467bcf2766bSFelix Fietkau 	path->bridge.vlan_proto = br->vlan_proto;
1468bcf2766bSFelix Fietkau }
1469bcf2766bSFelix Fietkau 
br_vlan_fill_forward_path_mode(struct net_bridge * br,struct net_bridge_port * dst,struct net_device_path * path)1470bcf2766bSFelix Fietkau int br_vlan_fill_forward_path_mode(struct net_bridge *br,
1471bcf2766bSFelix Fietkau 				   struct net_bridge_port *dst,
1472bcf2766bSFelix Fietkau 				   struct net_device_path *path)
1473bcf2766bSFelix Fietkau {
1474bcf2766bSFelix Fietkau 	struct net_bridge_vlan_group *vg;
1475bcf2766bSFelix Fietkau 	struct net_bridge_vlan *v;
1476bcf2766bSFelix Fietkau 
1477bcf2766bSFelix Fietkau 	if (!br_opt_get(br, BROPT_VLAN_ENABLED))
1478bcf2766bSFelix Fietkau 		return 0;
1479bcf2766bSFelix Fietkau 
1480bcf2766bSFelix Fietkau 	vg = nbp_vlan_group_rcu(dst);
1481bcf2766bSFelix Fietkau 	v = br_vlan_find(vg, path->bridge.vlan_id);
1482bcf2766bSFelix Fietkau 	if (!v || !br_vlan_should_use(v))
1483bcf2766bSFelix Fietkau 		return -EINVAL;
1484bcf2766bSFelix Fietkau 
1485bcf2766bSFelix Fietkau 	if (!(v->flags & BRIDGE_VLAN_INFO_UNTAGGED))
1486bcf2766bSFelix Fietkau 		return 0;
1487bcf2766bSFelix Fietkau 
1488bcf2766bSFelix Fietkau 	if (path->bridge.vlan_mode == DEV_PATH_BR_VLAN_TAG)
1489bcf2766bSFelix Fietkau 		path->bridge.vlan_mode = DEV_PATH_BR_VLAN_KEEP;
149026267bf9SFelix Fietkau 	else if (v->priv_flags & BR_VLFLAG_ADDED_BY_SWITCHDEV)
149126267bf9SFelix Fietkau 		path->bridge.vlan_mode = DEV_PATH_BR_VLAN_UNTAG_HW;
1492bcf2766bSFelix Fietkau 	else
1493bcf2766bSFelix Fietkau 		path->bridge.vlan_mode = DEV_PATH_BR_VLAN_UNTAG;
1494bcf2766bSFelix Fietkau 
1495bcf2766bSFelix Fietkau 	return 0;
1496bcf2766bSFelix Fietkau }
1497bcf2766bSFelix Fietkau 
br_vlan_get_info(const struct net_device * dev,u16 vid,struct bridge_vlan_info * p_vinfo)14984d4fd361SPetr Machata int br_vlan_get_info(const struct net_device *dev, u16 vid,
14994d4fd361SPetr Machata 		     struct bridge_vlan_info *p_vinfo)
15004d4fd361SPetr Machata {
15014d4fd361SPetr Machata 	struct net_bridge_vlan_group *vg;
15024d4fd361SPetr Machata 	struct net_bridge_vlan *v;
15034d4fd361SPetr Machata 	struct net_bridge_port *p;
15044d4fd361SPetr Machata 
15054d4fd361SPetr Machata 	ASSERT_RTNL();
15064d4fd361SPetr Machata 	p = br_port_get_check_rtnl(dev);
15074d4fd361SPetr Machata 	if (p)
15084d4fd361SPetr Machata 		vg = nbp_vlan_group(p);
15092b18d79eSPetr Machata 	else if (netif_is_bridge_master(dev))
15102b18d79eSPetr Machata 		vg = br_vlan_group(netdev_priv(dev));
15114d4fd361SPetr Machata 	else
15124d4fd361SPetr Machata 		return -EINVAL;
15134d4fd361SPetr Machata 
15144d4fd361SPetr Machata 	v = br_vlan_find(vg, vid);
15154d4fd361SPetr Machata 	if (!v)
15164d4fd361SPetr Machata 		return -ENOENT;
15174d4fd361SPetr Machata 
15184d4fd361SPetr Machata 	p_vinfo->vid = vid;
15194d4fd361SPetr Machata 	p_vinfo->flags = v->flags;
1520f40d9b20SVladimir Oltean 	if (vid == br_get_pvid(vg))
1521f40d9b20SVladimir Oltean 		p_vinfo->flags |= BRIDGE_VLAN_INFO_PVID;
15224d4fd361SPetr Machata 	return 0;
15234d4fd361SPetr Machata }
15244d4fd361SPetr Machata EXPORT_SYMBOL_GPL(br_vlan_get_info);
15259c0ec2e7SMike Manning 
br_vlan_get_info_rcu(const struct net_device * dev,u16 vid,struct bridge_vlan_info * p_vinfo)1526ee80dd2eSVladimir Oltean int br_vlan_get_info_rcu(const struct net_device *dev, u16 vid,
1527ee80dd2eSVladimir Oltean 			 struct bridge_vlan_info *p_vinfo)
1528ee80dd2eSVladimir Oltean {
1529ee80dd2eSVladimir Oltean 	struct net_bridge_vlan_group *vg;
1530ee80dd2eSVladimir Oltean 	struct net_bridge_vlan *v;
1531ee80dd2eSVladimir Oltean 	struct net_bridge_port *p;
1532ee80dd2eSVladimir Oltean 
1533ee80dd2eSVladimir Oltean 	p = br_port_get_check_rcu(dev);
1534ee80dd2eSVladimir Oltean 	if (p)
1535ee80dd2eSVladimir Oltean 		vg = nbp_vlan_group_rcu(p);
1536ee80dd2eSVladimir Oltean 	else if (netif_is_bridge_master(dev))
1537ee80dd2eSVladimir Oltean 		vg = br_vlan_group_rcu(netdev_priv(dev));
1538ee80dd2eSVladimir Oltean 	else
1539ee80dd2eSVladimir Oltean 		return -EINVAL;
1540ee80dd2eSVladimir Oltean 
1541ee80dd2eSVladimir Oltean 	v = br_vlan_find(vg, vid);
1542ee80dd2eSVladimir Oltean 	if (!v)
1543ee80dd2eSVladimir Oltean 		return -ENOENT;
1544ee80dd2eSVladimir Oltean 
1545ee80dd2eSVladimir Oltean 	p_vinfo->vid = vid;
1546ee80dd2eSVladimir Oltean 	p_vinfo->flags = v->flags;
1547ee80dd2eSVladimir Oltean 	if (vid == br_get_pvid(vg))
1548ee80dd2eSVladimir Oltean 		p_vinfo->flags |= BRIDGE_VLAN_INFO_PVID;
1549ee80dd2eSVladimir Oltean 	return 0;
1550ee80dd2eSVladimir Oltean }
1551ee80dd2eSVladimir Oltean EXPORT_SYMBOL_GPL(br_vlan_get_info_rcu);
1552ee80dd2eSVladimir Oltean 
br_vlan_is_bind_vlan_dev(const struct net_device * dev)15539c0ec2e7SMike Manning static int br_vlan_is_bind_vlan_dev(const struct net_device *dev)
15549c0ec2e7SMike Manning {
15559c0ec2e7SMike Manning 	return is_vlan_dev(dev) &&
15569c0ec2e7SMike Manning 		!!(vlan_dev_priv(dev)->flags & VLAN_FLAG_BRIDGE_BINDING);
15579c0ec2e7SMike Manning }
15589c0ec2e7SMike Manning 
br_vlan_is_bind_vlan_dev_fn(struct net_device * dev,__always_unused struct netdev_nested_priv * priv)15599c0ec2e7SMike Manning static int br_vlan_is_bind_vlan_dev_fn(struct net_device *dev,
1560eff74233STaehee Yoo 			       __always_unused struct netdev_nested_priv *priv)
15619c0ec2e7SMike Manning {
15629c0ec2e7SMike Manning 	return br_vlan_is_bind_vlan_dev(dev);
15639c0ec2e7SMike Manning }
15649c0ec2e7SMike Manning 
br_vlan_has_upper_bind_vlan_dev(struct net_device * dev)15659c0ec2e7SMike Manning static bool br_vlan_has_upper_bind_vlan_dev(struct net_device *dev)
15669c0ec2e7SMike Manning {
15679c0ec2e7SMike Manning 	int found;
15689c0ec2e7SMike Manning 
15699c0ec2e7SMike Manning 	rcu_read_lock();
15709c0ec2e7SMike Manning 	found = netdev_walk_all_upper_dev_rcu(dev, br_vlan_is_bind_vlan_dev_fn,
15719c0ec2e7SMike Manning 					      NULL);
15729c0ec2e7SMike Manning 	rcu_read_unlock();
15739c0ec2e7SMike Manning 
15749c0ec2e7SMike Manning 	return !!found;
15759c0ec2e7SMike Manning }
15769c0ec2e7SMike Manning 
15779c0ec2e7SMike Manning struct br_vlan_bind_walk_data {
15789c0ec2e7SMike Manning 	u16 vid;
15799c0ec2e7SMike Manning 	struct net_device *result;
15809c0ec2e7SMike Manning };
15819c0ec2e7SMike Manning 
br_vlan_match_bind_vlan_dev_fn(struct net_device * dev,struct netdev_nested_priv * priv)15829c0ec2e7SMike Manning static int br_vlan_match_bind_vlan_dev_fn(struct net_device *dev,
1583eff74233STaehee Yoo 					  struct netdev_nested_priv *priv)
15849c0ec2e7SMike Manning {
1585eff74233STaehee Yoo 	struct br_vlan_bind_walk_data *data = priv->data;
15869c0ec2e7SMike Manning 	int found = 0;
15879c0ec2e7SMike Manning 
15889c0ec2e7SMike Manning 	if (br_vlan_is_bind_vlan_dev(dev) &&
15899c0ec2e7SMike Manning 	    vlan_dev_priv(dev)->vlan_id == data->vid) {
15909c0ec2e7SMike Manning 		data->result = dev;
15919c0ec2e7SMike Manning 		found = 1;
15929c0ec2e7SMike Manning 	}
15939c0ec2e7SMike Manning 
15949c0ec2e7SMike Manning 	return found;
15959c0ec2e7SMike Manning }
15969c0ec2e7SMike Manning 
15979c0ec2e7SMike Manning static struct net_device *
br_vlan_get_upper_bind_vlan_dev(struct net_device * dev,u16 vid)15989c0ec2e7SMike Manning br_vlan_get_upper_bind_vlan_dev(struct net_device *dev, u16 vid)
15999c0ec2e7SMike Manning {
16009c0ec2e7SMike Manning 	struct br_vlan_bind_walk_data data = {
16019c0ec2e7SMike Manning 		.vid = vid,
16029c0ec2e7SMike Manning 	};
1603eff74233STaehee Yoo 	struct netdev_nested_priv priv = {
1604eff74233STaehee Yoo 		.data = (void *)&data,
1605eff74233STaehee Yoo 	};
16069c0ec2e7SMike Manning 
16079c0ec2e7SMike Manning 	rcu_read_lock();
16089c0ec2e7SMike Manning 	netdev_walk_all_upper_dev_rcu(dev, br_vlan_match_bind_vlan_dev_fn,
1609eff74233STaehee Yoo 				      &priv);
16109c0ec2e7SMike Manning 	rcu_read_unlock();
16119c0ec2e7SMike Manning 
16129c0ec2e7SMike Manning 	return data.result;
16139c0ec2e7SMike Manning }
16149c0ec2e7SMike Manning 
br_vlan_is_dev_up(const struct net_device * dev)16159c0ec2e7SMike Manning static bool br_vlan_is_dev_up(const struct net_device *dev)
16169c0ec2e7SMike Manning {
16179c0ec2e7SMike Manning 	return  !!(dev->flags & IFF_UP) && netif_oper_up(dev);
16189c0ec2e7SMike Manning }
16199c0ec2e7SMike Manning 
br_vlan_set_vlan_dev_state(const struct net_bridge * br,struct net_device * vlan_dev)16209c0ec2e7SMike Manning static void br_vlan_set_vlan_dev_state(const struct net_bridge *br,
16219c0ec2e7SMike Manning 				       struct net_device *vlan_dev)
16229c0ec2e7SMike Manning {
16239c0ec2e7SMike Manning 	u16 vid = vlan_dev_priv(vlan_dev)->vlan_id;
16249c0ec2e7SMike Manning 	struct net_bridge_vlan_group *vg;
16259c0ec2e7SMike Manning 	struct net_bridge_port *p;
16269c0ec2e7SMike Manning 	bool has_carrier = false;
16279c0ec2e7SMike Manning 
16288e1acd4fSMike Manning 	if (!netif_carrier_ok(br->dev)) {
16298e1acd4fSMike Manning 		netif_carrier_off(vlan_dev);
16308e1acd4fSMike Manning 		return;
16318e1acd4fSMike Manning 	}
16328e1acd4fSMike Manning 
16339c0ec2e7SMike Manning 	list_for_each_entry(p, &br->port_list, list) {
16349c0ec2e7SMike Manning 		vg = nbp_vlan_group(p);
16359c0ec2e7SMike Manning 		if (br_vlan_find(vg, vid) && br_vlan_is_dev_up(p->dev)) {
16369c0ec2e7SMike Manning 			has_carrier = true;
16379c0ec2e7SMike Manning 			break;
16389c0ec2e7SMike Manning 		}
16399c0ec2e7SMike Manning 	}
16409c0ec2e7SMike Manning 
16419c0ec2e7SMike Manning 	if (has_carrier)
16429c0ec2e7SMike Manning 		netif_carrier_on(vlan_dev);
16439c0ec2e7SMike Manning 	else
16449c0ec2e7SMike Manning 		netif_carrier_off(vlan_dev);
16459c0ec2e7SMike Manning }
16469c0ec2e7SMike Manning 
br_vlan_set_all_vlan_dev_state(struct net_bridge_port * p)16479c0ec2e7SMike Manning static void br_vlan_set_all_vlan_dev_state(struct net_bridge_port *p)
16489c0ec2e7SMike Manning {
16499c0ec2e7SMike Manning 	struct net_bridge_vlan_group *vg = nbp_vlan_group(p);
16509c0ec2e7SMike Manning 	struct net_bridge_vlan *vlan;
16519c0ec2e7SMike Manning 	struct net_device *vlan_dev;
16529c0ec2e7SMike Manning 
16539c0ec2e7SMike Manning 	list_for_each_entry(vlan, &vg->vlan_list, vlist) {
16549c0ec2e7SMike Manning 		vlan_dev = br_vlan_get_upper_bind_vlan_dev(p->br->dev,
16559c0ec2e7SMike Manning 							   vlan->vid);
16569c0ec2e7SMike Manning 		if (vlan_dev) {
16578e1acd4fSMike Manning 			if (br_vlan_is_dev_up(p->dev)) {
16588e1acd4fSMike Manning 				if (netif_carrier_ok(p->br->dev))
16599c0ec2e7SMike Manning 					netif_carrier_on(vlan_dev);
16608e1acd4fSMike Manning 			} else {
16619c0ec2e7SMike Manning 				br_vlan_set_vlan_dev_state(p->br, vlan_dev);
16629c0ec2e7SMike Manning 			}
16639c0ec2e7SMike Manning 		}
16649c0ec2e7SMike Manning 	}
16658e1acd4fSMike Manning }
16669c0ec2e7SMike Manning 
br_vlan_upper_change(struct net_device * dev,struct net_device * upper_dev,bool linking)16679c0ec2e7SMike Manning static void br_vlan_upper_change(struct net_device *dev,
16689c0ec2e7SMike Manning 				 struct net_device *upper_dev,
16699c0ec2e7SMike Manning 				 bool linking)
16709c0ec2e7SMike Manning {
16719c0ec2e7SMike Manning 	struct net_bridge *br = netdev_priv(dev);
16729c0ec2e7SMike Manning 
16739c0ec2e7SMike Manning 	if (!br_vlan_is_bind_vlan_dev(upper_dev))
16749c0ec2e7SMike Manning 		return;
16759c0ec2e7SMike Manning 
16769c0ec2e7SMike Manning 	if (linking) {
16779c0ec2e7SMike Manning 		br_vlan_set_vlan_dev_state(br, upper_dev);
16789c0ec2e7SMike Manning 		br_opt_toggle(br, BROPT_VLAN_BRIDGE_BINDING, true);
16799c0ec2e7SMike Manning 	} else {
16809c0ec2e7SMike Manning 		br_opt_toggle(br, BROPT_VLAN_BRIDGE_BINDING,
16819c0ec2e7SMike Manning 			      br_vlan_has_upper_bind_vlan_dev(dev));
16829c0ec2e7SMike Manning 	}
16839c0ec2e7SMike Manning }
16849c0ec2e7SMike Manning 
16858e1acd4fSMike Manning struct br_vlan_link_state_walk_data {
16868e1acd4fSMike Manning 	struct net_bridge *br;
16878e1acd4fSMike Manning };
16888e1acd4fSMike Manning 
br_vlan_link_state_change_fn(struct net_device * vlan_dev,struct netdev_nested_priv * priv)16898e1acd4fSMike Manning static int br_vlan_link_state_change_fn(struct net_device *vlan_dev,
1690eff74233STaehee Yoo 					struct netdev_nested_priv *priv)
16918e1acd4fSMike Manning {
1692eff74233STaehee Yoo 	struct br_vlan_link_state_walk_data *data = priv->data;
16938e1acd4fSMike Manning 
16948e1acd4fSMike Manning 	if (br_vlan_is_bind_vlan_dev(vlan_dev))
16958e1acd4fSMike Manning 		br_vlan_set_vlan_dev_state(data->br, vlan_dev);
16968e1acd4fSMike Manning 
16978e1acd4fSMike Manning 	return 0;
16988e1acd4fSMike Manning }
16998e1acd4fSMike Manning 
br_vlan_link_state_change(struct net_device * dev,struct net_bridge * br)17008e1acd4fSMike Manning static void br_vlan_link_state_change(struct net_device *dev,
17018e1acd4fSMike Manning 				      struct net_bridge *br)
17028e1acd4fSMike Manning {
17038e1acd4fSMike Manning 	struct br_vlan_link_state_walk_data data = {
17048e1acd4fSMike Manning 		.br = br
17058e1acd4fSMike Manning 	};
1706eff74233STaehee Yoo 	struct netdev_nested_priv priv = {
1707eff74233STaehee Yoo 		.data = (void *)&data,
1708eff74233STaehee Yoo 	};
17098e1acd4fSMike Manning 
17108e1acd4fSMike Manning 	rcu_read_lock();
17118e1acd4fSMike Manning 	netdev_walk_all_upper_dev_rcu(dev, br_vlan_link_state_change_fn,
1712eff74233STaehee Yoo 				      &priv);
17138e1acd4fSMike Manning 	rcu_read_unlock();
17148e1acd4fSMike Manning }
17158e1acd4fSMike Manning 
17169c0ec2e7SMike Manning /* Must be protected by RTNL. */
nbp_vlan_set_vlan_dev_state(struct net_bridge_port * p,u16 vid)171780900acdSMike Manning static void nbp_vlan_set_vlan_dev_state(struct net_bridge_port *p, u16 vid)
171880900acdSMike Manning {
171980900acdSMike Manning 	struct net_device *vlan_dev;
172080900acdSMike Manning 
172180900acdSMike Manning 	if (!br_opt_get(p->br, BROPT_VLAN_BRIDGE_BINDING))
172280900acdSMike Manning 		return;
172380900acdSMike Manning 
172480900acdSMike Manning 	vlan_dev = br_vlan_get_upper_bind_vlan_dev(p->br->dev, vid);
172580900acdSMike Manning 	if (vlan_dev)
172680900acdSMike Manning 		br_vlan_set_vlan_dev_state(p->br, vlan_dev);
172780900acdSMike Manning }
172880900acdSMike Manning 
172980900acdSMike Manning /* Must be protected by RTNL. */
br_vlan_bridge_event(struct net_device * dev,unsigned long event,void * ptr)1730091adf9bSNikolay Aleksandrov int br_vlan_bridge_event(struct net_device *dev, unsigned long event, void *ptr)
17319c0ec2e7SMike Manning {
17329c0ec2e7SMike Manning 	struct netdev_notifier_changeupper_info *info;
1733091adf9bSNikolay Aleksandrov 	struct net_bridge *br = netdev_priv(dev);
1734f545923bSNikolay Aleksandrov 	int vlcmd = 0, ret = 0;
1735f545923bSNikolay Aleksandrov 	bool changed = false;
17369c0ec2e7SMike Manning 
17379c0ec2e7SMike Manning 	switch (event) {
1738091adf9bSNikolay Aleksandrov 	case NETDEV_REGISTER:
1739091adf9bSNikolay Aleksandrov 		ret = br_vlan_add(br, br->default_pvid,
1740091adf9bSNikolay Aleksandrov 				  BRIDGE_VLAN_INFO_PVID |
1741091adf9bSNikolay Aleksandrov 				  BRIDGE_VLAN_INFO_UNTAGGED |
1742091adf9bSNikolay Aleksandrov 				  BRIDGE_VLAN_INFO_BRENTRY, &changed, NULL);
1743f545923bSNikolay Aleksandrov 		vlcmd = RTM_NEWVLAN;
1744091adf9bSNikolay Aleksandrov 		break;
1745091adf9bSNikolay Aleksandrov 	case NETDEV_UNREGISTER:
1746f545923bSNikolay Aleksandrov 		changed = !br_vlan_delete(br, br->default_pvid);
1747f545923bSNikolay Aleksandrov 		vlcmd = RTM_DELVLAN;
1748091adf9bSNikolay Aleksandrov 		break;
17499c0ec2e7SMike Manning 	case NETDEV_CHANGEUPPER:
17509c0ec2e7SMike Manning 		info = ptr;
17519c0ec2e7SMike Manning 		br_vlan_upper_change(dev, info->upper_dev, info->linking);
17529c0ec2e7SMike Manning 		break;
17538e1acd4fSMike Manning 
17548e1acd4fSMike Manning 	case NETDEV_CHANGE:
17558e1acd4fSMike Manning 	case NETDEV_UP:
17568e1acd4fSMike Manning 		if (!br_opt_get(br, BROPT_VLAN_BRIDGE_BINDING))
1757091adf9bSNikolay Aleksandrov 			break;
17588e1acd4fSMike Manning 		br_vlan_link_state_change(dev, br);
17598e1acd4fSMike Manning 		break;
17609c0ec2e7SMike Manning 	}
1761f545923bSNikolay Aleksandrov 	if (changed)
1762f545923bSNikolay Aleksandrov 		br_vlan_notify(br, NULL, br->default_pvid, 0, vlcmd);
1763091adf9bSNikolay Aleksandrov 
1764091adf9bSNikolay Aleksandrov 	return ret;
17659c0ec2e7SMike Manning }
17669c0ec2e7SMike Manning 
17679c0ec2e7SMike Manning /* Must be protected by RTNL. */
br_vlan_port_event(struct net_bridge_port * p,unsigned long event)17689c0ec2e7SMike Manning void br_vlan_port_event(struct net_bridge_port *p, unsigned long event)
17699c0ec2e7SMike Manning {
17709c0ec2e7SMike Manning 	if (!br_opt_get(p->br, BROPT_VLAN_BRIDGE_BINDING))
17719c0ec2e7SMike Manning 		return;
17729c0ec2e7SMike Manning 
17739c0ec2e7SMike Manning 	switch (event) {
17749c0ec2e7SMike Manning 	case NETDEV_CHANGE:
17759c0ec2e7SMike Manning 	case NETDEV_DOWN:
17769c0ec2e7SMike Manning 	case NETDEV_UP:
17779c0ec2e7SMike Manning 		br_vlan_set_all_vlan_dev_state(p);
17789c0ec2e7SMike Manning 		break;
17799c0ec2e7SMike Manning 	}
17809c0ec2e7SMike Manning }
17818dcea187SNikolay Aleksandrov 
br_vlan_stats_fill(struct sk_buff * skb,const struct net_bridge_vlan * v)178256d09976SNikolay Aleksandrov static bool br_vlan_stats_fill(struct sk_buff *skb,
178356d09976SNikolay Aleksandrov 			       const struct net_bridge_vlan *v)
178456d09976SNikolay Aleksandrov {
1785281cc284SHeiner Kallweit 	struct pcpu_sw_netstats stats;
178656d09976SNikolay Aleksandrov 	struct nlattr *nest;
178756d09976SNikolay Aleksandrov 
178856d09976SNikolay Aleksandrov 	nest = nla_nest_start(skb, BRIDGE_VLANDB_ENTRY_STATS);
178956d09976SNikolay Aleksandrov 	if (!nest)
179056d09976SNikolay Aleksandrov 		return false;
179156d09976SNikolay Aleksandrov 
179256d09976SNikolay Aleksandrov 	br_vlan_get_stats(v, &stats);
17939962acefSEric Dumazet 	if (nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_RX_BYTES,
17949962acefSEric Dumazet 			      u64_stats_read(&stats.rx_bytes),
179556d09976SNikolay Aleksandrov 			      BRIDGE_VLANDB_STATS_PAD) ||
179656d09976SNikolay Aleksandrov 	    nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_RX_PACKETS,
17979962acefSEric Dumazet 			      u64_stats_read(&stats.rx_packets),
17989962acefSEric Dumazet 			      BRIDGE_VLANDB_STATS_PAD) ||
17999962acefSEric Dumazet 	    nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_TX_BYTES,
18009962acefSEric Dumazet 			      u64_stats_read(&stats.tx_bytes),
180156d09976SNikolay Aleksandrov 			      BRIDGE_VLANDB_STATS_PAD) ||
180256d09976SNikolay Aleksandrov 	    nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_TX_PACKETS,
18039962acefSEric Dumazet 			      u64_stats_read(&stats.tx_packets),
18049962acefSEric Dumazet 			      BRIDGE_VLANDB_STATS_PAD))
180556d09976SNikolay Aleksandrov 		goto out_err;
180656d09976SNikolay Aleksandrov 
180756d09976SNikolay Aleksandrov 	nla_nest_end(skb, nest);
180856d09976SNikolay Aleksandrov 
180956d09976SNikolay Aleksandrov 	return true;
181056d09976SNikolay Aleksandrov 
181156d09976SNikolay Aleksandrov out_err:
181256d09976SNikolay Aleksandrov 	nla_nest_cancel(skb, nest);
181356d09976SNikolay Aleksandrov 	return false;
181456d09976SNikolay Aleksandrov }
181556d09976SNikolay Aleksandrov 
18167a53e718SNikolay Aleksandrov /* v_opts is used to dump the options which must be equal in the whole range */
br_vlan_fill_vids(struct sk_buff * skb,u16 vid,u16 vid_range,const struct net_bridge_vlan * v_opts,const struct net_bridge_port * p,u16 flags,bool dump_stats)18170ab55879SNikolay Aleksandrov static bool br_vlan_fill_vids(struct sk_buff *skb, u16 vid, u16 vid_range,
18187a53e718SNikolay Aleksandrov 			      const struct net_bridge_vlan *v_opts,
1819a1aee20dSPetr Machata 			      const struct net_bridge_port *p,
182056d09976SNikolay Aleksandrov 			      u16 flags,
182156d09976SNikolay Aleksandrov 			      bool dump_stats)
18228dcea187SNikolay Aleksandrov {
18238dcea187SNikolay Aleksandrov 	struct bridge_vlan_info info;
18248dcea187SNikolay Aleksandrov 	struct nlattr *nest;
18258dcea187SNikolay Aleksandrov 
18268dcea187SNikolay Aleksandrov 	nest = nla_nest_start(skb, BRIDGE_VLANDB_ENTRY);
18278dcea187SNikolay Aleksandrov 	if (!nest)
18288dcea187SNikolay Aleksandrov 		return false;
18298dcea187SNikolay Aleksandrov 
18308dcea187SNikolay Aleksandrov 	memset(&info, 0, sizeof(info));
18318dcea187SNikolay Aleksandrov 	info.vid = vid;
18328dcea187SNikolay Aleksandrov 	if (flags & BRIDGE_VLAN_INFO_UNTAGGED)
18338dcea187SNikolay Aleksandrov 		info.flags |= BRIDGE_VLAN_INFO_UNTAGGED;
18348dcea187SNikolay Aleksandrov 	if (flags & BRIDGE_VLAN_INFO_PVID)
18358dcea187SNikolay Aleksandrov 		info.flags |= BRIDGE_VLAN_INFO_PVID;
18368dcea187SNikolay Aleksandrov 
18378dcea187SNikolay Aleksandrov 	if (nla_put(skb, BRIDGE_VLANDB_ENTRY_INFO, sizeof(info), &info))
18388dcea187SNikolay Aleksandrov 		goto out_err;
18398dcea187SNikolay Aleksandrov 
18400ab55879SNikolay Aleksandrov 	if (vid_range && vid < vid_range &&
18410ab55879SNikolay Aleksandrov 	    !(flags & BRIDGE_VLAN_INFO_PVID) &&
18420ab55879SNikolay Aleksandrov 	    nla_put_u16(skb, BRIDGE_VLANDB_ENTRY_RANGE, vid_range))
18430ab55879SNikolay Aleksandrov 		goto out_err;
18440ab55879SNikolay Aleksandrov 
184556d09976SNikolay Aleksandrov 	if (v_opts) {
1846a1aee20dSPetr Machata 		if (!br_vlan_opts_fill(skb, v_opts, p))
18477a53e718SNikolay Aleksandrov 			goto out_err;
18487a53e718SNikolay Aleksandrov 
184956d09976SNikolay Aleksandrov 		if (dump_stats && !br_vlan_stats_fill(skb, v_opts))
185056d09976SNikolay Aleksandrov 			goto out_err;
185156d09976SNikolay Aleksandrov 	}
185256d09976SNikolay Aleksandrov 
18538dcea187SNikolay Aleksandrov 	nla_nest_end(skb, nest);
18548dcea187SNikolay Aleksandrov 
18558dcea187SNikolay Aleksandrov 	return true;
18568dcea187SNikolay Aleksandrov 
18578dcea187SNikolay Aleksandrov out_err:
18588dcea187SNikolay Aleksandrov 	nla_nest_cancel(skb, nest);
18598dcea187SNikolay Aleksandrov 	return false;
18608dcea187SNikolay Aleksandrov }
18618dcea187SNikolay Aleksandrov 
rtnl_vlan_nlmsg_size(void)1862cf5bddb9SNikolay Aleksandrov static size_t rtnl_vlan_nlmsg_size(void)
1863cf5bddb9SNikolay Aleksandrov {
1864cf5bddb9SNikolay Aleksandrov 	return NLMSG_ALIGN(sizeof(struct br_vlan_msg))
1865cf5bddb9SNikolay Aleksandrov 		+ nla_total_size(0) /* BRIDGE_VLANDB_ENTRY */
1866cf5bddb9SNikolay Aleksandrov 		+ nla_total_size(sizeof(u16)) /* BRIDGE_VLANDB_ENTRY_RANGE */
18677a53e718SNikolay Aleksandrov 		+ nla_total_size(sizeof(struct bridge_vlan_info)) /* BRIDGE_VLANDB_ENTRY_INFO */
18687a53e718SNikolay Aleksandrov 		+ br_vlan_opts_nl_size(); /* bridge vlan options */
1869cf5bddb9SNikolay Aleksandrov }
1870cf5bddb9SNikolay Aleksandrov 
br_vlan_notify(const struct net_bridge * br,const struct net_bridge_port * p,u16 vid,u16 vid_range,int cmd)1871cf5bddb9SNikolay Aleksandrov void br_vlan_notify(const struct net_bridge *br,
1872cf5bddb9SNikolay Aleksandrov 		    const struct net_bridge_port *p,
1873cf5bddb9SNikolay Aleksandrov 		    u16 vid, u16 vid_range,
1874cf5bddb9SNikolay Aleksandrov 		    int cmd)
1875cf5bddb9SNikolay Aleksandrov {
1876cf5bddb9SNikolay Aleksandrov 	struct net_bridge_vlan_group *vg;
18777a53e718SNikolay Aleksandrov 	struct net_bridge_vlan *v = NULL;
1878cf5bddb9SNikolay Aleksandrov 	struct br_vlan_msg *bvm;
1879cf5bddb9SNikolay Aleksandrov 	struct nlmsghdr *nlh;
1880cf5bddb9SNikolay Aleksandrov 	struct sk_buff *skb;
1881cf5bddb9SNikolay Aleksandrov 	int err = -ENOBUFS;
1882cf5bddb9SNikolay Aleksandrov 	struct net *net;
1883cf5bddb9SNikolay Aleksandrov 	u16 flags = 0;
1884cf5bddb9SNikolay Aleksandrov 	int ifindex;
1885cf5bddb9SNikolay Aleksandrov 
1886cf5bddb9SNikolay Aleksandrov 	/* right now notifications are done only with rtnl held */
1887cf5bddb9SNikolay Aleksandrov 	ASSERT_RTNL();
1888cf5bddb9SNikolay Aleksandrov 
1889cf5bddb9SNikolay Aleksandrov 	if (p) {
1890cf5bddb9SNikolay Aleksandrov 		ifindex = p->dev->ifindex;
1891cf5bddb9SNikolay Aleksandrov 		vg = nbp_vlan_group(p);
1892cf5bddb9SNikolay Aleksandrov 		net = dev_net(p->dev);
1893cf5bddb9SNikolay Aleksandrov 	} else {
1894cf5bddb9SNikolay Aleksandrov 		ifindex = br->dev->ifindex;
1895cf5bddb9SNikolay Aleksandrov 		vg = br_vlan_group(br);
1896cf5bddb9SNikolay Aleksandrov 		net = dev_net(br->dev);
1897cf5bddb9SNikolay Aleksandrov 	}
1898cf5bddb9SNikolay Aleksandrov 
1899cf5bddb9SNikolay Aleksandrov 	skb = nlmsg_new(rtnl_vlan_nlmsg_size(), GFP_KERNEL);
1900cf5bddb9SNikolay Aleksandrov 	if (!skb)
1901cf5bddb9SNikolay Aleksandrov 		goto out_err;
1902cf5bddb9SNikolay Aleksandrov 
1903cf5bddb9SNikolay Aleksandrov 	err = -EMSGSIZE;
1904cf5bddb9SNikolay Aleksandrov 	nlh = nlmsg_put(skb, 0, 0, cmd, sizeof(*bvm), 0);
1905cf5bddb9SNikolay Aleksandrov 	if (!nlh)
1906cf5bddb9SNikolay Aleksandrov 		goto out_err;
1907cf5bddb9SNikolay Aleksandrov 	bvm = nlmsg_data(nlh);
1908cf5bddb9SNikolay Aleksandrov 	memset(bvm, 0, sizeof(*bvm));
1909cf5bddb9SNikolay Aleksandrov 	bvm->family = AF_BRIDGE;
1910cf5bddb9SNikolay Aleksandrov 	bvm->ifindex = ifindex;
1911cf5bddb9SNikolay Aleksandrov 
1912cf5bddb9SNikolay Aleksandrov 	switch (cmd) {
1913cf5bddb9SNikolay Aleksandrov 	case RTM_NEWVLAN:
1914cf5bddb9SNikolay Aleksandrov 		/* need to find the vlan due to flags/options */
1915cf5bddb9SNikolay Aleksandrov 		v = br_vlan_find(vg, vid);
1916cf5bddb9SNikolay Aleksandrov 		if (!v || !br_vlan_should_use(v))
1917cf5bddb9SNikolay Aleksandrov 			goto out_kfree;
1918cf5bddb9SNikolay Aleksandrov 
1919cf5bddb9SNikolay Aleksandrov 		flags = v->flags;
1920cf5bddb9SNikolay Aleksandrov 		if (br_get_pvid(vg) == v->vid)
1921cf5bddb9SNikolay Aleksandrov 			flags |= BRIDGE_VLAN_INFO_PVID;
1922cf5bddb9SNikolay Aleksandrov 		break;
1923cf5bddb9SNikolay Aleksandrov 	case RTM_DELVLAN:
1924cf5bddb9SNikolay Aleksandrov 		break;
1925cf5bddb9SNikolay Aleksandrov 	default:
1926cf5bddb9SNikolay Aleksandrov 		goto out_kfree;
1927cf5bddb9SNikolay Aleksandrov 	}
1928cf5bddb9SNikolay Aleksandrov 
1929a1aee20dSPetr Machata 	if (!br_vlan_fill_vids(skb, vid, vid_range, v, p, flags, false))
1930cf5bddb9SNikolay Aleksandrov 		goto out_err;
1931cf5bddb9SNikolay Aleksandrov 
1932cf5bddb9SNikolay Aleksandrov 	nlmsg_end(skb, nlh);
1933cf5bddb9SNikolay Aleksandrov 	rtnl_notify(skb, net, 0, RTNLGRP_BRVLAN, NULL, GFP_KERNEL);
1934cf5bddb9SNikolay Aleksandrov 	return;
1935cf5bddb9SNikolay Aleksandrov 
1936cf5bddb9SNikolay Aleksandrov out_err:
1937cf5bddb9SNikolay Aleksandrov 	rtnl_set_sk_err(net, RTNLGRP_BRVLAN, err);
1938cf5bddb9SNikolay Aleksandrov out_kfree:
1939cf5bddb9SNikolay Aleksandrov 	kfree_skb(skb);
1940cf5bddb9SNikolay Aleksandrov }
1941cf5bddb9SNikolay Aleksandrov 
19420ab55879SNikolay Aleksandrov /* check if v_curr can enter a range ending in range_end */
br_vlan_can_enter_range(const struct net_bridge_vlan * v_curr,const struct net_bridge_vlan * range_end)1943a5d29ae2SNikolay Aleksandrov bool br_vlan_can_enter_range(const struct net_bridge_vlan *v_curr,
19440ab55879SNikolay Aleksandrov 			     const struct net_bridge_vlan *range_end)
19450ab55879SNikolay Aleksandrov {
19460ab55879SNikolay Aleksandrov 	return v_curr->vid - range_end->vid == 1 &&
19477a53e718SNikolay Aleksandrov 	       range_end->flags == v_curr->flags &&
194899f7c5e0SNikolay Aleksandrov 	       br_vlan_opts_eq_range(v_curr, range_end);
19490ab55879SNikolay Aleksandrov }
19500ab55879SNikolay Aleksandrov 
br_vlan_dump_dev(const struct net_device * dev,struct sk_buff * skb,struct netlink_callback * cb,u32 dump_flags)19518dcea187SNikolay Aleksandrov static int br_vlan_dump_dev(const struct net_device *dev,
19528dcea187SNikolay Aleksandrov 			    struct sk_buff *skb,
195356d09976SNikolay Aleksandrov 			    struct netlink_callback *cb,
195456d09976SNikolay Aleksandrov 			    u32 dump_flags)
19558dcea187SNikolay Aleksandrov {
19560ab55879SNikolay Aleksandrov 	struct net_bridge_vlan *v, *range_start = NULL, *range_end = NULL;
1957743a53d9SNikolay Aleksandrov 	bool dump_global = !!(dump_flags & BRIDGE_VLANDB_DUMPF_GLOBAL);
195856d09976SNikolay Aleksandrov 	bool dump_stats = !!(dump_flags & BRIDGE_VLANDB_DUMPF_STATS);
19598dcea187SNikolay Aleksandrov 	struct net_bridge_vlan_group *vg;
19608dcea187SNikolay Aleksandrov 	int idx = 0, s_idx = cb->args[1];
19618dcea187SNikolay Aleksandrov 	struct nlmsghdr *nlh = NULL;
19628dcea187SNikolay Aleksandrov 	struct net_bridge_port *p;
19638dcea187SNikolay Aleksandrov 	struct br_vlan_msg *bvm;
19648dcea187SNikolay Aleksandrov 	struct net_bridge *br;
19658dcea187SNikolay Aleksandrov 	int err = 0;
19668dcea187SNikolay Aleksandrov 	u16 pvid;
19678dcea187SNikolay Aleksandrov 
19688dcea187SNikolay Aleksandrov 	if (!netif_is_bridge_master(dev) && !netif_is_bridge_port(dev))
19698dcea187SNikolay Aleksandrov 		return -EINVAL;
19708dcea187SNikolay Aleksandrov 
19718dcea187SNikolay Aleksandrov 	if (netif_is_bridge_master(dev)) {
19728dcea187SNikolay Aleksandrov 		br = netdev_priv(dev);
19738dcea187SNikolay Aleksandrov 		vg = br_vlan_group_rcu(br);
19748dcea187SNikolay Aleksandrov 		p = NULL;
19758dcea187SNikolay Aleksandrov 	} else {
1976743a53d9SNikolay Aleksandrov 		/* global options are dumped only for bridge devices */
1977743a53d9SNikolay Aleksandrov 		if (dump_global)
1978743a53d9SNikolay Aleksandrov 			return 0;
1979743a53d9SNikolay Aleksandrov 
19808dcea187SNikolay Aleksandrov 		p = br_port_get_rcu(dev);
19818dcea187SNikolay Aleksandrov 		if (WARN_ON(!p))
19828dcea187SNikolay Aleksandrov 			return -EINVAL;
19838dcea187SNikolay Aleksandrov 		vg = nbp_vlan_group_rcu(p);
19848dcea187SNikolay Aleksandrov 		br = p->br;
19858dcea187SNikolay Aleksandrov 	}
19868dcea187SNikolay Aleksandrov 
19878dcea187SNikolay Aleksandrov 	if (!vg)
19888dcea187SNikolay Aleksandrov 		return 0;
19898dcea187SNikolay Aleksandrov 
19908dcea187SNikolay Aleksandrov 	nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
19918dcea187SNikolay Aleksandrov 			RTM_NEWVLAN, sizeof(*bvm), NLM_F_MULTI);
19928dcea187SNikolay Aleksandrov 	if (!nlh)
19938dcea187SNikolay Aleksandrov 		return -EMSGSIZE;
19948dcea187SNikolay Aleksandrov 	bvm = nlmsg_data(nlh);
19958dcea187SNikolay Aleksandrov 	memset(bvm, 0, sizeof(*bvm));
19968dcea187SNikolay Aleksandrov 	bvm->family = PF_BRIDGE;
19978dcea187SNikolay Aleksandrov 	bvm->ifindex = dev->ifindex;
19988dcea187SNikolay Aleksandrov 	pvid = br_get_pvid(vg);
19998dcea187SNikolay Aleksandrov 
20000ab55879SNikolay Aleksandrov 	/* idx must stay at range's beginning until it is filled in */
20018dcea187SNikolay Aleksandrov 	list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
2002743a53d9SNikolay Aleksandrov 		if (!dump_global && !br_vlan_should_use(v))
20038dcea187SNikolay Aleksandrov 			continue;
20040ab55879SNikolay Aleksandrov 		if (idx < s_idx) {
20050ab55879SNikolay Aleksandrov 			idx++;
20060ab55879SNikolay Aleksandrov 			continue;
20070ab55879SNikolay Aleksandrov 		}
20080ab55879SNikolay Aleksandrov 
20090ab55879SNikolay Aleksandrov 		if (!range_start) {
20100ab55879SNikolay Aleksandrov 			range_start = v;
20110ab55879SNikolay Aleksandrov 			range_end = v;
20120ab55879SNikolay Aleksandrov 			continue;
20130ab55879SNikolay Aleksandrov 		}
20140ab55879SNikolay Aleksandrov 
2015743a53d9SNikolay Aleksandrov 		if (dump_global) {
2016743a53d9SNikolay Aleksandrov 			if (br_vlan_global_opts_can_enter_range(v, range_end))
20176c4110d9SNikolay Aleksandrov 				goto update_end;
2018743a53d9SNikolay Aleksandrov 			if (!br_vlan_global_opts_fill(skb, range_start->vid,
2019743a53d9SNikolay Aleksandrov 						      range_end->vid,
2020743a53d9SNikolay Aleksandrov 						      range_start)) {
2021743a53d9SNikolay Aleksandrov 				err = -EMSGSIZE;
2022743a53d9SNikolay Aleksandrov 				break;
2023743a53d9SNikolay Aleksandrov 			}
2024743a53d9SNikolay Aleksandrov 			/* advance number of filled vlans */
2025743a53d9SNikolay Aleksandrov 			idx += range_end->vid - range_start->vid + 1;
2026743a53d9SNikolay Aleksandrov 
2027743a53d9SNikolay Aleksandrov 			range_start = v;
2028743a53d9SNikolay Aleksandrov 		} else if (dump_stats || v->vid == pvid ||
202956d09976SNikolay Aleksandrov 			   !br_vlan_can_enter_range(v, range_end)) {
203056d09976SNikolay Aleksandrov 			u16 vlan_flags = br_vlan_flags(range_start, pvid);
20310ab55879SNikolay Aleksandrov 
20320ab55879SNikolay Aleksandrov 			if (!br_vlan_fill_vids(skb, range_start->vid,
20337a53e718SNikolay Aleksandrov 					       range_end->vid, range_start,
2034a1aee20dSPetr Machata 					       p, vlan_flags, dump_stats)) {
20358dcea187SNikolay Aleksandrov 				err = -EMSGSIZE;
20368dcea187SNikolay Aleksandrov 				break;
20378dcea187SNikolay Aleksandrov 			}
20380ab55879SNikolay Aleksandrov 			/* advance number of filled vlans */
20390ab55879SNikolay Aleksandrov 			idx += range_end->vid - range_start->vid + 1;
20400ab55879SNikolay Aleksandrov 
20410ab55879SNikolay Aleksandrov 			range_start = v;
20428dcea187SNikolay Aleksandrov 		}
20436c4110d9SNikolay Aleksandrov update_end:
20440ab55879SNikolay Aleksandrov 		range_end = v;
20450ab55879SNikolay Aleksandrov 	}
20460ab55879SNikolay Aleksandrov 
20470ab55879SNikolay Aleksandrov 	/* err will be 0 and range_start will be set in 3 cases here:
20480ab55879SNikolay Aleksandrov 	 * - first vlan (range_start == range_end)
20490ab55879SNikolay Aleksandrov 	 * - last vlan (range_start == range_end, not in range)
20500ab55879SNikolay Aleksandrov 	 * - last vlan range (range_start != range_end, in range)
20510ab55879SNikolay Aleksandrov 	 */
2052743a53d9SNikolay Aleksandrov 	if (!err && range_start) {
2053743a53d9SNikolay Aleksandrov 		if (dump_global &&
2054743a53d9SNikolay Aleksandrov 		    !br_vlan_global_opts_fill(skb, range_start->vid,
2055743a53d9SNikolay Aleksandrov 					      range_end->vid, range_start))
2056743a53d9SNikolay Aleksandrov 			err = -EMSGSIZE;
2057743a53d9SNikolay Aleksandrov 		else if (!dump_global &&
2058743a53d9SNikolay Aleksandrov 			 !br_vlan_fill_vids(skb, range_start->vid,
2059743a53d9SNikolay Aleksandrov 					    range_end->vid, range_start,
2060a1aee20dSPetr Machata 					    p, br_vlan_flags(range_start, pvid),
206156d09976SNikolay Aleksandrov 					    dump_stats))
20620ab55879SNikolay Aleksandrov 			err = -EMSGSIZE;
2063743a53d9SNikolay Aleksandrov 	}
20640ab55879SNikolay Aleksandrov 
20650ab55879SNikolay Aleksandrov 	cb->args[1] = err ? idx : 0;
20660ab55879SNikolay Aleksandrov 
20678dcea187SNikolay Aleksandrov 	nlmsg_end(skb, nlh);
20688dcea187SNikolay Aleksandrov 
20698dcea187SNikolay Aleksandrov 	return err;
20708dcea187SNikolay Aleksandrov }
20718dcea187SNikolay Aleksandrov 
207256d09976SNikolay Aleksandrov static const struct nla_policy br_vlan_db_dump_pol[BRIDGE_VLANDB_DUMP_MAX + 1] = {
207356d09976SNikolay Aleksandrov 	[BRIDGE_VLANDB_DUMP_FLAGS] = { .type = NLA_U32 },
207456d09976SNikolay Aleksandrov };
207556d09976SNikolay Aleksandrov 
br_vlan_rtm_dump(struct sk_buff * skb,struct netlink_callback * cb)20768dcea187SNikolay Aleksandrov static int br_vlan_rtm_dump(struct sk_buff *skb, struct netlink_callback *cb)
20778dcea187SNikolay Aleksandrov {
207856d09976SNikolay Aleksandrov 	struct nlattr *dtb[BRIDGE_VLANDB_DUMP_MAX + 1];
20798dcea187SNikolay Aleksandrov 	int idx = 0, err = 0, s_idx = cb->args[0];
20808dcea187SNikolay Aleksandrov 	struct net *net = sock_net(skb->sk);
20818dcea187SNikolay Aleksandrov 	struct br_vlan_msg *bvm;
20828dcea187SNikolay Aleksandrov 	struct net_device *dev;
208356d09976SNikolay Aleksandrov 	u32 dump_flags = 0;
20848dcea187SNikolay Aleksandrov 
208556d09976SNikolay Aleksandrov 	err = nlmsg_parse(cb->nlh, sizeof(*bvm), dtb, BRIDGE_VLANDB_DUMP_MAX,
208656d09976SNikolay Aleksandrov 			  br_vlan_db_dump_pol, cb->extack);
20878dcea187SNikolay Aleksandrov 	if (err < 0)
20888dcea187SNikolay Aleksandrov 		return err;
20898dcea187SNikolay Aleksandrov 
20908dcea187SNikolay Aleksandrov 	bvm = nlmsg_data(cb->nlh);
209156d09976SNikolay Aleksandrov 	if (dtb[BRIDGE_VLANDB_DUMP_FLAGS])
209256d09976SNikolay Aleksandrov 		dump_flags = nla_get_u32(dtb[BRIDGE_VLANDB_DUMP_FLAGS]);
20938dcea187SNikolay Aleksandrov 
20948dcea187SNikolay Aleksandrov 	rcu_read_lock();
20958dcea187SNikolay Aleksandrov 	if (bvm->ifindex) {
20968dcea187SNikolay Aleksandrov 		dev = dev_get_by_index_rcu(net, bvm->ifindex);
20978dcea187SNikolay Aleksandrov 		if (!dev) {
20988dcea187SNikolay Aleksandrov 			err = -ENODEV;
20998dcea187SNikolay Aleksandrov 			goto out_err;
21008dcea187SNikolay Aleksandrov 		}
210156d09976SNikolay Aleksandrov 		err = br_vlan_dump_dev(dev, skb, cb, dump_flags);
2102dcb2c5c6SNikolay Aleksandrov 		/* if the dump completed without an error we return 0 here */
2103dcb2c5c6SNikolay Aleksandrov 		if (err != -EMSGSIZE)
21048dcea187SNikolay Aleksandrov 			goto out_err;
21058dcea187SNikolay Aleksandrov 	} else {
21068dcea187SNikolay Aleksandrov 		for_each_netdev_rcu(net, dev) {
21078dcea187SNikolay Aleksandrov 			if (idx < s_idx)
21088dcea187SNikolay Aleksandrov 				goto skip;
21098dcea187SNikolay Aleksandrov 
211056d09976SNikolay Aleksandrov 			err = br_vlan_dump_dev(dev, skb, cb, dump_flags);
21118dcea187SNikolay Aleksandrov 			if (err == -EMSGSIZE)
21128dcea187SNikolay Aleksandrov 				break;
21138dcea187SNikolay Aleksandrov skip:
21148dcea187SNikolay Aleksandrov 			idx++;
21158dcea187SNikolay Aleksandrov 		}
21168dcea187SNikolay Aleksandrov 	}
21178dcea187SNikolay Aleksandrov 	cb->args[0] = idx;
21188dcea187SNikolay Aleksandrov 	rcu_read_unlock();
21198dcea187SNikolay Aleksandrov 
21208dcea187SNikolay Aleksandrov 	return skb->len;
21218dcea187SNikolay Aleksandrov 
21228dcea187SNikolay Aleksandrov out_err:
21238dcea187SNikolay Aleksandrov 	rcu_read_unlock();
21248dcea187SNikolay Aleksandrov 
21258dcea187SNikolay Aleksandrov 	return err;
21268dcea187SNikolay Aleksandrov }
21278dcea187SNikolay Aleksandrov 
2128f26b2965SNikolay Aleksandrov static const struct nla_policy br_vlan_db_policy[BRIDGE_VLANDB_ENTRY_MAX + 1] = {
21298140860cSJohannes Berg 	[BRIDGE_VLANDB_ENTRY_INFO]	=
21308140860cSJohannes Berg 		NLA_POLICY_EXACT_LEN(sizeof(struct bridge_vlan_info)),
21310ab55879SNikolay Aleksandrov 	[BRIDGE_VLANDB_ENTRY_RANGE]	= { .type = NLA_U16 },
2132a580c76dSNikolay Aleksandrov 	[BRIDGE_VLANDB_ENTRY_STATE]	= { .type = NLA_U8 },
2133fa388f29SNikolay Aleksandrov 	[BRIDGE_VLANDB_ENTRY_TUNNEL_INFO] = { .type = NLA_NESTED },
21342796d846SNikolay Aleksandrov 	[BRIDGE_VLANDB_ENTRY_MCAST_ROUTER]	= { .type = NLA_U8 },
2135a1aee20dSPetr Machata 	[BRIDGE_VLANDB_ENTRY_MCAST_N_GROUPS]	= { .type = NLA_REJECT },
2136a1aee20dSPetr Machata 	[BRIDGE_VLANDB_ENTRY_MCAST_MAX_GROUPS]	= { .type = NLA_U32 },
2137*83f6d600SIdo Schimmel 	[BRIDGE_VLANDB_ENTRY_NEIGH_SUPPRESS]	= NLA_POLICY_MAX(NLA_U8, 1),
2138f26b2965SNikolay Aleksandrov };
2139f26b2965SNikolay Aleksandrov 
br_vlan_rtm_process_one(struct net_device * dev,const struct nlattr * attr,int cmd,struct netlink_ext_ack * extack)2140f26b2965SNikolay Aleksandrov static int br_vlan_rtm_process_one(struct net_device *dev,
2141f26b2965SNikolay Aleksandrov 				   const struct nlattr *attr,
2142f26b2965SNikolay Aleksandrov 				   int cmd, struct netlink_ext_ack *extack)
2143f26b2965SNikolay Aleksandrov {
21440ab55879SNikolay Aleksandrov 	struct bridge_vlan_info *vinfo, vrange_end, *vinfo_last = NULL;
2145f26b2965SNikolay Aleksandrov 	struct nlattr *tb[BRIDGE_VLANDB_ENTRY_MAX + 1];
2146a5d29ae2SNikolay Aleksandrov 	bool changed = false, skip_processing = false;
2147f26b2965SNikolay Aleksandrov 	struct net_bridge_vlan_group *vg;
2148f26b2965SNikolay Aleksandrov 	struct net_bridge_port *p = NULL;
2149f26b2965SNikolay Aleksandrov 	int err = 0, cmdmap = 0;
2150f26b2965SNikolay Aleksandrov 	struct net_bridge *br;
2151f26b2965SNikolay Aleksandrov 
2152f26b2965SNikolay Aleksandrov 	if (netif_is_bridge_master(dev)) {
2153f26b2965SNikolay Aleksandrov 		br = netdev_priv(dev);
2154f26b2965SNikolay Aleksandrov 		vg = br_vlan_group(br);
2155f26b2965SNikolay Aleksandrov 	} else {
2156f26b2965SNikolay Aleksandrov 		p = br_port_get_rtnl(dev);
2157f26b2965SNikolay Aleksandrov 		if (WARN_ON(!p))
2158f26b2965SNikolay Aleksandrov 			return -ENODEV;
2159f26b2965SNikolay Aleksandrov 		br = p->br;
2160f26b2965SNikolay Aleksandrov 		vg = nbp_vlan_group(p);
2161f26b2965SNikolay Aleksandrov 	}
2162f26b2965SNikolay Aleksandrov 
2163f26b2965SNikolay Aleksandrov 	if (WARN_ON(!vg))
2164f26b2965SNikolay Aleksandrov 		return -ENODEV;
2165f26b2965SNikolay Aleksandrov 
2166f26b2965SNikolay Aleksandrov 	err = nla_parse_nested(tb, BRIDGE_VLANDB_ENTRY_MAX, attr,
2167f26b2965SNikolay Aleksandrov 			       br_vlan_db_policy, extack);
2168f26b2965SNikolay Aleksandrov 	if (err)
2169f26b2965SNikolay Aleksandrov 		return err;
2170f26b2965SNikolay Aleksandrov 
2171f26b2965SNikolay Aleksandrov 	if (!tb[BRIDGE_VLANDB_ENTRY_INFO]) {
2172f26b2965SNikolay Aleksandrov 		NL_SET_ERR_MSG_MOD(extack, "Missing vlan entry info");
2173f26b2965SNikolay Aleksandrov 		return -EINVAL;
2174f26b2965SNikolay Aleksandrov 	}
21750ab55879SNikolay Aleksandrov 	memset(&vrange_end, 0, sizeof(vrange_end));
2176f26b2965SNikolay Aleksandrov 
2177f26b2965SNikolay Aleksandrov 	vinfo = nla_data(tb[BRIDGE_VLANDB_ENTRY_INFO]);
2178f26b2965SNikolay Aleksandrov 	if (vinfo->flags & (BRIDGE_VLAN_INFO_RANGE_BEGIN |
2179f26b2965SNikolay Aleksandrov 			    BRIDGE_VLAN_INFO_RANGE_END)) {
2180f26b2965SNikolay Aleksandrov 		NL_SET_ERR_MSG_MOD(extack, "Old-style vlan ranges are not allowed when using RTM vlan calls");
2181f26b2965SNikolay Aleksandrov 		return -EINVAL;
2182f26b2965SNikolay Aleksandrov 	}
2183f26b2965SNikolay Aleksandrov 	if (!br_vlan_valid_id(vinfo->vid, extack))
2184f26b2965SNikolay Aleksandrov 		return -EINVAL;
2185f26b2965SNikolay Aleksandrov 
21860ab55879SNikolay Aleksandrov 	if (tb[BRIDGE_VLANDB_ENTRY_RANGE]) {
21870ab55879SNikolay Aleksandrov 		vrange_end.vid = nla_get_u16(tb[BRIDGE_VLANDB_ENTRY_RANGE]);
21880ab55879SNikolay Aleksandrov 		/* validate user-provided flags without RANGE_BEGIN */
21890ab55879SNikolay Aleksandrov 		vrange_end.flags = BRIDGE_VLAN_INFO_RANGE_END | vinfo->flags;
21900ab55879SNikolay Aleksandrov 		vinfo->flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN;
21910ab55879SNikolay Aleksandrov 
21920ab55879SNikolay Aleksandrov 		/* vinfo_last is the range start, vinfo the range end */
21930ab55879SNikolay Aleksandrov 		vinfo_last = vinfo;
21940ab55879SNikolay Aleksandrov 		vinfo = &vrange_end;
21950ab55879SNikolay Aleksandrov 
21960ab55879SNikolay Aleksandrov 		if (!br_vlan_valid_id(vinfo->vid, extack) ||
21970ab55879SNikolay Aleksandrov 		    !br_vlan_valid_range(vinfo, vinfo_last, extack))
21980ab55879SNikolay Aleksandrov 			return -EINVAL;
21990ab55879SNikolay Aleksandrov 	}
22000ab55879SNikolay Aleksandrov 
2201f26b2965SNikolay Aleksandrov 	switch (cmd) {
2202f26b2965SNikolay Aleksandrov 	case RTM_NEWVLAN:
2203f26b2965SNikolay Aleksandrov 		cmdmap = RTM_SETLINK;
2204a5d29ae2SNikolay Aleksandrov 		skip_processing = !!(vinfo->flags & BRIDGE_VLAN_INFO_ONLY_OPTS);
2205f26b2965SNikolay Aleksandrov 		break;
2206adb3ce9bSNikolay Aleksandrov 	case RTM_DELVLAN:
2207adb3ce9bSNikolay Aleksandrov 		cmdmap = RTM_DELLINK;
2208adb3ce9bSNikolay Aleksandrov 		break;
2209f26b2965SNikolay Aleksandrov 	}
2210f26b2965SNikolay Aleksandrov 
2211a5d29ae2SNikolay Aleksandrov 	if (!skip_processing) {
2212a5d29ae2SNikolay Aleksandrov 		struct bridge_vlan_info *tmp_last = vinfo_last;
2213a5d29ae2SNikolay Aleksandrov 
2214a5d29ae2SNikolay Aleksandrov 		/* br_process_vlan_info may overwrite vinfo_last */
2215a5d29ae2SNikolay Aleksandrov 		err = br_process_vlan_info(br, p, cmdmap, vinfo, &tmp_last,
2216a5d29ae2SNikolay Aleksandrov 					   &changed, extack);
2217a5d29ae2SNikolay Aleksandrov 
2218a5d29ae2SNikolay Aleksandrov 		/* notify first if anything changed */
2219f26b2965SNikolay Aleksandrov 		if (changed)
2220f26b2965SNikolay Aleksandrov 			br_ifinfo_notify(cmdmap, br, p);
2221f26b2965SNikolay Aleksandrov 
2222a5d29ae2SNikolay Aleksandrov 		if (err)
2223a5d29ae2SNikolay Aleksandrov 			return err;
2224a5d29ae2SNikolay Aleksandrov 	}
2225a5d29ae2SNikolay Aleksandrov 
2226a5d29ae2SNikolay Aleksandrov 	/* deal with options */
2227a5d29ae2SNikolay Aleksandrov 	if (cmd == RTM_NEWVLAN) {
2228a5d29ae2SNikolay Aleksandrov 		struct net_bridge_vlan *range_start, *range_end;
2229a5d29ae2SNikolay Aleksandrov 
2230a5d29ae2SNikolay Aleksandrov 		if (vinfo_last) {
2231a5d29ae2SNikolay Aleksandrov 			range_start = br_vlan_find(vg, vinfo_last->vid);
2232a5d29ae2SNikolay Aleksandrov 			range_end = br_vlan_find(vg, vinfo->vid);
2233a5d29ae2SNikolay Aleksandrov 		} else {
2234a5d29ae2SNikolay Aleksandrov 			range_start = br_vlan_find(vg, vinfo->vid);
2235a5d29ae2SNikolay Aleksandrov 			range_end = range_start;
2236a5d29ae2SNikolay Aleksandrov 		}
2237a5d29ae2SNikolay Aleksandrov 
2238a5d29ae2SNikolay Aleksandrov 		err = br_vlan_process_options(br, p, range_start, range_end,
2239a5d29ae2SNikolay Aleksandrov 					      tb, extack);
2240a5d29ae2SNikolay Aleksandrov 	}
2241a5d29ae2SNikolay Aleksandrov 
2242f26b2965SNikolay Aleksandrov 	return err;
2243f26b2965SNikolay Aleksandrov }
2244f26b2965SNikolay Aleksandrov 
br_vlan_rtm_process(struct sk_buff * skb,struct nlmsghdr * nlh,struct netlink_ext_ack * extack)2245f26b2965SNikolay Aleksandrov static int br_vlan_rtm_process(struct sk_buff *skb, struct nlmsghdr *nlh,
2246f26b2965SNikolay Aleksandrov 			       struct netlink_ext_ack *extack)
2247f26b2965SNikolay Aleksandrov {
2248f26b2965SNikolay Aleksandrov 	struct net *net = sock_net(skb->sk);
2249f26b2965SNikolay Aleksandrov 	struct br_vlan_msg *bvm;
2250f26b2965SNikolay Aleksandrov 	struct net_device *dev;
2251f26b2965SNikolay Aleksandrov 	struct nlattr *attr;
2252f26b2965SNikolay Aleksandrov 	int err, vlans = 0;
2253f26b2965SNikolay Aleksandrov 	int rem;
2254f26b2965SNikolay Aleksandrov 
2255f26b2965SNikolay Aleksandrov 	/* this should validate the header and check for remaining bytes */
2256f26b2965SNikolay Aleksandrov 	err = nlmsg_parse(nlh, sizeof(*bvm), NULL, BRIDGE_VLANDB_MAX, NULL,
2257f26b2965SNikolay Aleksandrov 			  extack);
2258f26b2965SNikolay Aleksandrov 	if (err < 0)
2259f26b2965SNikolay Aleksandrov 		return err;
2260f26b2965SNikolay Aleksandrov 
2261f26b2965SNikolay Aleksandrov 	bvm = nlmsg_data(nlh);
2262f26b2965SNikolay Aleksandrov 	dev = __dev_get_by_index(net, bvm->ifindex);
2263f26b2965SNikolay Aleksandrov 	if (!dev)
2264f26b2965SNikolay Aleksandrov 		return -ENODEV;
2265f26b2965SNikolay Aleksandrov 
2266f26b2965SNikolay Aleksandrov 	if (!netif_is_bridge_master(dev) && !netif_is_bridge_port(dev)) {
2267f26b2965SNikolay Aleksandrov 		NL_SET_ERR_MSG_MOD(extack, "The device is not a valid bridge or bridge port");
2268f26b2965SNikolay Aleksandrov 		return -EINVAL;
2269f26b2965SNikolay Aleksandrov 	}
2270f26b2965SNikolay Aleksandrov 
2271f26b2965SNikolay Aleksandrov 	nlmsg_for_each_attr(attr, nlh, sizeof(*bvm), rem) {
227247ecd2dbSNikolay Aleksandrov 		switch (nla_type(attr)) {
227347ecd2dbSNikolay Aleksandrov 		case BRIDGE_VLANDB_ENTRY:
227447ecd2dbSNikolay Aleksandrov 			err = br_vlan_rtm_process_one(dev, attr,
227547ecd2dbSNikolay Aleksandrov 						      nlh->nlmsg_type,
227647ecd2dbSNikolay Aleksandrov 						      extack);
227747ecd2dbSNikolay Aleksandrov 			break;
227847ecd2dbSNikolay Aleksandrov 		case BRIDGE_VLANDB_GLOBAL_OPTIONS:
227947ecd2dbSNikolay Aleksandrov 			err = br_vlan_rtm_process_global_options(dev, attr,
228047ecd2dbSNikolay Aleksandrov 								 nlh->nlmsg_type,
228147ecd2dbSNikolay Aleksandrov 								 extack);
228247ecd2dbSNikolay Aleksandrov 			break;
228347ecd2dbSNikolay Aleksandrov 		default:
2284f26b2965SNikolay Aleksandrov 			continue;
228547ecd2dbSNikolay Aleksandrov 		}
2286f26b2965SNikolay Aleksandrov 
2287f26b2965SNikolay Aleksandrov 		vlans++;
2288f26b2965SNikolay Aleksandrov 		if (err)
2289f26b2965SNikolay Aleksandrov 			break;
2290f26b2965SNikolay Aleksandrov 	}
2291f26b2965SNikolay Aleksandrov 	if (!vlans) {
2292f26b2965SNikolay Aleksandrov 		NL_SET_ERR_MSG_MOD(extack, "No vlans found to process");
2293f26b2965SNikolay Aleksandrov 		err = -EINVAL;
2294f26b2965SNikolay Aleksandrov 	}
2295f26b2965SNikolay Aleksandrov 
2296f26b2965SNikolay Aleksandrov 	return err;
2297f26b2965SNikolay Aleksandrov }
2298f26b2965SNikolay Aleksandrov 
br_vlan_rtnl_init(void)22998dcea187SNikolay Aleksandrov void br_vlan_rtnl_init(void)
23008dcea187SNikolay Aleksandrov {
23018dcea187SNikolay Aleksandrov 	rtnl_register_module(THIS_MODULE, PF_BRIDGE, RTM_GETVLAN, NULL,
23028dcea187SNikolay Aleksandrov 			     br_vlan_rtm_dump, 0);
2303f26b2965SNikolay Aleksandrov 	rtnl_register_module(THIS_MODULE, PF_BRIDGE, RTM_NEWVLAN,
2304f26b2965SNikolay Aleksandrov 			     br_vlan_rtm_process, NULL, 0);
2305adb3ce9bSNikolay Aleksandrov 	rtnl_register_module(THIS_MODULE, PF_BRIDGE, RTM_DELVLAN,
2306adb3ce9bSNikolay Aleksandrov 			     br_vlan_rtm_process, NULL, 0);
23078dcea187SNikolay Aleksandrov }
23088dcea187SNikolay Aleksandrov 
br_vlan_rtnl_uninit(void)23098dcea187SNikolay Aleksandrov void br_vlan_rtnl_uninit(void)
23108dcea187SNikolay Aleksandrov {
23118dcea187SNikolay Aleksandrov 	rtnl_unregister(PF_BRIDGE, RTM_GETVLAN);
2312f26b2965SNikolay Aleksandrov 	rtnl_unregister(PF_BRIDGE, RTM_NEWVLAN);
2313adb3ce9bSNikolay Aleksandrov 	rtnl_unregister(PF_BRIDGE, RTM_DELVLAN);
23148dcea187SNikolay Aleksandrov }
2315