diff mbox series

Sv: FAILED: patch "[PATCH] net: dsa: microchip: fix bridging with more than two member" failed to apply to 5.16-stable tree

Message ID DB7PR08MB38675030606F175301EDE48AB53F9@DB7PR08MB3867.eurprd08.prod.outlook.com
State New
Headers show
Series Sv: FAILED: patch "[PATCH] net: dsa: microchip: fix bridging with more than two member" failed to apply to 5.16-stable tree | expand

Commit Message

Svenning Sørensen Feb. 26, 2022, 1:17 p.m. UTC
Commit b3612ccdf284 ("net: dsa: microchip: implement multi-bridge support")
plugged a packet leak between ports that were members of different bridges.
Unfortunately, this broke another use case, namely that of more than two
ports that are members of the same bridge.

After that commit, when a port is added to a bridge, hardware bridging
between other member ports of that bridge will be cleared, preventing
packet exchange between them.

Fix by ensuring that the Port VLAN Membership bitmap includes any existing
ports in the bridge, not just the port being added.

Upstream commit 3d00827a90db6f79abc7cdc553887f89a2e0a184, backported to 5.16.

Fixes: b3612ccdf284 ("net: dsa: microchip: implement multi-bridge support")
Signed-off-by: Svenning Sørensen <sss@secomea.com>
Tested-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 drivers/net/dsa/microchip/ksz_common.c | 26 +++++++++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)

--
2.20.1

Backported upstream commit 3d00827a90db6f79abc7cdc553887f89a2e0a184 to 5.16.
Sorry about the subject; the MS webmail client doesn't seem allow me to change it when
replying to a message :(

Svenning
diff mbox series

Patch

diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
index 8a04302018dc..7ab9ab58de65 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c
@@ -26,7 +26,7 @@  void ksz_update_port_member(struct ksz_device *dev, int port)
        struct dsa_switch *ds = dev->ds;
        u8 port_member = 0, cpu_port;
        const struct dsa_port *dp;
-       int i;
+       int i, j;

        if (!dsa_is_user_port(ds, port))
                return;
@@ -45,13 +45,33 @@  void ksz_update_port_member(struct ksz_device *dev, int port)
                        continue;
                if (!dp->bridge_dev || dp->bridge_dev != other_dp->bridge_dev)
                        continue;
+               if (other_p->stp_state != BR_STATE_FORWARDING)
+                       continue;

-               if (other_p->stp_state == BR_STATE_FORWARDING &&
-                   p->stp_state == BR_STATE_FORWARDING) {
+               if (p->stp_state == BR_STATE_FORWARDING) {
                        val |= BIT(port);
                        port_member |= BIT(i);
                }

+               /* Retain port [i]'s relationship to other ports than [port] */
+               for (j = 0; j < ds->num_ports; j++) {
+                       const struct dsa_port *third_dp;
+                       struct ksz_port *third_p;
+
+                       if (j == i)
+                               continue;
+                       if (j == port)
+                               continue;
+                       if (!dsa_is_user_port(ds, j))
+                               continue;
+                       third_p = &dev->ports[j];
+                       if (third_p->stp_state != BR_STATE_FORWARDING)
+                               continue;
+                       third_dp = dsa_to_port(ds, j);
+                       if (third_dp->bridge_dev == dp->bridge_dev)
+                               val |= BIT(j);
+               }
+
                dev->dev_ops->cfg_port_member(dev, i, val | cpu_port);
        }