@@ -181,7 +181,8 @@ int dsa_port_enable_rt(struct dsa_port *dp, struct phy_device *phy);
int dsa_port_enable(struct dsa_port *dp, struct phy_device *phy);
void dsa_port_disable_rt(struct dsa_port *dp);
void dsa_port_disable(struct dsa_port *dp);
-int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br);
+int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br,
+ struct netlink_ext_ack *extack);
void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br);
int dsa_port_lag_change(struct dsa_port *dp,
struct netdev_lag_lower_state_info *linfo);
@@ -261,6 +262,9 @@ static inline bool dsa_tree_offloads_netdev(struct dsa_switch_tree *dst,
/* slave.c */
extern const struct dsa_device_ops notag_netdev_ops;
+int dsa_check_bridge_for_overlapping_8021q_uppers(struct net_device *bridge_dev,
+ struct net_device *skip,
+ u16 vid);
void dsa_slave_mii_bus_init(struct dsa_switch *ds);
int dsa_slave_create(struct dsa_port *dp);
void dsa_slave_destroy(struct net_device *slave_dev);
@@ -144,7 +144,8 @@ static void dsa_port_change_brport_flags(struct dsa_port *dp,
}
}
-int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br)
+int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br,
+ struct netlink_ext_ack *extack)
{
struct dsa_notifier_bridge_info info = {
.tree_index = dp->ds->dst->index,
@@ -152,8 +153,28 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br)
.port = dp->index,
.br = br,
};
+ struct net_device *slave = dp->slave;
+ struct net_device *upper_dev;
+ struct list_head *iter;
int err;
+ netdev_for_each_upper_dev_rcu(slave, upper_dev, iter) {
+ u16 vid;
+
+ if (!is_vlan_dev(upper_dev))
+ continue;
+
+ vid = vlan_dev_vlan_id(upper_dev);
+
+ err = dsa_check_bridge_for_overlapping_8021q_uppers(br, slave,
+ vid);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Configuration would leak VLAN-tagged packets between bridge ports");
+ return err;
+ }
+ }
+
/* Notify the port driver to set its configurable flags in a way that
* matches the initial settings of a bridge port.
*/
@@ -323,9 +323,9 @@ static int dsa_slave_port_attr_set(struct net_device *dev,
return ret;
}
-static int
-dsa_check_bridge_for_overlapping_8021q_uppers(struct net_device *bridge_dev,
- u16 vid)
+int dsa_check_bridge_for_overlapping_8021q_uppers(struct net_device *bridge_dev,
+ struct net_device *skip,
+ u16 vid)
{
struct list_head *iter_upper, *iter_lower;
struct net_device *upper, *lower;
@@ -334,6 +334,9 @@ dsa_check_bridge_for_overlapping_8021q_uppers(struct net_device *bridge_dev,
if (!dsa_slave_dev_check(lower))
continue;
+ if (lower == skip)
+ continue;
+
netdev_for_each_upper_dev_rcu(lower, upper, iter_upper) {
u16 upper_vid;
@@ -373,6 +376,7 @@ static int dsa_slave_vlan_add(struct net_device *dev,
*/
if (br_vlan_enabled(dp->bridge_dev)) {
err = dsa_check_bridge_for_overlapping_8021q_uppers(dp->bridge_dev,
+ NULL,
vlan.vid);
if (err) {
NL_SET_ERR_MSG_MOD(extack,
@@ -1969,7 +1973,8 @@ static int dsa_slave_changeupper(struct net_device *dev,
if (netif_is_bridge_master(info->upper_dev)) {
if (info->linking) {
- err = dsa_port_bridge_join(dp, info->upper_dev);
+ err = dsa_port_bridge_join(dp, info->upper_dev,
+ info->info.extack);
if (!err)
dsa_bridge_mtu_normalization(dp);
err = notifier_from_errno(err);