xref: /openbmc/linux/net/bridge/br_netlink.c (revision ced8283f90b88bbf7ec9a6b869586b611167394e)
111dc1f36SStephen Hemminger /*
211dc1f36SStephen Hemminger  *	Bridge netlink control interface
311dc1f36SStephen Hemminger  *
411dc1f36SStephen Hemminger  *	Authors:
511dc1f36SStephen Hemminger  *	Stephen Hemminger		<shemminger@osdl.org>
611dc1f36SStephen Hemminger  *
711dc1f36SStephen Hemminger  *	This program is free software; you can redistribute it and/or
811dc1f36SStephen Hemminger  *	modify it under the terms of the GNU General Public License
911dc1f36SStephen Hemminger  *	as published by the Free Software Foundation; either version
1011dc1f36SStephen Hemminger  *	2 of the License, or (at your option) any later version.
1111dc1f36SStephen Hemminger  */
1211dc1f36SStephen Hemminger 
1311dc1f36SStephen Hemminger #include <linux/kernel.h>
145a0e3ad6STejun Heo #include <linux/slab.h>
15bb900b27Sstephen hemminger #include <linux/etherdevice.h>
1632fe21c0SThomas Graf #include <net/rtnetlink.h>
17881d966bSEric W. Biederman #include <net/net_namespace.h>
18b854272bSDenis V. Lunev #include <net/sock.h>
19407af329SVlad Yasevich #include <uapi/linux/if_bridge.h>
20bb900b27Sstephen hemminger 
2111dc1f36SStephen Hemminger #include "br_private.h"
22b03b6dd5SVitalii Demianets #include "br_private_stp.h"
2311dc1f36SStephen Hemminger 
2425c71c75Sstephen hemminger static inline size_t br_port_info_size(void)
2525c71c75Sstephen hemminger {
2625c71c75Sstephen hemminger 	return nla_total_size(1)	/* IFLA_BRPORT_STATE  */
2725c71c75Sstephen hemminger 		+ nla_total_size(2)	/* IFLA_BRPORT_PRIORITY */
2825c71c75Sstephen hemminger 		+ nla_total_size(4)	/* IFLA_BRPORT_COST */
2925c71c75Sstephen hemminger 		+ nla_total_size(1)	/* IFLA_BRPORT_MODE */
30a2e01a65Sstephen hemminger 		+ nla_total_size(1)	/* IFLA_BRPORT_GUARD */
311007dd1aSstephen hemminger 		+ nla_total_size(1)	/* IFLA_BRPORT_PROTECT */
323da889b6Sstephen hemminger 		+ nla_total_size(1)	/* IFLA_BRPORT_FAST_LEAVE */
339ba18891SVlad Yasevich 		+ nla_total_size(1)	/* IFLA_BRPORT_LEARNING */
34867a5943SVlad Yasevich 		+ nla_total_size(1)	/* IFLA_BRPORT_UNICAST_FLOOD */
3525c71c75Sstephen hemminger 		+ 0;
3625c71c75Sstephen hemminger }
3725c71c75Sstephen hemminger 
38339bf98fSThomas Graf static inline size_t br_nlmsg_size(void)
39339bf98fSThomas Graf {
40339bf98fSThomas Graf 	return NLMSG_ALIGN(sizeof(struct ifinfomsg))
41339bf98fSThomas Graf 		+ nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
42339bf98fSThomas Graf 		+ nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */
43339bf98fSThomas Graf 		+ nla_total_size(4) /* IFLA_MASTER */
44339bf98fSThomas Graf 		+ nla_total_size(4) /* IFLA_MTU */
45339bf98fSThomas Graf 		+ nla_total_size(4) /* IFLA_LINK */
46339bf98fSThomas Graf 		+ nla_total_size(1) /* IFLA_OPERSTATE */
4725c71c75Sstephen hemminger 		+ nla_total_size(br_port_info_size()); /* IFLA_PROTINFO */
4825c71c75Sstephen hemminger }
4925c71c75Sstephen hemminger 
5025c71c75Sstephen hemminger static int br_port_fill_attrs(struct sk_buff *skb,
5125c71c75Sstephen hemminger 			      const struct net_bridge_port *p)
5225c71c75Sstephen hemminger {
5325c71c75Sstephen hemminger 	u8 mode = !!(p->flags & BR_HAIRPIN_MODE);
5425c71c75Sstephen hemminger 
5525c71c75Sstephen hemminger 	if (nla_put_u8(skb, IFLA_BRPORT_STATE, p->state) ||
5625c71c75Sstephen hemminger 	    nla_put_u16(skb, IFLA_BRPORT_PRIORITY, p->priority) ||
5725c71c75Sstephen hemminger 	    nla_put_u32(skb, IFLA_BRPORT_COST, p->path_cost) ||
58a2e01a65Sstephen hemminger 	    nla_put_u8(skb, IFLA_BRPORT_MODE, mode) ||
591007dd1aSstephen hemminger 	    nla_put_u8(skb, IFLA_BRPORT_GUARD, !!(p->flags & BR_BPDU_GUARD)) ||
60c2d3babfSDavid S. Miller 	    nla_put_u8(skb, IFLA_BRPORT_PROTECT, !!(p->flags & BR_ROOT_BLOCK)) ||
619ba18891SVlad Yasevich 	    nla_put_u8(skb, IFLA_BRPORT_FAST_LEAVE, !!(p->flags & BR_MULTICAST_FAST_LEAVE)) ||
62867a5943SVlad Yasevich 	    nla_put_u8(skb, IFLA_BRPORT_LEARNING, !!(p->flags & BR_LEARNING)) ||
63867a5943SVlad Yasevich 	    nla_put_u8(skb, IFLA_BRPORT_UNICAST_FLOOD, !!(p->flags & BR_FLOOD)))
6425c71c75Sstephen hemminger 		return -EMSGSIZE;
6525c71c75Sstephen hemminger 
6625c71c75Sstephen hemminger 	return 0;
67339bf98fSThomas Graf }
68339bf98fSThomas Graf 
6911dc1f36SStephen Hemminger /*
7011dc1f36SStephen Hemminger  * Create one netlink message for one interface
7111dc1f36SStephen Hemminger  * Contains port and master info as well as carrier and bridge state.
7211dc1f36SStephen Hemminger  */
736cbdceebSVlad Yasevich static int br_fill_ifinfo(struct sk_buff *skb,
746cbdceebSVlad Yasevich 			  const struct net_bridge_port *port,
756cbdceebSVlad Yasevich 			  u32 pid, u32 seq, int event, unsigned int flags,
766cbdceebSVlad Yasevich 			  u32 filter_mask, const struct net_device *dev)
7711dc1f36SStephen Hemminger {
786cbdceebSVlad Yasevich 	const struct net_bridge *br;
7974685962SThomas Graf 	struct ifinfomsg *hdr;
8011dc1f36SStephen Hemminger 	struct nlmsghdr *nlh;
8111dc1f36SStephen Hemminger 	u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN;
8211dc1f36SStephen Hemminger 
836cbdceebSVlad Yasevich 	if (port)
846cbdceebSVlad Yasevich 		br = port->br;
856cbdceebSVlad Yasevich 	else
866cbdceebSVlad Yasevich 		br = netdev_priv(dev);
876cbdceebSVlad Yasevich 
8828a16c97Sstephen hemminger 	br_debug(br, "br_fill_info event %d port %s master %s\n",
8911dc1f36SStephen Hemminger 		     event, dev->name, br->dev->name);
9011dc1f36SStephen Hemminger 
9174685962SThomas Graf 	nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags);
9274685962SThomas Graf 	if (nlh == NULL)
9326932566SPatrick McHardy 		return -EMSGSIZE;
9411dc1f36SStephen Hemminger 
9574685962SThomas Graf 	hdr = nlmsg_data(nlh);
9674685962SThomas Graf 	hdr->ifi_family = AF_BRIDGE;
9774685962SThomas Graf 	hdr->__ifi_pad = 0;
9874685962SThomas Graf 	hdr->ifi_type = dev->type;
9974685962SThomas Graf 	hdr->ifi_index = dev->ifindex;
10074685962SThomas Graf 	hdr->ifi_flags = dev_get_flags(dev);
10174685962SThomas Graf 	hdr->ifi_change = 0;
10211dc1f36SStephen Hemminger 
1032eb812e6SDavid S. Miller 	if (nla_put_string(skb, IFLA_IFNAME, dev->name) ||
1042eb812e6SDavid S. Miller 	    nla_put_u32(skb, IFLA_MASTER, br->dev->ifindex) ||
1052eb812e6SDavid S. Miller 	    nla_put_u32(skb, IFLA_MTU, dev->mtu) ||
1062eb812e6SDavid S. Miller 	    nla_put_u8(skb, IFLA_OPERSTATE, operstate) ||
1072eb812e6SDavid S. Miller 	    (dev->addr_len &&
1082eb812e6SDavid S. Miller 	     nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr)) ||
1092eb812e6SDavid S. Miller 	    (dev->ifindex != dev->iflink &&
11025c71c75Sstephen hemminger 	     nla_put_u32(skb, IFLA_LINK, dev->iflink)))
1112eb812e6SDavid S. Miller 		goto nla_put_failure;
11225c71c75Sstephen hemminger 
1136cbdceebSVlad Yasevich 	if (event == RTM_NEWLINK && port) {
11425c71c75Sstephen hemminger 		struct nlattr *nest
11525c71c75Sstephen hemminger 			= nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED);
11625c71c75Sstephen hemminger 
11725c71c75Sstephen hemminger 		if (nest == NULL || br_port_fill_attrs(skb, port) < 0)
11825c71c75Sstephen hemminger 			goto nla_put_failure;
11925c71c75Sstephen hemminger 		nla_nest_end(skb, nest);
12025c71c75Sstephen hemminger 	}
12125c71c75Sstephen hemminger 
1226cbdceebSVlad Yasevich 	/* Check if  the VID information is requested */
1236cbdceebSVlad Yasevich 	if (filter_mask & RTEXT_FILTER_BRVLAN) {
1246cbdceebSVlad Yasevich 		struct nlattr *af;
1256cbdceebSVlad Yasevich 		const struct net_port_vlans *pv;
1266cbdceebSVlad Yasevich 		struct bridge_vlan_info vinfo;
1276cbdceebSVlad Yasevich 		u16 vid;
128552406c4SVlad Yasevich 		u16 pvid;
1296cbdceebSVlad Yasevich 
1306cbdceebSVlad Yasevich 		if (port)
1316cbdceebSVlad Yasevich 			pv = nbp_get_vlan_info(port);
1326cbdceebSVlad Yasevich 		else
1336cbdceebSVlad Yasevich 			pv = br_get_vlan_info(br);
1346cbdceebSVlad Yasevich 
135ef40b7efSToshiaki Makita 		if (!pv || bitmap_empty(pv->vlan_bitmap, VLAN_N_VID))
1366cbdceebSVlad Yasevich 			goto done;
1376cbdceebSVlad Yasevich 
1386cbdceebSVlad Yasevich 		af = nla_nest_start(skb, IFLA_AF_SPEC);
1396cbdceebSVlad Yasevich 		if (!af)
1406cbdceebSVlad Yasevich 			goto nla_put_failure;
1416cbdceebSVlad Yasevich 
142552406c4SVlad Yasevich 		pvid = br_get_pvid(pv);
143ef40b7efSToshiaki Makita 		for_each_set_bit(vid, pv->vlan_bitmap, VLAN_N_VID) {
1446cbdceebSVlad Yasevich 			vinfo.vid = vid;
1456cbdceebSVlad Yasevich 			vinfo.flags = 0;
146552406c4SVlad Yasevich 			if (vid == pvid)
147552406c4SVlad Yasevich 				vinfo.flags |= BRIDGE_VLAN_INFO_PVID;
14835e03f3aSVlad Yasevich 
14935e03f3aSVlad Yasevich 			if (test_bit(vid, pv->untagged_bitmap))
15035e03f3aSVlad Yasevich 				vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED;
15135e03f3aSVlad Yasevich 
1526cbdceebSVlad Yasevich 			if (nla_put(skb, IFLA_BRIDGE_VLAN_INFO,
1536cbdceebSVlad Yasevich 				    sizeof(vinfo), &vinfo))
1546cbdceebSVlad Yasevich 				goto nla_put_failure;
1556cbdceebSVlad Yasevich 		}
1566cbdceebSVlad Yasevich 
1576cbdceebSVlad Yasevich 		nla_nest_end(skb, af);
1586cbdceebSVlad Yasevich 	}
1596cbdceebSVlad Yasevich 
1606cbdceebSVlad Yasevich done:
16174685962SThomas Graf 	return nlmsg_end(skb, nlh);
16211dc1f36SStephen Hemminger 
16374685962SThomas Graf nla_put_failure:
16426932566SPatrick McHardy 	nlmsg_cancel(skb, nlh);
16526932566SPatrick McHardy 	return -EMSGSIZE;
16611dc1f36SStephen Hemminger }
16711dc1f36SStephen Hemminger 
16811dc1f36SStephen Hemminger /*
16911dc1f36SStephen Hemminger  * Notify listeners of a change in port information
17011dc1f36SStephen Hemminger  */
17111dc1f36SStephen Hemminger void br_ifinfo_notify(int event, struct net_bridge_port *port)
17211dc1f36SStephen Hemminger {
173407af329SVlad Yasevich 	struct net *net;
17411dc1f36SStephen Hemminger 	struct sk_buff *skb;
175280a306cSThomas Graf 	int err = -ENOBUFS;
17611dc1f36SStephen Hemminger 
177407af329SVlad Yasevich 	if (!port)
178407af329SVlad Yasevich 		return;
179407af329SVlad Yasevich 
180407af329SVlad Yasevich 	net = dev_net(port->dev);
18128a16c97Sstephen hemminger 	br_debug(port->br, "port %u(%s) event %d\n",
18295c96174SEric Dumazet 		 (unsigned int)port->port_no, port->dev->name, event);
18328a16c97Sstephen hemminger 
184339bf98fSThomas Graf 	skb = nlmsg_new(br_nlmsg_size(), GFP_ATOMIC);
185280a306cSThomas Graf 	if (skb == NULL)
186280a306cSThomas Graf 		goto errout;
18711dc1f36SStephen Hemminger 
1886cbdceebSVlad Yasevich 	err = br_fill_ifinfo(skb, port, 0, 0, event, 0, 0, port->dev);
18926932566SPatrick McHardy 	if (err < 0) {
19026932566SPatrick McHardy 		/* -EMSGSIZE implies BUG in br_nlmsg_size() */
19126932566SPatrick McHardy 		WARN_ON(err == -EMSGSIZE);
19226932566SPatrick McHardy 		kfree_skb(skb);
19326932566SPatrick McHardy 		goto errout;
19426932566SPatrick McHardy 	}
1951ce85fe4SPablo Neira Ayuso 	rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
1961ce85fe4SPablo Neira Ayuso 	return;
197280a306cSThomas Graf errout:
1984aa678baSAlexey Dobriyan 	rtnl_set_sk_err(net, RTNLGRP_LINK, err);
19911dc1f36SStephen Hemminger }
20011dc1f36SStephen Hemminger 
201407af329SVlad Yasevich 
20211dc1f36SStephen Hemminger /*
20311dc1f36SStephen Hemminger  * Dump information about all ports, in response to GETLINK
20411dc1f36SStephen Hemminger  */
205e5a55a89SJohn Fastabend int br_getlink(struct sk_buff *skb, u32 pid, u32 seq,
2066cbdceebSVlad Yasevich 	       struct net_device *dev, u32 filter_mask)
20711dc1f36SStephen Hemminger {
208e5a55a89SJohn Fastabend 	int err = 0;
2091fb1754aSHong Zhiguo 	struct net_bridge_port *port = br_port_get_rtnl(dev);
210b5ed54e9Sstephen hemminger 
2116cbdceebSVlad Yasevich 	if (!port && !(filter_mask & RTEXT_FILTER_BRVLAN))
212e5a55a89SJohn Fastabend 		goto out;
21311dc1f36SStephen Hemminger 
2146cbdceebSVlad Yasevich 	err = br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, NLM_F_MULTI,
2156cbdceebSVlad Yasevich 			     filter_mask, dev);
216e5a55a89SJohn Fastabend out:
217e5a55a89SJohn Fastabend 	return err;
21811dc1f36SStephen Hemminger }
21911dc1f36SStephen Hemminger 
22015004cabSCong Wang static const struct nla_policy ifla_br_policy[IFLA_MAX+1] = {
221407af329SVlad Yasevich 	[IFLA_BRIDGE_FLAGS]	= { .type = NLA_U16 },
222407af329SVlad Yasevich 	[IFLA_BRIDGE_MODE]	= { .type = NLA_U16 },
223407af329SVlad Yasevich 	[IFLA_BRIDGE_VLAN_INFO]	= { .type = NLA_BINARY,
224407af329SVlad Yasevich 				    .len = sizeof(struct bridge_vlan_info), },
225407af329SVlad Yasevich };
226407af329SVlad Yasevich 
227407af329SVlad Yasevich static int br_afspec(struct net_bridge *br,
228407af329SVlad Yasevich 		     struct net_bridge_port *p,
229407af329SVlad Yasevich 		     struct nlattr *af_spec,
230407af329SVlad Yasevich 		     int cmd)
231407af329SVlad Yasevich {
232407af329SVlad Yasevich 	struct nlattr *tb[IFLA_BRIDGE_MAX+1];
233407af329SVlad Yasevich 	int err = 0;
234407af329SVlad Yasevich 
235407af329SVlad Yasevich 	err = nla_parse_nested(tb, IFLA_BRIDGE_MAX, af_spec, ifla_br_policy);
236407af329SVlad Yasevich 	if (err)
237407af329SVlad Yasevich 		return err;
238407af329SVlad Yasevich 
239407af329SVlad Yasevich 	if (tb[IFLA_BRIDGE_VLAN_INFO]) {
240407af329SVlad Yasevich 		struct bridge_vlan_info *vinfo;
241407af329SVlad Yasevich 
242407af329SVlad Yasevich 		vinfo = nla_data(tb[IFLA_BRIDGE_VLAN_INFO]);
243407af329SVlad Yasevich 
2448adff41cSToshiaki Makita 		if (!vinfo->vid || vinfo->vid >= VLAN_VID_MASK)
245407af329SVlad Yasevich 			return -EINVAL;
246407af329SVlad Yasevich 
247407af329SVlad Yasevich 		switch (cmd) {
248407af329SVlad Yasevich 		case RTM_SETLINK:
249407af329SVlad Yasevich 			if (p) {
250552406c4SVlad Yasevich 				err = nbp_vlan_add(p, vinfo->vid, vinfo->flags);
251407af329SVlad Yasevich 				if (err)
252407af329SVlad Yasevich 					break;
253407af329SVlad Yasevich 
254407af329SVlad Yasevich 				if (vinfo->flags & BRIDGE_VLAN_INFO_MASTER)
255552406c4SVlad Yasevich 					err = br_vlan_add(p->br, vinfo->vid,
256552406c4SVlad Yasevich 							  vinfo->flags);
257407af329SVlad Yasevich 			} else
258552406c4SVlad Yasevich 				err = br_vlan_add(br, vinfo->vid, vinfo->flags);
259407af329SVlad Yasevich 
260407af329SVlad Yasevich 			if (err)
261407af329SVlad Yasevich 				break;
262407af329SVlad Yasevich 
263407af329SVlad Yasevich 			break;
264407af329SVlad Yasevich 
265407af329SVlad Yasevich 		case RTM_DELLINK:
266407af329SVlad Yasevich 			if (p) {
267407af329SVlad Yasevich 				nbp_vlan_delete(p, vinfo->vid);
268407af329SVlad Yasevich 				if (vinfo->flags & BRIDGE_VLAN_INFO_MASTER)
269407af329SVlad Yasevich 					br_vlan_delete(p->br, vinfo->vid);
270407af329SVlad Yasevich 			} else
271407af329SVlad Yasevich 				br_vlan_delete(br, vinfo->vid);
272407af329SVlad Yasevich 			break;
273407af329SVlad Yasevich 		}
274407af329SVlad Yasevich 	}
275407af329SVlad Yasevich 
276407af329SVlad Yasevich 	return err;
277407af329SVlad Yasevich }
278407af329SVlad Yasevich 
27925c71c75Sstephen hemminger static const struct nla_policy ifla_brport_policy[IFLA_BRPORT_MAX + 1] = {
28025c71c75Sstephen hemminger 	[IFLA_BRPORT_STATE]	= { .type = NLA_U8 },
28125c71c75Sstephen hemminger 	[IFLA_BRPORT_COST]	= { .type = NLA_U32 },
28225c71c75Sstephen hemminger 	[IFLA_BRPORT_PRIORITY]	= { .type = NLA_U16 },
28325c71c75Sstephen hemminger 	[IFLA_BRPORT_MODE]	= { .type = NLA_U8 },
284a2e01a65Sstephen hemminger 	[IFLA_BRPORT_GUARD]	= { .type = NLA_U8 },
2851007dd1aSstephen hemminger 	[IFLA_BRPORT_PROTECT]	= { .type = NLA_U8 },
2869ba18891SVlad Yasevich 	[IFLA_BRPORT_LEARNING]	= { .type = NLA_U8 },
287867a5943SVlad Yasevich 	[IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_U8 },
28825c71c75Sstephen hemminger };
28925c71c75Sstephen hemminger 
29025c71c75Sstephen hemminger /* Change the state of the port and notify spanning tree */
29125c71c75Sstephen hemminger static int br_set_port_state(struct net_bridge_port *p, u8 state)
29211dc1f36SStephen Hemminger {
29325c71c75Sstephen hemminger 	if (state > BR_STATE_BLOCKING)
294b5ed54e9Sstephen hemminger 		return -EINVAL;
29511dc1f36SStephen Hemminger 
29611dc1f36SStephen Hemminger 	/* if kernel STP is running, don't allow changes */
2979cde0708SStephen Hemminger 	if (p->br->stp_enabled == BR_KERNEL_STP)
29811dc1f36SStephen Hemminger 		return -EBUSY;
29911dc1f36SStephen Hemminger 
300576eb625Sstephen hemminger 	/* if device is not up, change is not allowed
301576eb625Sstephen hemminger 	 * if link is not present, only allowable state is disabled
302576eb625Sstephen hemminger 	 */
30325c71c75Sstephen hemminger 	if (!netif_running(p->dev) ||
304576eb625Sstephen hemminger 	    (!netif_oper_up(p->dev) && state != BR_STATE_DISABLED))
30511dc1f36SStephen Hemminger 		return -ENETDOWN;
30611dc1f36SStephen Hemminger 
30725c71c75Sstephen hemminger 	p->state = state;
30811dc1f36SStephen Hemminger 	br_log_state(p);
30925c71c75Sstephen hemminger 	br_port_state_selection(p->br);
31025c71c75Sstephen hemminger 	return 0;
31125c71c75Sstephen hemminger }
31225c71c75Sstephen hemminger 
31325c71c75Sstephen hemminger /* Set/clear or port flags based on attribute */
31425c71c75Sstephen hemminger static void br_set_port_flag(struct net_bridge_port *p, struct nlattr *tb[],
31525c71c75Sstephen hemminger 			   int attrtype, unsigned long mask)
31625c71c75Sstephen hemminger {
31725c71c75Sstephen hemminger 	if (tb[attrtype]) {
31825c71c75Sstephen hemminger 		u8 flag = nla_get_u8(tb[attrtype]);
31925c71c75Sstephen hemminger 		if (flag)
32025c71c75Sstephen hemminger 			p->flags |= mask;
32125c71c75Sstephen hemminger 		else
32225c71c75Sstephen hemminger 			p->flags &= ~mask;
32325c71c75Sstephen hemminger 	}
32425c71c75Sstephen hemminger }
32525c71c75Sstephen hemminger 
32625c71c75Sstephen hemminger /* Process bridge protocol info on port */
32725c71c75Sstephen hemminger static int br_setport(struct net_bridge_port *p, struct nlattr *tb[])
32825c71c75Sstephen hemminger {
32925c71c75Sstephen hemminger 	int err;
330e028e4b8SVlad Yasevich 	unsigned long old_flags = p->flags;
33125c71c75Sstephen hemminger 
33225c71c75Sstephen hemminger 	br_set_port_flag(p, tb, IFLA_BRPORT_MODE, BR_HAIRPIN_MODE);
333a2e01a65Sstephen hemminger 	br_set_port_flag(p, tb, IFLA_BRPORT_GUARD, BR_BPDU_GUARD);
334c2d3babfSDavid S. Miller 	br_set_port_flag(p, tb, IFLA_BRPORT_FAST_LEAVE, BR_MULTICAST_FAST_LEAVE);
3353d84fa98SVlad Yasevich 	br_set_port_flag(p, tb, IFLA_BRPORT_PROTECT, BR_ROOT_BLOCK);
3369ba18891SVlad Yasevich 	br_set_port_flag(p, tb, IFLA_BRPORT_LEARNING, BR_LEARNING);
337867a5943SVlad Yasevich 	br_set_port_flag(p, tb, IFLA_BRPORT_UNICAST_FLOOD, BR_FLOOD);
33825c71c75Sstephen hemminger 
33925c71c75Sstephen hemminger 	if (tb[IFLA_BRPORT_COST]) {
34025c71c75Sstephen hemminger 		err = br_stp_set_path_cost(p, nla_get_u32(tb[IFLA_BRPORT_COST]));
34125c71c75Sstephen hemminger 		if (err)
34225c71c75Sstephen hemminger 			return err;
34325c71c75Sstephen hemminger 	}
34425c71c75Sstephen hemminger 
34525c71c75Sstephen hemminger 	if (tb[IFLA_BRPORT_PRIORITY]) {
34625c71c75Sstephen hemminger 		err = br_stp_set_port_priority(p, nla_get_u16(tb[IFLA_BRPORT_PRIORITY]));
34725c71c75Sstephen hemminger 		if (err)
34825c71c75Sstephen hemminger 			return err;
34925c71c75Sstephen hemminger 	}
35025c71c75Sstephen hemminger 
35125c71c75Sstephen hemminger 	if (tb[IFLA_BRPORT_STATE]) {
35225c71c75Sstephen hemminger 		err = br_set_port_state(p, nla_get_u8(tb[IFLA_BRPORT_STATE]));
35325c71c75Sstephen hemminger 		if (err)
35425c71c75Sstephen hemminger 			return err;
35525c71c75Sstephen hemminger 	}
356e028e4b8SVlad Yasevich 
357e028e4b8SVlad Yasevich 	br_port_flags_change(p, old_flags ^ p->flags);
35825c71c75Sstephen hemminger 	return 0;
35925c71c75Sstephen hemminger }
36025c71c75Sstephen hemminger 
36125c71c75Sstephen hemminger /* Change state and parameters on port. */
36225c71c75Sstephen hemminger int br_setlink(struct net_device *dev, struct nlmsghdr *nlh)
36325c71c75Sstephen hemminger {
36425c71c75Sstephen hemminger 	struct nlattr *protinfo;
365407af329SVlad Yasevich 	struct nlattr *afspec;
36625c71c75Sstephen hemminger 	struct net_bridge_port *p;
3672062cc20SDan Carpenter 	struct nlattr *tb[IFLA_BRPORT_MAX + 1];
3687b99a993SHong zhi guo 	int err = 0;
36925c71c75Sstephen hemminger 
370c60ee67fSHong zhi guo 	protinfo = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_PROTINFO);
371c60ee67fSHong zhi guo 	afspec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
372407af329SVlad Yasevich 	if (!protinfo && !afspec)
37325c71c75Sstephen hemminger 		return 0;
37425c71c75Sstephen hemminger 
37525c71c75Sstephen hemminger 	p = br_port_get_rtnl(dev);
376407af329SVlad Yasevich 	/* We want to accept dev as bridge itself if the AF_SPEC
3778e3bff96Sstephen hemminger 	 * is set to see if someone is setting vlan info on the bridge
378407af329SVlad Yasevich 	 */
3797b99a993SHong zhi guo 	if (!p && !afspec)
38025c71c75Sstephen hemminger 		return -EINVAL;
38125c71c75Sstephen hemminger 
382407af329SVlad Yasevich 	if (p && protinfo) {
38325c71c75Sstephen hemminger 		if (protinfo->nla_type & NLA_F_NESTED) {
38425c71c75Sstephen hemminger 			err = nla_parse_nested(tb, IFLA_BRPORT_MAX,
38525c71c75Sstephen hemminger 					       protinfo, ifla_brport_policy);
38625c71c75Sstephen hemminger 			if (err)
38725c71c75Sstephen hemminger 				return err;
388b03b6dd5SVitalii Demianets 
389b03b6dd5SVitalii Demianets 			spin_lock_bh(&p->br->lock);
39025c71c75Sstephen hemminger 			err = br_setport(p, tb);
391b03b6dd5SVitalii Demianets 			spin_unlock_bh(&p->br->lock);
39225c71c75Sstephen hemminger 		} else {
3938e3bff96Sstephen hemminger 			/* Binary compatibility with old RSTP */
39425c71c75Sstephen hemminger 			if (nla_len(protinfo) < sizeof(u8))
39525c71c75Sstephen hemminger 				return -EINVAL;
396b03b6dd5SVitalii Demianets 
39725c71c75Sstephen hemminger 			spin_lock_bh(&p->br->lock);
39825c71c75Sstephen hemminger 			err = br_set_port_state(p, nla_get_u8(protinfo));
39925c71c75Sstephen hemminger 			spin_unlock_bh(&p->br->lock);
40025c71c75Sstephen hemminger 		}
401407af329SVlad Yasevich 		if (err)
402407af329SVlad Yasevich 			goto out;
403407af329SVlad Yasevich 	}
404407af329SVlad Yasevich 
405407af329SVlad Yasevich 	if (afspec) {
406407af329SVlad Yasevich 		err = br_afspec((struct net_bridge *)netdev_priv(dev), p,
407407af329SVlad Yasevich 				afspec, RTM_SETLINK);
408407af329SVlad Yasevich 	}
40925c71c75Sstephen hemminger 
41025c71c75Sstephen hemminger 	if (err == 0)
41125c71c75Sstephen hemminger 		br_ifinfo_notify(RTM_NEWLINK, p);
41225c71c75Sstephen hemminger 
413407af329SVlad Yasevich out:
41425c71c75Sstephen hemminger 	return err;
41511dc1f36SStephen Hemminger }
41611dc1f36SStephen Hemminger 
417407af329SVlad Yasevich /* Delete port information */
418407af329SVlad Yasevich int br_dellink(struct net_device *dev, struct nlmsghdr *nlh)
419407af329SVlad Yasevich {
420407af329SVlad Yasevich 	struct nlattr *afspec;
421407af329SVlad Yasevich 	struct net_bridge_port *p;
422407af329SVlad Yasevich 	int err;
423407af329SVlad Yasevich 
424c60ee67fSHong zhi guo 	afspec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
425407af329SVlad Yasevich 	if (!afspec)
426407af329SVlad Yasevich 		return 0;
427407af329SVlad Yasevich 
428407af329SVlad Yasevich 	p = br_port_get_rtnl(dev);
429407af329SVlad Yasevich 	/* We want to accept dev as bridge itself as well */
430407af329SVlad Yasevich 	if (!p && !(dev->priv_flags & IFF_EBRIDGE))
431407af329SVlad Yasevich 		return -EINVAL;
432407af329SVlad Yasevich 
433407af329SVlad Yasevich 	err = br_afspec((struct net_bridge *)netdev_priv(dev), p,
434407af329SVlad Yasevich 			afspec, RTM_DELLINK);
435407af329SVlad Yasevich 
436407af329SVlad Yasevich 	return err;
437407af329SVlad Yasevich }
438bb900b27Sstephen hemminger static int br_validate(struct nlattr *tb[], struct nlattr *data[])
43911dc1f36SStephen Hemminger {
440bb900b27Sstephen hemminger 	if (tb[IFLA_ADDRESS]) {
441bb900b27Sstephen hemminger 		if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
442bb900b27Sstephen hemminger 			return -EINVAL;
443bb900b27Sstephen hemminger 		if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
444bb900b27Sstephen hemminger 			return -EADDRNOTAVAIL;
445bb900b27Sstephen hemminger 	}
44632fe21c0SThomas Graf 
44732fe21c0SThomas Graf 	return 0;
44811dc1f36SStephen Hemminger }
44911dc1f36SStephen Hemminger 
45030313a3dSToshiaki Makita static int br_dev_newlink(struct net *src_net, struct net_device *dev,
45130313a3dSToshiaki Makita 			  struct nlattr *tb[], struct nlattr *data[])
45230313a3dSToshiaki Makita {
45330313a3dSToshiaki Makita 	struct net_bridge *br = netdev_priv(dev);
45430313a3dSToshiaki Makita 
45530313a3dSToshiaki Makita 	if (tb[IFLA_ADDRESS]) {
45630313a3dSToshiaki Makita 		spin_lock_bh(&br->lock);
45730313a3dSToshiaki Makita 		br_stp_change_bridge_id(br, nla_data(tb[IFLA_ADDRESS]));
45830313a3dSToshiaki Makita 		spin_unlock_bh(&br->lock);
45930313a3dSToshiaki Makita 	}
46030313a3dSToshiaki Makita 
46130313a3dSToshiaki Makita 	return register_netdevice(dev);
46230313a3dSToshiaki Makita }
46330313a3dSToshiaki Makita 
464*ced8283fSJiri Pirko static int br_port_fill_slave_info(struct sk_buff *skb,
465*ced8283fSJiri Pirko 				   const struct net_device *brdev,
466*ced8283fSJiri Pirko 				   const struct net_device *dev)
467*ced8283fSJiri Pirko {
468*ced8283fSJiri Pirko 	return br_port_fill_attrs(skb, br_port_get_rtnl(dev));
469*ced8283fSJiri Pirko }
470*ced8283fSJiri Pirko 
471*ced8283fSJiri Pirko static size_t br_port_get_slave_size(const struct net_device *brdev,
472*ced8283fSJiri Pirko 				     const struct net_device *dev)
473*ced8283fSJiri Pirko {
474*ced8283fSJiri Pirko 	return br_port_info_size();
475*ced8283fSJiri Pirko }
476*ced8283fSJiri Pirko 
4776cbdceebSVlad Yasevich static size_t br_get_link_af_size(const struct net_device *dev)
4786cbdceebSVlad Yasevich {
4796cbdceebSVlad Yasevich 	struct net_port_vlans *pv;
4806cbdceebSVlad Yasevich 
4816cbdceebSVlad Yasevich 	if (br_port_exists(dev))
4821fb1754aSHong Zhiguo 		pv = nbp_get_vlan_info(br_port_get_rtnl(dev));
4836cbdceebSVlad Yasevich 	else if (dev->priv_flags & IFF_EBRIDGE)
4846cbdceebSVlad Yasevich 		pv = br_get_vlan_info((struct net_bridge *)netdev_priv(dev));
4856cbdceebSVlad Yasevich 	else
4866cbdceebSVlad Yasevich 		return 0;
4876cbdceebSVlad Yasevich 
4886cbdceebSVlad Yasevich 	if (!pv)
4896cbdceebSVlad Yasevich 		return 0;
4906cbdceebSVlad Yasevich 
4916cbdceebSVlad Yasevich 	/* Each VLAN is returned in bridge_vlan_info along with flags */
4926cbdceebSVlad Yasevich 	return pv->num_vlans * nla_total_size(sizeof(struct bridge_vlan_info));
4936cbdceebSVlad Yasevich }
4946cbdceebSVlad Yasevich 
49515004cabSCong Wang static struct rtnl_af_ops br_af_ops = {
4966cbdceebSVlad Yasevich 	.family			= AF_BRIDGE,
4976cbdceebSVlad Yasevich 	.get_link_af_size	= br_get_link_af_size,
4986cbdceebSVlad Yasevich };
4996cbdceebSVlad Yasevich 
500149ddd83Sstephen hemminger struct rtnl_link_ops br_link_ops __read_mostly = {
501bb900b27Sstephen hemminger 	.kind			= "bridge",
502bb900b27Sstephen hemminger 	.priv_size		= sizeof(struct net_bridge),
503bb900b27Sstephen hemminger 	.setup			= br_dev_setup,
504bb900b27Sstephen hemminger 	.validate		= br_validate,
50530313a3dSToshiaki Makita 	.newlink		= br_dev_newlink,
5061ce5cce8Sstephen hemminger 	.dellink		= br_dev_delete,
507*ced8283fSJiri Pirko 	.get_slave_size		= br_port_get_slave_size,
508*ced8283fSJiri Pirko 	.fill_slave_info	= br_port_fill_slave_info,
509bb900b27Sstephen hemminger };
510bb900b27Sstephen hemminger 
511bb900b27Sstephen hemminger int __init br_netlink_init(void)
51211dc1f36SStephen Hemminger {
5133ec8e9f0SVlad Yasevich 	int err;
5143ec8e9f0SVlad Yasevich 
5153ec8e9f0SVlad Yasevich 	br_mdb_init();
5163678a9d8Sstephen hemminger 	rtnl_af_register(&br_af_ops);
5173ec8e9f0SVlad Yasevich 
5186cbdceebSVlad Yasevich 	err = rtnl_link_register(&br_link_ops);
5196cbdceebSVlad Yasevich 	if (err)
5206cbdceebSVlad Yasevich 		goto out_af;
5216cbdceebSVlad Yasevich 
5223ec8e9f0SVlad Yasevich 	return 0;
5236cbdceebSVlad Yasevich 
5246cbdceebSVlad Yasevich out_af:
5256cbdceebSVlad Yasevich 	rtnl_af_unregister(&br_af_ops);
5263ec8e9f0SVlad Yasevich 	br_mdb_uninit();
5273ec8e9f0SVlad Yasevich 	return err;
52811dc1f36SStephen Hemminger }
52911dc1f36SStephen Hemminger 
530bb900b27Sstephen hemminger void __exit br_netlink_fini(void)
531bb900b27Sstephen hemminger {
5323ec8e9f0SVlad Yasevich 	br_mdb_uninit();
5336cbdceebSVlad Yasevich 	rtnl_af_unregister(&br_af_ops);
534bb900b27Sstephen hemminger 	rtnl_link_unregister(&br_link_ops);
535bb900b27Sstephen hemminger }
536