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