aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/neighbour.c
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2006-08-07 20:55:40 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-09-22 17:53:59 -0400
commit5208debd0f1da07bbb350f8b0b142775d4f002ea (patch)
treefc8d407d963c6d4b36a708006487327336b04c25 /net/core/neighbour.c
parenta14a49d2b7b9290e87751f21f503f1954267d4c4 (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/neighbour.c')
-rw-r--r--net/core/neighbour.c90
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
1507int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 1507int 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
1579out_dev_put: 1591out_dev_put:
1580 if (dev) 1592 if (dev)
1581 dev_put(dev); 1593 dev_put(dev);