diff options
Diffstat (limited to 'net/dsa/slave.c')
-rw-r--r-- | net/dsa/slave.c | 110 |
1 files changed, 106 insertions, 4 deletions
diff --git a/net/dsa/slave.c b/net/dsa/slave.c index a78b2bba0332..90629b12beaf 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c | |||
@@ -983,6 +983,72 @@ static int dsa_slave_get_ts_info(struct net_device *dev, | |||
983 | return ds->ops->get_ts_info(ds, p->dp->index, ts); | 983 | return ds->ops->get_ts_info(ds, p->dp->index, ts); |
984 | } | 984 | } |
985 | 985 | ||
986 | static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto, | ||
987 | u16 vid) | ||
988 | { | ||
989 | struct dsa_port *dp = dsa_slave_to_port(dev); | ||
990 | struct switchdev_obj_port_vlan vlan = { | ||
991 | .vid_begin = vid, | ||
992 | .vid_end = vid, | ||
993 | /* This API only allows programming tagged, non-PVID VIDs */ | ||
994 | .flags = 0, | ||
995 | }; | ||
996 | struct bridge_vlan_info info; | ||
997 | int ret; | ||
998 | |||
999 | /* Check for a possible bridge VLAN entry now since there is no | ||
1000 | * need to emulate the switchdev prepare + commit phase. | ||
1001 | */ | ||
1002 | if (dp->bridge_dev) { | ||
1003 | /* br_vlan_get_info() returns -EINVAL or -ENOENT if the | ||
1004 | * device, respectively the VID is not found, returning | ||
1005 | * 0 means success, which is a failure for us here. | ||
1006 | */ | ||
1007 | ret = br_vlan_get_info(dp->bridge_dev, vid, &info); | ||
1008 | if (ret == 0) | ||
1009 | return -EBUSY; | ||
1010 | } | ||
1011 | |||
1012 | ret = dsa_port_vlan_add(dp, &vlan, NULL); | ||
1013 | if (ret == -EOPNOTSUPP) | ||
1014 | ret = 0; | ||
1015 | |||
1016 | return ret; | ||
1017 | } | ||
1018 | |||
1019 | static int dsa_slave_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, | ||
1020 | u16 vid) | ||
1021 | { | ||
1022 | struct dsa_port *dp = dsa_slave_to_port(dev); | ||
1023 | struct switchdev_obj_port_vlan vlan = { | ||
1024 | .vid_begin = vid, | ||
1025 | .vid_end = vid, | ||
1026 | /* This API only allows programming tagged, non-PVID VIDs */ | ||
1027 | .flags = 0, | ||
1028 | }; | ||
1029 | struct bridge_vlan_info info; | ||
1030 | int ret; | ||
1031 | |||
1032 | /* Check for a possible bridge VLAN entry now since there is no | ||
1033 | * need to emulate the switchdev prepare + commit phase. | ||
1034 | */ | ||
1035 | if (dp->bridge_dev) { | ||
1036 | /* br_vlan_get_info() returns -EINVAL or -ENOENT if the | ||
1037 | * device, respectively the VID is not found, returning | ||
1038 | * 0 means success, which is a failure for us here. | ||
1039 | */ | ||
1040 | ret = br_vlan_get_info(dp->bridge_dev, vid, &info); | ||
1041 | if (ret == 0) | ||
1042 | return -EBUSY; | ||
1043 | } | ||
1044 | |||
1045 | ret = dsa_port_vlan_del(dp, &vlan); | ||
1046 | if (ret == -EOPNOTSUPP) | ||
1047 | ret = 0; | ||
1048 | |||
1049 | return ret; | ||
1050 | } | ||
1051 | |||
986 | static const struct ethtool_ops dsa_slave_ethtool_ops = { | 1052 | static const struct ethtool_ops dsa_slave_ethtool_ops = { |
987 | .get_drvinfo = dsa_slave_get_drvinfo, | 1053 | .get_drvinfo = dsa_slave_get_drvinfo, |
988 | .get_regs_len = dsa_slave_get_regs_len, | 1054 | .get_regs_len = dsa_slave_get_regs_len, |
@@ -1048,6 +1114,8 @@ static const struct net_device_ops dsa_slave_netdev_ops = { | |||
1048 | .ndo_setup_tc = dsa_slave_setup_tc, | 1114 | .ndo_setup_tc = dsa_slave_setup_tc, |
1049 | .ndo_get_stats64 = dsa_slave_get_stats64, | 1115 | .ndo_get_stats64 = dsa_slave_get_stats64, |
1050 | .ndo_get_port_parent_id = dsa_slave_get_port_parent_id, | 1116 | .ndo_get_port_parent_id = dsa_slave_get_port_parent_id, |
1117 | .ndo_vlan_rx_add_vid = dsa_slave_vlan_rx_add_vid, | ||
1118 | .ndo_vlan_rx_kill_vid = dsa_slave_vlan_rx_kill_vid, | ||
1051 | }; | 1119 | }; |
1052 | 1120 | ||
1053 | static const struct switchdev_ops dsa_slave_switchdev_ops = { | 1121 | static const struct switchdev_ops dsa_slave_switchdev_ops = { |
@@ -1307,7 +1375,8 @@ int dsa_slave_create(struct dsa_port *port) | |||
1307 | if (slave_dev == NULL) | 1375 | if (slave_dev == NULL) |
1308 | return -ENOMEM; | 1376 | return -ENOMEM; |
1309 | 1377 | ||
1310 | slave_dev->features = master->vlan_features | NETIF_F_HW_TC; | 1378 | slave_dev->features = master->vlan_features | NETIF_F_HW_TC | |
1379 | NETIF_F_HW_VLAN_CTAG_FILTER; | ||
1311 | slave_dev->hw_features |= NETIF_F_HW_TC; | 1380 | slave_dev->hw_features |= NETIF_F_HW_TC; |
1312 | slave_dev->ethtool_ops = &dsa_slave_ethtool_ops; | 1381 | slave_dev->ethtool_ops = &dsa_slave_ethtool_ops; |
1313 | eth_hw_addr_inherit(slave_dev, master); | 1382 | eth_hw_addr_inherit(slave_dev, master); |
@@ -1408,16 +1477,49 @@ static int dsa_slave_changeupper(struct net_device *dev, | |||
1408 | return err; | 1477 | return err; |
1409 | } | 1478 | } |
1410 | 1479 | ||
1480 | static int dsa_slave_upper_vlan_check(struct net_device *dev, | ||
1481 | struct netdev_notifier_changeupper_info * | ||
1482 | info) | ||
1483 | { | ||
1484 | struct netlink_ext_ack *ext_ack; | ||
1485 | struct net_device *slave; | ||
1486 | struct dsa_port *dp; | ||
1487 | |||
1488 | ext_ack = netdev_notifier_info_to_extack(&info->info); | ||
1489 | |||
1490 | if (!is_vlan_dev(dev)) | ||
1491 | return NOTIFY_DONE; | ||
1492 | |||
1493 | slave = vlan_dev_real_dev(dev); | ||
1494 | if (!dsa_slave_dev_check(slave)) | ||
1495 | return NOTIFY_DONE; | ||
1496 | |||
1497 | dp = dsa_slave_to_port(slave); | ||
1498 | if (!dp->bridge_dev) | ||
1499 | return NOTIFY_DONE; | ||
1500 | |||
1501 | /* Deny enslaving a VLAN device into a VLAN-aware bridge */ | ||
1502 | if (br_vlan_enabled(dp->bridge_dev) && | ||
1503 | netif_is_bridge_master(info->upper_dev) && info->linking) { | ||
1504 | NL_SET_ERR_MSG_MOD(ext_ack, | ||
1505 | "Cannot enslave VLAN device into VLAN aware bridge"); | ||
1506 | return notifier_from_errno(-EINVAL); | ||
1507 | } | ||
1508 | |||
1509 | return NOTIFY_DONE; | ||
1510 | } | ||
1511 | |||
1411 | static int dsa_slave_netdevice_event(struct notifier_block *nb, | 1512 | static int dsa_slave_netdevice_event(struct notifier_block *nb, |
1412 | unsigned long event, void *ptr) | 1513 | unsigned long event, void *ptr) |
1413 | { | 1514 | { |
1414 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); | 1515 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); |
1415 | 1516 | ||
1416 | if (!dsa_slave_dev_check(dev)) | 1517 | if (event == NETDEV_CHANGEUPPER) { |
1417 | return NOTIFY_DONE; | 1518 | if (!dsa_slave_dev_check(dev)) |
1519 | return dsa_slave_upper_vlan_check(dev, ptr); | ||
1418 | 1520 | ||
1419 | if (event == NETDEV_CHANGEUPPER) | ||
1420 | return dsa_slave_changeupper(dev, ptr); | 1521 | return dsa_slave_changeupper(dev, ptr); |
1522 | } | ||
1421 | 1523 | ||
1422 | return NOTIFY_DONE; | 1524 | return NOTIFY_DONE; |
1423 | } | 1525 | } |