aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/neighbour.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/core/neighbour.c')
-rw-r--r--net/core/neighbour.c53
1 files changed, 34 insertions, 19 deletions
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index fe2113f54e2b..39c07cc66ee7 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -30,6 +30,7 @@
30#include <net/dst.h> 30#include <net/dst.h>
31#include <net/sock.h> 31#include <net/sock.h>
32#include <net/netevent.h> 32#include <net/netevent.h>
33#include <net/netlink.h>
33#include <linux/rtnetlink.h> 34#include <linux/rtnetlink.h>
34#include <linux/random.h> 35#include <linux/random.h>
35#include <linux/string.h> 36#include <linux/string.h>
@@ -1440,48 +1441,62 @@ int neigh_table_clear(struct neigh_table *tbl)
1440 1441
1441int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 1442int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
1442{ 1443{
1443 struct ndmsg *ndm = NLMSG_DATA(nlh); 1444 struct ndmsg *ndm;
1444 struct rtattr **nda = arg; 1445 struct nlattr *dst_attr;
1445 struct neigh_table *tbl; 1446 struct neigh_table *tbl;
1446 struct net_device *dev = NULL; 1447 struct net_device *dev = NULL;
1447 int err = -ENODEV; 1448 int err = -EINVAL;
1448 1449
1449 if (ndm->ndm_ifindex && 1450 if (nlmsg_len(nlh) < sizeof(*ndm))
1450 (dev = dev_get_by_index(ndm->ndm_ifindex)) == NULL) 1451 goto out;
1452
1453 dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST);
1454 if (dst_attr == NULL)
1451 goto out; 1455 goto out;
1452 1456
1457 ndm = nlmsg_data(nlh);
1458 if (ndm->ndm_ifindex) {
1459 dev = dev_get_by_index(ndm->ndm_ifindex);
1460 if (dev == NULL) {
1461 err = -ENODEV;
1462 goto out;
1463 }
1464 }
1465
1453 read_lock(&neigh_tbl_lock); 1466 read_lock(&neigh_tbl_lock);
1454 for (tbl = neigh_tables; tbl; tbl = tbl->next) { 1467 for (tbl = neigh_tables; tbl; tbl = tbl->next) {
1455 struct rtattr *dst_attr = nda[NDA_DST - 1]; 1468 struct neighbour *neigh;
1456 struct neighbour *n;
1457 1469
1458 if (tbl->family != ndm->ndm_family) 1470 if (tbl->family != ndm->ndm_family)
1459 continue; 1471 continue;
1460 read_unlock(&neigh_tbl_lock); 1472 read_unlock(&neigh_tbl_lock);
1461 1473
1462 err = -EINVAL; 1474 if (nla_len(dst_attr) < tbl->key_len)
1463 if (!dst_attr || RTA_PAYLOAD(dst_attr) < tbl->key_len)
1464 goto out_dev_put; 1475 goto out_dev_put;
1465 1476
1466 if (ndm->ndm_flags & NTF_PROXY) { 1477 if (ndm->ndm_flags & NTF_PROXY) {
1467 err = pneigh_delete(tbl, RTA_DATA(dst_attr), dev); 1478 err = pneigh_delete(tbl, nla_data(dst_attr), dev);
1468 goto out_dev_put; 1479 goto out_dev_put;
1469 } 1480 }
1470 1481
1471 if (!dev) 1482 if (dev == NULL)
1472 goto out; 1483 goto out_dev_put;
1473 1484
1474 n = neigh_lookup(tbl, RTA_DATA(dst_attr), dev); 1485 neigh = neigh_lookup(tbl, nla_data(dst_attr), dev);
1475 if (n) { 1486 if (neigh == NULL) {
1476 err = neigh_update(n, NULL, NUD_FAILED, 1487 err = -ENOENT;
1477 NEIGH_UPDATE_F_OVERRIDE| 1488 goto out_dev_put;
1478 NEIGH_UPDATE_F_ADMIN);
1479 neigh_release(n);
1480 } 1489 }
1490
1491 err = neigh_update(neigh, NULL, NUD_FAILED,
1492 NEIGH_UPDATE_F_OVERRIDE |
1493 NEIGH_UPDATE_F_ADMIN);
1494 neigh_release(neigh);
1481 goto out_dev_put; 1495 goto out_dev_put;
1482 } 1496 }
1483 read_unlock(&neigh_tbl_lock); 1497 read_unlock(&neigh_tbl_lock);
1484 err = -EADDRNOTAVAIL; 1498 err = -EAFNOSUPPORT;
1499
1485out_dev_put: 1500out_dev_put:
1486 if (dev) 1501 if (dev)
1487 dev_put(dev); 1502 dev_put(dev);