cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

br_stp_if.c (8628B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *	Spanning tree protocol; interface code
      4 *	Linux ethernet bridge
      5 *
      6 *	Authors:
      7 *	Lennert Buytenhek		<buytenh@gnu.org>
      8 */
      9
     10#include <linux/kernel.h>
     11#include <linux/kmod.h>
     12#include <linux/etherdevice.h>
     13#include <linux/rtnetlink.h>
     14#include <net/switchdev.h>
     15
     16#include "br_private.h"
     17#include "br_private_stp.h"
     18
     19
     20/* Port id is composed of priority and port number.
     21 * NB: some bits of priority are dropped to
     22 *     make room for more ports.
     23 */
     24static inline port_id br_make_port_id(__u8 priority, __u16 port_no)
     25{
     26	return ((u16)priority << BR_PORT_BITS)
     27		| (port_no & ((1<<BR_PORT_BITS)-1));
     28}
     29
     30#define BR_MAX_PORT_PRIORITY ((u16)~0 >> BR_PORT_BITS)
     31
     32/* called under bridge lock */
     33void br_init_port(struct net_bridge_port *p)
     34{
     35	int err;
     36
     37	p->port_id = br_make_port_id(p->priority, p->port_no);
     38	br_become_designated_port(p);
     39	br_set_state(p, BR_STATE_BLOCKING);
     40	p->topology_change_ack = 0;
     41	p->config_pending = 0;
     42
     43	err = __set_ageing_time(p->dev, p->br->ageing_time);
     44	if (err)
     45		netdev_err(p->dev, "failed to offload ageing time\n");
     46}
     47
     48/* NO locks held */
     49void br_stp_enable_bridge(struct net_bridge *br)
     50{
     51	struct net_bridge_port *p;
     52
     53	spin_lock_bh(&br->lock);
     54	if (br->stp_enabled == BR_KERNEL_STP)
     55		mod_timer(&br->hello_timer, jiffies + br->hello_time);
     56	mod_delayed_work(system_long_wq, &br->gc_work, HZ / 10);
     57
     58	br_config_bpdu_generation(br);
     59
     60	list_for_each_entry(p, &br->port_list, list) {
     61		if (netif_running(p->dev) && netif_oper_up(p->dev))
     62			br_stp_enable_port(p);
     63
     64	}
     65	spin_unlock_bh(&br->lock);
     66}
     67
     68/* NO locks held */
     69void br_stp_disable_bridge(struct net_bridge *br)
     70{
     71	struct net_bridge_port *p;
     72
     73	spin_lock_bh(&br->lock);
     74	list_for_each_entry(p, &br->port_list, list) {
     75		if (p->state != BR_STATE_DISABLED)
     76			br_stp_disable_port(p);
     77
     78	}
     79
     80	__br_set_topology_change(br, 0);
     81	br->topology_change_detected = 0;
     82	spin_unlock_bh(&br->lock);
     83
     84	del_timer_sync(&br->hello_timer);
     85	del_timer_sync(&br->topology_change_timer);
     86	del_timer_sync(&br->tcn_timer);
     87	cancel_delayed_work_sync(&br->gc_work);
     88}
     89
     90/* called under bridge lock */
     91void br_stp_enable_port(struct net_bridge_port *p)
     92{
     93	br_init_port(p);
     94	br_port_state_selection(p->br);
     95	br_ifinfo_notify(RTM_NEWLINK, NULL, p);
     96}
     97
     98/* called under bridge lock */
     99void br_stp_disable_port(struct net_bridge_port *p)
    100{
    101	struct net_bridge *br = p->br;
    102	int wasroot;
    103
    104	wasroot = br_is_root_bridge(br);
    105	br_become_designated_port(p);
    106	br_set_state(p, BR_STATE_DISABLED);
    107	p->topology_change_ack = 0;
    108	p->config_pending = 0;
    109
    110	br_ifinfo_notify(RTM_NEWLINK, NULL, p);
    111
    112	del_timer(&p->message_age_timer);
    113	del_timer(&p->forward_delay_timer);
    114	del_timer(&p->hold_timer);
    115
    116	if (!rcu_access_pointer(p->backup_port))
    117		br_fdb_delete_by_port(br, p, 0, 0);
    118	br_multicast_disable_port(p);
    119
    120	br_configuration_update(br);
    121
    122	br_port_state_selection(br);
    123
    124	if (br_is_root_bridge(br) && !wasroot)
    125		br_become_root_bridge(br);
    126}
    127
    128static int br_stp_call_user(struct net_bridge *br, char *arg)
    129{
    130	char *argv[] = { BR_STP_PROG, br->dev->name, arg, NULL };
    131	char *envp[] = { NULL };
    132	int rc;
    133
    134	/* call userspace STP and report program errors */
    135	rc = call_usermodehelper(BR_STP_PROG, argv, envp, UMH_WAIT_PROC);
    136	if (rc > 0) {
    137		if (rc & 0xff)
    138			br_debug(br, BR_STP_PROG " received signal %d\n",
    139				 rc & 0x7f);
    140		else
    141			br_debug(br, BR_STP_PROG " exited with code %d\n",
    142				 (rc >> 8) & 0xff);
    143	}
    144
    145	return rc;
    146}
    147
    148static void br_stp_start(struct net_bridge *br)
    149{
    150	int err = -ENOENT;
    151
    152	if (net_eq(dev_net(br->dev), &init_net))
    153		err = br_stp_call_user(br, "start");
    154
    155	if (err && err != -ENOENT)
    156		br_err(br, "failed to start userspace STP (%d)\n", err);
    157
    158	spin_lock_bh(&br->lock);
    159
    160	if (br->bridge_forward_delay < BR_MIN_FORWARD_DELAY)
    161		__br_set_forward_delay(br, BR_MIN_FORWARD_DELAY);
    162	else if (br->bridge_forward_delay > BR_MAX_FORWARD_DELAY)
    163		__br_set_forward_delay(br, BR_MAX_FORWARD_DELAY);
    164
    165	if (!err) {
    166		br->stp_enabled = BR_USER_STP;
    167		br_debug(br, "userspace STP started\n");
    168	} else {
    169		br->stp_enabled = BR_KERNEL_STP;
    170		br_debug(br, "using kernel STP\n");
    171
    172		/* To start timers on any ports left in blocking */
    173		if (br->dev->flags & IFF_UP)
    174			mod_timer(&br->hello_timer, jiffies + br->hello_time);
    175		br_port_state_selection(br);
    176	}
    177
    178	spin_unlock_bh(&br->lock);
    179}
    180
    181static void br_stp_stop(struct net_bridge *br)
    182{
    183	int err;
    184
    185	if (br->stp_enabled == BR_USER_STP) {
    186		err = br_stp_call_user(br, "stop");
    187		if (err)
    188			br_err(br, "failed to stop userspace STP (%d)\n", err);
    189
    190		/* To start timers on any ports left in blocking */
    191		spin_lock_bh(&br->lock);
    192		br_port_state_selection(br);
    193		spin_unlock_bh(&br->lock);
    194	}
    195
    196	br->stp_enabled = BR_NO_STP;
    197}
    198
    199int br_stp_set_enabled(struct net_bridge *br, unsigned long val,
    200		       struct netlink_ext_ack *extack)
    201{
    202	ASSERT_RTNL();
    203
    204	if (br_mrp_enabled(br)) {
    205		NL_SET_ERR_MSG_MOD(extack,
    206				   "STP can't be enabled if MRP is already enabled");
    207		return -EINVAL;
    208	}
    209
    210	if (val) {
    211		if (br->stp_enabled == BR_NO_STP)
    212			br_stp_start(br);
    213	} else {
    214		if (br->stp_enabled != BR_NO_STP)
    215			br_stp_stop(br);
    216	}
    217
    218	return 0;
    219}
    220
    221/* called under bridge lock */
    222void br_stp_change_bridge_id(struct net_bridge *br, const unsigned char *addr)
    223{
    224	/* should be aligned on 2 bytes for ether_addr_equal() */
    225	unsigned short oldaddr_aligned[ETH_ALEN >> 1];
    226	unsigned char *oldaddr = (unsigned char *)oldaddr_aligned;
    227	struct net_bridge_port *p;
    228	int wasroot;
    229
    230	wasroot = br_is_root_bridge(br);
    231
    232	br_fdb_change_mac_address(br, addr);
    233
    234	memcpy(oldaddr, br->bridge_id.addr, ETH_ALEN);
    235	memcpy(br->bridge_id.addr, addr, ETH_ALEN);
    236	eth_hw_addr_set(br->dev, addr);
    237
    238	list_for_each_entry(p, &br->port_list, list) {
    239		if (ether_addr_equal(p->designated_bridge.addr, oldaddr))
    240			memcpy(p->designated_bridge.addr, addr, ETH_ALEN);
    241
    242		if (ether_addr_equal(p->designated_root.addr, oldaddr))
    243			memcpy(p->designated_root.addr, addr, ETH_ALEN);
    244	}
    245
    246	br_configuration_update(br);
    247	br_port_state_selection(br);
    248	if (br_is_root_bridge(br) && !wasroot)
    249		br_become_root_bridge(br);
    250}
    251
    252/* should be aligned on 2 bytes for ether_addr_equal() */
    253static const unsigned short br_mac_zero_aligned[ETH_ALEN >> 1];
    254
    255/* called under bridge lock */
    256bool br_stp_recalculate_bridge_id(struct net_bridge *br)
    257{
    258	const unsigned char *br_mac_zero =
    259			(const unsigned char *)br_mac_zero_aligned;
    260	const unsigned char *addr = br_mac_zero;
    261	struct net_bridge_port *p;
    262
    263	/* user has chosen a value so keep it */
    264	if (br->dev->addr_assign_type == NET_ADDR_SET)
    265		return false;
    266
    267	list_for_each_entry(p, &br->port_list, list) {
    268		if (addr == br_mac_zero ||
    269		    memcmp(p->dev->dev_addr, addr, ETH_ALEN) < 0)
    270			addr = p->dev->dev_addr;
    271
    272	}
    273
    274	if (ether_addr_equal(br->bridge_id.addr, addr))
    275		return false;	/* no change */
    276
    277	br_stp_change_bridge_id(br, addr);
    278	return true;
    279}
    280
    281/* Acquires and releases bridge lock */
    282void br_stp_set_bridge_priority(struct net_bridge *br, u16 newprio)
    283{
    284	struct net_bridge_port *p;
    285	int wasroot;
    286
    287	spin_lock_bh(&br->lock);
    288	wasroot = br_is_root_bridge(br);
    289
    290	list_for_each_entry(p, &br->port_list, list) {
    291		if (p->state != BR_STATE_DISABLED &&
    292		    br_is_designated_port(p)) {
    293			p->designated_bridge.prio[0] = (newprio >> 8) & 0xFF;
    294			p->designated_bridge.prio[1] = newprio & 0xFF;
    295		}
    296
    297	}
    298
    299	br->bridge_id.prio[0] = (newprio >> 8) & 0xFF;
    300	br->bridge_id.prio[1] = newprio & 0xFF;
    301	br_configuration_update(br);
    302	br_port_state_selection(br);
    303	if (br_is_root_bridge(br) && !wasroot)
    304		br_become_root_bridge(br);
    305	spin_unlock_bh(&br->lock);
    306}
    307
    308/* called under bridge lock */
    309int br_stp_set_port_priority(struct net_bridge_port *p, unsigned long newprio)
    310{
    311	port_id new_port_id;
    312
    313	if (newprio > BR_MAX_PORT_PRIORITY)
    314		return -ERANGE;
    315
    316	new_port_id = br_make_port_id(newprio, p->port_no);
    317	if (br_is_designated_port(p))
    318		p->designated_port = new_port_id;
    319
    320	p->port_id = new_port_id;
    321	p->priority = newprio;
    322	if (!memcmp(&p->br->bridge_id, &p->designated_bridge, 8) &&
    323	    p->port_id < p->designated_port) {
    324		br_become_designated_port(p);
    325		br_port_state_selection(p->br);
    326	}
    327
    328	return 0;
    329}
    330
    331/* called under bridge lock */
    332int br_stp_set_path_cost(struct net_bridge_port *p, unsigned long path_cost)
    333{
    334	if (path_cost < BR_MIN_PATH_COST ||
    335	    path_cost > BR_MAX_PATH_COST)
    336		return -ERANGE;
    337
    338	p->flags |= BR_ADMIN_COST;
    339	p->path_cost = path_cost;
    340	br_configuration_update(p->br);
    341	br_port_state_selection(p->br);
    342	return 0;
    343}
    344
    345ssize_t br_show_bridge_id(char *buf, const struct bridge_id *id)
    346{
    347	return sprintf(buf, "%.2x%.2x.%.2x%.2x%.2x%.2x%.2x%.2x\n",
    348	       id->prio[0], id->prio[1],
    349	       id->addr[0], id->addr[1], id->addr[2],
    350	       id->addr[3], id->addr[4], id->addr[5]);
    351}