diff options
author | Thomas Graf <tgraf@suug.ch> | 2006-08-07 20:55:40 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-09-22 17:53:59 -0400 |
commit | 5208debd0f1da07bbb350f8b0b142775d4f002ea (patch) | |
tree | fc8d407d963c6d4b36a708006487327336b04c25 /net/core | |
parent | a14a49d2b7b9290e87751f21f503f1954267d4c4 (diff) |
[NEIGH]: Convert neighbour addition to new netlink api
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>
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/neighbour.c | 90 |
1 files changed, 51 insertions, 39 deletions
diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 39c07cc66ee7..6036f43c1fd6 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c | |||
@@ -1506,76 +1506,88 @@ out: | |||
1506 | 1506 | ||
1507 | int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 1507 | int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
1508 | { | 1508 | { |
1509 | struct ndmsg *ndm = NLMSG_DATA(nlh); | 1509 | struct ndmsg *ndm; |
1510 | struct rtattr **nda = arg; | 1510 | struct nlattr *tb[NDA_MAX+1]; |
1511 | struct neigh_table *tbl; | 1511 | struct neigh_table *tbl; |
1512 | struct net_device *dev = NULL; | 1512 | struct net_device *dev = NULL; |
1513 | int err = -ENODEV; | 1513 | int err; |
1514 | |||
1515 | err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL); | ||
1516 | if (err < 0) | ||
1517 | goto out; | ||
1514 | 1518 | ||
1515 | if (ndm->ndm_ifindex && | 1519 | err = -EINVAL; |
1516 | (dev = dev_get_by_index(ndm->ndm_ifindex)) == NULL) | 1520 | if (tb[NDA_DST] == NULL) |
1517 | goto out; | 1521 | goto out; |
1518 | 1522 | ||
1523 | ndm = nlmsg_data(nlh); | ||
1524 | if (ndm->ndm_ifindex) { | ||
1525 | dev = dev_get_by_index(ndm->ndm_ifindex); | ||
1526 | if (dev == NULL) { | ||
1527 | err = -ENODEV; | ||
1528 | goto out; | ||
1529 | } | ||
1530 | |||
1531 | if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len) | ||
1532 | goto out_dev_put; | ||
1533 | } | ||
1534 | |||
1519 | read_lock(&neigh_tbl_lock); | 1535 | read_lock(&neigh_tbl_lock); |
1520 | for (tbl = neigh_tables; tbl; tbl = tbl->next) { | 1536 | for (tbl = neigh_tables; tbl; tbl = tbl->next) { |
1521 | struct rtattr *lladdr_attr = nda[NDA_LLADDR - 1]; | 1537 | int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE; |
1522 | struct rtattr *dst_attr = nda[NDA_DST - 1]; | 1538 | struct neighbour *neigh; |
1523 | int override = 1; | 1539 | void *dst, *lladdr; |
1524 | struct neighbour *n; | ||
1525 | 1540 | ||
1526 | if (tbl->family != ndm->ndm_family) | 1541 | if (tbl->family != ndm->ndm_family) |
1527 | continue; | 1542 | continue; |
1528 | read_unlock(&neigh_tbl_lock); | 1543 | read_unlock(&neigh_tbl_lock); |
1529 | 1544 | ||
1530 | err = -EINVAL; | 1545 | if (nla_len(tb[NDA_DST]) < tbl->key_len) |
1531 | if (!dst_attr || RTA_PAYLOAD(dst_attr) < tbl->key_len) | ||
1532 | goto out_dev_put; | 1546 | goto out_dev_put; |
1547 | dst = nla_data(tb[NDA_DST]); | ||
1548 | lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL; | ||
1533 | 1549 | ||
1534 | if (ndm->ndm_flags & NTF_PROXY) { | 1550 | if (ndm->ndm_flags & NTF_PROXY) { |
1535 | err = -ENOBUFS; | 1551 | err = 0; |
1536 | if (pneigh_lookup(tbl, RTA_DATA(dst_attr), dev, 1)) | 1552 | if (pneigh_lookup(tbl, dst, dev, 1) == NULL) |
1537 | err = 0; | 1553 | err = -ENOBUFS; |
1538 | goto out_dev_put; | 1554 | goto out_dev_put; |
1539 | } | 1555 | } |
1540 | 1556 | ||
1541 | err = -EINVAL; | 1557 | if (dev == NULL) |
1542 | if (!dev) | ||
1543 | goto out; | ||
1544 | if (lladdr_attr && RTA_PAYLOAD(lladdr_attr) < dev->addr_len) | ||
1545 | goto out_dev_put; | 1558 | goto out_dev_put; |
1559 | |||
1560 | neigh = neigh_lookup(tbl, dst, dev); | ||
1561 | if (neigh == NULL) { | ||
1562 | if (!(nlh->nlmsg_flags & NLM_F_CREATE)) { | ||
1563 | err = -ENOENT; | ||
1564 | goto out_dev_put; | ||
1565 | } | ||
1546 | 1566 | ||
1547 | n = neigh_lookup(tbl, RTA_DATA(dst_attr), dev); | 1567 | neigh = __neigh_lookup_errno(tbl, dst, dev); |
1548 | if (n) { | 1568 | if (IS_ERR(neigh)) { |
1549 | if (nlh->nlmsg_flags & NLM_F_EXCL) { | 1569 | err = PTR_ERR(neigh); |
1550 | err = -EEXIST; | ||
1551 | neigh_release(n); | ||
1552 | goto out_dev_put; | 1570 | goto out_dev_put; |
1553 | } | 1571 | } |
1554 | |||
1555 | override = nlh->nlmsg_flags & NLM_F_REPLACE; | ||
1556 | } else if (!(nlh->nlmsg_flags & NLM_F_CREATE)) { | ||
1557 | err = -ENOENT; | ||
1558 | goto out_dev_put; | ||
1559 | } else { | 1572 | } else { |
1560 | n = __neigh_lookup_errno(tbl, RTA_DATA(dst_attr), dev); | 1573 | if (nlh->nlmsg_flags & NLM_F_EXCL) { |
1561 | if (IS_ERR(n)) { | 1574 | err = -EEXIST; |
1562 | err = PTR_ERR(n); | 1575 | neigh_release(neigh); |
1563 | goto out_dev_put; | 1576 | goto out_dev_put; |
1564 | } | 1577 | } |
1565 | } | ||
1566 | 1578 | ||
1567 | err = neigh_update(n, | 1579 | if (!(nlh->nlmsg_flags & NLM_F_REPLACE)) |
1568 | lladdr_attr ? RTA_DATA(lladdr_attr) : NULL, | 1580 | flags &= ~NEIGH_UPDATE_F_OVERRIDE; |
1569 | ndm->ndm_state, | 1581 | } |
1570 | (override ? NEIGH_UPDATE_F_OVERRIDE : 0) | | ||
1571 | NEIGH_UPDATE_F_ADMIN); | ||
1572 | 1582 | ||
1573 | neigh_release(n); | 1583 | err = neigh_update(neigh, lladdr, ndm->ndm_state, flags); |
1584 | neigh_release(neigh); | ||
1574 | goto out_dev_put; | 1585 | goto out_dev_put; |
1575 | } | 1586 | } |
1576 | 1587 | ||
1577 | read_unlock(&neigh_tbl_lock); | 1588 | read_unlock(&neigh_tbl_lock); |
1578 | err = -EADDRNOTAVAIL; | 1589 | err = -EAFNOSUPPORT; |
1590 | |||
1579 | out_dev_put: | 1591 | out_dev_put: |
1580 | if (dev) | 1592 | if (dev) |
1581 | dev_put(dev); | 1593 | dev_put(dev); |