18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Sysfs attributes of bridge ports 48c2ecf20Sopenharmony_ci * Linux ethernet bridge 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Authors: 78c2ecf20Sopenharmony_ci * Stephen Hemminger <shemminger@osdl.org> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/capability.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 138c2ecf20Sopenharmony_ci#include <linux/if_bridge.h> 148c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h> 158c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 168c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "br_private.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistruct brport_attribute { 218c2ecf20Sopenharmony_ci struct attribute attr; 228c2ecf20Sopenharmony_ci ssize_t (*show)(struct net_bridge_port *, char *); 238c2ecf20Sopenharmony_ci int (*store)(struct net_bridge_port *, unsigned long); 248c2ecf20Sopenharmony_ci int (*store_raw)(struct net_bridge_port *, char *); 258c2ecf20Sopenharmony_ci}; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define BRPORT_ATTR_RAW(_name, _mode, _show, _store) \ 288c2ecf20Sopenharmony_ciconst struct brport_attribute brport_attr_##_name = { \ 298c2ecf20Sopenharmony_ci .attr = {.name = __stringify(_name), \ 308c2ecf20Sopenharmony_ci .mode = _mode }, \ 318c2ecf20Sopenharmony_ci .show = _show, \ 328c2ecf20Sopenharmony_ci .store_raw = _store, \ 338c2ecf20Sopenharmony_ci}; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define BRPORT_ATTR(_name, _mode, _show, _store) \ 368c2ecf20Sopenharmony_ciconst struct brport_attribute brport_attr_##_name = { \ 378c2ecf20Sopenharmony_ci .attr = {.name = __stringify(_name), \ 388c2ecf20Sopenharmony_ci .mode = _mode }, \ 398c2ecf20Sopenharmony_ci .show = _show, \ 408c2ecf20Sopenharmony_ci .store = _store, \ 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define BRPORT_ATTR_FLAG(_name, _mask) \ 448c2ecf20Sopenharmony_cistatic ssize_t show_##_name(struct net_bridge_port *p, char *buf) \ 458c2ecf20Sopenharmony_ci{ \ 468c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", !!(p->flags & _mask)); \ 478c2ecf20Sopenharmony_ci} \ 488c2ecf20Sopenharmony_cistatic int store_##_name(struct net_bridge_port *p, unsigned long v) \ 498c2ecf20Sopenharmony_ci{ \ 508c2ecf20Sopenharmony_ci return store_flag(p, v, _mask); \ 518c2ecf20Sopenharmony_ci} \ 528c2ecf20Sopenharmony_cistatic BRPORT_ATTR(_name, 0644, \ 538c2ecf20Sopenharmony_ci show_##_name, store_##_name) 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic int store_flag(struct net_bridge_port *p, unsigned long v, 568c2ecf20Sopenharmony_ci unsigned long mask) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci unsigned long flags = p->flags; 598c2ecf20Sopenharmony_ci int err; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci if (v) 628c2ecf20Sopenharmony_ci flags |= mask; 638c2ecf20Sopenharmony_ci else 648c2ecf20Sopenharmony_ci flags &= ~mask; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if (flags != p->flags) { 678c2ecf20Sopenharmony_ci err = br_switchdev_set_port_flag(p, flags, mask); 688c2ecf20Sopenharmony_ci if (err) 698c2ecf20Sopenharmony_ci return err; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci p->flags = flags; 728c2ecf20Sopenharmony_ci br_port_flags_change(p, mask); 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci return 0; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic ssize_t show_path_cost(struct net_bridge_port *p, char *buf) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", p->path_cost); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic BRPORT_ATTR(path_cost, 0644, 838c2ecf20Sopenharmony_ci show_path_cost, br_stp_set_path_cost); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic ssize_t show_priority(struct net_bridge_port *p, char *buf) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", p->priority); 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic BRPORT_ATTR(priority, 0644, 918c2ecf20Sopenharmony_ci show_priority, br_stp_set_port_priority); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic ssize_t show_designated_root(struct net_bridge_port *p, char *buf) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci return br_show_bridge_id(buf, &p->designated_root); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_cistatic BRPORT_ATTR(designated_root, 0444, show_designated_root, NULL); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic ssize_t show_designated_bridge(struct net_bridge_port *p, char *buf) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci return br_show_bridge_id(buf, &p->designated_bridge); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_cistatic BRPORT_ATTR(designated_bridge, 0444, show_designated_bridge, NULL); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic ssize_t show_designated_port(struct net_bridge_port *p, char *buf) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", p->designated_port); 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_cistatic BRPORT_ATTR(designated_port, 0444, show_designated_port, NULL); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic ssize_t show_designated_cost(struct net_bridge_port *p, char *buf) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", p->designated_cost); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_cistatic BRPORT_ATTR(designated_cost, 0444, show_designated_cost, NULL); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic ssize_t show_port_id(struct net_bridge_port *p, char *buf) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci return sprintf(buf, "0x%x\n", p->port_id); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_cistatic BRPORT_ATTR(port_id, 0444, show_port_id, NULL); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic ssize_t show_port_no(struct net_bridge_port *p, char *buf) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci return sprintf(buf, "0x%x\n", p->port_no); 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic BRPORT_ATTR(port_no, 0444, show_port_no, NULL); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic ssize_t show_change_ack(struct net_bridge_port *p, char *buf) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", p->topology_change_ack); 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_cistatic BRPORT_ATTR(change_ack, 0444, show_change_ack, NULL); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic ssize_t show_config_pending(struct net_bridge_port *p, char *buf) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", p->config_pending); 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_cistatic BRPORT_ATTR(config_pending, 0444, show_config_pending, NULL); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic ssize_t show_port_state(struct net_bridge_port *p, char *buf) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", p->state); 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_cistatic BRPORT_ATTR(state, 0444, show_port_state, NULL); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic ssize_t show_message_age_timer(struct net_bridge_port *p, 1498c2ecf20Sopenharmony_ci char *buf) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci return sprintf(buf, "%ld\n", br_timer_value(&p->message_age_timer)); 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_cistatic BRPORT_ATTR(message_age_timer, 0444, show_message_age_timer, NULL); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic ssize_t show_forward_delay_timer(struct net_bridge_port *p, 1568c2ecf20Sopenharmony_ci char *buf) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci return sprintf(buf, "%ld\n", br_timer_value(&p->forward_delay_timer)); 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_cistatic BRPORT_ATTR(forward_delay_timer, 0444, show_forward_delay_timer, NULL); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic ssize_t show_hold_timer(struct net_bridge_port *p, 1638c2ecf20Sopenharmony_ci char *buf) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci return sprintf(buf, "%ld\n", br_timer_value(&p->hold_timer)); 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_cistatic BRPORT_ATTR(hold_timer, 0444, show_hold_timer, NULL); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic int store_flush(struct net_bridge_port *p, unsigned long v) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci br_fdb_delete_by_port(p->br, p, 0, 0); // Don't delete local entry 1728c2ecf20Sopenharmony_ci return 0; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_cistatic BRPORT_ATTR(flush, 0200, NULL, store_flush); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic ssize_t show_group_fwd_mask(struct net_bridge_port *p, char *buf) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci return sprintf(buf, "%#x\n", p->group_fwd_mask); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic int store_group_fwd_mask(struct net_bridge_port *p, 1828c2ecf20Sopenharmony_ci unsigned long v) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci if (v & BR_GROUPFWD_MACPAUSE) 1858c2ecf20Sopenharmony_ci return -EINVAL; 1868c2ecf20Sopenharmony_ci p->group_fwd_mask = v; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci return 0; 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_cistatic BRPORT_ATTR(group_fwd_mask, 0644, show_group_fwd_mask, 1918c2ecf20Sopenharmony_ci store_group_fwd_mask); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic ssize_t show_backup_port(struct net_bridge_port *p, char *buf) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci struct net_bridge_port *backup_p; 1968c2ecf20Sopenharmony_ci int ret = 0; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci rcu_read_lock(); 1998c2ecf20Sopenharmony_ci backup_p = rcu_dereference(p->backup_port); 2008c2ecf20Sopenharmony_ci if (backup_p) 2018c2ecf20Sopenharmony_ci ret = sprintf(buf, "%s\n", backup_p->dev->name); 2028c2ecf20Sopenharmony_ci rcu_read_unlock(); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci return ret; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic int store_backup_port(struct net_bridge_port *p, char *buf) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci struct net_device *backup_dev = NULL; 2108c2ecf20Sopenharmony_ci char *nl = strchr(buf, '\n'); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (nl) 2138c2ecf20Sopenharmony_ci *nl = '\0'; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (strlen(buf) > 0) { 2168c2ecf20Sopenharmony_ci backup_dev = __dev_get_by_name(dev_net(p->dev), buf); 2178c2ecf20Sopenharmony_ci if (!backup_dev) 2188c2ecf20Sopenharmony_ci return -ENOENT; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci return nbp_backup_change(p, backup_dev); 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_cistatic BRPORT_ATTR_RAW(backup_port, 0644, show_backup_port, store_backup_port); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ciBRPORT_ATTR_FLAG(hairpin_mode, BR_HAIRPIN_MODE); 2268c2ecf20Sopenharmony_ciBRPORT_ATTR_FLAG(bpdu_guard, BR_BPDU_GUARD); 2278c2ecf20Sopenharmony_ciBRPORT_ATTR_FLAG(root_block, BR_ROOT_BLOCK); 2288c2ecf20Sopenharmony_ciBRPORT_ATTR_FLAG(learning, BR_LEARNING); 2298c2ecf20Sopenharmony_ciBRPORT_ATTR_FLAG(unicast_flood, BR_FLOOD); 2308c2ecf20Sopenharmony_ciBRPORT_ATTR_FLAG(proxyarp, BR_PROXYARP); 2318c2ecf20Sopenharmony_ciBRPORT_ATTR_FLAG(proxyarp_wifi, BR_PROXYARP_WIFI); 2328c2ecf20Sopenharmony_ciBRPORT_ATTR_FLAG(multicast_flood, BR_MCAST_FLOOD); 2338c2ecf20Sopenharmony_ciBRPORT_ATTR_FLAG(broadcast_flood, BR_BCAST_FLOOD); 2348c2ecf20Sopenharmony_ciBRPORT_ATTR_FLAG(neigh_suppress, BR_NEIGH_SUPPRESS); 2358c2ecf20Sopenharmony_ciBRPORT_ATTR_FLAG(isolated, BR_ISOLATED); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci#ifdef CONFIG_BRIDGE_IGMP_SNOOPING 2388c2ecf20Sopenharmony_cistatic ssize_t show_multicast_router(struct net_bridge_port *p, char *buf) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", p->multicast_router); 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic int store_multicast_router(struct net_bridge_port *p, 2448c2ecf20Sopenharmony_ci unsigned long v) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci return br_multicast_set_port_router(p, v); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_cistatic BRPORT_ATTR(multicast_router, 0644, show_multicast_router, 2498c2ecf20Sopenharmony_ci store_multicast_router); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ciBRPORT_ATTR_FLAG(multicast_fast_leave, BR_MULTICAST_FAST_LEAVE); 2528c2ecf20Sopenharmony_ciBRPORT_ATTR_FLAG(multicast_to_unicast, BR_MULTICAST_TO_UNICAST); 2538c2ecf20Sopenharmony_ci#endif 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic const struct brport_attribute *brport_attrs[] = { 2568c2ecf20Sopenharmony_ci &brport_attr_path_cost, 2578c2ecf20Sopenharmony_ci &brport_attr_priority, 2588c2ecf20Sopenharmony_ci &brport_attr_port_id, 2598c2ecf20Sopenharmony_ci &brport_attr_port_no, 2608c2ecf20Sopenharmony_ci &brport_attr_designated_root, 2618c2ecf20Sopenharmony_ci &brport_attr_designated_bridge, 2628c2ecf20Sopenharmony_ci &brport_attr_designated_port, 2638c2ecf20Sopenharmony_ci &brport_attr_designated_cost, 2648c2ecf20Sopenharmony_ci &brport_attr_state, 2658c2ecf20Sopenharmony_ci &brport_attr_change_ack, 2668c2ecf20Sopenharmony_ci &brport_attr_config_pending, 2678c2ecf20Sopenharmony_ci &brport_attr_message_age_timer, 2688c2ecf20Sopenharmony_ci &brport_attr_forward_delay_timer, 2698c2ecf20Sopenharmony_ci &brport_attr_hold_timer, 2708c2ecf20Sopenharmony_ci &brport_attr_flush, 2718c2ecf20Sopenharmony_ci &brport_attr_hairpin_mode, 2728c2ecf20Sopenharmony_ci &brport_attr_bpdu_guard, 2738c2ecf20Sopenharmony_ci &brport_attr_root_block, 2748c2ecf20Sopenharmony_ci &brport_attr_learning, 2758c2ecf20Sopenharmony_ci &brport_attr_unicast_flood, 2768c2ecf20Sopenharmony_ci#ifdef CONFIG_BRIDGE_IGMP_SNOOPING 2778c2ecf20Sopenharmony_ci &brport_attr_multicast_router, 2788c2ecf20Sopenharmony_ci &brport_attr_multicast_fast_leave, 2798c2ecf20Sopenharmony_ci &brport_attr_multicast_to_unicast, 2808c2ecf20Sopenharmony_ci#endif 2818c2ecf20Sopenharmony_ci &brport_attr_proxyarp, 2828c2ecf20Sopenharmony_ci &brport_attr_proxyarp_wifi, 2838c2ecf20Sopenharmony_ci &brport_attr_multicast_flood, 2848c2ecf20Sopenharmony_ci &brport_attr_broadcast_flood, 2858c2ecf20Sopenharmony_ci &brport_attr_group_fwd_mask, 2868c2ecf20Sopenharmony_ci &brport_attr_neigh_suppress, 2878c2ecf20Sopenharmony_ci &brport_attr_isolated, 2888c2ecf20Sopenharmony_ci &brport_attr_backup_port, 2898c2ecf20Sopenharmony_ci NULL 2908c2ecf20Sopenharmony_ci}; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci#define to_brport_attr(_at) container_of(_at, struct brport_attribute, attr) 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic ssize_t brport_show(struct kobject *kobj, 2958c2ecf20Sopenharmony_ci struct attribute *attr, char *buf) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci struct brport_attribute *brport_attr = to_brport_attr(attr); 2988c2ecf20Sopenharmony_ci struct net_bridge_port *p = kobj_to_brport(kobj); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci if (!brport_attr->show) 3018c2ecf20Sopenharmony_ci return -EINVAL; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci return brport_attr->show(p, buf); 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic ssize_t brport_store(struct kobject *kobj, 3078c2ecf20Sopenharmony_ci struct attribute *attr, 3088c2ecf20Sopenharmony_ci const char *buf, size_t count) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci struct brport_attribute *brport_attr = to_brport_attr(attr); 3118c2ecf20Sopenharmony_ci struct net_bridge_port *p = kobj_to_brport(kobj); 3128c2ecf20Sopenharmony_ci ssize_t ret = -EINVAL; 3138c2ecf20Sopenharmony_ci unsigned long val; 3148c2ecf20Sopenharmony_ci char *endp; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (!ns_capable(dev_net(p->dev)->user_ns, CAP_NET_ADMIN)) 3178c2ecf20Sopenharmony_ci return -EPERM; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if (!rtnl_trylock()) 3208c2ecf20Sopenharmony_ci return restart_syscall(); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (brport_attr->store_raw) { 3238c2ecf20Sopenharmony_ci char *buf_copy; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci buf_copy = kstrndup(buf, count, GFP_KERNEL); 3268c2ecf20Sopenharmony_ci if (!buf_copy) { 3278c2ecf20Sopenharmony_ci ret = -ENOMEM; 3288c2ecf20Sopenharmony_ci goto out_unlock; 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci spin_lock_bh(&p->br->lock); 3318c2ecf20Sopenharmony_ci ret = brport_attr->store_raw(p, buf_copy); 3328c2ecf20Sopenharmony_ci spin_unlock_bh(&p->br->lock); 3338c2ecf20Sopenharmony_ci kfree(buf_copy); 3348c2ecf20Sopenharmony_ci } else if (brport_attr->store) { 3358c2ecf20Sopenharmony_ci val = simple_strtoul(buf, &endp, 0); 3368c2ecf20Sopenharmony_ci if (endp == buf) 3378c2ecf20Sopenharmony_ci goto out_unlock; 3388c2ecf20Sopenharmony_ci spin_lock_bh(&p->br->lock); 3398c2ecf20Sopenharmony_ci ret = brport_attr->store(p, val); 3408c2ecf20Sopenharmony_ci spin_unlock_bh(&p->br->lock); 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci if (!ret) { 3448c2ecf20Sopenharmony_ci br_ifinfo_notify(RTM_NEWLINK, NULL, p); 3458c2ecf20Sopenharmony_ci ret = count; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ciout_unlock: 3488c2ecf20Sopenharmony_ci rtnl_unlock(); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci return ret; 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ciconst struct sysfs_ops brport_sysfs_ops = { 3548c2ecf20Sopenharmony_ci .show = brport_show, 3558c2ecf20Sopenharmony_ci .store = brport_store, 3568c2ecf20Sopenharmony_ci}; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci/* 3598c2ecf20Sopenharmony_ci * Add sysfs entries to ethernet device added to a bridge. 3608c2ecf20Sopenharmony_ci * Creates a brport subdirectory with bridge attributes. 3618c2ecf20Sopenharmony_ci * Puts symlink in bridge's brif subdirectory 3628c2ecf20Sopenharmony_ci */ 3638c2ecf20Sopenharmony_ciint br_sysfs_addif(struct net_bridge_port *p) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci struct net_bridge *br = p->br; 3668c2ecf20Sopenharmony_ci const struct brport_attribute **a; 3678c2ecf20Sopenharmony_ci int err; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci err = sysfs_create_link(&p->kobj, &br->dev->dev.kobj, 3708c2ecf20Sopenharmony_ci SYSFS_BRIDGE_PORT_LINK); 3718c2ecf20Sopenharmony_ci if (err) 3728c2ecf20Sopenharmony_ci return err; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci for (a = brport_attrs; *a; ++a) { 3758c2ecf20Sopenharmony_ci err = sysfs_create_file(&p->kobj, &((*a)->attr)); 3768c2ecf20Sopenharmony_ci if (err) 3778c2ecf20Sopenharmony_ci return err; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci strlcpy(p->sysfs_name, p->dev->name, IFNAMSIZ); 3818c2ecf20Sopenharmony_ci return sysfs_create_link(br->ifobj, &p->kobj, p->sysfs_name); 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci/* Rename bridge's brif symlink */ 3858c2ecf20Sopenharmony_ciint br_sysfs_renameif(struct net_bridge_port *p) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci struct net_bridge *br = p->br; 3888c2ecf20Sopenharmony_ci int err; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci /* If a rename fails, the rollback will cause another 3918c2ecf20Sopenharmony_ci * rename call with the existing name. 3928c2ecf20Sopenharmony_ci */ 3938c2ecf20Sopenharmony_ci if (!strncmp(p->sysfs_name, p->dev->name, IFNAMSIZ)) 3948c2ecf20Sopenharmony_ci return 0; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci err = sysfs_rename_link(br->ifobj, &p->kobj, 3978c2ecf20Sopenharmony_ci p->sysfs_name, p->dev->name); 3988c2ecf20Sopenharmony_ci if (err) 3998c2ecf20Sopenharmony_ci netdev_notice(br->dev, "unable to rename link %s to %s", 4008c2ecf20Sopenharmony_ci p->sysfs_name, p->dev->name); 4018c2ecf20Sopenharmony_ci else 4028c2ecf20Sopenharmony_ci strlcpy(p->sysfs_name, p->dev->name, IFNAMSIZ); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci return err; 4058c2ecf20Sopenharmony_ci} 406