diff options
Diffstat (limited to 'net/core/neighbour.c')
-rw-r--r-- | net/core/neighbour.c | 53 |
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 | ||
1441 | int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 1442 | int 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 | |||
1485 | out_dev_put: | 1500 | out_dev_put: |
1486 | if (dev) | 1501 | if (dev) |
1487 | dev_put(dev); | 1502 | dev_put(dev); |