162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Device handling code 462306a36Sopenharmony_ci * Linux ethernet bridge 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Authors: 762306a36Sopenharmony_ci * Lennert Buytenhek <buytenh@gnu.org> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/netdevice.h> 1262306a36Sopenharmony_ci#include <linux/netpoll.h> 1362306a36Sopenharmony_ci#include <linux/etherdevice.h> 1462306a36Sopenharmony_ci#include <linux/ethtool.h> 1562306a36Sopenharmony_ci#include <linux/list.h> 1662306a36Sopenharmony_ci#include <linux/netfilter_bridge.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <linux/uaccess.h> 1962306a36Sopenharmony_ci#include "br_private.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define COMMON_FEATURES (NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | \ 2262306a36Sopenharmony_ci NETIF_F_GSO_MASK | NETIF_F_HW_CSUM) 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ciconst struct nf_br_ops __rcu *nf_br_ops __read_mostly; 2562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nf_br_ops); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* net device transmit always called with BH disabled */ 2862306a36Sopenharmony_cinetdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci struct net_bridge_mcast_port *pmctx_null = NULL; 3162306a36Sopenharmony_ci struct net_bridge *br = netdev_priv(dev); 3262306a36Sopenharmony_ci struct net_bridge_mcast *brmctx = &br->multicast_ctx; 3362306a36Sopenharmony_ci struct net_bridge_fdb_entry *dst; 3462306a36Sopenharmony_ci struct net_bridge_mdb_entry *mdst; 3562306a36Sopenharmony_ci const struct nf_br_ops *nf_ops; 3662306a36Sopenharmony_ci u8 state = BR_STATE_FORWARDING; 3762306a36Sopenharmony_ci struct net_bridge_vlan *vlan; 3862306a36Sopenharmony_ci const unsigned char *dest; 3962306a36Sopenharmony_ci u16 vid = 0; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci memset(skb->cb, 0, sizeof(struct br_input_skb_cb)); 4262306a36Sopenharmony_ci br_tc_skb_miss_set(skb, false); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci rcu_read_lock(); 4562306a36Sopenharmony_ci nf_ops = rcu_dereference(nf_br_ops); 4662306a36Sopenharmony_ci if (nf_ops && nf_ops->br_dev_xmit_hook(skb)) { 4762306a36Sopenharmony_ci rcu_read_unlock(); 4862306a36Sopenharmony_ci return NETDEV_TX_OK; 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci dev_sw_netstats_tx_add(dev, 1, skb->len); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci br_switchdev_frame_unmark(skb); 5462306a36Sopenharmony_ci BR_INPUT_SKB_CB(skb)->brdev = dev; 5562306a36Sopenharmony_ci BR_INPUT_SKB_CB(skb)->frag_max_size = 0; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci skb_reset_mac_header(skb); 5862306a36Sopenharmony_ci skb_pull(skb, ETH_HLEN); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci if (!br_allowed_ingress(br, br_vlan_group_rcu(br), skb, &vid, 6162306a36Sopenharmony_ci &state, &vlan)) 6262306a36Sopenharmony_ci goto out; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_INET) && 6562306a36Sopenharmony_ci (eth_hdr(skb)->h_proto == htons(ETH_P_ARP) || 6662306a36Sopenharmony_ci eth_hdr(skb)->h_proto == htons(ETH_P_RARP)) && 6762306a36Sopenharmony_ci br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED)) { 6862306a36Sopenharmony_ci br_do_proxy_suppress_arp(skb, br, vid, NULL); 6962306a36Sopenharmony_ci } else if (IS_ENABLED(CONFIG_IPV6) && 7062306a36Sopenharmony_ci skb->protocol == htons(ETH_P_IPV6) && 7162306a36Sopenharmony_ci br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED) && 7262306a36Sopenharmony_ci pskb_may_pull(skb, sizeof(struct ipv6hdr) + 7362306a36Sopenharmony_ci sizeof(struct nd_msg)) && 7462306a36Sopenharmony_ci ipv6_hdr(skb)->nexthdr == IPPROTO_ICMPV6) { 7562306a36Sopenharmony_ci struct nd_msg *msg, _msg; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci msg = br_is_nd_neigh_msg(skb, &_msg); 7862306a36Sopenharmony_ci if (msg) 7962306a36Sopenharmony_ci br_do_suppress_nd(skb, br, vid, NULL, msg); 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci dest = eth_hdr(skb)->h_dest; 8362306a36Sopenharmony_ci if (is_broadcast_ether_addr(dest)) { 8462306a36Sopenharmony_ci br_flood(br, skb, BR_PKT_BROADCAST, false, true, vid); 8562306a36Sopenharmony_ci } else if (is_multicast_ether_addr(dest)) { 8662306a36Sopenharmony_ci if (unlikely(netpoll_tx_running(dev))) { 8762306a36Sopenharmony_ci br_flood(br, skb, BR_PKT_MULTICAST, false, true, vid); 8862306a36Sopenharmony_ci goto out; 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci if (br_multicast_rcv(&brmctx, &pmctx_null, vlan, skb, vid)) { 9162306a36Sopenharmony_ci kfree_skb(skb); 9262306a36Sopenharmony_ci goto out; 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci mdst = br_mdb_get(brmctx, skb, vid); 9662306a36Sopenharmony_ci if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) && 9762306a36Sopenharmony_ci br_multicast_querier_exists(brmctx, eth_hdr(skb), mdst)) 9862306a36Sopenharmony_ci br_multicast_flood(mdst, skb, brmctx, false, true); 9962306a36Sopenharmony_ci else 10062306a36Sopenharmony_ci br_flood(br, skb, BR_PKT_MULTICAST, false, true, vid); 10162306a36Sopenharmony_ci } else if ((dst = br_fdb_find_rcu(br, dest, vid)) != NULL) { 10262306a36Sopenharmony_ci br_forward(dst->dst, skb, false, true); 10362306a36Sopenharmony_ci } else { 10462306a36Sopenharmony_ci br_flood(br, skb, BR_PKT_UNICAST, false, true, vid); 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ciout: 10762306a36Sopenharmony_ci rcu_read_unlock(); 10862306a36Sopenharmony_ci return NETDEV_TX_OK; 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic struct lock_class_key bridge_netdev_addr_lock_key; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic void br_set_lockdep_class(struct net_device *dev) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci lockdep_set_class(&dev->addr_list_lock, &bridge_netdev_addr_lock_key); 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic int br_dev_init(struct net_device *dev) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci struct net_bridge *br = netdev_priv(dev); 12162306a36Sopenharmony_ci int err; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); 12462306a36Sopenharmony_ci if (!dev->tstats) 12562306a36Sopenharmony_ci return -ENOMEM; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci err = br_fdb_hash_init(br); 12862306a36Sopenharmony_ci if (err) { 12962306a36Sopenharmony_ci free_percpu(dev->tstats); 13062306a36Sopenharmony_ci return err; 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci err = br_mdb_hash_init(br); 13462306a36Sopenharmony_ci if (err) { 13562306a36Sopenharmony_ci free_percpu(dev->tstats); 13662306a36Sopenharmony_ci br_fdb_hash_fini(br); 13762306a36Sopenharmony_ci return err; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci err = br_vlan_init(br); 14162306a36Sopenharmony_ci if (err) { 14262306a36Sopenharmony_ci free_percpu(dev->tstats); 14362306a36Sopenharmony_ci br_mdb_hash_fini(br); 14462306a36Sopenharmony_ci br_fdb_hash_fini(br); 14562306a36Sopenharmony_ci return err; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci err = br_multicast_init_stats(br); 14962306a36Sopenharmony_ci if (err) { 15062306a36Sopenharmony_ci free_percpu(dev->tstats); 15162306a36Sopenharmony_ci br_vlan_flush(br); 15262306a36Sopenharmony_ci br_mdb_hash_fini(br); 15362306a36Sopenharmony_ci br_fdb_hash_fini(br); 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci br_set_lockdep_class(dev); 15762306a36Sopenharmony_ci return err; 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic void br_dev_uninit(struct net_device *dev) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci struct net_bridge *br = netdev_priv(dev); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci br_multicast_dev_del(br); 16562306a36Sopenharmony_ci br_multicast_uninit_stats(br); 16662306a36Sopenharmony_ci br_vlan_flush(br); 16762306a36Sopenharmony_ci br_mdb_hash_fini(br); 16862306a36Sopenharmony_ci br_fdb_hash_fini(br); 16962306a36Sopenharmony_ci free_percpu(dev->tstats); 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic int br_dev_open(struct net_device *dev) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct net_bridge *br = netdev_priv(dev); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci netdev_update_features(dev); 17762306a36Sopenharmony_ci netif_start_queue(dev); 17862306a36Sopenharmony_ci br_stp_enable_bridge(br); 17962306a36Sopenharmony_ci br_multicast_open(br); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci if (br_opt_get(br, BROPT_MULTICAST_ENABLED)) 18262306a36Sopenharmony_ci br_multicast_join_snoopers(br); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci return 0; 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistatic void br_dev_set_multicast_list(struct net_device *dev) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic void br_dev_change_rx_flags(struct net_device *dev, int change) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci if (change & IFF_PROMISC) 19462306a36Sopenharmony_ci br_manage_promisc(netdev_priv(dev)); 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic int br_dev_stop(struct net_device *dev) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci struct net_bridge *br = netdev_priv(dev); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci br_stp_disable_bridge(br); 20262306a36Sopenharmony_ci br_multicast_stop(br); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci if (br_opt_get(br, BROPT_MULTICAST_ENABLED)) 20562306a36Sopenharmony_ci br_multicast_leave_snoopers(br); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci netif_stop_queue(dev); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci return 0; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic int br_change_mtu(struct net_device *dev, int new_mtu) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct net_bridge *br = netdev_priv(dev); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci dev->mtu = new_mtu; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci /* this flag will be cleared if the MTU was automatically adjusted */ 21962306a36Sopenharmony_ci br_opt_toggle(br, BROPT_MTU_SET_BY_USER, true); 22062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) 22162306a36Sopenharmony_ci /* remember the MTU in the rtable for PMTU */ 22262306a36Sopenharmony_ci dst_metric_set(&br->fake_rtable.dst, RTAX_MTU, new_mtu); 22362306a36Sopenharmony_ci#endif 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci return 0; 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci/* Allow setting mac address to any valid ethernet address. */ 22962306a36Sopenharmony_cistatic int br_set_mac_address(struct net_device *dev, void *p) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci struct net_bridge *br = netdev_priv(dev); 23262306a36Sopenharmony_ci struct sockaddr *addr = p; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (!is_valid_ether_addr(addr->sa_data)) 23562306a36Sopenharmony_ci return -EADDRNOTAVAIL; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* dev_set_mac_addr() can be called by a master device on bridge's 23862306a36Sopenharmony_ci * NETDEV_UNREGISTER, but since it's being destroyed do nothing 23962306a36Sopenharmony_ci */ 24062306a36Sopenharmony_ci if (dev->reg_state != NETREG_REGISTERED) 24162306a36Sopenharmony_ci return -EBUSY; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci spin_lock_bh(&br->lock); 24462306a36Sopenharmony_ci if (!ether_addr_equal(dev->dev_addr, addr->sa_data)) { 24562306a36Sopenharmony_ci /* Mac address will be changed in br_stp_change_bridge_id(). */ 24662306a36Sopenharmony_ci br_stp_change_bridge_id(br, addr->sa_data); 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci spin_unlock_bh(&br->lock); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci return 0; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic void br_getinfo(struct net_device *dev, struct ethtool_drvinfo *info) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci strscpy(info->driver, "bridge", sizeof(info->driver)); 25662306a36Sopenharmony_ci strscpy(info->version, BR_VERSION, sizeof(info->version)); 25762306a36Sopenharmony_ci strscpy(info->fw_version, "N/A", sizeof(info->fw_version)); 25862306a36Sopenharmony_ci strscpy(info->bus_info, "N/A", sizeof(info->bus_info)); 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cistatic int br_get_link_ksettings(struct net_device *dev, 26262306a36Sopenharmony_ci struct ethtool_link_ksettings *cmd) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci struct net_bridge *br = netdev_priv(dev); 26562306a36Sopenharmony_ci struct net_bridge_port *p; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci cmd->base.duplex = DUPLEX_UNKNOWN; 26862306a36Sopenharmony_ci cmd->base.port = PORT_OTHER; 26962306a36Sopenharmony_ci cmd->base.speed = SPEED_UNKNOWN; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci list_for_each_entry(p, &br->port_list, list) { 27262306a36Sopenharmony_ci struct ethtool_link_ksettings ecmd; 27362306a36Sopenharmony_ci struct net_device *pdev = p->dev; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (!netif_running(pdev) || !netif_oper_up(pdev)) 27662306a36Sopenharmony_ci continue; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (__ethtool_get_link_ksettings(pdev, &ecmd)) 27962306a36Sopenharmony_ci continue; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci if (ecmd.base.speed == (__u32)SPEED_UNKNOWN) 28262306a36Sopenharmony_ci continue; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (cmd->base.speed == (__u32)SPEED_UNKNOWN || 28562306a36Sopenharmony_ci cmd->base.speed < ecmd.base.speed) 28662306a36Sopenharmony_ci cmd->base.speed = ecmd.base.speed; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci return 0; 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cistatic netdev_features_t br_fix_features(struct net_device *dev, 29362306a36Sopenharmony_ci netdev_features_t features) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci struct net_bridge *br = netdev_priv(dev); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci return br_features_recompute(br, features); 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 30162306a36Sopenharmony_cistatic void br_poll_controller(struct net_device *br_dev) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic void br_netpoll_cleanup(struct net_device *dev) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci struct net_bridge *br = netdev_priv(dev); 30862306a36Sopenharmony_ci struct net_bridge_port *p; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci list_for_each_entry(p, &br->port_list, list) 31162306a36Sopenharmony_ci br_netpoll_disable(p); 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic int __br_netpoll_enable(struct net_bridge_port *p) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci struct netpoll *np; 31762306a36Sopenharmony_ci int err; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci np = kzalloc(sizeof(*p->np), GFP_KERNEL); 32062306a36Sopenharmony_ci if (!np) 32162306a36Sopenharmony_ci return -ENOMEM; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci err = __netpoll_setup(np, p->dev); 32462306a36Sopenharmony_ci if (err) { 32562306a36Sopenharmony_ci kfree(np); 32662306a36Sopenharmony_ci return err; 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci p->np = np; 33062306a36Sopenharmony_ci return err; 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ciint br_netpoll_enable(struct net_bridge_port *p) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci if (!p->br->dev->npinfo) 33662306a36Sopenharmony_ci return 0; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci return __br_netpoll_enable(p); 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic int br_netpoll_setup(struct net_device *dev, struct netpoll_info *ni) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci struct net_bridge *br = netdev_priv(dev); 34462306a36Sopenharmony_ci struct net_bridge_port *p; 34562306a36Sopenharmony_ci int err = 0; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci list_for_each_entry(p, &br->port_list, list) { 34862306a36Sopenharmony_ci if (!p->dev) 34962306a36Sopenharmony_ci continue; 35062306a36Sopenharmony_ci err = __br_netpoll_enable(p); 35162306a36Sopenharmony_ci if (err) 35262306a36Sopenharmony_ci goto fail; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ciout: 35662306a36Sopenharmony_ci return err; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cifail: 35962306a36Sopenharmony_ci br_netpoll_cleanup(dev); 36062306a36Sopenharmony_ci goto out; 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_civoid br_netpoll_disable(struct net_bridge_port *p) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci struct netpoll *np = p->np; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (!np) 36862306a36Sopenharmony_ci return; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci p->np = NULL; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci __netpoll_free(np); 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci#endif 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic int br_add_slave(struct net_device *dev, struct net_device *slave_dev, 37862306a36Sopenharmony_ci struct netlink_ext_ack *extack) 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci struct net_bridge *br = netdev_priv(dev); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci return br_add_if(br, slave_dev, extack); 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_cistatic int br_del_slave(struct net_device *dev, struct net_device *slave_dev) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci struct net_bridge *br = netdev_priv(dev); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci return br_del_if(br, slave_dev); 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic int br_fill_forward_path(struct net_device_path_ctx *ctx, 39462306a36Sopenharmony_ci struct net_device_path *path) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci struct net_bridge_fdb_entry *f; 39762306a36Sopenharmony_ci struct net_bridge_port *dst; 39862306a36Sopenharmony_ci struct net_bridge *br; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci if (netif_is_bridge_port(ctx->dev)) 40162306a36Sopenharmony_ci return -1; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci br = netdev_priv(ctx->dev); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci br_vlan_fill_forward_path_pvid(br, ctx, path); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci f = br_fdb_find_rcu(br, ctx->daddr, path->bridge.vlan_id); 40862306a36Sopenharmony_ci if (!f || !f->dst) 40962306a36Sopenharmony_ci return -1; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci dst = READ_ONCE(f->dst); 41262306a36Sopenharmony_ci if (!dst) 41362306a36Sopenharmony_ci return -1; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (br_vlan_fill_forward_path_mode(br, dst, path)) 41662306a36Sopenharmony_ci return -1; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci path->type = DEV_PATH_BRIDGE; 41962306a36Sopenharmony_ci path->dev = dst->br->dev; 42062306a36Sopenharmony_ci ctx->dev = dst->dev; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci switch (path->bridge.vlan_mode) { 42362306a36Sopenharmony_ci case DEV_PATH_BR_VLAN_TAG: 42462306a36Sopenharmony_ci if (ctx->num_vlans >= ARRAY_SIZE(ctx->vlan)) 42562306a36Sopenharmony_ci return -ENOSPC; 42662306a36Sopenharmony_ci ctx->vlan[ctx->num_vlans].id = path->bridge.vlan_id; 42762306a36Sopenharmony_ci ctx->vlan[ctx->num_vlans].proto = path->bridge.vlan_proto; 42862306a36Sopenharmony_ci ctx->num_vlans++; 42962306a36Sopenharmony_ci break; 43062306a36Sopenharmony_ci case DEV_PATH_BR_VLAN_UNTAG_HW: 43162306a36Sopenharmony_ci case DEV_PATH_BR_VLAN_UNTAG: 43262306a36Sopenharmony_ci ctx->num_vlans--; 43362306a36Sopenharmony_ci break; 43462306a36Sopenharmony_ci case DEV_PATH_BR_VLAN_KEEP: 43562306a36Sopenharmony_ci break; 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci return 0; 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_cistatic const struct ethtool_ops br_ethtool_ops = { 44262306a36Sopenharmony_ci .get_drvinfo = br_getinfo, 44362306a36Sopenharmony_ci .get_link = ethtool_op_get_link, 44462306a36Sopenharmony_ci .get_link_ksettings = br_get_link_ksettings, 44562306a36Sopenharmony_ci}; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_cistatic const struct net_device_ops br_netdev_ops = { 44862306a36Sopenharmony_ci .ndo_open = br_dev_open, 44962306a36Sopenharmony_ci .ndo_stop = br_dev_stop, 45062306a36Sopenharmony_ci .ndo_init = br_dev_init, 45162306a36Sopenharmony_ci .ndo_uninit = br_dev_uninit, 45262306a36Sopenharmony_ci .ndo_start_xmit = br_dev_xmit, 45362306a36Sopenharmony_ci .ndo_get_stats64 = dev_get_tstats64, 45462306a36Sopenharmony_ci .ndo_set_mac_address = br_set_mac_address, 45562306a36Sopenharmony_ci .ndo_set_rx_mode = br_dev_set_multicast_list, 45662306a36Sopenharmony_ci .ndo_change_rx_flags = br_dev_change_rx_flags, 45762306a36Sopenharmony_ci .ndo_change_mtu = br_change_mtu, 45862306a36Sopenharmony_ci .ndo_siocdevprivate = br_dev_siocdevprivate, 45962306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 46062306a36Sopenharmony_ci .ndo_netpoll_setup = br_netpoll_setup, 46162306a36Sopenharmony_ci .ndo_netpoll_cleanup = br_netpoll_cleanup, 46262306a36Sopenharmony_ci .ndo_poll_controller = br_poll_controller, 46362306a36Sopenharmony_ci#endif 46462306a36Sopenharmony_ci .ndo_add_slave = br_add_slave, 46562306a36Sopenharmony_ci .ndo_del_slave = br_del_slave, 46662306a36Sopenharmony_ci .ndo_fix_features = br_fix_features, 46762306a36Sopenharmony_ci .ndo_fdb_add = br_fdb_add, 46862306a36Sopenharmony_ci .ndo_fdb_del = br_fdb_delete, 46962306a36Sopenharmony_ci .ndo_fdb_del_bulk = br_fdb_delete_bulk, 47062306a36Sopenharmony_ci .ndo_fdb_dump = br_fdb_dump, 47162306a36Sopenharmony_ci .ndo_fdb_get = br_fdb_get, 47262306a36Sopenharmony_ci .ndo_mdb_add = br_mdb_add, 47362306a36Sopenharmony_ci .ndo_mdb_del = br_mdb_del, 47462306a36Sopenharmony_ci .ndo_mdb_dump = br_mdb_dump, 47562306a36Sopenharmony_ci .ndo_bridge_getlink = br_getlink, 47662306a36Sopenharmony_ci .ndo_bridge_setlink = br_setlink, 47762306a36Sopenharmony_ci .ndo_bridge_dellink = br_dellink, 47862306a36Sopenharmony_ci .ndo_features_check = passthru_features_check, 47962306a36Sopenharmony_ci .ndo_fill_forward_path = br_fill_forward_path, 48062306a36Sopenharmony_ci}; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_cistatic struct device_type br_type = { 48362306a36Sopenharmony_ci .name = "bridge", 48462306a36Sopenharmony_ci}; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_civoid br_dev_setup(struct net_device *dev) 48762306a36Sopenharmony_ci{ 48862306a36Sopenharmony_ci struct net_bridge *br = netdev_priv(dev); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci eth_hw_addr_random(dev); 49162306a36Sopenharmony_ci ether_setup(dev); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci dev->netdev_ops = &br_netdev_ops; 49462306a36Sopenharmony_ci dev->needs_free_netdev = true; 49562306a36Sopenharmony_ci dev->ethtool_ops = &br_ethtool_ops; 49662306a36Sopenharmony_ci SET_NETDEV_DEVTYPE(dev, &br_type); 49762306a36Sopenharmony_ci dev->priv_flags = IFF_EBRIDGE | IFF_NO_QUEUE; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci dev->features = COMMON_FEATURES | NETIF_F_LLTX | NETIF_F_NETNS_LOCAL | 50062306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX; 50162306a36Sopenharmony_ci dev->hw_features = COMMON_FEATURES | NETIF_F_HW_VLAN_CTAG_TX | 50262306a36Sopenharmony_ci NETIF_F_HW_VLAN_STAG_TX; 50362306a36Sopenharmony_ci dev->vlan_features = COMMON_FEATURES; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci br->dev = dev; 50662306a36Sopenharmony_ci spin_lock_init(&br->lock); 50762306a36Sopenharmony_ci INIT_LIST_HEAD(&br->port_list); 50862306a36Sopenharmony_ci INIT_HLIST_HEAD(&br->fdb_list); 50962306a36Sopenharmony_ci INIT_HLIST_HEAD(&br->frame_type_list); 51062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_BRIDGE_MRP) 51162306a36Sopenharmony_ci INIT_HLIST_HEAD(&br->mrp_list); 51262306a36Sopenharmony_ci#endif 51362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_BRIDGE_CFM) 51462306a36Sopenharmony_ci INIT_HLIST_HEAD(&br->mep_list); 51562306a36Sopenharmony_ci#endif 51662306a36Sopenharmony_ci spin_lock_init(&br->hash_lock); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci br->bridge_id.prio[0] = 0x80; 51962306a36Sopenharmony_ci br->bridge_id.prio[1] = 0x00; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci ether_addr_copy(br->group_addr, eth_stp_addr); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci br->stp_enabled = BR_NO_STP; 52462306a36Sopenharmony_ci br->group_fwd_mask = BR_GROUPFWD_DEFAULT; 52562306a36Sopenharmony_ci br->group_fwd_mask_required = BR_GROUPFWD_DEFAULT; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci br->designated_root = br->bridge_id; 52862306a36Sopenharmony_ci br->bridge_max_age = br->max_age = 20 * HZ; 52962306a36Sopenharmony_ci br->bridge_hello_time = br->hello_time = 2 * HZ; 53062306a36Sopenharmony_ci br->bridge_forward_delay = br->forward_delay = 15 * HZ; 53162306a36Sopenharmony_ci br->bridge_ageing_time = br->ageing_time = BR_DEFAULT_AGEING_TIME; 53262306a36Sopenharmony_ci dev->max_mtu = ETH_MAX_MTU; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci br_netfilter_rtable_init(br); 53562306a36Sopenharmony_ci br_stp_timer_init(br); 53662306a36Sopenharmony_ci br_multicast_init(br); 53762306a36Sopenharmony_ci INIT_DELAYED_WORK(&br->gc_work, br_fdb_cleanup); 53862306a36Sopenharmony_ci} 539