|
@@ -199,6 +199,83 @@ out:
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+struct dsa_slave_dump_ctx {
|
|
|
+ struct net_device *dev;
|
|
|
+ struct sk_buff *skb;
|
|
|
+ struct netlink_callback *cb;
|
|
|
+ int idx;
|
|
|
+};
|
|
|
+
|
|
|
+static int
|
|
|
+dsa_slave_port_fdb_do_dump(const unsigned char *addr, u16 vid,
|
|
|
+ bool is_static, void *data)
|
|
|
+{
|
|
|
+ struct dsa_slave_dump_ctx *dump = data;
|
|
|
+ u32 portid = NETLINK_CB(dump->cb->skb).portid;
|
|
|
+ u32 seq = dump->cb->nlh->nlmsg_seq;
|
|
|
+ struct nlmsghdr *nlh;
|
|
|
+ struct ndmsg *ndm;
|
|
|
+
|
|
|
+ if (dump->idx < dump->cb->args[2])
|
|
|
+ goto skip;
|
|
|
+
|
|
|
+ nlh = nlmsg_put(dump->skb, portid, seq, RTM_NEWNEIGH,
|
|
|
+ sizeof(*ndm), NLM_F_MULTI);
|
|
|
+ if (!nlh)
|
|
|
+ return -EMSGSIZE;
|
|
|
+
|
|
|
+ ndm = nlmsg_data(nlh);
|
|
|
+ ndm->ndm_family = AF_BRIDGE;
|
|
|
+ ndm->ndm_pad1 = 0;
|
|
|
+ ndm->ndm_pad2 = 0;
|
|
|
+ ndm->ndm_flags = NTF_SELF;
|
|
|
+ ndm->ndm_type = 0;
|
|
|
+ ndm->ndm_ifindex = dump->dev->ifindex;
|
|
|
+ ndm->ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE;
|
|
|
+
|
|
|
+ if (nla_put(dump->skb, NDA_LLADDR, ETH_ALEN, addr))
|
|
|
+ goto nla_put_failure;
|
|
|
+
|
|
|
+ if (vid && nla_put_u16(dump->skb, NDA_VLAN, vid))
|
|
|
+ goto nla_put_failure;
|
|
|
+
|
|
|
+ nlmsg_end(dump->skb, nlh);
|
|
|
+
|
|
|
+skip:
|
|
|
+ dump->idx++;
|
|
|
+ return 0;
|
|
|
+
|
|
|
+nla_put_failure:
|
|
|
+ nlmsg_cancel(dump->skb, nlh);
|
|
|
+ return -EMSGSIZE;
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+dsa_slave_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
|
|
|
+ struct net_device *dev, struct net_device *filter_dev,
|
|
|
+ int *idx)
|
|
|
+{
|
|
|
+ struct dsa_slave_dump_ctx dump = {
|
|
|
+ .dev = dev,
|
|
|
+ .skb = skb,
|
|
|
+ .cb = cb,
|
|
|
+ .idx = *idx,
|
|
|
+ };
|
|
|
+ struct dsa_slave_priv *p = netdev_priv(dev);
|
|
|
+ struct dsa_port *dp = p->dp;
|
|
|
+ struct dsa_switch *ds = dp->ds;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ if (!ds->ops->port_fdb_dump)
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+
|
|
|
+ err = ds->ops->port_fdb_dump(ds, dp->index,
|
|
|
+ dsa_slave_port_fdb_do_dump,
|
|
|
+ &dump);
|
|
|
+ *idx = dump.idx;
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
|
|
{
|
|
|
struct dsa_slave_priv *p = netdev_priv(dev);
|
|
@@ -287,26 +364,6 @@ static int dsa_slave_port_obj_del(struct net_device *dev,
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
-static int dsa_slave_port_obj_dump(struct net_device *dev,
|
|
|
- struct switchdev_obj *obj,
|
|
|
- switchdev_obj_dump_cb_t *cb)
|
|
|
-{
|
|
|
- struct dsa_slave_priv *p = netdev_priv(dev);
|
|
|
- struct dsa_port *dp = p->dp;
|
|
|
- int err;
|
|
|
-
|
|
|
- switch (obj->id) {
|
|
|
- case SWITCHDEV_OBJ_ID_PORT_FDB:
|
|
|
- err = dsa_port_fdb_dump(dp, SWITCHDEV_OBJ_PORT_FDB(obj), cb);
|
|
|
- break;
|
|
|
- default:
|
|
|
- err = -EOPNOTSUPP;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- return err;
|
|
|
-}
|
|
|
-
|
|
|
static int dsa_slave_port_attr_get(struct net_device *dev,
|
|
|
struct switchdev_attr *attr)
|
|
|
{
|
|
@@ -974,7 +1031,7 @@ static const struct net_device_ops dsa_slave_netdev_ops = {
|
|
|
.ndo_set_mac_address = dsa_slave_set_mac_address,
|
|
|
.ndo_fdb_add = dsa_legacy_fdb_add,
|
|
|
.ndo_fdb_del = dsa_legacy_fdb_del,
|
|
|
- .ndo_fdb_dump = switchdev_port_fdb_dump,
|
|
|
+ .ndo_fdb_dump = dsa_slave_fdb_dump,
|
|
|
.ndo_do_ioctl = dsa_slave_ioctl,
|
|
|
.ndo_get_iflink = dsa_slave_get_iflink,
|
|
|
#ifdef CONFIG_NET_POLL_CONTROLLER
|
|
@@ -992,7 +1049,6 @@ static const struct switchdev_ops dsa_slave_switchdev_ops = {
|
|
|
.switchdev_port_attr_set = dsa_slave_port_attr_set,
|
|
|
.switchdev_port_obj_add = dsa_slave_port_obj_add,
|
|
|
.switchdev_port_obj_del = dsa_slave_port_obj_del,
|
|
|
- .switchdev_port_obj_dump = dsa_slave_port_obj_dump,
|
|
|
};
|
|
|
|
|
|
static struct device_type dsa_type = {
|