|
@@ -1980,6 +1980,37 @@ errout:
|
|
|
rtnl_set_sk_err(net, RTNLGRP_LINK, err);
|
|
|
}
|
|
|
|
|
|
+static int nlmsg_populate_fdb_fill(struct sk_buff *skb,
|
|
|
+ struct net_device *dev,
|
|
|
+ u8 *addr, u32 pid, u32 seq,
|
|
|
+ int type, unsigned int flags)
|
|
|
+{
|
|
|
+ struct nlmsghdr *nlh;
|
|
|
+ struct ndmsg *ndm;
|
|
|
+
|
|
|
+ nlh = nlmsg_put(skb, pid, seq, type, 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 = flags;
|
|
|
+ ndm->ndm_type = 0;
|
|
|
+ ndm->ndm_ifindex = dev->ifindex;
|
|
|
+ ndm->ndm_state = NUD_PERMANENT;
|
|
|
+
|
|
|
+ if (nla_put(skb, NDA_LLADDR, ETH_ALEN, addr))
|
|
|
+ goto nla_put_failure;
|
|
|
+
|
|
|
+ return nlmsg_end(skb, nlh);
|
|
|
+
|
|
|
+nla_put_failure:
|
|
|
+ nlmsg_cancel(skb, nlh);
|
|
|
+ return -EMSGSIZE;
|
|
|
+}
|
|
|
+
|
|
|
static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
|
|
|
{
|
|
|
struct net *net = sock_net(skb->sk);
|
|
@@ -2101,6 +2132,59 @@ out:
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+static int nlmsg_populate_fdb(struct sk_buff *skb,
|
|
|
+ struct netlink_callback *cb,
|
|
|
+ struct net_device *dev,
|
|
|
+ int *idx,
|
|
|
+ struct netdev_hw_addr_list *list)
|
|
|
+{
|
|
|
+ struct netdev_hw_addr *ha;
|
|
|
+ int err;
|
|
|
+ u32 pid, seq;
|
|
|
+
|
|
|
+ pid = NETLINK_CB(cb->skb).pid;
|
|
|
+ seq = cb->nlh->nlmsg_seq;
|
|
|
+
|
|
|
+ list_for_each_entry(ha, &list->list, list) {
|
|
|
+ if (*idx < cb->args[0])
|
|
|
+ goto skip;
|
|
|
+
|
|
|
+ err = nlmsg_populate_fdb_fill(skb, dev, ha->addr,
|
|
|
+ pid, seq, 0, NTF_SELF);
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+skip:
|
|
|
+ *idx += 1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * ndo_dflt_fdb_dump: default netdevice operation to dump an FDB table.
|
|
|
+ * @nlh: netlink message header
|
|
|
+ * @dev: netdevice
|
|
|
+ *
|
|
|
+ * Default netdevice operation to dump the existing unicast address list.
|
|
|
+ * Returns zero on success.
|
|
|
+ */
|
|
|
+int ndo_dflt_fdb_dump(struct sk_buff *skb,
|
|
|
+ struct netlink_callback *cb,
|
|
|
+ struct net_device *dev,
|
|
|
+ int idx)
|
|
|
+{
|
|
|
+ int err;
|
|
|
+
|
|
|
+ netif_addr_lock_bh(dev);
|
|
|
+ err = nlmsg_populate_fdb(skb, cb, dev, &idx, &dev->uc);
|
|
|
+ if (err)
|
|
|
+ goto out;
|
|
|
+ nlmsg_populate_fdb(skb, cb, dev, &idx, &dev->mc);
|
|
|
+out:
|
|
|
+ netif_addr_unlock_bh(dev);
|
|
|
+ return idx;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(ndo_dflt_fdb_dump);
|
|
|
+
|
|
|
static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
|
|
{
|
|
|
int idx = 0;
|