xref: /OK3568_Linux_fs/kernel/net/bridge/br_mdb.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #include <linux/err.h>
3*4882a593Smuzhiyun #include <linux/igmp.h>
4*4882a593Smuzhiyun #include <linux/kernel.h>
5*4882a593Smuzhiyun #include <linux/netdevice.h>
6*4882a593Smuzhiyun #include <linux/rculist.h>
7*4882a593Smuzhiyun #include <linux/skbuff.h>
8*4882a593Smuzhiyun #include <linux/if_ether.h>
9*4882a593Smuzhiyun #include <net/ip.h>
10*4882a593Smuzhiyun #include <net/netlink.h>
11*4882a593Smuzhiyun #include <net/switchdev.h>
12*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
13*4882a593Smuzhiyun #include <net/ipv6.h>
14*4882a593Smuzhiyun #include <net/addrconf.h>
15*4882a593Smuzhiyun #endif
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #include "br_private.h"
18*4882a593Smuzhiyun 
br_rports_fill_info(struct sk_buff * skb,struct netlink_callback * cb,struct net_device * dev)19*4882a593Smuzhiyun static int br_rports_fill_info(struct sk_buff *skb, struct netlink_callback *cb,
20*4882a593Smuzhiyun 			       struct net_device *dev)
21*4882a593Smuzhiyun {
22*4882a593Smuzhiyun 	struct net_bridge *br = netdev_priv(dev);
23*4882a593Smuzhiyun 	struct net_bridge_port *p;
24*4882a593Smuzhiyun 	struct nlattr *nest, *port_nest;
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun 	if (!br->multicast_router || hlist_empty(&br->router_list))
27*4882a593Smuzhiyun 		return 0;
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun 	nest = nla_nest_start_noflag(skb, MDBA_ROUTER);
30*4882a593Smuzhiyun 	if (nest == NULL)
31*4882a593Smuzhiyun 		return -EMSGSIZE;
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun 	hlist_for_each_entry_rcu(p, &br->router_list, rlist) {
34*4882a593Smuzhiyun 		if (!p)
35*4882a593Smuzhiyun 			continue;
36*4882a593Smuzhiyun 		port_nest = nla_nest_start_noflag(skb, MDBA_ROUTER_PORT);
37*4882a593Smuzhiyun 		if (!port_nest)
38*4882a593Smuzhiyun 			goto fail;
39*4882a593Smuzhiyun 		if (nla_put_nohdr(skb, sizeof(u32), &p->dev->ifindex) ||
40*4882a593Smuzhiyun 		    nla_put_u32(skb, MDBA_ROUTER_PATTR_TIMER,
41*4882a593Smuzhiyun 				br_timer_value(&p->multicast_router_timer)) ||
42*4882a593Smuzhiyun 		    nla_put_u8(skb, MDBA_ROUTER_PATTR_TYPE,
43*4882a593Smuzhiyun 			       p->multicast_router)) {
44*4882a593Smuzhiyun 			nla_nest_cancel(skb, port_nest);
45*4882a593Smuzhiyun 			goto fail;
46*4882a593Smuzhiyun 		}
47*4882a593Smuzhiyun 		nla_nest_end(skb, port_nest);
48*4882a593Smuzhiyun 	}
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 	nla_nest_end(skb, nest);
51*4882a593Smuzhiyun 	return 0;
52*4882a593Smuzhiyun fail:
53*4882a593Smuzhiyun 	nla_nest_cancel(skb, nest);
54*4882a593Smuzhiyun 	return -EMSGSIZE;
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun 
__mdb_entry_fill_flags(struct br_mdb_entry * e,unsigned char flags)57*4882a593Smuzhiyun static void __mdb_entry_fill_flags(struct br_mdb_entry *e, unsigned char flags)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun 	e->state = flags & MDB_PG_FLAGS_PERMANENT;
60*4882a593Smuzhiyun 	e->flags = 0;
61*4882a593Smuzhiyun 	if (flags & MDB_PG_FLAGS_OFFLOAD)
62*4882a593Smuzhiyun 		e->flags |= MDB_FLAGS_OFFLOAD;
63*4882a593Smuzhiyun 	if (flags & MDB_PG_FLAGS_FAST_LEAVE)
64*4882a593Smuzhiyun 		e->flags |= MDB_FLAGS_FAST_LEAVE;
65*4882a593Smuzhiyun 	if (flags & MDB_PG_FLAGS_STAR_EXCL)
66*4882a593Smuzhiyun 		e->flags |= MDB_FLAGS_STAR_EXCL;
67*4882a593Smuzhiyun 	if (flags & MDB_PG_FLAGS_BLOCKED)
68*4882a593Smuzhiyun 		e->flags |= MDB_FLAGS_BLOCKED;
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun 
__mdb_entry_to_br_ip(struct br_mdb_entry * entry,struct br_ip * ip,struct nlattr ** mdb_attrs)71*4882a593Smuzhiyun static void __mdb_entry_to_br_ip(struct br_mdb_entry *entry, struct br_ip *ip,
72*4882a593Smuzhiyun 				 struct nlattr **mdb_attrs)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun 	memset(ip, 0, sizeof(struct br_ip));
75*4882a593Smuzhiyun 	ip->vid = entry->vid;
76*4882a593Smuzhiyun 	ip->proto = entry->addr.proto;
77*4882a593Smuzhiyun 	switch (ip->proto) {
78*4882a593Smuzhiyun 	case htons(ETH_P_IP):
79*4882a593Smuzhiyun 		ip->dst.ip4 = entry->addr.u.ip4;
80*4882a593Smuzhiyun 		if (mdb_attrs && mdb_attrs[MDBE_ATTR_SOURCE])
81*4882a593Smuzhiyun 			ip->src.ip4 = nla_get_in_addr(mdb_attrs[MDBE_ATTR_SOURCE]);
82*4882a593Smuzhiyun 		break;
83*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
84*4882a593Smuzhiyun 	case htons(ETH_P_IPV6):
85*4882a593Smuzhiyun 		ip->dst.ip6 = entry->addr.u.ip6;
86*4882a593Smuzhiyun 		if (mdb_attrs && mdb_attrs[MDBE_ATTR_SOURCE])
87*4882a593Smuzhiyun 			ip->src.ip6 = nla_get_in6_addr(mdb_attrs[MDBE_ATTR_SOURCE]);
88*4882a593Smuzhiyun 		break;
89*4882a593Smuzhiyun #endif
90*4882a593Smuzhiyun 	}
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun 
__mdb_fill_srcs(struct sk_buff * skb,struct net_bridge_port_group * p)94*4882a593Smuzhiyun static int __mdb_fill_srcs(struct sk_buff *skb,
95*4882a593Smuzhiyun 			   struct net_bridge_port_group *p)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun 	struct net_bridge_group_src *ent;
98*4882a593Smuzhiyun 	struct nlattr *nest, *nest_ent;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	if (hlist_empty(&p->src_list))
101*4882a593Smuzhiyun 		return 0;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	nest = nla_nest_start(skb, MDBA_MDB_EATTR_SRC_LIST);
104*4882a593Smuzhiyun 	if (!nest)
105*4882a593Smuzhiyun 		return -EMSGSIZE;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	hlist_for_each_entry_rcu(ent, &p->src_list, node,
108*4882a593Smuzhiyun 				 lockdep_is_held(&p->key.port->br->multicast_lock)) {
109*4882a593Smuzhiyun 		nest_ent = nla_nest_start(skb, MDBA_MDB_SRCLIST_ENTRY);
110*4882a593Smuzhiyun 		if (!nest_ent)
111*4882a593Smuzhiyun 			goto out_cancel_err;
112*4882a593Smuzhiyun 		switch (ent->addr.proto) {
113*4882a593Smuzhiyun 		case htons(ETH_P_IP):
114*4882a593Smuzhiyun 			if (nla_put_in_addr(skb, MDBA_MDB_SRCATTR_ADDRESS,
115*4882a593Smuzhiyun 					    ent->addr.src.ip4)) {
116*4882a593Smuzhiyun 				nla_nest_cancel(skb, nest_ent);
117*4882a593Smuzhiyun 				goto out_cancel_err;
118*4882a593Smuzhiyun 			}
119*4882a593Smuzhiyun 			break;
120*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
121*4882a593Smuzhiyun 		case htons(ETH_P_IPV6):
122*4882a593Smuzhiyun 			if (nla_put_in6_addr(skb, MDBA_MDB_SRCATTR_ADDRESS,
123*4882a593Smuzhiyun 					     &ent->addr.src.ip6)) {
124*4882a593Smuzhiyun 				nla_nest_cancel(skb, nest_ent);
125*4882a593Smuzhiyun 				goto out_cancel_err;
126*4882a593Smuzhiyun 			}
127*4882a593Smuzhiyun 			break;
128*4882a593Smuzhiyun #endif
129*4882a593Smuzhiyun 		default:
130*4882a593Smuzhiyun 			nla_nest_cancel(skb, nest_ent);
131*4882a593Smuzhiyun 			continue;
132*4882a593Smuzhiyun 		}
133*4882a593Smuzhiyun 		if (nla_put_u32(skb, MDBA_MDB_SRCATTR_TIMER,
134*4882a593Smuzhiyun 				br_timer_value(&ent->timer))) {
135*4882a593Smuzhiyun 			nla_nest_cancel(skb, nest_ent);
136*4882a593Smuzhiyun 			goto out_cancel_err;
137*4882a593Smuzhiyun 		}
138*4882a593Smuzhiyun 		nla_nest_end(skb, nest_ent);
139*4882a593Smuzhiyun 	}
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	nla_nest_end(skb, nest);
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	return 0;
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun out_cancel_err:
146*4882a593Smuzhiyun 	nla_nest_cancel(skb, nest);
147*4882a593Smuzhiyun 	return -EMSGSIZE;
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun 
__mdb_fill_info(struct sk_buff * skb,struct net_bridge_mdb_entry * mp,struct net_bridge_port_group * p)150*4882a593Smuzhiyun static int __mdb_fill_info(struct sk_buff *skb,
151*4882a593Smuzhiyun 			   struct net_bridge_mdb_entry *mp,
152*4882a593Smuzhiyun 			   struct net_bridge_port_group *p)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun 	bool dump_srcs_mode = false;
155*4882a593Smuzhiyun 	struct timer_list *mtimer;
156*4882a593Smuzhiyun 	struct nlattr *nest_ent;
157*4882a593Smuzhiyun 	struct br_mdb_entry e;
158*4882a593Smuzhiyun 	u8 flags = 0;
159*4882a593Smuzhiyun 	int ifindex;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	memset(&e, 0, sizeof(e));
162*4882a593Smuzhiyun 	if (p) {
163*4882a593Smuzhiyun 		ifindex = p->key.port->dev->ifindex;
164*4882a593Smuzhiyun 		mtimer = &p->timer;
165*4882a593Smuzhiyun 		flags = p->flags;
166*4882a593Smuzhiyun 	} else {
167*4882a593Smuzhiyun 		ifindex = mp->br->dev->ifindex;
168*4882a593Smuzhiyun 		mtimer = &mp->timer;
169*4882a593Smuzhiyun 	}
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	__mdb_entry_fill_flags(&e, flags);
172*4882a593Smuzhiyun 	e.ifindex = ifindex;
173*4882a593Smuzhiyun 	e.vid = mp->addr.vid;
174*4882a593Smuzhiyun 	if (mp->addr.proto == htons(ETH_P_IP))
175*4882a593Smuzhiyun 		e.addr.u.ip4 = mp->addr.dst.ip4;
176*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
177*4882a593Smuzhiyun 	if (mp->addr.proto == htons(ETH_P_IPV6))
178*4882a593Smuzhiyun 		e.addr.u.ip6 = mp->addr.dst.ip6;
179*4882a593Smuzhiyun #endif
180*4882a593Smuzhiyun 	e.addr.proto = mp->addr.proto;
181*4882a593Smuzhiyun 	nest_ent = nla_nest_start_noflag(skb,
182*4882a593Smuzhiyun 					 MDBA_MDB_ENTRY_INFO);
183*4882a593Smuzhiyun 	if (!nest_ent)
184*4882a593Smuzhiyun 		return -EMSGSIZE;
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	if (nla_put_nohdr(skb, sizeof(e), &e) ||
187*4882a593Smuzhiyun 	    nla_put_u32(skb,
188*4882a593Smuzhiyun 			MDBA_MDB_EATTR_TIMER,
189*4882a593Smuzhiyun 			br_timer_value(mtimer)))
190*4882a593Smuzhiyun 		goto nest_err;
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	switch (mp->addr.proto) {
193*4882a593Smuzhiyun 	case htons(ETH_P_IP):
194*4882a593Smuzhiyun 		dump_srcs_mode = !!(mp->br->multicast_igmp_version == 3);
195*4882a593Smuzhiyun 		if (mp->addr.src.ip4) {
196*4882a593Smuzhiyun 			if (nla_put_in_addr(skb, MDBA_MDB_EATTR_SOURCE,
197*4882a593Smuzhiyun 					    mp->addr.src.ip4))
198*4882a593Smuzhiyun 				goto nest_err;
199*4882a593Smuzhiyun 			break;
200*4882a593Smuzhiyun 		}
201*4882a593Smuzhiyun 		break;
202*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
203*4882a593Smuzhiyun 	case htons(ETH_P_IPV6):
204*4882a593Smuzhiyun 		dump_srcs_mode = !!(mp->br->multicast_mld_version == 2);
205*4882a593Smuzhiyun 		if (!ipv6_addr_any(&mp->addr.src.ip6)) {
206*4882a593Smuzhiyun 			if (nla_put_in6_addr(skb, MDBA_MDB_EATTR_SOURCE,
207*4882a593Smuzhiyun 					     &mp->addr.src.ip6))
208*4882a593Smuzhiyun 				goto nest_err;
209*4882a593Smuzhiyun 			break;
210*4882a593Smuzhiyun 		}
211*4882a593Smuzhiyun 		break;
212*4882a593Smuzhiyun #endif
213*4882a593Smuzhiyun 	}
214*4882a593Smuzhiyun 	if (p) {
215*4882a593Smuzhiyun 		if (nla_put_u8(skb, MDBA_MDB_EATTR_RTPROT, p->rt_protocol))
216*4882a593Smuzhiyun 			goto nest_err;
217*4882a593Smuzhiyun 		if (dump_srcs_mode &&
218*4882a593Smuzhiyun 		    (__mdb_fill_srcs(skb, p) ||
219*4882a593Smuzhiyun 		     nla_put_u8(skb, MDBA_MDB_EATTR_GROUP_MODE,
220*4882a593Smuzhiyun 				p->filter_mode)))
221*4882a593Smuzhiyun 			goto nest_err;
222*4882a593Smuzhiyun 	}
223*4882a593Smuzhiyun 	nla_nest_end(skb, nest_ent);
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	return 0;
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun nest_err:
228*4882a593Smuzhiyun 	nla_nest_cancel(skb, nest_ent);
229*4882a593Smuzhiyun 	return -EMSGSIZE;
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun 
br_mdb_fill_info(struct sk_buff * skb,struct netlink_callback * cb,struct net_device * dev)232*4882a593Smuzhiyun static int br_mdb_fill_info(struct sk_buff *skb, struct netlink_callback *cb,
233*4882a593Smuzhiyun 			    struct net_device *dev)
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun 	int idx = 0, s_idx = cb->args[1], err = 0, pidx = 0, s_pidx = cb->args[2];
236*4882a593Smuzhiyun 	struct net_bridge *br = netdev_priv(dev);
237*4882a593Smuzhiyun 	struct net_bridge_mdb_entry *mp;
238*4882a593Smuzhiyun 	struct nlattr *nest, *nest2;
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	if (!br_opt_get(br, BROPT_MULTICAST_ENABLED))
241*4882a593Smuzhiyun 		return 0;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	nest = nla_nest_start_noflag(skb, MDBA_MDB);
244*4882a593Smuzhiyun 	if (nest == NULL)
245*4882a593Smuzhiyun 		return -EMSGSIZE;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	hlist_for_each_entry_rcu(mp, &br->mdb_list, mdb_node) {
248*4882a593Smuzhiyun 		struct net_bridge_port_group *p;
249*4882a593Smuzhiyun 		struct net_bridge_port_group __rcu **pp;
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 		if (idx < s_idx)
252*4882a593Smuzhiyun 			goto skip;
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 		nest2 = nla_nest_start_noflag(skb, MDBA_MDB_ENTRY);
255*4882a593Smuzhiyun 		if (!nest2) {
256*4882a593Smuzhiyun 			err = -EMSGSIZE;
257*4882a593Smuzhiyun 			break;
258*4882a593Smuzhiyun 		}
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 		if (!s_pidx && mp->host_joined) {
261*4882a593Smuzhiyun 			err = __mdb_fill_info(skb, mp, NULL);
262*4882a593Smuzhiyun 			if (err) {
263*4882a593Smuzhiyun 				nla_nest_cancel(skb, nest2);
264*4882a593Smuzhiyun 				break;
265*4882a593Smuzhiyun 			}
266*4882a593Smuzhiyun 		}
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 		for (pp = &mp->ports; (p = rcu_dereference(*pp)) != NULL;
269*4882a593Smuzhiyun 		      pp = &p->next) {
270*4882a593Smuzhiyun 			if (!p->key.port)
271*4882a593Smuzhiyun 				continue;
272*4882a593Smuzhiyun 			if (pidx < s_pidx)
273*4882a593Smuzhiyun 				goto skip_pg;
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 			err = __mdb_fill_info(skb, mp, p);
276*4882a593Smuzhiyun 			if (err) {
277*4882a593Smuzhiyun 				nla_nest_end(skb, nest2);
278*4882a593Smuzhiyun 				goto out;
279*4882a593Smuzhiyun 			}
280*4882a593Smuzhiyun skip_pg:
281*4882a593Smuzhiyun 			pidx++;
282*4882a593Smuzhiyun 		}
283*4882a593Smuzhiyun 		pidx = 0;
284*4882a593Smuzhiyun 		s_pidx = 0;
285*4882a593Smuzhiyun 		nla_nest_end(skb, nest2);
286*4882a593Smuzhiyun skip:
287*4882a593Smuzhiyun 		idx++;
288*4882a593Smuzhiyun 	}
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun out:
291*4882a593Smuzhiyun 	cb->args[1] = idx;
292*4882a593Smuzhiyun 	cb->args[2] = pidx;
293*4882a593Smuzhiyun 	nla_nest_end(skb, nest);
294*4882a593Smuzhiyun 	return err;
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun 
br_mdb_valid_dump_req(const struct nlmsghdr * nlh,struct netlink_ext_ack * extack)297*4882a593Smuzhiyun static int br_mdb_valid_dump_req(const struct nlmsghdr *nlh,
298*4882a593Smuzhiyun 				 struct netlink_ext_ack *extack)
299*4882a593Smuzhiyun {
300*4882a593Smuzhiyun 	struct br_port_msg *bpm;
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*bpm))) {
303*4882a593Smuzhiyun 		NL_SET_ERR_MSG_MOD(extack, "Invalid header for mdb dump request");
304*4882a593Smuzhiyun 		return -EINVAL;
305*4882a593Smuzhiyun 	}
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	bpm = nlmsg_data(nlh);
308*4882a593Smuzhiyun 	if (bpm->ifindex) {
309*4882a593Smuzhiyun 		NL_SET_ERR_MSG_MOD(extack, "Filtering by device index is not supported for mdb dump request");
310*4882a593Smuzhiyun 		return -EINVAL;
311*4882a593Smuzhiyun 	}
312*4882a593Smuzhiyun 	if (nlmsg_attrlen(nlh, sizeof(*bpm))) {
313*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "Invalid data after header in mdb dump request");
314*4882a593Smuzhiyun 		return -EINVAL;
315*4882a593Smuzhiyun 	}
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	return 0;
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun 
br_mdb_dump(struct sk_buff * skb,struct netlink_callback * cb)320*4882a593Smuzhiyun static int br_mdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun 	struct net_device *dev;
323*4882a593Smuzhiyun 	struct net *net = sock_net(skb->sk);
324*4882a593Smuzhiyun 	struct nlmsghdr *nlh = NULL;
325*4882a593Smuzhiyun 	int idx = 0, s_idx;
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	if (cb->strict_check) {
328*4882a593Smuzhiyun 		int err = br_mdb_valid_dump_req(cb->nlh, cb->extack);
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 		if (err < 0)
331*4882a593Smuzhiyun 			return err;
332*4882a593Smuzhiyun 	}
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	s_idx = cb->args[0];
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	rcu_read_lock();
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 	cb->seq = net->dev_base_seq;
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	for_each_netdev_rcu(net, dev) {
341*4882a593Smuzhiyun 		if (dev->priv_flags & IFF_EBRIDGE) {
342*4882a593Smuzhiyun 			struct br_port_msg *bpm;
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 			if (idx < s_idx)
345*4882a593Smuzhiyun 				goto skip;
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 			nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid,
348*4882a593Smuzhiyun 					cb->nlh->nlmsg_seq, RTM_GETMDB,
349*4882a593Smuzhiyun 					sizeof(*bpm), NLM_F_MULTI);
350*4882a593Smuzhiyun 			if (nlh == NULL)
351*4882a593Smuzhiyun 				break;
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 			bpm = nlmsg_data(nlh);
354*4882a593Smuzhiyun 			memset(bpm, 0, sizeof(*bpm));
355*4882a593Smuzhiyun 			bpm->ifindex = dev->ifindex;
356*4882a593Smuzhiyun 			if (br_mdb_fill_info(skb, cb, dev) < 0)
357*4882a593Smuzhiyun 				goto out;
358*4882a593Smuzhiyun 			if (br_rports_fill_info(skb, cb, dev) < 0)
359*4882a593Smuzhiyun 				goto out;
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 			cb->args[1] = 0;
362*4882a593Smuzhiyun 			nlmsg_end(skb, nlh);
363*4882a593Smuzhiyun 		skip:
364*4882a593Smuzhiyun 			idx++;
365*4882a593Smuzhiyun 		}
366*4882a593Smuzhiyun 	}
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun out:
369*4882a593Smuzhiyun 	if (nlh)
370*4882a593Smuzhiyun 		nlmsg_end(skb, nlh);
371*4882a593Smuzhiyun 	rcu_read_unlock();
372*4882a593Smuzhiyun 	cb->args[0] = idx;
373*4882a593Smuzhiyun 	return skb->len;
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun 
nlmsg_populate_mdb_fill(struct sk_buff * skb,struct net_device * dev,struct net_bridge_mdb_entry * mp,struct net_bridge_port_group * pg,int type)376*4882a593Smuzhiyun static int nlmsg_populate_mdb_fill(struct sk_buff *skb,
377*4882a593Smuzhiyun 				   struct net_device *dev,
378*4882a593Smuzhiyun 				   struct net_bridge_mdb_entry *mp,
379*4882a593Smuzhiyun 				   struct net_bridge_port_group *pg,
380*4882a593Smuzhiyun 				   int type)
381*4882a593Smuzhiyun {
382*4882a593Smuzhiyun 	struct nlmsghdr *nlh;
383*4882a593Smuzhiyun 	struct br_port_msg *bpm;
384*4882a593Smuzhiyun 	struct nlattr *nest, *nest2;
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	nlh = nlmsg_put(skb, 0, 0, type, sizeof(*bpm), 0);
387*4882a593Smuzhiyun 	if (!nlh)
388*4882a593Smuzhiyun 		return -EMSGSIZE;
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	bpm = nlmsg_data(nlh);
391*4882a593Smuzhiyun 	memset(bpm, 0, sizeof(*bpm));
392*4882a593Smuzhiyun 	bpm->family  = AF_BRIDGE;
393*4882a593Smuzhiyun 	bpm->ifindex = dev->ifindex;
394*4882a593Smuzhiyun 	nest = nla_nest_start_noflag(skb, MDBA_MDB);
395*4882a593Smuzhiyun 	if (nest == NULL)
396*4882a593Smuzhiyun 		goto cancel;
397*4882a593Smuzhiyun 	nest2 = nla_nest_start_noflag(skb, MDBA_MDB_ENTRY);
398*4882a593Smuzhiyun 	if (nest2 == NULL)
399*4882a593Smuzhiyun 		goto end;
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	if (__mdb_fill_info(skb, mp, pg))
402*4882a593Smuzhiyun 		goto end;
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	nla_nest_end(skb, nest2);
405*4882a593Smuzhiyun 	nla_nest_end(skb, nest);
406*4882a593Smuzhiyun 	nlmsg_end(skb, nlh);
407*4882a593Smuzhiyun 	return 0;
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun end:
410*4882a593Smuzhiyun 	nla_nest_end(skb, nest);
411*4882a593Smuzhiyun cancel:
412*4882a593Smuzhiyun 	nlmsg_cancel(skb, nlh);
413*4882a593Smuzhiyun 	return -EMSGSIZE;
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun 
rtnl_mdb_nlmsg_size(struct net_bridge_port_group * pg)416*4882a593Smuzhiyun static size_t rtnl_mdb_nlmsg_size(struct net_bridge_port_group *pg)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun 	size_t nlmsg_size = NLMSG_ALIGN(sizeof(struct br_port_msg)) +
419*4882a593Smuzhiyun 			    nla_total_size(sizeof(struct br_mdb_entry)) +
420*4882a593Smuzhiyun 			    nla_total_size(sizeof(u32));
421*4882a593Smuzhiyun 	struct net_bridge_group_src *ent;
422*4882a593Smuzhiyun 	size_t addr_size = 0;
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	if (!pg)
425*4882a593Smuzhiyun 		goto out;
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	/* MDBA_MDB_EATTR_RTPROT */
428*4882a593Smuzhiyun 	nlmsg_size += nla_total_size(sizeof(u8));
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	switch (pg->key.addr.proto) {
431*4882a593Smuzhiyun 	case htons(ETH_P_IP):
432*4882a593Smuzhiyun 		/* MDBA_MDB_EATTR_SOURCE */
433*4882a593Smuzhiyun 		if (pg->key.addr.src.ip4)
434*4882a593Smuzhiyun 			nlmsg_size += nla_total_size(sizeof(__be32));
435*4882a593Smuzhiyun 		if (pg->key.port->br->multicast_igmp_version == 2)
436*4882a593Smuzhiyun 			goto out;
437*4882a593Smuzhiyun 		addr_size = sizeof(__be32);
438*4882a593Smuzhiyun 		break;
439*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
440*4882a593Smuzhiyun 	case htons(ETH_P_IPV6):
441*4882a593Smuzhiyun 		/* MDBA_MDB_EATTR_SOURCE */
442*4882a593Smuzhiyun 		if (!ipv6_addr_any(&pg->key.addr.src.ip6))
443*4882a593Smuzhiyun 			nlmsg_size += nla_total_size(sizeof(struct in6_addr));
444*4882a593Smuzhiyun 		if (pg->key.port->br->multicast_mld_version == 1)
445*4882a593Smuzhiyun 			goto out;
446*4882a593Smuzhiyun 		addr_size = sizeof(struct in6_addr);
447*4882a593Smuzhiyun 		break;
448*4882a593Smuzhiyun #endif
449*4882a593Smuzhiyun 	}
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	/* MDBA_MDB_EATTR_GROUP_MODE */
452*4882a593Smuzhiyun 	nlmsg_size += nla_total_size(sizeof(u8));
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	/* MDBA_MDB_EATTR_SRC_LIST nested attr */
455*4882a593Smuzhiyun 	if (!hlist_empty(&pg->src_list))
456*4882a593Smuzhiyun 		nlmsg_size += nla_total_size(0);
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	hlist_for_each_entry(ent, &pg->src_list, node) {
459*4882a593Smuzhiyun 		/* MDBA_MDB_SRCLIST_ENTRY nested attr +
460*4882a593Smuzhiyun 		 * MDBA_MDB_SRCATTR_ADDRESS + MDBA_MDB_SRCATTR_TIMER
461*4882a593Smuzhiyun 		 */
462*4882a593Smuzhiyun 		nlmsg_size += nla_total_size(0) +
463*4882a593Smuzhiyun 			      nla_total_size(addr_size) +
464*4882a593Smuzhiyun 			      nla_total_size(sizeof(u32));
465*4882a593Smuzhiyun 	}
466*4882a593Smuzhiyun out:
467*4882a593Smuzhiyun 	return nlmsg_size;
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun struct br_mdb_complete_info {
471*4882a593Smuzhiyun 	struct net_bridge_port *port;
472*4882a593Smuzhiyun 	struct br_ip ip;
473*4882a593Smuzhiyun };
474*4882a593Smuzhiyun 
br_mdb_complete(struct net_device * dev,int err,void * priv)475*4882a593Smuzhiyun static void br_mdb_complete(struct net_device *dev, int err, void *priv)
476*4882a593Smuzhiyun {
477*4882a593Smuzhiyun 	struct br_mdb_complete_info *data = priv;
478*4882a593Smuzhiyun 	struct net_bridge_port_group __rcu **pp;
479*4882a593Smuzhiyun 	struct net_bridge_port_group *p;
480*4882a593Smuzhiyun 	struct net_bridge_mdb_entry *mp;
481*4882a593Smuzhiyun 	struct net_bridge_port *port = data->port;
482*4882a593Smuzhiyun 	struct net_bridge *br = port->br;
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	if (err)
485*4882a593Smuzhiyun 		goto err;
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	spin_lock_bh(&br->multicast_lock);
488*4882a593Smuzhiyun 	mp = br_mdb_ip_get(br, &data->ip);
489*4882a593Smuzhiyun 	if (!mp)
490*4882a593Smuzhiyun 		goto out;
491*4882a593Smuzhiyun 	for (pp = &mp->ports; (p = mlock_dereference(*pp, br)) != NULL;
492*4882a593Smuzhiyun 	     pp = &p->next) {
493*4882a593Smuzhiyun 		if (p->key.port != port)
494*4882a593Smuzhiyun 			continue;
495*4882a593Smuzhiyun 		p->flags |= MDB_PG_FLAGS_OFFLOAD;
496*4882a593Smuzhiyun 	}
497*4882a593Smuzhiyun out:
498*4882a593Smuzhiyun 	spin_unlock_bh(&br->multicast_lock);
499*4882a593Smuzhiyun err:
500*4882a593Smuzhiyun 	kfree(priv);
501*4882a593Smuzhiyun }
502*4882a593Smuzhiyun 
br_mdb_switchdev_host_port(struct net_device * dev,struct net_device * lower_dev,struct net_bridge_mdb_entry * mp,int type)503*4882a593Smuzhiyun static void br_mdb_switchdev_host_port(struct net_device *dev,
504*4882a593Smuzhiyun 				       struct net_device *lower_dev,
505*4882a593Smuzhiyun 				       struct net_bridge_mdb_entry *mp,
506*4882a593Smuzhiyun 				       int type)
507*4882a593Smuzhiyun {
508*4882a593Smuzhiyun 	struct switchdev_obj_port_mdb mdb = {
509*4882a593Smuzhiyun 		.obj = {
510*4882a593Smuzhiyun 			.id = SWITCHDEV_OBJ_ID_HOST_MDB,
511*4882a593Smuzhiyun 			.flags = SWITCHDEV_F_DEFER,
512*4882a593Smuzhiyun 		},
513*4882a593Smuzhiyun 		.vid = mp->addr.vid,
514*4882a593Smuzhiyun 	};
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	if (mp->addr.proto == htons(ETH_P_IP))
517*4882a593Smuzhiyun 		ip_eth_mc_map(mp->addr.dst.ip4, mdb.addr);
518*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
519*4882a593Smuzhiyun 	else
520*4882a593Smuzhiyun 		ipv6_eth_mc_map(&mp->addr.dst.ip6, mdb.addr);
521*4882a593Smuzhiyun #endif
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 	mdb.obj.orig_dev = dev;
524*4882a593Smuzhiyun 	switch (type) {
525*4882a593Smuzhiyun 	case RTM_NEWMDB:
526*4882a593Smuzhiyun 		switchdev_port_obj_add(lower_dev, &mdb.obj, NULL);
527*4882a593Smuzhiyun 		break;
528*4882a593Smuzhiyun 	case RTM_DELMDB:
529*4882a593Smuzhiyun 		switchdev_port_obj_del(lower_dev, &mdb.obj);
530*4882a593Smuzhiyun 		break;
531*4882a593Smuzhiyun 	}
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun 
br_mdb_switchdev_host(struct net_device * dev,struct net_bridge_mdb_entry * mp,int type)534*4882a593Smuzhiyun static void br_mdb_switchdev_host(struct net_device *dev,
535*4882a593Smuzhiyun 				  struct net_bridge_mdb_entry *mp, int type)
536*4882a593Smuzhiyun {
537*4882a593Smuzhiyun 	struct net_device *lower_dev;
538*4882a593Smuzhiyun 	struct list_head *iter;
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	netdev_for_each_lower_dev(dev, lower_dev, iter)
541*4882a593Smuzhiyun 		br_mdb_switchdev_host_port(dev, lower_dev, mp, type);
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun 
br_mdb_notify(struct net_device * dev,struct net_bridge_mdb_entry * mp,struct net_bridge_port_group * pg,int type)544*4882a593Smuzhiyun void br_mdb_notify(struct net_device *dev,
545*4882a593Smuzhiyun 		   struct net_bridge_mdb_entry *mp,
546*4882a593Smuzhiyun 		   struct net_bridge_port_group *pg,
547*4882a593Smuzhiyun 		   int type)
548*4882a593Smuzhiyun {
549*4882a593Smuzhiyun 	struct br_mdb_complete_info *complete_info;
550*4882a593Smuzhiyun 	struct switchdev_obj_port_mdb mdb = {
551*4882a593Smuzhiyun 		.obj = {
552*4882a593Smuzhiyun 			.id = SWITCHDEV_OBJ_ID_PORT_MDB,
553*4882a593Smuzhiyun 			.flags = SWITCHDEV_F_DEFER,
554*4882a593Smuzhiyun 		},
555*4882a593Smuzhiyun 		.vid = mp->addr.vid,
556*4882a593Smuzhiyun 	};
557*4882a593Smuzhiyun 	struct net *net = dev_net(dev);
558*4882a593Smuzhiyun 	struct sk_buff *skb;
559*4882a593Smuzhiyun 	int err = -ENOBUFS;
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun 	if (pg) {
562*4882a593Smuzhiyun 		if (mp->addr.proto == htons(ETH_P_IP))
563*4882a593Smuzhiyun 			ip_eth_mc_map(mp->addr.dst.ip4, mdb.addr);
564*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
565*4882a593Smuzhiyun 		else
566*4882a593Smuzhiyun 			ipv6_eth_mc_map(&mp->addr.dst.ip6, mdb.addr);
567*4882a593Smuzhiyun #endif
568*4882a593Smuzhiyun 		mdb.obj.orig_dev = pg->key.port->dev;
569*4882a593Smuzhiyun 		switch (type) {
570*4882a593Smuzhiyun 		case RTM_NEWMDB:
571*4882a593Smuzhiyun 			complete_info = kmalloc(sizeof(*complete_info), GFP_ATOMIC);
572*4882a593Smuzhiyun 			if (!complete_info)
573*4882a593Smuzhiyun 				break;
574*4882a593Smuzhiyun 			complete_info->port = pg->key.port;
575*4882a593Smuzhiyun 			complete_info->ip = mp->addr;
576*4882a593Smuzhiyun 			mdb.obj.complete_priv = complete_info;
577*4882a593Smuzhiyun 			mdb.obj.complete = br_mdb_complete;
578*4882a593Smuzhiyun 			if (switchdev_port_obj_add(pg->key.port->dev, &mdb.obj, NULL))
579*4882a593Smuzhiyun 				kfree(complete_info);
580*4882a593Smuzhiyun 			break;
581*4882a593Smuzhiyun 		case RTM_DELMDB:
582*4882a593Smuzhiyun 			switchdev_port_obj_del(pg->key.port->dev, &mdb.obj);
583*4882a593Smuzhiyun 			break;
584*4882a593Smuzhiyun 		}
585*4882a593Smuzhiyun 	} else {
586*4882a593Smuzhiyun 		br_mdb_switchdev_host(dev, mp, type);
587*4882a593Smuzhiyun 	}
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	skb = nlmsg_new(rtnl_mdb_nlmsg_size(pg), GFP_ATOMIC);
590*4882a593Smuzhiyun 	if (!skb)
591*4882a593Smuzhiyun 		goto errout;
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	err = nlmsg_populate_mdb_fill(skb, dev, mp, pg, type);
594*4882a593Smuzhiyun 	if (err < 0) {
595*4882a593Smuzhiyun 		kfree_skb(skb);
596*4882a593Smuzhiyun 		goto errout;
597*4882a593Smuzhiyun 	}
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 	rtnl_notify(skb, net, 0, RTNLGRP_MDB, NULL, GFP_ATOMIC);
600*4882a593Smuzhiyun 	return;
601*4882a593Smuzhiyun errout:
602*4882a593Smuzhiyun 	rtnl_set_sk_err(net, RTNLGRP_MDB, err);
603*4882a593Smuzhiyun }
604*4882a593Smuzhiyun 
nlmsg_populate_rtr_fill(struct sk_buff * skb,struct net_device * dev,int ifindex,u32 pid,u32 seq,int type,unsigned int flags)605*4882a593Smuzhiyun static int nlmsg_populate_rtr_fill(struct sk_buff *skb,
606*4882a593Smuzhiyun 				   struct net_device *dev,
607*4882a593Smuzhiyun 				   int ifindex, u32 pid,
608*4882a593Smuzhiyun 				   u32 seq, int type, unsigned int flags)
609*4882a593Smuzhiyun {
610*4882a593Smuzhiyun 	struct br_port_msg *bpm;
611*4882a593Smuzhiyun 	struct nlmsghdr *nlh;
612*4882a593Smuzhiyun 	struct nlattr *nest;
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*bpm), 0);
615*4882a593Smuzhiyun 	if (!nlh)
616*4882a593Smuzhiyun 		return -EMSGSIZE;
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 	bpm = nlmsg_data(nlh);
619*4882a593Smuzhiyun 	memset(bpm, 0, sizeof(*bpm));
620*4882a593Smuzhiyun 	bpm->family = AF_BRIDGE;
621*4882a593Smuzhiyun 	bpm->ifindex = dev->ifindex;
622*4882a593Smuzhiyun 	nest = nla_nest_start_noflag(skb, MDBA_ROUTER);
623*4882a593Smuzhiyun 	if (!nest)
624*4882a593Smuzhiyun 		goto cancel;
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun 	if (nla_put_u32(skb, MDBA_ROUTER_PORT, ifindex))
627*4882a593Smuzhiyun 		goto end;
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun 	nla_nest_end(skb, nest);
630*4882a593Smuzhiyun 	nlmsg_end(skb, nlh);
631*4882a593Smuzhiyun 	return 0;
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun end:
634*4882a593Smuzhiyun 	nla_nest_end(skb, nest);
635*4882a593Smuzhiyun cancel:
636*4882a593Smuzhiyun 	nlmsg_cancel(skb, nlh);
637*4882a593Smuzhiyun 	return -EMSGSIZE;
638*4882a593Smuzhiyun }
639*4882a593Smuzhiyun 
rtnl_rtr_nlmsg_size(void)640*4882a593Smuzhiyun static inline size_t rtnl_rtr_nlmsg_size(void)
641*4882a593Smuzhiyun {
642*4882a593Smuzhiyun 	return NLMSG_ALIGN(sizeof(struct br_port_msg))
643*4882a593Smuzhiyun 		+ nla_total_size(sizeof(__u32));
644*4882a593Smuzhiyun }
645*4882a593Smuzhiyun 
br_rtr_notify(struct net_device * dev,struct net_bridge_port * port,int type)646*4882a593Smuzhiyun void br_rtr_notify(struct net_device *dev, struct net_bridge_port *port,
647*4882a593Smuzhiyun 		   int type)
648*4882a593Smuzhiyun {
649*4882a593Smuzhiyun 	struct net *net = dev_net(dev);
650*4882a593Smuzhiyun 	struct sk_buff *skb;
651*4882a593Smuzhiyun 	int err = -ENOBUFS;
652*4882a593Smuzhiyun 	int ifindex;
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun 	ifindex = port ? port->dev->ifindex : 0;
655*4882a593Smuzhiyun 	skb = nlmsg_new(rtnl_rtr_nlmsg_size(), GFP_ATOMIC);
656*4882a593Smuzhiyun 	if (!skb)
657*4882a593Smuzhiyun 		goto errout;
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun 	err = nlmsg_populate_rtr_fill(skb, dev, ifindex, 0, 0, type, NTF_SELF);
660*4882a593Smuzhiyun 	if (err < 0) {
661*4882a593Smuzhiyun 		kfree_skb(skb);
662*4882a593Smuzhiyun 		goto errout;
663*4882a593Smuzhiyun 	}
664*4882a593Smuzhiyun 
665*4882a593Smuzhiyun 	rtnl_notify(skb, net, 0, RTNLGRP_MDB, NULL, GFP_ATOMIC);
666*4882a593Smuzhiyun 	return;
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun errout:
669*4882a593Smuzhiyun 	rtnl_set_sk_err(net, RTNLGRP_MDB, err);
670*4882a593Smuzhiyun }
671*4882a593Smuzhiyun 
is_valid_mdb_entry(struct br_mdb_entry * entry,struct netlink_ext_ack * extack)672*4882a593Smuzhiyun static bool is_valid_mdb_entry(struct br_mdb_entry *entry,
673*4882a593Smuzhiyun 			       struct netlink_ext_ack *extack)
674*4882a593Smuzhiyun {
675*4882a593Smuzhiyun 	if (entry->ifindex == 0) {
676*4882a593Smuzhiyun 		NL_SET_ERR_MSG_MOD(extack, "Zero entry ifindex is not allowed");
677*4882a593Smuzhiyun 		return false;
678*4882a593Smuzhiyun 	}
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun 	if (entry->addr.proto == htons(ETH_P_IP)) {
681*4882a593Smuzhiyun 		if (!ipv4_is_multicast(entry->addr.u.ip4)) {
682*4882a593Smuzhiyun 			NL_SET_ERR_MSG_MOD(extack, "IPv4 entry group address is not multicast");
683*4882a593Smuzhiyun 			return false;
684*4882a593Smuzhiyun 		}
685*4882a593Smuzhiyun 		if (ipv4_is_local_multicast(entry->addr.u.ip4)) {
686*4882a593Smuzhiyun 			NL_SET_ERR_MSG_MOD(extack, "IPv4 entry group address is local multicast");
687*4882a593Smuzhiyun 			return false;
688*4882a593Smuzhiyun 		}
689*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
690*4882a593Smuzhiyun 	} else if (entry->addr.proto == htons(ETH_P_IPV6)) {
691*4882a593Smuzhiyun 		if (ipv6_addr_is_ll_all_nodes(&entry->addr.u.ip6)) {
692*4882a593Smuzhiyun 			NL_SET_ERR_MSG_MOD(extack, "IPv6 entry group address is link-local all nodes");
693*4882a593Smuzhiyun 			return false;
694*4882a593Smuzhiyun 		}
695*4882a593Smuzhiyun #endif
696*4882a593Smuzhiyun 	} else {
697*4882a593Smuzhiyun 		NL_SET_ERR_MSG_MOD(extack, "Unknown entry protocol");
698*4882a593Smuzhiyun 		return false;
699*4882a593Smuzhiyun 	}
700*4882a593Smuzhiyun 
701*4882a593Smuzhiyun 	if (entry->state != MDB_PERMANENT && entry->state != MDB_TEMPORARY) {
702*4882a593Smuzhiyun 		NL_SET_ERR_MSG_MOD(extack, "Unknown entry state");
703*4882a593Smuzhiyun 		return false;
704*4882a593Smuzhiyun 	}
705*4882a593Smuzhiyun 	if (entry->vid >= VLAN_VID_MASK) {
706*4882a593Smuzhiyun 		NL_SET_ERR_MSG_MOD(extack, "Invalid entry VLAN id");
707*4882a593Smuzhiyun 		return false;
708*4882a593Smuzhiyun 	}
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun 	return true;
711*4882a593Smuzhiyun }
712*4882a593Smuzhiyun 
is_valid_mdb_source(struct nlattr * attr,__be16 proto,struct netlink_ext_ack * extack)713*4882a593Smuzhiyun static bool is_valid_mdb_source(struct nlattr *attr, __be16 proto,
714*4882a593Smuzhiyun 				struct netlink_ext_ack *extack)
715*4882a593Smuzhiyun {
716*4882a593Smuzhiyun 	switch (proto) {
717*4882a593Smuzhiyun 	case htons(ETH_P_IP):
718*4882a593Smuzhiyun 		if (nla_len(attr) != sizeof(struct in_addr)) {
719*4882a593Smuzhiyun 			NL_SET_ERR_MSG_MOD(extack, "IPv4 invalid source address length");
720*4882a593Smuzhiyun 			return false;
721*4882a593Smuzhiyun 		}
722*4882a593Smuzhiyun 		if (ipv4_is_multicast(nla_get_in_addr(attr))) {
723*4882a593Smuzhiyun 			NL_SET_ERR_MSG_MOD(extack, "IPv4 multicast source address is not allowed");
724*4882a593Smuzhiyun 			return false;
725*4882a593Smuzhiyun 		}
726*4882a593Smuzhiyun 		break;
727*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
728*4882a593Smuzhiyun 	case htons(ETH_P_IPV6): {
729*4882a593Smuzhiyun 		struct in6_addr src;
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun 		if (nla_len(attr) != sizeof(struct in6_addr)) {
732*4882a593Smuzhiyun 			NL_SET_ERR_MSG_MOD(extack, "IPv6 invalid source address length");
733*4882a593Smuzhiyun 			return false;
734*4882a593Smuzhiyun 		}
735*4882a593Smuzhiyun 		src = nla_get_in6_addr(attr);
736*4882a593Smuzhiyun 		if (ipv6_addr_is_multicast(&src)) {
737*4882a593Smuzhiyun 			NL_SET_ERR_MSG_MOD(extack, "IPv6 multicast source address is not allowed");
738*4882a593Smuzhiyun 			return false;
739*4882a593Smuzhiyun 		}
740*4882a593Smuzhiyun 		break;
741*4882a593Smuzhiyun 	}
742*4882a593Smuzhiyun #endif
743*4882a593Smuzhiyun 	default:
744*4882a593Smuzhiyun 		NL_SET_ERR_MSG_MOD(extack, "Invalid protocol used with source address");
745*4882a593Smuzhiyun 		return false;
746*4882a593Smuzhiyun 	}
747*4882a593Smuzhiyun 
748*4882a593Smuzhiyun 	return true;
749*4882a593Smuzhiyun }
750*4882a593Smuzhiyun 
751*4882a593Smuzhiyun static const struct nla_policy br_mdbe_attrs_pol[MDBE_ATTR_MAX + 1] = {
752*4882a593Smuzhiyun 	[MDBE_ATTR_SOURCE] = NLA_POLICY_RANGE(NLA_BINARY,
753*4882a593Smuzhiyun 					      sizeof(struct in_addr),
754*4882a593Smuzhiyun 					      sizeof(struct in6_addr)),
755*4882a593Smuzhiyun };
756*4882a593Smuzhiyun 
br_mdb_parse(struct sk_buff * skb,struct nlmsghdr * nlh,struct net_device ** pdev,struct br_mdb_entry ** pentry,struct nlattr ** mdb_attrs,struct netlink_ext_ack * extack)757*4882a593Smuzhiyun static int br_mdb_parse(struct sk_buff *skb, struct nlmsghdr *nlh,
758*4882a593Smuzhiyun 			struct net_device **pdev, struct br_mdb_entry **pentry,
759*4882a593Smuzhiyun 			struct nlattr **mdb_attrs, struct netlink_ext_ack *extack)
760*4882a593Smuzhiyun {
761*4882a593Smuzhiyun 	struct net *net = sock_net(skb->sk);
762*4882a593Smuzhiyun 	struct br_mdb_entry *entry;
763*4882a593Smuzhiyun 	struct br_port_msg *bpm;
764*4882a593Smuzhiyun 	struct nlattr *tb[MDBA_SET_ENTRY_MAX+1];
765*4882a593Smuzhiyun 	struct net_device *dev;
766*4882a593Smuzhiyun 	int err;
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun 	err = nlmsg_parse_deprecated(nlh, sizeof(*bpm), tb,
769*4882a593Smuzhiyun 				     MDBA_SET_ENTRY_MAX, NULL, NULL);
770*4882a593Smuzhiyun 	if (err < 0)
771*4882a593Smuzhiyun 		return err;
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 	bpm = nlmsg_data(nlh);
774*4882a593Smuzhiyun 	if (bpm->ifindex == 0) {
775*4882a593Smuzhiyun 		NL_SET_ERR_MSG_MOD(extack, "Invalid bridge ifindex");
776*4882a593Smuzhiyun 		return -EINVAL;
777*4882a593Smuzhiyun 	}
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun 	dev = __dev_get_by_index(net, bpm->ifindex);
780*4882a593Smuzhiyun 	if (dev == NULL) {
781*4882a593Smuzhiyun 		NL_SET_ERR_MSG_MOD(extack, "Bridge device doesn't exist");
782*4882a593Smuzhiyun 		return -ENODEV;
783*4882a593Smuzhiyun 	}
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 	if (!(dev->priv_flags & IFF_EBRIDGE)) {
786*4882a593Smuzhiyun 		NL_SET_ERR_MSG_MOD(extack, "Device is not a bridge");
787*4882a593Smuzhiyun 		return -EOPNOTSUPP;
788*4882a593Smuzhiyun 	}
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun 	*pdev = dev;
791*4882a593Smuzhiyun 
792*4882a593Smuzhiyun 	if (!tb[MDBA_SET_ENTRY]) {
793*4882a593Smuzhiyun 		NL_SET_ERR_MSG_MOD(extack, "Missing MDBA_SET_ENTRY attribute");
794*4882a593Smuzhiyun 		return -EINVAL;
795*4882a593Smuzhiyun 	}
796*4882a593Smuzhiyun 	if (nla_len(tb[MDBA_SET_ENTRY]) != sizeof(struct br_mdb_entry)) {
797*4882a593Smuzhiyun 		NL_SET_ERR_MSG_MOD(extack, "Invalid MDBA_SET_ENTRY attribute length");
798*4882a593Smuzhiyun 		return -EINVAL;
799*4882a593Smuzhiyun 	}
800*4882a593Smuzhiyun 
801*4882a593Smuzhiyun 	entry = nla_data(tb[MDBA_SET_ENTRY]);
802*4882a593Smuzhiyun 	if (!is_valid_mdb_entry(entry, extack))
803*4882a593Smuzhiyun 		return -EINVAL;
804*4882a593Smuzhiyun 	*pentry = entry;
805*4882a593Smuzhiyun 
806*4882a593Smuzhiyun 	if (tb[MDBA_SET_ENTRY_ATTRS]) {
807*4882a593Smuzhiyun 		err = nla_parse_nested(mdb_attrs, MDBE_ATTR_MAX,
808*4882a593Smuzhiyun 				       tb[MDBA_SET_ENTRY_ATTRS],
809*4882a593Smuzhiyun 				       br_mdbe_attrs_pol, extack);
810*4882a593Smuzhiyun 		if (err)
811*4882a593Smuzhiyun 			return err;
812*4882a593Smuzhiyun 		if (mdb_attrs[MDBE_ATTR_SOURCE] &&
813*4882a593Smuzhiyun 		    !is_valid_mdb_source(mdb_attrs[MDBE_ATTR_SOURCE],
814*4882a593Smuzhiyun 					 entry->addr.proto, extack))
815*4882a593Smuzhiyun 			return -EINVAL;
816*4882a593Smuzhiyun 	} else {
817*4882a593Smuzhiyun 		memset(mdb_attrs, 0,
818*4882a593Smuzhiyun 		       sizeof(struct nlattr *) * (MDBE_ATTR_MAX + 1));
819*4882a593Smuzhiyun 	}
820*4882a593Smuzhiyun 
821*4882a593Smuzhiyun 	return 0;
822*4882a593Smuzhiyun }
823*4882a593Smuzhiyun 
br_mdb_add_group(struct net_bridge * br,struct net_bridge_port * port,struct br_mdb_entry * entry,struct nlattr ** mdb_attrs,struct netlink_ext_ack * extack)824*4882a593Smuzhiyun static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port,
825*4882a593Smuzhiyun 			    struct br_mdb_entry *entry,
826*4882a593Smuzhiyun 			    struct nlattr **mdb_attrs,
827*4882a593Smuzhiyun 			    struct netlink_ext_ack *extack)
828*4882a593Smuzhiyun {
829*4882a593Smuzhiyun 	struct net_bridge_mdb_entry *mp, *star_mp;
830*4882a593Smuzhiyun 	struct net_bridge_port_group *p;
831*4882a593Smuzhiyun 	struct net_bridge_port_group __rcu **pp;
832*4882a593Smuzhiyun 	struct br_ip group, star_group;
833*4882a593Smuzhiyun 	unsigned long now = jiffies;
834*4882a593Smuzhiyun 	u8 filter_mode;
835*4882a593Smuzhiyun 	int err;
836*4882a593Smuzhiyun 
837*4882a593Smuzhiyun 	__mdb_entry_to_br_ip(entry, &group, mdb_attrs);
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun 	/* host join errors which can happen before creating the group */
840*4882a593Smuzhiyun 	if (!port) {
841*4882a593Smuzhiyun 		/* don't allow any flags for host-joined groups */
842*4882a593Smuzhiyun 		if (entry->state) {
843*4882a593Smuzhiyun 			NL_SET_ERR_MSG_MOD(extack, "Flags are not allowed for host groups");
844*4882a593Smuzhiyun 			return -EINVAL;
845*4882a593Smuzhiyun 		}
846*4882a593Smuzhiyun 		if (!br_multicast_is_star_g(&group)) {
847*4882a593Smuzhiyun 			NL_SET_ERR_MSG_MOD(extack, "Groups with sources cannot be manually host joined");
848*4882a593Smuzhiyun 			return -EINVAL;
849*4882a593Smuzhiyun 		}
850*4882a593Smuzhiyun 	}
851*4882a593Smuzhiyun 
852*4882a593Smuzhiyun 	mp = br_mdb_ip_get(br, &group);
853*4882a593Smuzhiyun 	if (!mp) {
854*4882a593Smuzhiyun 		mp = br_multicast_new_group(br, &group);
855*4882a593Smuzhiyun 		err = PTR_ERR_OR_ZERO(mp);
856*4882a593Smuzhiyun 		if (err)
857*4882a593Smuzhiyun 			return err;
858*4882a593Smuzhiyun 	}
859*4882a593Smuzhiyun 
860*4882a593Smuzhiyun 	/* host join */
861*4882a593Smuzhiyun 	if (!port) {
862*4882a593Smuzhiyun 		if (mp->host_joined) {
863*4882a593Smuzhiyun 			NL_SET_ERR_MSG_MOD(extack, "Group is already joined by host");
864*4882a593Smuzhiyun 			return -EEXIST;
865*4882a593Smuzhiyun 		}
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun 		br_multicast_host_join(mp, false);
868*4882a593Smuzhiyun 		br_mdb_notify(br->dev, mp, NULL, RTM_NEWMDB);
869*4882a593Smuzhiyun 
870*4882a593Smuzhiyun 		return 0;
871*4882a593Smuzhiyun 	}
872*4882a593Smuzhiyun 
873*4882a593Smuzhiyun 	for (pp = &mp->ports;
874*4882a593Smuzhiyun 	     (p = mlock_dereference(*pp, br)) != NULL;
875*4882a593Smuzhiyun 	     pp = &p->next) {
876*4882a593Smuzhiyun 		if (p->key.port == port) {
877*4882a593Smuzhiyun 			NL_SET_ERR_MSG_MOD(extack, "Group is already joined by port");
878*4882a593Smuzhiyun 			return -EEXIST;
879*4882a593Smuzhiyun 		}
880*4882a593Smuzhiyun 		if ((unsigned long)p->key.port < (unsigned long)port)
881*4882a593Smuzhiyun 			break;
882*4882a593Smuzhiyun 	}
883*4882a593Smuzhiyun 
884*4882a593Smuzhiyun 	filter_mode = br_multicast_is_star_g(&group) ? MCAST_EXCLUDE :
885*4882a593Smuzhiyun 						       MCAST_INCLUDE;
886*4882a593Smuzhiyun 
887*4882a593Smuzhiyun 	p = br_multicast_new_port_group(port, &group, *pp, entry->state, NULL,
888*4882a593Smuzhiyun 					filter_mode, RTPROT_STATIC);
889*4882a593Smuzhiyun 	if (unlikely(!p)) {
890*4882a593Smuzhiyun 		NL_SET_ERR_MSG_MOD(extack, "Couldn't allocate new port group");
891*4882a593Smuzhiyun 		return -ENOMEM;
892*4882a593Smuzhiyun 	}
893*4882a593Smuzhiyun 	rcu_assign_pointer(*pp, p);
894*4882a593Smuzhiyun 	if (entry->state == MDB_TEMPORARY)
895*4882a593Smuzhiyun 		mod_timer(&p->timer, now + br->multicast_membership_interval);
896*4882a593Smuzhiyun 	br_mdb_notify(br->dev, mp, p, RTM_NEWMDB);
897*4882a593Smuzhiyun 	/* if we are adding a new EXCLUDE port group (*,G) it needs to be also
898*4882a593Smuzhiyun 	 * added to all S,G entries for proper replication, if we are adding
899*4882a593Smuzhiyun 	 * a new INCLUDE port (S,G) then all of *,G EXCLUDE ports need to be
900*4882a593Smuzhiyun 	 * added to it for proper replication
901*4882a593Smuzhiyun 	 */
902*4882a593Smuzhiyun 	if (br_multicast_should_handle_mode(br, group.proto)) {
903*4882a593Smuzhiyun 		switch (filter_mode) {
904*4882a593Smuzhiyun 		case MCAST_EXCLUDE:
905*4882a593Smuzhiyun 			br_multicast_star_g_handle_mode(p, MCAST_EXCLUDE);
906*4882a593Smuzhiyun 			break;
907*4882a593Smuzhiyun 		case MCAST_INCLUDE:
908*4882a593Smuzhiyun 			star_group = p->key.addr;
909*4882a593Smuzhiyun 			memset(&star_group.src, 0, sizeof(star_group.src));
910*4882a593Smuzhiyun 			star_mp = br_mdb_ip_get(br, &star_group);
911*4882a593Smuzhiyun 			if (star_mp)
912*4882a593Smuzhiyun 				br_multicast_sg_add_exclude_ports(star_mp, p);
913*4882a593Smuzhiyun 			break;
914*4882a593Smuzhiyun 		}
915*4882a593Smuzhiyun 	}
916*4882a593Smuzhiyun 
917*4882a593Smuzhiyun 	return 0;
918*4882a593Smuzhiyun }
919*4882a593Smuzhiyun 
__br_mdb_add(struct net * net,struct net_bridge * br,struct net_bridge_port * p,struct br_mdb_entry * entry,struct nlattr ** mdb_attrs,struct netlink_ext_ack * extack)920*4882a593Smuzhiyun static int __br_mdb_add(struct net *net, struct net_bridge *br,
921*4882a593Smuzhiyun 			struct net_bridge_port *p,
922*4882a593Smuzhiyun 			struct br_mdb_entry *entry,
923*4882a593Smuzhiyun 			struct nlattr **mdb_attrs,
924*4882a593Smuzhiyun 			struct netlink_ext_ack *extack)
925*4882a593Smuzhiyun {
926*4882a593Smuzhiyun 	int ret;
927*4882a593Smuzhiyun 
928*4882a593Smuzhiyun 	spin_lock_bh(&br->multicast_lock);
929*4882a593Smuzhiyun 	ret = br_mdb_add_group(br, p, entry, mdb_attrs, extack);
930*4882a593Smuzhiyun 	spin_unlock_bh(&br->multicast_lock);
931*4882a593Smuzhiyun 
932*4882a593Smuzhiyun 	return ret;
933*4882a593Smuzhiyun }
934*4882a593Smuzhiyun 
br_mdb_add(struct sk_buff * skb,struct nlmsghdr * nlh,struct netlink_ext_ack * extack)935*4882a593Smuzhiyun static int br_mdb_add(struct sk_buff *skb, struct nlmsghdr *nlh,
936*4882a593Smuzhiyun 		      struct netlink_ext_ack *extack)
937*4882a593Smuzhiyun {
938*4882a593Smuzhiyun 	struct nlattr *mdb_attrs[MDBE_ATTR_MAX + 1];
939*4882a593Smuzhiyun 	struct net *net = sock_net(skb->sk);
940*4882a593Smuzhiyun 	struct net_bridge_vlan_group *vg;
941*4882a593Smuzhiyun 	struct net_bridge_port *p = NULL;
942*4882a593Smuzhiyun 	struct net_device *dev, *pdev;
943*4882a593Smuzhiyun 	struct br_mdb_entry *entry;
944*4882a593Smuzhiyun 	struct net_bridge_vlan *v;
945*4882a593Smuzhiyun 	struct net_bridge *br;
946*4882a593Smuzhiyun 	int err;
947*4882a593Smuzhiyun 
948*4882a593Smuzhiyun 	err = br_mdb_parse(skb, nlh, &dev, &entry, mdb_attrs, extack);
949*4882a593Smuzhiyun 	if (err < 0)
950*4882a593Smuzhiyun 		return err;
951*4882a593Smuzhiyun 
952*4882a593Smuzhiyun 	br = netdev_priv(dev);
953*4882a593Smuzhiyun 
954*4882a593Smuzhiyun 	if (!netif_running(br->dev)) {
955*4882a593Smuzhiyun 		NL_SET_ERR_MSG_MOD(extack, "Bridge device is not running");
956*4882a593Smuzhiyun 		return -EINVAL;
957*4882a593Smuzhiyun 	}
958*4882a593Smuzhiyun 
959*4882a593Smuzhiyun 	if (!br_opt_get(br, BROPT_MULTICAST_ENABLED)) {
960*4882a593Smuzhiyun 		NL_SET_ERR_MSG_MOD(extack, "Bridge's multicast processing is disabled");
961*4882a593Smuzhiyun 		return -EINVAL;
962*4882a593Smuzhiyun 	}
963*4882a593Smuzhiyun 
964*4882a593Smuzhiyun 	if (entry->ifindex != br->dev->ifindex) {
965*4882a593Smuzhiyun 		pdev = __dev_get_by_index(net, entry->ifindex);
966*4882a593Smuzhiyun 		if (!pdev) {
967*4882a593Smuzhiyun 			NL_SET_ERR_MSG_MOD(extack, "Port net device doesn't exist");
968*4882a593Smuzhiyun 			return -ENODEV;
969*4882a593Smuzhiyun 		}
970*4882a593Smuzhiyun 
971*4882a593Smuzhiyun 		p = br_port_get_rtnl(pdev);
972*4882a593Smuzhiyun 		if (!p) {
973*4882a593Smuzhiyun 			NL_SET_ERR_MSG_MOD(extack, "Net device is not a bridge port");
974*4882a593Smuzhiyun 			return -EINVAL;
975*4882a593Smuzhiyun 		}
976*4882a593Smuzhiyun 
977*4882a593Smuzhiyun 		if (p->br != br) {
978*4882a593Smuzhiyun 			NL_SET_ERR_MSG_MOD(extack, "Port belongs to a different bridge device");
979*4882a593Smuzhiyun 			return -EINVAL;
980*4882a593Smuzhiyun 		}
981*4882a593Smuzhiyun 		if (p->state == BR_STATE_DISABLED) {
982*4882a593Smuzhiyun 			NL_SET_ERR_MSG_MOD(extack, "Port is in disabled state");
983*4882a593Smuzhiyun 			return -EINVAL;
984*4882a593Smuzhiyun 		}
985*4882a593Smuzhiyun 		vg = nbp_vlan_group(p);
986*4882a593Smuzhiyun 	} else {
987*4882a593Smuzhiyun 		vg = br_vlan_group(br);
988*4882a593Smuzhiyun 	}
989*4882a593Smuzhiyun 
990*4882a593Smuzhiyun 	/* If vlan filtering is enabled and VLAN is not specified
991*4882a593Smuzhiyun 	 * install mdb entry on all vlans configured on the port.
992*4882a593Smuzhiyun 	 */
993*4882a593Smuzhiyun 	if (br_vlan_enabled(br->dev) && vg && entry->vid == 0) {
994*4882a593Smuzhiyun 		list_for_each_entry(v, &vg->vlan_list, vlist) {
995*4882a593Smuzhiyun 			entry->vid = v->vid;
996*4882a593Smuzhiyun 			err = __br_mdb_add(net, br, p, entry, mdb_attrs, extack);
997*4882a593Smuzhiyun 			if (err)
998*4882a593Smuzhiyun 				break;
999*4882a593Smuzhiyun 		}
1000*4882a593Smuzhiyun 	} else {
1001*4882a593Smuzhiyun 		err = __br_mdb_add(net, br, p, entry, mdb_attrs, extack);
1002*4882a593Smuzhiyun 	}
1003*4882a593Smuzhiyun 
1004*4882a593Smuzhiyun 	return err;
1005*4882a593Smuzhiyun }
1006*4882a593Smuzhiyun 
__br_mdb_del(struct net_bridge * br,struct br_mdb_entry * entry,struct nlattr ** mdb_attrs)1007*4882a593Smuzhiyun static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry,
1008*4882a593Smuzhiyun 			struct nlattr **mdb_attrs)
1009*4882a593Smuzhiyun {
1010*4882a593Smuzhiyun 	struct net_bridge_mdb_entry *mp;
1011*4882a593Smuzhiyun 	struct net_bridge_port_group *p;
1012*4882a593Smuzhiyun 	struct net_bridge_port_group __rcu **pp;
1013*4882a593Smuzhiyun 	struct br_ip ip;
1014*4882a593Smuzhiyun 	int err = -EINVAL;
1015*4882a593Smuzhiyun 
1016*4882a593Smuzhiyun 	if (!netif_running(br->dev) || !br_opt_get(br, BROPT_MULTICAST_ENABLED))
1017*4882a593Smuzhiyun 		return -EINVAL;
1018*4882a593Smuzhiyun 
1019*4882a593Smuzhiyun 	__mdb_entry_to_br_ip(entry, &ip, mdb_attrs);
1020*4882a593Smuzhiyun 
1021*4882a593Smuzhiyun 	spin_lock_bh(&br->multicast_lock);
1022*4882a593Smuzhiyun 	mp = br_mdb_ip_get(br, &ip);
1023*4882a593Smuzhiyun 	if (!mp)
1024*4882a593Smuzhiyun 		goto unlock;
1025*4882a593Smuzhiyun 
1026*4882a593Smuzhiyun 	/* host leave */
1027*4882a593Smuzhiyun 	if (entry->ifindex == mp->br->dev->ifindex && mp->host_joined) {
1028*4882a593Smuzhiyun 		br_multicast_host_leave(mp, false);
1029*4882a593Smuzhiyun 		err = 0;
1030*4882a593Smuzhiyun 		br_mdb_notify(br->dev, mp, NULL, RTM_DELMDB);
1031*4882a593Smuzhiyun 		if (!mp->ports && netif_running(br->dev))
1032*4882a593Smuzhiyun 			mod_timer(&mp->timer, jiffies);
1033*4882a593Smuzhiyun 		goto unlock;
1034*4882a593Smuzhiyun 	}
1035*4882a593Smuzhiyun 
1036*4882a593Smuzhiyun 	for (pp = &mp->ports;
1037*4882a593Smuzhiyun 	     (p = mlock_dereference(*pp, br)) != NULL;
1038*4882a593Smuzhiyun 	     pp = &p->next) {
1039*4882a593Smuzhiyun 		if (!p->key.port || p->key.port->dev->ifindex != entry->ifindex)
1040*4882a593Smuzhiyun 			continue;
1041*4882a593Smuzhiyun 
1042*4882a593Smuzhiyun 		if (p->key.port->state == BR_STATE_DISABLED)
1043*4882a593Smuzhiyun 			goto unlock;
1044*4882a593Smuzhiyun 
1045*4882a593Smuzhiyun 		br_multicast_del_pg(mp, p, pp);
1046*4882a593Smuzhiyun 		err = 0;
1047*4882a593Smuzhiyun 		break;
1048*4882a593Smuzhiyun 	}
1049*4882a593Smuzhiyun 
1050*4882a593Smuzhiyun unlock:
1051*4882a593Smuzhiyun 	spin_unlock_bh(&br->multicast_lock);
1052*4882a593Smuzhiyun 	return err;
1053*4882a593Smuzhiyun }
1054*4882a593Smuzhiyun 
br_mdb_del(struct sk_buff * skb,struct nlmsghdr * nlh,struct netlink_ext_ack * extack)1055*4882a593Smuzhiyun static int br_mdb_del(struct sk_buff *skb, struct nlmsghdr *nlh,
1056*4882a593Smuzhiyun 		      struct netlink_ext_ack *extack)
1057*4882a593Smuzhiyun {
1058*4882a593Smuzhiyun 	struct nlattr *mdb_attrs[MDBE_ATTR_MAX + 1];
1059*4882a593Smuzhiyun 	struct net *net = sock_net(skb->sk);
1060*4882a593Smuzhiyun 	struct net_bridge_vlan_group *vg;
1061*4882a593Smuzhiyun 	struct net_bridge_port *p = NULL;
1062*4882a593Smuzhiyun 	struct net_device *dev, *pdev;
1063*4882a593Smuzhiyun 	struct br_mdb_entry *entry;
1064*4882a593Smuzhiyun 	struct net_bridge_vlan *v;
1065*4882a593Smuzhiyun 	struct net_bridge *br;
1066*4882a593Smuzhiyun 	int err;
1067*4882a593Smuzhiyun 
1068*4882a593Smuzhiyun 	err = br_mdb_parse(skb, nlh, &dev, &entry, mdb_attrs, extack);
1069*4882a593Smuzhiyun 	if (err < 0)
1070*4882a593Smuzhiyun 		return err;
1071*4882a593Smuzhiyun 
1072*4882a593Smuzhiyun 	br = netdev_priv(dev);
1073*4882a593Smuzhiyun 
1074*4882a593Smuzhiyun 	if (entry->ifindex != br->dev->ifindex) {
1075*4882a593Smuzhiyun 		pdev = __dev_get_by_index(net, entry->ifindex);
1076*4882a593Smuzhiyun 		if (!pdev)
1077*4882a593Smuzhiyun 			return -ENODEV;
1078*4882a593Smuzhiyun 
1079*4882a593Smuzhiyun 		p = br_port_get_rtnl(pdev);
1080*4882a593Smuzhiyun 		if (!p || p->br != br || p->state == BR_STATE_DISABLED)
1081*4882a593Smuzhiyun 			return -EINVAL;
1082*4882a593Smuzhiyun 		vg = nbp_vlan_group(p);
1083*4882a593Smuzhiyun 	} else {
1084*4882a593Smuzhiyun 		vg = br_vlan_group(br);
1085*4882a593Smuzhiyun 	}
1086*4882a593Smuzhiyun 
1087*4882a593Smuzhiyun 	/* If vlan filtering is enabled and VLAN is not specified
1088*4882a593Smuzhiyun 	 * delete mdb entry on all vlans configured on the port.
1089*4882a593Smuzhiyun 	 */
1090*4882a593Smuzhiyun 	if (br_vlan_enabled(br->dev) && vg && entry->vid == 0) {
1091*4882a593Smuzhiyun 		list_for_each_entry(v, &vg->vlan_list, vlist) {
1092*4882a593Smuzhiyun 			entry->vid = v->vid;
1093*4882a593Smuzhiyun 			err = __br_mdb_del(br, entry, mdb_attrs);
1094*4882a593Smuzhiyun 		}
1095*4882a593Smuzhiyun 	} else {
1096*4882a593Smuzhiyun 		err = __br_mdb_del(br, entry, mdb_attrs);
1097*4882a593Smuzhiyun 	}
1098*4882a593Smuzhiyun 
1099*4882a593Smuzhiyun 	return err;
1100*4882a593Smuzhiyun }
1101*4882a593Smuzhiyun 
br_mdb_init(void)1102*4882a593Smuzhiyun void br_mdb_init(void)
1103*4882a593Smuzhiyun {
1104*4882a593Smuzhiyun 	rtnl_register_module(THIS_MODULE, PF_BRIDGE, RTM_GETMDB, NULL, br_mdb_dump, 0);
1105*4882a593Smuzhiyun 	rtnl_register_module(THIS_MODULE, PF_BRIDGE, RTM_NEWMDB, br_mdb_add, NULL, 0);
1106*4882a593Smuzhiyun 	rtnl_register_module(THIS_MODULE, PF_BRIDGE, RTM_DELMDB, br_mdb_del, NULL, 0);
1107*4882a593Smuzhiyun }
1108*4882a593Smuzhiyun 
br_mdb_uninit(void)1109*4882a593Smuzhiyun void br_mdb_uninit(void)
1110*4882a593Smuzhiyun {
1111*4882a593Smuzhiyun 	rtnl_unregister(PF_BRIDGE, RTM_GETMDB);
1112*4882a593Smuzhiyun 	rtnl_unregister(PF_BRIDGE, RTM_NEWMDB);
1113*4882a593Smuzhiyun 	rtnl_unregister(PF_BRIDGE, RTM_DELMDB);
1114*4882a593Smuzhiyun }
1115