[NEIGH]: Convert neighbour addition to new netlink api
authorThomas Graf <tgraf@suug.ch>
Tue, 8 Aug 2006 00:55:40 +0000 (17:55 -0700)
committerDavid S. Miller <davem@sunset.davemloft.net>
Fri, 22 Sep 2006 21:53:59 +0000 (14:53 -0700)
Fixes:
    Return EAFNOSUPPORT if no table matches the specified
    address family.

Signed-off-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/core/neighbour.c

index 39c07cc66ee747224df7bc1e0aa10fcba9e78f22..6036f43c1fd6dba873bafe6e999467499ceede90 100644 (file)
@@ -1506,76 +1506,88 @@ out:
 
 int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
-       struct ndmsg *ndm = NLMSG_DATA(nlh);
-       struct rtattr **nda = arg;
+       struct ndmsg *ndm;
+       struct nlattr *tb[NDA_MAX+1];
        struct neigh_table *tbl;
        struct net_device *dev = NULL;
-       int err = -ENODEV;
+       int err;
+
+       err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
+       if (err < 0)
+               goto out;
 
-       if (ndm->ndm_ifindex &&
-           (dev = dev_get_by_index(ndm->ndm_ifindex)) == NULL)
+       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;
+               }
+
+               if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len)
+                       goto out_dev_put;
+       }
+
        read_lock(&neigh_tbl_lock);
        for (tbl = neigh_tables; tbl; tbl = tbl->next) {
-               struct rtattr *lladdr_attr = nda[NDA_LLADDR - 1];
-               struct rtattr *dst_attr = nda[NDA_DST - 1];
-               int override = 1;
-               struct neighbour *n;
+               int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE;
+               struct neighbour *neigh;
+               void *dst, *lladdr;
 
                if (tbl->family != ndm->ndm_family)
                        continue;
                read_unlock(&neigh_tbl_lock);
 
-               err = -EINVAL;
-               if (!dst_attr || RTA_PAYLOAD(dst_attr) < tbl->key_len)
+               if (nla_len(tb[NDA_DST]) < tbl->key_len)
                        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) {
-                       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;
                }
 
-               err = -EINVAL;
-               if (!dev)
-                       goto out;
-               if (lladdr_attr && RTA_PAYLOAD(lladdr_attr) < dev->addr_len)
+               if (dev == NULL)
                        goto out_dev_put;
+
+               neigh = neigh_lookup(tbl, dst, dev);
+               if (neigh == NULL) {
+                       if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
+                               err = -ENOENT;
+                               goto out_dev_put;
+                       }
        
-               n = neigh_lookup(tbl, RTA_DATA(dst_attr), dev);
-               if (n) {
-                       if (nlh->nlmsg_flags & NLM_F_EXCL) {
-                               err = -EEXIST;
-                               neigh_release(n);
+                       neigh = __neigh_lookup_errno(tbl, dst, dev);
+                       if (IS_ERR(neigh)) {
+                               err = PTR_ERR(neigh);
                                goto out_dev_put;
                        }
-                       
-                       override = nlh->nlmsg_flags & NLM_F_REPLACE;
-               } else if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
-                       err = -ENOENT;
-                       goto out_dev_put;
                } else {
-                       n = __neigh_lookup_errno(tbl, RTA_DATA(dst_attr), dev);
-                       if (IS_ERR(n)) {
-                               err = PTR_ERR(n);
+                       if (nlh->nlmsg_flags & NLM_F_EXCL) {
+                               err = -EEXIST;
+                               neigh_release(neigh);
                                goto out_dev_put;
                        }
-               }
 
-               err = neigh_update(n,
-                                  lladdr_attr ? RTA_DATA(lladdr_attr) : NULL,
-                                  ndm->ndm_state,
-                                  (override ? NEIGH_UPDATE_F_OVERRIDE : 0) |
-                                  NEIGH_UPDATE_F_ADMIN);
+                       if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
+                               flags &= ~NEIGH_UPDATE_F_OVERRIDE;
+               }
 
-               neigh_release(n);
+               err = neigh_update(neigh, lladdr, ndm->ndm_state, flags);
+               neigh_release(neigh);
                goto out_dev_put;
        }
 
        read_unlock(&neigh_tbl_lock);
-       err = -EADDRNOTAVAIL;
+       err = -EAFNOSUPPORT;
+
 out_dev_put:
        if (dev)
                dev_put(dev);