Commit 5208debd authored by Thomas Graf's avatar Thomas Graf Committed by David S. Miller

[NEIGH]: Convert neighbour addition to new netlink api

Fixes:
    Return EAFNOSUPPORT if no table matches the specified
    address family.
Signed-off-by: default avatarThomas Graf <tgraf@suug.ch>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a14a49d2
...@@ -1506,76 +1506,88 @@ out: ...@@ -1506,76 +1506,88 @@ out:
int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
{ {
struct ndmsg *ndm = NLMSG_DATA(nlh); struct ndmsg *ndm;
struct rtattr **nda = arg; struct nlattr *tb[NDA_MAX+1];
struct neigh_table *tbl; struct neigh_table *tbl;
struct net_device *dev = NULL; struct net_device *dev = NULL;
int err = -ENODEV; int err;
if (ndm->ndm_ifindex && err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
(dev = dev_get_by_index(ndm->ndm_ifindex)) == NULL) if (err < 0)
goto out;
err = -EINVAL;
if (tb[NDA_DST] == NULL)
goto out;
ndm = nlmsg_data(nlh);
if (ndm->ndm_ifindex) {
dev = dev_get_by_index(ndm->ndm_ifindex);
if (dev == NULL) {
err = -ENODEV;
goto out; goto out;
}
if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len)
goto out_dev_put;
}
read_lock(&neigh_tbl_lock); read_lock(&neigh_tbl_lock);
for (tbl = neigh_tables; tbl; tbl = tbl->next) { for (tbl = neigh_tables; tbl; tbl = tbl->next) {
struct rtattr *lladdr_attr = nda[NDA_LLADDR - 1]; int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE;
struct rtattr *dst_attr = nda[NDA_DST - 1]; struct neighbour *neigh;
int override = 1; void *dst, *lladdr;
struct neighbour *n;
if (tbl->family != ndm->ndm_family) if (tbl->family != ndm->ndm_family)
continue; continue;
read_unlock(&neigh_tbl_lock); read_unlock(&neigh_tbl_lock);
err = -EINVAL; if (nla_len(tb[NDA_DST]) < tbl->key_len)
if (!dst_attr || RTA_PAYLOAD(dst_attr) < tbl->key_len)
goto out_dev_put; goto out_dev_put;
dst = nla_data(tb[NDA_DST]);
lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
if (ndm->ndm_flags & NTF_PROXY) { if (ndm->ndm_flags & NTF_PROXY) {
err = -ENOBUFS;
if (pneigh_lookup(tbl, RTA_DATA(dst_attr), dev, 1))
err = 0; err = 0;
if (pneigh_lookup(tbl, dst, dev, 1) == NULL)
err = -ENOBUFS;
goto out_dev_put; goto out_dev_put;
} }
err = -EINVAL; if (dev == NULL)
if (!dev)
goto out;
if (lladdr_attr && RTA_PAYLOAD(lladdr_attr) < dev->addr_len)
goto out_dev_put; goto out_dev_put;
n = neigh_lookup(tbl, RTA_DATA(dst_attr), dev); neigh = neigh_lookup(tbl, dst, dev);
if (n) { if (neigh == NULL) {
if (nlh->nlmsg_flags & NLM_F_EXCL) { if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
err = -EEXIST; err = -ENOENT;
neigh_release(n);
goto out_dev_put; goto out_dev_put;
} }
override = nlh->nlmsg_flags & NLM_F_REPLACE; neigh = __neigh_lookup_errno(tbl, dst, dev);
} else if (!(nlh->nlmsg_flags & NLM_F_CREATE)) { if (IS_ERR(neigh)) {
err = -ENOENT; err = PTR_ERR(neigh);
goto out_dev_put; goto out_dev_put;
}
} else { } else {
n = __neigh_lookup_errno(tbl, RTA_DATA(dst_attr), dev); if (nlh->nlmsg_flags & NLM_F_EXCL) {
if (IS_ERR(n)) { err = -EEXIST;
err = PTR_ERR(n); neigh_release(neigh);
goto out_dev_put; goto out_dev_put;
} }
}
err = neigh_update(n, if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
lladdr_attr ? RTA_DATA(lladdr_attr) : NULL, flags &= ~NEIGH_UPDATE_F_OVERRIDE;
ndm->ndm_state, }
(override ? NEIGH_UPDATE_F_OVERRIDE : 0) |
NEIGH_UPDATE_F_ADMIN);
neigh_release(n); err = neigh_update(neigh, lladdr, ndm->ndm_state, flags);
neigh_release(neigh);
goto out_dev_put; goto out_dev_put;
} }
read_unlock(&neigh_tbl_lock); read_unlock(&neigh_tbl_lock);
err = -EADDRNOTAVAIL; err = -EAFNOSUPPORT;
out_dev_put: out_dev_put:
if (dev) if (dev)
dev_put(dev); dev_put(dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment