--- zzzz-none-000/linux-4.4.271/net/bridge/br_forward.c 2021-06-03 06:22:09.000000000 +0000 +++ maple-fsgw-759/linux-4.4.271/net/bridge/br_forward.c 2023-12-20 10:37:40.000000000 +0000 @@ -21,6 +21,8 @@ #include #include "br_private.h" +#include + static int deliver_clone(const struct net_bridge_port *prev, struct sk_buff *skb, void (*__packet_hook)(const struct net_bridge_port *p, @@ -40,6 +42,7 @@ int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb) { skb_push(skb, ETH_HLEN); + if (!is_skb_forwardable(skb->dev, skb)) goto drop; @@ -69,7 +72,7 @@ int br_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb) { - return NF_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING, + return BR_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING, net, sk, skb, NULL, skb->dev, br_dev_queue_push_xmit); @@ -96,7 +99,7 @@ return; } - NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, + BR_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, dev_net(skb->dev), NULL, skb,NULL, skb->dev, br_forward_finish); } @@ -120,7 +123,7 @@ skb->dev = to->dev; skb_forward_csum(skb); - NF_HOOK(NFPROTO_BRIDGE, NF_BR_FORWARD, + BR_HOOK(NFPROTO_BRIDGE, NF_BR_FORWARD, dev_net(indev), NULL, skb, indev, skb->dev, br_forward_finish); } @@ -135,12 +138,11 @@ kfree_skb(skb); } -EXPORT_SYMBOL_GPL(br_deliver); /* called with rcu_read_lock */ void br_forward(const struct net_bridge_port *to, struct sk_buff *skb, struct sk_buff *skb0) { - if (to && should_deliver(to, skb)) { + if (to && should_deliver(to, skb) && !(to->flags & BR_ISOLATE_MODE)) { if (skb0) deliver_clone(to, skb, __br_forward); else @@ -196,17 +198,41 @@ struct sk_buff *skb0, void (*__packet_hook)(const struct net_bridge_port *p, struct sk_buff *skb), - bool unicast) + bool unicast, bool forward) { struct net_bridge_port *p; struct net_bridge_port *prev; + enum br_pkt_type pkt_type = BR_PKT_UNICAST; + const unsigned char *dest; + + dest = eth_hdr(skb)->h_dest; + if (is_broadcast_ether_addr(dest)) + pkt_type = BR_PKT_BROADCAST; + else if (is_multicast_ether_addr(dest)) + pkt_type = BR_PKT_MULTICAST; prev = NULL; list_for_each_entry_rcu(p, &br->port_list, list) { - /* Do not flood unicast traffic to ports that turn it off */ - if (unicast && !(p->flags & BR_FLOOD)) + if (forward && (p->flags & BR_ISOLATE_MODE)) continue; + /* Do not flood unicast traffic to ports that turn it off, nor + * other traffic if flood off, except for traffic we originate + */ + switch (pkt_type) { + case BR_PKT_UNICAST: + if (!(p->flags & BR_FLOOD)) + continue; + break; + case BR_PKT_MULTICAST: + if (!(p->flags & BR_MCAST_FLOOD) && skb->dev != br->dev) + continue; + break; + case BR_PKT_BROADCAST: + if (!(p->flags & BR_BCAST_FLOOD) && skb->dev != br->dev) + continue; + break; + } /* Do not flood to ports that enable proxy ARP */ if (p->flags & BR_PROXYARP) @@ -238,17 +264,54 @@ /* called with rcu_read_lock */ void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb, bool unicast) { - br_flood(br, skb, NULL, __br_deliver, unicast); + /* FIXME: Try to accelerate */ + avm_pa_do_not_accelerate(skb); + br_flood(br, skb, NULL, __br_deliver, unicast, false); } +EXPORT_SYMBOL_GPL(br_deliver); /* called under bridge lock */ void br_flood_forward(struct net_bridge *br, struct sk_buff *skb, struct sk_buff *skb2, bool unicast) { - br_flood(br, skb, skb2, __br_forward, unicast); + /* FIXME: Try to accelerate */ + avm_pa_do_not_accelerate(skb); + if (br_flood_rl(br, skb, skb->dev)) + br_flood(br, skb, skb2, __br_forward, unicast, true); + else if (!skb2) + kfree_skb(skb); } +EXPORT_SYMBOL_GPL(br_forward); #ifdef CONFIG_BRIDGE_IGMP_SNOOPING + +static void maybe_deliver_addr(struct net_bridge_port *p, struct sk_buff *skb, + const unsigned char *addr, + void (*__packet_hook)(const struct net_bridge_port *p, + struct sk_buff *skb)) +{ + struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev; + const unsigned char *src = eth_hdr(skb)->h_source; + + if (!should_deliver(p, skb)) + return; + + /* Even with hairpin, no soliloquies - prevent breaking IPv6 DAD */ + if (skb->dev == p->dev && ether_addr_equal(src, addr)) + return; + + skb = skb_copy(skb, GFP_ATOMIC); + if (!skb) { + dev->stats.tx_dropped++; + return; + } + + if (!is_broadcast_ether_addr(addr)) + memcpy(eth_hdr(skb)->h_dest, addr, ETH_ALEN); + + __packet_hook(p, skb); +} + /* called with rcu_read_lock */ static void br_multicast_flood(struct net_bridge_mdb_entry *mdst, struct sk_buff *skb, struct sk_buff *skb0, @@ -271,10 +334,20 @@ rport = rp ? hlist_entry(rp, struct net_bridge_port, rlist) : NULL; - port = (unsigned long)lport > (unsigned long)rport ? - lport : rport; + if ((unsigned long)lport > (unsigned long)rport) { + port = lport; + + if (port->flags & BR_MULTICAST_TO_UNICAST) { + maybe_deliver_addr(lport, skb, p->eth_addr, + __packet_hook); + goto delivered; + } + } else { + port = rport; + } prev = maybe_deliver(prev, port, skb, __packet_hook); +delivered: if (IS_ERR(prev)) goto out;