xref: /openbmc/linux/net/bridge/br_sysfs_if.c (revision 993e1634)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *	Sysfs attributes of bridge ports
41da177e4SLinus Torvalds  *	Linux ethernet bridge
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  *	Authors:
71da177e4SLinus Torvalds  *	Stephen Hemminger		<shemminger@osdl.org>
81da177e4SLinus Torvalds  */
91da177e4SLinus Torvalds 
104fc268d2SRandy Dunlap #include <linux/capability.h>
111da177e4SLinus Torvalds #include <linux/kernel.h>
121da177e4SLinus Torvalds #include <linux/netdevice.h>
131da177e4SLinus Torvalds #include <linux/if_bridge.h>
141da177e4SLinus Torvalds #include <linux/rtnetlink.h>
151da177e4SLinus Torvalds #include <linux/spinlock.h>
16174cd4b1SIngo Molnar #include <linux/sched/signal.h>
171da177e4SLinus Torvalds 
181da177e4SLinus Torvalds #include "br_private.h"
191da177e4SLinus Torvalds 
201e16f382SNikolay Aleksandrov /* IMPORTANT: new bridge port options must be added with netlink support only
211e16f382SNikolay Aleksandrov  *            please do not add new sysfs entries
221e16f382SNikolay Aleksandrov  */
231e16f382SNikolay Aleksandrov 
241da177e4SLinus Torvalds struct brport_attribute {
251da177e4SLinus Torvalds 	struct attribute	attr;
261da177e4SLinus Torvalds 	ssize_t (*show)(struct net_bridge_port *, char *);
2714f98f25Sstephen hemminger 	int (*store)(struct net_bridge_port *, unsigned long);
28a5f3ea54SNikolay Aleksandrov 	int (*store_raw)(struct net_bridge_port *, char *);
29a5f3ea54SNikolay Aleksandrov };
30a5f3ea54SNikolay Aleksandrov 
31a5f3ea54SNikolay Aleksandrov #define BRPORT_ATTR_RAW(_name, _mode, _show, _store)			\
32a5f3ea54SNikolay Aleksandrov const struct brport_attribute brport_attr_##_name = {			\
33a5f3ea54SNikolay Aleksandrov 	.attr		= {.name = __stringify(_name),			\
34a5f3ea54SNikolay Aleksandrov 			   .mode = _mode },				\
35a5f3ea54SNikolay Aleksandrov 	.show		= _show,					\
36a5f3ea54SNikolay Aleksandrov 	.store_raw	= _store,					\
371da177e4SLinus Torvalds };
381da177e4SLinus Torvalds 
391da177e4SLinus Torvalds #define BRPORT_ATTR(_name, _mode, _show, _store)		\
405a0d513bSstephen hemminger const struct brport_attribute brport_attr_##_name = { 	        \
411da177e4SLinus Torvalds 	.attr = {.name = __stringify(_name), 			\
427b595756STejun Heo 		 .mode = _mode },				\
431da177e4SLinus Torvalds 	.show	= _show,					\
441da177e4SLinus Torvalds 	.store	= _store,					\
451da177e4SLinus Torvalds };
461da177e4SLinus Torvalds 
47cd753732Sstephen hemminger #define BRPORT_ATTR_FLAG(_name, _mask)				\
48cd753732Sstephen hemminger static ssize_t show_##_name(struct net_bridge_port *p, char *buf) \
49cd753732Sstephen hemminger {								\
50cd753732Sstephen hemminger 	return sprintf(buf, "%d\n", !!(p->flags & _mask));	\
51cd753732Sstephen hemminger }								\
52cd753732Sstephen hemminger static int store_##_name(struct net_bridge_port *p, unsigned long v) \
53cd753732Sstephen hemminger {								\
5463c3a622SVlad Yasevich 	return store_flag(p, v, _mask);				\
55cd753732Sstephen hemminger }								\
56d6444062SJoe Perches static BRPORT_ATTR(_name, 0644,					\
57cd753732Sstephen hemminger 		   show_##_name, store_##_name)
58cd753732Sstephen hemminger 
store_flag(struct net_bridge_port * p,unsigned long v,unsigned long mask)5963c3a622SVlad Yasevich static int store_flag(struct net_bridge_port *p, unsigned long v,
6063c3a622SVlad Yasevich 		      unsigned long mask)
6163c3a622SVlad Yasevich {
62078bbb85SVladimir Oltean 	struct netlink_ext_ack extack = {0};
638043c845SVladimir Oltean 	unsigned long flags = p->flags;
648043c845SVladimir Oltean 	int err;
6563c3a622SVlad Yasevich 
6663c3a622SVlad Yasevich 	if (v)
6763c3a622SVlad Yasevich 		flags |= mask;
6863c3a622SVlad Yasevich 	else
6963c3a622SVlad Yasevich 		flags &= ~mask;
7063c3a622SVlad Yasevich 
7163c3a622SVlad Yasevich 	if (flags != p->flags) {
72078bbb85SVladimir Oltean 		err = br_switchdev_set_port_flag(p, flags, mask, &extack);
73078bbb85SVladimir Oltean 		if (err) {
74078bbb85SVladimir Oltean 			netdev_err(p->dev, "%s\n", extack._msg);
758043c845SVladimir Oltean 			return err;
76078bbb85SVladimir Oltean 		}
778043c845SVladimir Oltean 
7863c3a622SVlad Yasevich 		p->flags = flags;
79e028e4b8SVlad Yasevich 		br_port_flags_change(p, mask);
8063c3a622SVlad Yasevich 	}
8163c3a622SVlad Yasevich 	return 0;
8263c3a622SVlad Yasevich }
83cd753732Sstephen hemminger 
show_path_cost(struct net_bridge_port * p,char * buf)841da177e4SLinus Torvalds static ssize_t show_path_cost(struct net_bridge_port *p, char *buf)
851da177e4SLinus Torvalds {
861da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", p->path_cost);
871da177e4SLinus Torvalds }
8814f98f25Sstephen hemminger 
89d6444062SJoe Perches static BRPORT_ATTR(path_cost, 0644,
9014f98f25Sstephen hemminger 		   show_path_cost, br_stp_set_path_cost);
911da177e4SLinus Torvalds 
show_priority(struct net_bridge_port * p,char * buf)921da177e4SLinus Torvalds static ssize_t show_priority(struct net_bridge_port *p, char *buf)
931da177e4SLinus Torvalds {
941da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", p->priority);
951da177e4SLinus Torvalds }
9614f98f25Sstephen hemminger 
97d6444062SJoe Perches static BRPORT_ATTR(priority, 0644,
9814f98f25Sstephen hemminger 			 show_priority, br_stp_set_port_priority);
991da177e4SLinus Torvalds 
show_designated_root(struct net_bridge_port * p,char * buf)1001da177e4SLinus Torvalds static ssize_t show_designated_root(struct net_bridge_port *p, char *buf)
1011da177e4SLinus Torvalds {
1021da177e4SLinus Torvalds 	return br_show_bridge_id(buf, &p->designated_root);
1031da177e4SLinus Torvalds }
104d6444062SJoe Perches static BRPORT_ATTR(designated_root, 0444, show_designated_root, NULL);
1051da177e4SLinus Torvalds 
show_designated_bridge(struct net_bridge_port * p,char * buf)1061da177e4SLinus Torvalds static ssize_t show_designated_bridge(struct net_bridge_port *p, char *buf)
1071da177e4SLinus Torvalds {
1081da177e4SLinus Torvalds 	return br_show_bridge_id(buf, &p->designated_bridge);
1091da177e4SLinus Torvalds }
110d6444062SJoe Perches static BRPORT_ATTR(designated_bridge, 0444, show_designated_bridge, NULL);
1111da177e4SLinus Torvalds 
show_designated_port(struct net_bridge_port * p,char * buf)1121da177e4SLinus Torvalds static ssize_t show_designated_port(struct net_bridge_port *p, char *buf)
1131da177e4SLinus Torvalds {
1141da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", p->designated_port);
1151da177e4SLinus Torvalds }
116d6444062SJoe Perches static BRPORT_ATTR(designated_port, 0444, show_designated_port, NULL);
1171da177e4SLinus Torvalds 
show_designated_cost(struct net_bridge_port * p,char * buf)1181da177e4SLinus Torvalds static ssize_t show_designated_cost(struct net_bridge_port *p, char *buf)
1191da177e4SLinus Torvalds {
1201da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", p->designated_cost);
1211da177e4SLinus Torvalds }
122d6444062SJoe Perches static BRPORT_ATTR(designated_cost, 0444, show_designated_cost, NULL);
1231da177e4SLinus Torvalds 
show_port_id(struct net_bridge_port * p,char * buf)1241da177e4SLinus Torvalds static ssize_t show_port_id(struct net_bridge_port *p, char *buf)
1251da177e4SLinus Torvalds {
1261da177e4SLinus Torvalds 	return sprintf(buf, "0x%x\n", p->port_id);
1271da177e4SLinus Torvalds }
128d6444062SJoe Perches static BRPORT_ATTR(port_id, 0444, show_port_id, NULL);
1291da177e4SLinus Torvalds 
show_port_no(struct net_bridge_port * p,char * buf)1301da177e4SLinus Torvalds static ssize_t show_port_no(struct net_bridge_port *p, char *buf)
1311da177e4SLinus Torvalds {
1321da177e4SLinus Torvalds 	return sprintf(buf, "0x%x\n", p->port_no);
1331da177e4SLinus Torvalds }
1341da177e4SLinus Torvalds 
135d6444062SJoe Perches static BRPORT_ATTR(port_no, 0444, show_port_no, NULL);
1361da177e4SLinus Torvalds 
show_change_ack(struct net_bridge_port * p,char * buf)1371da177e4SLinus Torvalds static ssize_t show_change_ack(struct net_bridge_port *p, char *buf)
1381da177e4SLinus Torvalds {
1391da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", p->topology_change_ack);
1401da177e4SLinus Torvalds }
141d6444062SJoe Perches static BRPORT_ATTR(change_ack, 0444, show_change_ack, NULL);
1421da177e4SLinus Torvalds 
show_config_pending(struct net_bridge_port * p,char * buf)1431da177e4SLinus Torvalds static ssize_t show_config_pending(struct net_bridge_port *p, char *buf)
1441da177e4SLinus Torvalds {
1451da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", p->config_pending);
1461da177e4SLinus Torvalds }
147d6444062SJoe Perches static BRPORT_ATTR(config_pending, 0444, show_config_pending, NULL);
1481da177e4SLinus Torvalds 
show_port_state(struct net_bridge_port * p,char * buf)1491da177e4SLinus Torvalds static ssize_t show_port_state(struct net_bridge_port *p, char *buf)
1501da177e4SLinus Torvalds {
1511da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", p->state);
1521da177e4SLinus Torvalds }
153d6444062SJoe Perches static BRPORT_ATTR(state, 0444, show_port_state, NULL);
1541da177e4SLinus Torvalds 
show_message_age_timer(struct net_bridge_port * p,char * buf)1551da177e4SLinus Torvalds static ssize_t show_message_age_timer(struct net_bridge_port *p,
1561da177e4SLinus Torvalds 					    char *buf)
1571da177e4SLinus Torvalds {
1581da177e4SLinus Torvalds 	return sprintf(buf, "%ld\n", br_timer_value(&p->message_age_timer));
1591da177e4SLinus Torvalds }
160d6444062SJoe Perches static BRPORT_ATTR(message_age_timer, 0444, show_message_age_timer, NULL);
1611da177e4SLinus Torvalds 
show_forward_delay_timer(struct net_bridge_port * p,char * buf)1621da177e4SLinus Torvalds static ssize_t show_forward_delay_timer(struct net_bridge_port *p,
1631da177e4SLinus Torvalds 					    char *buf)
1641da177e4SLinus Torvalds {
1651da177e4SLinus Torvalds 	return sprintf(buf, "%ld\n", br_timer_value(&p->forward_delay_timer));
1661da177e4SLinus Torvalds }
167d6444062SJoe Perches static BRPORT_ATTR(forward_delay_timer, 0444, show_forward_delay_timer, NULL);
1681da177e4SLinus Torvalds 
show_hold_timer(struct net_bridge_port * p,char * buf)1691da177e4SLinus Torvalds static ssize_t show_hold_timer(struct net_bridge_port *p,
1701da177e4SLinus Torvalds 					    char *buf)
1711da177e4SLinus Torvalds {
1721da177e4SLinus Torvalds 	return sprintf(buf, "%ld\n", br_timer_value(&p->hold_timer));
1731da177e4SLinus Torvalds }
174d6444062SJoe Perches static BRPORT_ATTR(hold_timer, 0444, show_hold_timer, NULL);
1751da177e4SLinus Torvalds 
store_flush(struct net_bridge_port * p,unsigned long v)17614f98f25Sstephen hemminger static int store_flush(struct net_bridge_port *p, unsigned long v)
1779cf63747SStephen Hemminger {
1781ea2d020SNikolay Aleksandrov 	br_fdb_delete_by_port(p->br, p, 0, 0); // Don't delete local entry
1799cf63747SStephen Hemminger 	return 0;
1809cf63747SStephen Hemminger }
181d6444062SJoe Perches static BRPORT_ATTR(flush, 0200, NULL, store_flush);
1829cf63747SStephen Hemminger 
show_group_fwd_mask(struct net_bridge_port * p,char * buf)1835af48b59SNikolay Aleksandrov static ssize_t show_group_fwd_mask(struct net_bridge_port *p, char *buf)
1845af48b59SNikolay Aleksandrov {
1855af48b59SNikolay Aleksandrov 	return sprintf(buf, "%#x\n", p->group_fwd_mask);
1865af48b59SNikolay Aleksandrov }
1875af48b59SNikolay Aleksandrov 
store_group_fwd_mask(struct net_bridge_port * p,unsigned long v)1885af48b59SNikolay Aleksandrov static int store_group_fwd_mask(struct net_bridge_port *p,
1895af48b59SNikolay Aleksandrov 				unsigned long v)
1905af48b59SNikolay Aleksandrov {
1915af48b59SNikolay Aleksandrov 	if (v & BR_GROUPFWD_MACPAUSE)
1925af48b59SNikolay Aleksandrov 		return -EINVAL;
1935af48b59SNikolay Aleksandrov 	p->group_fwd_mask = v;
1945af48b59SNikolay Aleksandrov 
1955af48b59SNikolay Aleksandrov 	return 0;
1965af48b59SNikolay Aleksandrov }
197d6444062SJoe Perches static BRPORT_ATTR(group_fwd_mask, 0644, show_group_fwd_mask,
1985af48b59SNikolay Aleksandrov 		   store_group_fwd_mask);
1995af48b59SNikolay Aleksandrov 
show_backup_port(struct net_bridge_port * p,char * buf)2002756f68cSNikolay Aleksandrov static ssize_t show_backup_port(struct net_bridge_port *p, char *buf)
2012756f68cSNikolay Aleksandrov {
2022756f68cSNikolay Aleksandrov 	struct net_bridge_port *backup_p;
2032756f68cSNikolay Aleksandrov 	int ret = 0;
2042756f68cSNikolay Aleksandrov 
2052756f68cSNikolay Aleksandrov 	rcu_read_lock();
2062756f68cSNikolay Aleksandrov 	backup_p = rcu_dereference(p->backup_port);
2072756f68cSNikolay Aleksandrov 	if (backup_p)
2082756f68cSNikolay Aleksandrov 		ret = sprintf(buf, "%s\n", backup_p->dev->name);
2092756f68cSNikolay Aleksandrov 	rcu_read_unlock();
2102756f68cSNikolay Aleksandrov 
2112756f68cSNikolay Aleksandrov 	return ret;
2122756f68cSNikolay Aleksandrov }
2132756f68cSNikolay Aleksandrov 
store_backup_port(struct net_bridge_port * p,char * buf)2142756f68cSNikolay Aleksandrov static int store_backup_port(struct net_bridge_port *p, char *buf)
2152756f68cSNikolay Aleksandrov {
2162756f68cSNikolay Aleksandrov 	struct net_device *backup_dev = NULL;
2172756f68cSNikolay Aleksandrov 	char *nl = strchr(buf, '\n');
2182756f68cSNikolay Aleksandrov 
2192756f68cSNikolay Aleksandrov 	if (nl)
2202756f68cSNikolay Aleksandrov 		*nl = '\0';
2212756f68cSNikolay Aleksandrov 
2222756f68cSNikolay Aleksandrov 	if (strlen(buf) > 0) {
2232756f68cSNikolay Aleksandrov 		backup_dev = __dev_get_by_name(dev_net(p->dev), buf);
2242756f68cSNikolay Aleksandrov 		if (!backup_dev)
2252756f68cSNikolay Aleksandrov 			return -ENOENT;
2262756f68cSNikolay Aleksandrov 	}
2272756f68cSNikolay Aleksandrov 
2282756f68cSNikolay Aleksandrov 	return nbp_backup_change(p, backup_dev);
2292756f68cSNikolay Aleksandrov }
2302756f68cSNikolay Aleksandrov static BRPORT_ATTR_RAW(backup_port, 0644, show_backup_port, store_backup_port);
2312756f68cSNikolay Aleksandrov 
232cd753732Sstephen hemminger BRPORT_ATTR_FLAG(hairpin_mode, BR_HAIRPIN_MODE);
233a2e01a65Sstephen hemminger BRPORT_ATTR_FLAG(bpdu_guard, BR_BPDU_GUARD);
2341007dd1aSstephen hemminger BRPORT_ATTR_FLAG(root_block, BR_ROOT_BLOCK);
2359ba18891SVlad Yasevich BRPORT_ATTR_FLAG(learning, BR_LEARNING);
236867a5943SVlad Yasevich BRPORT_ATTR_FLAG(unicast_flood, BR_FLOOD);
23795850116SKyeyoon Park BRPORT_ATTR_FLAG(proxyarp, BR_PROXYARP);
238842a9ae0SJouni Malinen BRPORT_ATTR_FLAG(proxyarp_wifi, BR_PROXYARP_WIFI);
239b6cb5ac8SNikolay Aleksandrov BRPORT_ATTR_FLAG(multicast_flood, BR_MCAST_FLOOD);
24099f906e9SMike Manning BRPORT_ATTR_FLAG(broadcast_flood, BR_BCAST_FLOOD);
241821f1b21SRoopa Prabhu BRPORT_ATTR_FLAG(neigh_suppress, BR_NEIGH_SUPPRESS);
2427d850abdSNikolay Aleksandrov BRPORT_ATTR_FLAG(isolated, BR_ISOLATED);
2433982d3d2SFischer, Anna 
2440909e117SHerbert Xu #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
show_multicast_router(struct net_bridge_port * p,char * buf)2450909e117SHerbert Xu static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
2460909e117SHerbert Xu {
2479632233eSNikolay Aleksandrov 	return sprintf(buf, "%d\n", p->multicast_ctx.multicast_router);
2480909e117SHerbert Xu }
2490909e117SHerbert Xu 
store_multicast_router(struct net_bridge_port * p,unsigned long v)25014f98f25Sstephen hemminger static int store_multicast_router(struct net_bridge_port *p,
2510909e117SHerbert Xu 				      unsigned long v)
2520909e117SHerbert Xu {
253a53581d5SNikolay Aleksandrov 	return br_multicast_set_port_router(&p->multicast_ctx, v);
2540909e117SHerbert Xu }
255d6444062SJoe Perches static BRPORT_ATTR(multicast_router, 0644, show_multicast_router,
2560909e117SHerbert Xu 		   store_multicast_router);
25750426b59SAmerigo Wang 
258c2d3babfSDavid S. Miller BRPORT_ATTR_FLAG(multicast_fast_leave, BR_MULTICAST_FAST_LEAVE);
2596db6f0eaSFelix Fietkau BRPORT_ATTR_FLAG(multicast_to_unicast, BR_MULTICAST_TO_UNICAST);
2600909e117SHerbert Xu #endif
2610909e117SHerbert Xu 
2625a0d513bSstephen hemminger static const struct brport_attribute *brport_attrs[] = {
2631da177e4SLinus Torvalds 	&brport_attr_path_cost,
2641da177e4SLinus Torvalds 	&brport_attr_priority,
2651da177e4SLinus Torvalds 	&brport_attr_port_id,
2661da177e4SLinus Torvalds 	&brport_attr_port_no,
2671da177e4SLinus Torvalds 	&brport_attr_designated_root,
2681da177e4SLinus Torvalds 	&brport_attr_designated_bridge,
2691da177e4SLinus Torvalds 	&brport_attr_designated_port,
2701da177e4SLinus Torvalds 	&brport_attr_designated_cost,
2711da177e4SLinus Torvalds 	&brport_attr_state,
2721da177e4SLinus Torvalds 	&brport_attr_change_ack,
2731da177e4SLinus Torvalds 	&brport_attr_config_pending,
2741da177e4SLinus Torvalds 	&brport_attr_message_age_timer,
2751da177e4SLinus Torvalds 	&brport_attr_forward_delay_timer,
2761da177e4SLinus Torvalds 	&brport_attr_hold_timer,
2779cf63747SStephen Hemminger 	&brport_attr_flush,
2783982d3d2SFischer, Anna 	&brport_attr_hairpin_mode,
279a2e01a65Sstephen hemminger 	&brport_attr_bpdu_guard,
2801007dd1aSstephen hemminger 	&brport_attr_root_block,
2819ba18891SVlad Yasevich 	&brport_attr_learning,
282867a5943SVlad Yasevich 	&brport_attr_unicast_flood,
2830909e117SHerbert Xu #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
2840909e117SHerbert Xu 	&brport_attr_multicast_router,
28550426b59SAmerigo Wang 	&brport_attr_multicast_fast_leave,
2866db6f0eaSFelix Fietkau 	&brport_attr_multicast_to_unicast,
2870909e117SHerbert Xu #endif
28895850116SKyeyoon Park 	&brport_attr_proxyarp,
289842a9ae0SJouni Malinen 	&brport_attr_proxyarp_wifi,
2904eb6753cSNikolay Aleksandrov 	&brport_attr_multicast_flood,
29199f906e9SMike Manning 	&brport_attr_broadcast_flood,
2925af48b59SNikolay Aleksandrov 	&brport_attr_group_fwd_mask,
293821f1b21SRoopa Prabhu 	&brport_attr_neigh_suppress,
2947d850abdSNikolay Aleksandrov 	&brport_attr_isolated,
2952756f68cSNikolay Aleksandrov 	&brport_attr_backup_port,
2961da177e4SLinus Torvalds 	NULL
2971da177e4SLinus Torvalds };
2981da177e4SLinus Torvalds 
2991da177e4SLinus Torvalds #define to_brport_attr(_at) container_of(_at, struct brport_attribute, attr)
3001da177e4SLinus Torvalds 
brport_show(struct kobject * kobj,struct attribute * attr,char * buf)3011da177e4SLinus Torvalds static ssize_t brport_show(struct kobject *kobj,
3021da177e4SLinus Torvalds 			   struct attribute *attr, char *buf)
3031da177e4SLinus Torvalds {
3041da177e4SLinus Torvalds 	struct brport_attribute *brport_attr = to_brport_attr(attr);
305705e0deaSTyler Hicks 	struct net_bridge_port *p = kobj_to_brport(kobj);
3061da177e4SLinus Torvalds 
3071b12580aSXin Long 	if (!brport_attr->show)
3081b12580aSXin Long 		return -EINVAL;
3091b12580aSXin Long 
3101da177e4SLinus Torvalds 	return brport_attr->show(p, buf);
3111da177e4SLinus Torvalds }
3121da177e4SLinus Torvalds 
brport_store(struct kobject * kobj,struct attribute * attr,const char * buf,size_t count)3131da177e4SLinus Torvalds static ssize_t brport_store(struct kobject *kobj,
3141da177e4SLinus Torvalds 			    struct attribute *attr,
3151da177e4SLinus Torvalds 			    const char *buf, size_t count)
3161da177e4SLinus Torvalds {
3171da177e4SLinus Torvalds 	struct brport_attribute *brport_attr = to_brport_attr(attr);
318705e0deaSTyler Hicks 	struct net_bridge_port *p = kobj_to_brport(kobj);
3191da177e4SLinus Torvalds 	ssize_t ret = -EINVAL;
3201da177e4SLinus Torvalds 	unsigned long val;
321a5f3ea54SNikolay Aleksandrov 	char *endp;
3221da177e4SLinus Torvalds 
323cb990503SEric W. Biederman 	if (!ns_capable(dev_net(p->dev)->user_ns, CAP_NET_ADMIN))
3241da177e4SLinus Torvalds 		return -EPERM;
3251da177e4SLinus Torvalds 
326af38f298SEric W. Biederman 	if (!rtnl_trylock())
327af38f298SEric W. Biederman 		return restart_syscall();
328a5f3ea54SNikolay Aleksandrov 
329a5f3ea54SNikolay Aleksandrov 	if (brport_attr->store_raw) {
330a5f3ea54SNikolay Aleksandrov 		char *buf_copy;
331a5f3ea54SNikolay Aleksandrov 
332a5f3ea54SNikolay Aleksandrov 		buf_copy = kstrndup(buf, count, GFP_KERNEL);
333a5f3ea54SNikolay Aleksandrov 		if (!buf_copy) {
334a5f3ea54SNikolay Aleksandrov 			ret = -ENOMEM;
335a5f3ea54SNikolay Aleksandrov 			goto out_unlock;
336a5f3ea54SNikolay Aleksandrov 		}
337a5f3ea54SNikolay Aleksandrov 		spin_lock_bh(&p->br->lock);
338a5f3ea54SNikolay Aleksandrov 		ret = brport_attr->store_raw(p, buf_copy);
339a5f3ea54SNikolay Aleksandrov 		spin_unlock_bh(&p->br->lock);
340a5f3ea54SNikolay Aleksandrov 		kfree(buf_copy);
341a5f3ea54SNikolay Aleksandrov 	} else if (brport_attr->store) {
342a5f3ea54SNikolay Aleksandrov 		val = simple_strtoul(buf, &endp, 0);
343a5f3ea54SNikolay Aleksandrov 		if (endp == buf)
344a5f3ea54SNikolay Aleksandrov 			goto out_unlock;
3451da177e4SLinus Torvalds 		spin_lock_bh(&p->br->lock);
3461da177e4SLinus Torvalds 		ret = brport_attr->store(p, val);
3471da177e4SLinus Torvalds 		spin_unlock_bh(&p->br->lock);
348a5f3ea54SNikolay Aleksandrov 	}
349a5f3ea54SNikolay Aleksandrov 
350bdaf0d5dSXin Long 	if (!ret) {
35192899063SNikolay Aleksandrov 		br_ifinfo_notify(RTM_NEWLINK, NULL, p);
3521da177e4SLinus Torvalds 		ret = count;
3531da177e4SLinus Torvalds 	}
354a5f3ea54SNikolay Aleksandrov out_unlock:
3551da177e4SLinus Torvalds 	rtnl_unlock();
356a5f3ea54SNikolay Aleksandrov 
3571da177e4SLinus Torvalds 	return ret;
3581da177e4SLinus Torvalds }
3591da177e4SLinus Torvalds 
36052cf25d0SEmese Revfy const struct sysfs_ops brport_sysfs_ops = {
3611da177e4SLinus Torvalds 	.show = brport_show,
3621da177e4SLinus Torvalds 	.store = brport_store,
3631da177e4SLinus Torvalds };
3641da177e4SLinus Torvalds 
3651da177e4SLinus Torvalds /*
3661da177e4SLinus Torvalds  * Add sysfs entries to ethernet device added to a bridge.
3671da177e4SLinus Torvalds  * Creates a brport subdirectory with bridge attributes.
368e0f43752SSimon Arlott  * Puts symlink in bridge's brif subdirectory
3691da177e4SLinus Torvalds  */
br_sysfs_addif(struct net_bridge_port * p)3701da177e4SLinus Torvalds int br_sysfs_addif(struct net_bridge_port *p)
3711da177e4SLinus Torvalds {
3721da177e4SLinus Torvalds 	struct net_bridge *br = p->br;
3735a0d513bSstephen hemminger 	const struct brport_attribute **a;
3741da177e4SLinus Torvalds 	int err;
3751da177e4SLinus Torvalds 
37643cb76d9SGreg Kroah-Hartman 	err = sysfs_create_link(&p->kobj, &br->dev->dev.kobj,
3771da177e4SLinus Torvalds 				SYSFS_BRIDGE_PORT_LINK);
3781da177e4SLinus Torvalds 	if (err)
379e0f43752SSimon Arlott 		return err;
3801da177e4SLinus Torvalds 
3811da177e4SLinus Torvalds 	for (a = brport_attrs; *a; ++a) {
3821da177e4SLinus Torvalds 		err = sysfs_create_file(&p->kobj, &((*a)->attr));
3831da177e4SLinus Torvalds 		if (err)
384e0f43752SSimon Arlott 			return err;
3851da177e4SLinus Torvalds 	}
3861da177e4SLinus Torvalds 
387*993e1634SWolfram Sang 	strscpy(p->sysfs_name, p->dev->name, IFNAMSIZ);
388e0f43752SSimon Arlott 	return sysfs_create_link(br->ifobj, &p->kobj, p->sysfs_name);
389e0f43752SSimon Arlott }
390e0f43752SSimon Arlott 
391e0f43752SSimon Arlott /* Rename bridge's brif symlink */
br_sysfs_renameif(struct net_bridge_port * p)392e0f43752SSimon Arlott int br_sysfs_renameif(struct net_bridge_port *p)
393e0f43752SSimon Arlott {
394e0f43752SSimon Arlott 	struct net_bridge *br = p->br;
395e0f43752SSimon Arlott 	int err;
396e0f43752SSimon Arlott 
397e0f43752SSimon Arlott 	/* If a rename fails, the rollback will cause another
398e0f43752SSimon Arlott 	 * rename call with the existing name.
399e0f43752SSimon Arlott 	 */
400e0f43752SSimon Arlott 	if (!strncmp(p->sysfs_name, p->dev->name, IFNAMSIZ))
401e0f43752SSimon Arlott 		return 0;
402e0f43752SSimon Arlott 
403e0f43752SSimon Arlott 	err = sysfs_rename_link(br->ifobj, &p->kobj,
404e0f43752SSimon Arlott 				p->sysfs_name, p->dev->name);
405e0f43752SSimon Arlott 	if (err)
406e0f43752SSimon Arlott 		netdev_notice(br->dev, "unable to rename link %s to %s",
407e0f43752SSimon Arlott 			      p->sysfs_name, p->dev->name);
408e0f43752SSimon Arlott 	else
409*993e1634SWolfram Sang 		strscpy(p->sysfs_name, p->dev->name, IFNAMSIZ);
410e0f43752SSimon Arlott 
4111da177e4SLinus Torvalds 	return err;
4121da177e4SLinus Torvalds }
413