diff options
| -rw-r--r-- | include/linux/rtnetlink.h | 107 | ||||
| -rw-r--r-- | include/net/neighbour.h | 4 | ||||
| -rw-r--r-- | net/core/neighbour.c | 317 | ||||
| -rw-r--r-- | net/core/rtnetlink.c | 20 | ||||
| -rw-r--r-- | security/selinux/nlmsgtab.c | 2 |
5 files changed, 439 insertions, 11 deletions
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index a09b5d42babf..5a5cda160267 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h | |||
| @@ -89,6 +89,13 @@ enum { | |||
| 89 | RTM_GETANYCAST = 62, | 89 | RTM_GETANYCAST = 62, |
| 90 | #define RTM_GETANYCAST RTM_GETANYCAST | 90 | #define RTM_GETANYCAST RTM_GETANYCAST |
| 91 | 91 | ||
| 92 | RTM_NEWNEIGHTBL = 64, | ||
| 93 | #define RTM_NEWNEIGHTBL RTM_NEWNEIGHTBL | ||
| 94 | RTM_GETNEIGHTBL = 66, | ||
| 95 | #define RTM_GETNEIGHTBL RTM_GETNEIGHTBL | ||
| 96 | RTM_SETNEIGHTBL, | ||
| 97 | #define RTM_SETNEIGHTBL RTM_SETNEIGHTBL | ||
| 98 | |||
| 92 | __RTM_MAX, | 99 | __RTM_MAX, |
| 93 | #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) | 100 | #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) |
| 94 | }; | 101 | }; |
| @@ -493,6 +500,106 @@ struct nda_cacheinfo | |||
| 493 | __u32 ndm_refcnt; | 500 | __u32 ndm_refcnt; |
| 494 | }; | 501 | }; |
| 495 | 502 | ||
| 503 | |||
| 504 | /***************************************************************** | ||
| 505 | * Neighbour tables specific messages. | ||
| 506 | * | ||
| 507 | * To retrieve the neighbour tables send RTM_GETNEIGHTBL with the | ||
| 508 | * NLM_F_DUMP flag set. Every neighbour table configuration is | ||
| 509 | * spread over multiple messages to avoid running into message | ||
| 510 | * size limits on systems with many interfaces. The first message | ||
| 511 | * in the sequence transports all not device specific data such as | ||
| 512 | * statistics, configuration, and the default parameter set. | ||
| 513 | * This message is followed by 0..n messages carrying device | ||
| 514 | * specific parameter sets. | ||
| 515 | * Although the ordering should be sufficient, NDTA_NAME can be | ||
| 516 | * used to identify sequences. The initial message can be identified | ||
| 517 | * by checking for NDTA_CONFIG. The device specific messages do | ||
| 518 | * not contain this TLV but have NDTPA_IFINDEX set to the | ||
| 519 | * corresponding interface index. | ||
| 520 | * | ||
| 521 | * To change neighbour table attributes, send RTM_SETNEIGHTBL | ||
| 522 | * with NDTA_NAME set. Changeable attribute include NDTA_THRESH[1-3], | ||
| 523 | * NDTA_GC_INTERVAL, and all TLVs in NDTA_PARMS unless marked | ||
| 524 | * otherwise. Device specific parameter sets can be changed by | ||
| 525 | * setting NDTPA_IFINDEX to the interface index of the corresponding | ||
| 526 | * device. | ||
| 527 | ****/ | ||
| 528 | |||
| 529 | struct ndt_stats | ||
| 530 | { | ||
| 531 | __u64 ndts_allocs; | ||
| 532 | __u64 ndts_destroys; | ||
| 533 | __u64 ndts_hash_grows; | ||
| 534 | __u64 ndts_res_failed; | ||
| 535 | __u64 ndts_lookups; | ||
| 536 | __u64 ndts_hits; | ||
| 537 | __u64 ndts_rcv_probes_mcast; | ||
| 538 | __u64 ndts_rcv_probes_ucast; | ||
| 539 | __u64 ndts_periodic_gc_runs; | ||
| 540 | __u64 ndts_forced_gc_runs; | ||
| 541 | }; | ||
| 542 | |||
| 543 | enum { | ||
| 544 | NDTPA_UNSPEC, | ||
| 545 | NDTPA_IFINDEX, /* u32, unchangeable */ | ||
| 546 | NDTPA_REFCNT, /* u32, read-only */ | ||
| 547 | NDTPA_REACHABLE_TIME, /* u64, read-only, msecs */ | ||
| 548 | NDTPA_BASE_REACHABLE_TIME, /* u64, msecs */ | ||
| 549 | NDTPA_RETRANS_TIME, /* u64, msecs */ | ||
| 550 | NDTPA_GC_STALETIME, /* u64, msecs */ | ||
| 551 | NDTPA_DELAY_PROBE_TIME, /* u64, msecs */ | ||
| 552 | NDTPA_QUEUE_LEN, /* u32 */ | ||
| 553 | NDTPA_APP_PROBES, /* u32 */ | ||
| 554 | NDTPA_UCAST_PROBES, /* u32 */ | ||
| 555 | NDTPA_MCAST_PROBES, /* u32 */ | ||
| 556 | NDTPA_ANYCAST_DELAY, /* u64, msecs */ | ||
| 557 | NDTPA_PROXY_DELAY, /* u64, msecs */ | ||
| 558 | NDTPA_PROXY_QLEN, /* u32 */ | ||
| 559 | NDTPA_LOCKTIME, /* u64, msecs */ | ||
| 560 | __NDTPA_MAX | ||
| 561 | }; | ||
| 562 | #define NDTPA_MAX (__NDTPA_MAX - 1) | ||
| 563 | |||
| 564 | struct ndtmsg | ||
| 565 | { | ||
| 566 | __u8 ndtm_family; | ||
| 567 | __u8 ndtm_pad1; | ||
| 568 | __u16 ndtm_pad2; | ||
| 569 | }; | ||
| 570 | |||
| 571 | struct ndt_config | ||
| 572 | { | ||
| 573 | __u16 ndtc_key_len; | ||
| 574 | __u16 ndtc_entry_size; | ||
| 575 | __u32 ndtc_entries; | ||
| 576 | __u32 ndtc_last_flush; /* delta to now in msecs */ | ||
| 577 | __u32 ndtc_last_rand; /* delta to now in msecs */ | ||
| 578 | __u32 ndtc_hash_rnd; | ||
| 579 | __u32 ndtc_hash_mask; | ||
| 580 | __u32 ndtc_hash_chain_gc; | ||
| 581 | __u32 ndtc_proxy_qlen; | ||
| 582 | }; | ||
| 583 | |||
| 584 | enum { | ||
| 585 | NDTA_UNSPEC, | ||
| 586 | NDTA_NAME, /* char *, unchangeable */ | ||
| 587 | NDTA_THRESH1, /* u32 */ | ||
| 588 | NDTA_THRESH2, /* u32 */ | ||
| 589 | NDTA_THRESH3, /* u32 */ | ||
| 590 | NDTA_CONFIG, /* struct ndt_config, read-only */ | ||
| 591 | NDTA_PARMS, /* nested TLV NDTPA_* */ | ||
| 592 | NDTA_STATS, /* struct ndt_stats, read-only */ | ||
| 593 | NDTA_GC_INTERVAL, /* u64, msecs */ | ||
| 594 | __NDTA_MAX | ||
| 595 | }; | ||
| 596 | #define NDTA_MAX (__NDTA_MAX - 1) | ||
| 597 | |||
| 598 | #define NDTA_RTA(r) ((struct rtattr*)(((char*)(r)) + \ | ||
| 599 | NLMSG_ALIGN(sizeof(struct ndtmsg)))) | ||
| 600 | #define NDTA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndtmsg)) | ||
| 601 | |||
| 602 | |||
| 496 | /**** | 603 | /**** |
| 497 | * General form of address family dependent message. | 604 | * General form of address family dependent message. |
| 498 | ****/ | 605 | ****/ |
diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 4f33bbc21e7f..17191ac9be70 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h | |||
| @@ -65,6 +65,7 @@ struct neighbour; | |||
| 65 | 65 | ||
| 66 | struct neigh_parms | 66 | struct neigh_parms |
| 67 | { | 67 | { |
| 68 | struct net_device *dev; | ||
| 68 | struct neigh_parms *next; | 69 | struct neigh_parms *next; |
| 69 | int (*neigh_setup)(struct neighbour *); | 70 | int (*neigh_setup)(struct neighbour *); |
| 70 | struct neigh_table *tbl; | 71 | struct neigh_table *tbl; |
| @@ -252,6 +253,9 @@ extern int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg); | |||
| 252 | extern int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg); | 253 | extern int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg); |
| 253 | extern void neigh_app_ns(struct neighbour *n); | 254 | extern void neigh_app_ns(struct neighbour *n); |
| 254 | 255 | ||
| 256 | extern int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb); | ||
| 257 | extern int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg); | ||
| 258 | |||
| 255 | extern void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie); | 259 | extern void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie); |
| 256 | extern void __neigh_for_each_release(struct neigh_table *tbl, int (*cb)(struct neighbour *)); | 260 | extern void __neigh_for_each_release(struct neigh_table *tbl, int (*cb)(struct neighbour *)); |
| 257 | extern void pneigh_for_each(struct neigh_table *tbl, void (*cb)(struct pneigh_entry *)); | 261 | extern void pneigh_for_each(struct neigh_table *tbl, void (*cb)(struct pneigh_entry *)); |
diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 43bdc521e20d..0841ac78c67d 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c | |||
| @@ -1276,9 +1276,14 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev, | |||
| 1276 | INIT_RCU_HEAD(&p->rcu_head); | 1276 | INIT_RCU_HEAD(&p->rcu_head); |
| 1277 | p->reachable_time = | 1277 | p->reachable_time = |
| 1278 | neigh_rand_reach_time(p->base_reachable_time); | 1278 | neigh_rand_reach_time(p->base_reachable_time); |
| 1279 | if (dev && dev->neigh_setup && dev->neigh_setup(dev, p)) { | 1279 | if (dev) { |
| 1280 | kfree(p); | 1280 | if (dev->neigh_setup && dev->neigh_setup(dev, p)) { |
| 1281 | return NULL; | 1281 | kfree(p); |
| 1282 | return NULL; | ||
| 1283 | } | ||
| 1284 | |||
| 1285 | dev_hold(dev); | ||
| 1286 | p->dev = dev; | ||
| 1282 | } | 1287 | } |
| 1283 | p->sysctl_table = NULL; | 1288 | p->sysctl_table = NULL; |
| 1284 | write_lock_bh(&tbl->lock); | 1289 | write_lock_bh(&tbl->lock); |
| @@ -1309,6 +1314,8 @@ void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms) | |||
| 1309 | *p = parms->next; | 1314 | *p = parms->next; |
| 1310 | parms->dead = 1; | 1315 | parms->dead = 1; |
| 1311 | write_unlock_bh(&tbl->lock); | 1316 | write_unlock_bh(&tbl->lock); |
| 1317 | if (parms->dev) | ||
| 1318 | dev_put(parms->dev); | ||
| 1312 | call_rcu(&parms->rcu_head, neigh_rcu_free_parms); | 1319 | call_rcu(&parms->rcu_head, neigh_rcu_free_parms); |
| 1313 | return; | 1320 | return; |
| 1314 | } | 1321 | } |
| @@ -1546,6 +1553,308 @@ out: | |||
| 1546 | return err; | 1553 | return err; |
| 1547 | } | 1554 | } |
| 1548 | 1555 | ||
| 1556 | static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms) | ||
| 1557 | { | ||
| 1558 | struct rtattr *nest = RTA_NEST(skb, NDTA_PARMS); | ||
| 1559 | |||
| 1560 | if (parms->dev) | ||
| 1561 | RTA_PUT_U32(skb, NDTPA_IFINDEX, parms->dev->ifindex); | ||
| 1562 | |||
| 1563 | RTA_PUT_U32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt)); | ||
| 1564 | RTA_PUT_U32(skb, NDTPA_QUEUE_LEN, parms->queue_len); | ||
| 1565 | RTA_PUT_U32(skb, NDTPA_PROXY_QLEN, parms->proxy_qlen); | ||
| 1566 | RTA_PUT_U32(skb, NDTPA_APP_PROBES, parms->app_probes); | ||
| 1567 | RTA_PUT_U32(skb, NDTPA_UCAST_PROBES, parms->ucast_probes); | ||
| 1568 | RTA_PUT_U32(skb, NDTPA_MCAST_PROBES, parms->mcast_probes); | ||
| 1569 | RTA_PUT_MSECS(skb, NDTPA_REACHABLE_TIME, parms->reachable_time); | ||
| 1570 | RTA_PUT_MSECS(skb, NDTPA_BASE_REACHABLE_TIME, | ||
| 1571 | parms->base_reachable_time); | ||
| 1572 | RTA_PUT_MSECS(skb, NDTPA_GC_STALETIME, parms->gc_staletime); | ||
| 1573 | RTA_PUT_MSECS(skb, NDTPA_DELAY_PROBE_TIME, parms->delay_probe_time); | ||
| 1574 | RTA_PUT_MSECS(skb, NDTPA_RETRANS_TIME, parms->retrans_time); | ||
| 1575 | RTA_PUT_MSECS(skb, NDTPA_ANYCAST_DELAY, parms->anycast_delay); | ||
| 1576 | RTA_PUT_MSECS(skb, NDTPA_PROXY_DELAY, parms->proxy_delay); | ||
| 1577 | RTA_PUT_MSECS(skb, NDTPA_LOCKTIME, parms->locktime); | ||
| 1578 | |||
| 1579 | return RTA_NEST_END(skb, nest); | ||
| 1580 | |||
| 1581 | rtattr_failure: | ||
| 1582 | return RTA_NEST_CANCEL(skb, nest); | ||
| 1583 | } | ||
| 1584 | |||
| 1585 | static int neightbl_fill_info(struct neigh_table *tbl, struct sk_buff *skb, | ||
| 1586 | struct netlink_callback *cb) | ||
| 1587 | { | ||
| 1588 | struct nlmsghdr *nlh; | ||
| 1589 | struct ndtmsg *ndtmsg; | ||
| 1590 | |||
| 1591 | nlh = NLMSG_PUT_ANSWER(skb, cb, RTM_NEWNEIGHTBL, sizeof(struct ndtmsg)); | ||
| 1592 | ndtmsg = NLMSG_DATA(nlh); | ||
| 1593 | |||
| 1594 | NLMSG_SET_MULTIPART(nlh); | ||
| 1595 | |||
| 1596 | read_lock_bh(&tbl->lock); | ||
| 1597 | ndtmsg->ndtm_family = tbl->family; | ||
| 1598 | |||
| 1599 | RTA_PUT_STRING(skb, NDTA_NAME, tbl->id); | ||
| 1600 | RTA_PUT_MSECS(skb, NDTA_GC_INTERVAL, tbl->gc_interval); | ||
| 1601 | RTA_PUT_U32(skb, NDTA_THRESH1, tbl->gc_thresh1); | ||
| 1602 | RTA_PUT_U32(skb, NDTA_THRESH2, tbl->gc_thresh2); | ||
| 1603 | RTA_PUT_U32(skb, NDTA_THRESH3, tbl->gc_thresh3); | ||
| 1604 | |||
| 1605 | { | ||
| 1606 | unsigned long now = jiffies; | ||
| 1607 | unsigned int flush_delta = now - tbl->last_flush; | ||
| 1608 | unsigned int rand_delta = now - tbl->last_rand; | ||
| 1609 | |||
| 1610 | struct ndt_config ndc = { | ||
| 1611 | .ndtc_key_len = tbl->key_len, | ||
| 1612 | .ndtc_entry_size = tbl->entry_size, | ||
| 1613 | .ndtc_entries = atomic_read(&tbl->entries), | ||
| 1614 | .ndtc_last_flush = jiffies_to_msecs(flush_delta), | ||
| 1615 | .ndtc_last_rand = jiffies_to_msecs(rand_delta), | ||
| 1616 | .ndtc_hash_rnd = tbl->hash_rnd, | ||
| 1617 | .ndtc_hash_mask = tbl->hash_mask, | ||
| 1618 | .ndtc_hash_chain_gc = tbl->hash_chain_gc, | ||
| 1619 | .ndtc_proxy_qlen = tbl->proxy_queue.qlen, | ||
| 1620 | }; | ||
| 1621 | |||
| 1622 | RTA_PUT(skb, NDTA_CONFIG, sizeof(ndc), &ndc); | ||
| 1623 | } | ||
| 1624 | |||
| 1625 | { | ||
| 1626 | int cpu; | ||
| 1627 | struct ndt_stats ndst; | ||
| 1628 | |||
| 1629 | memset(&ndst, 0, sizeof(ndst)); | ||
| 1630 | |||
| 1631 | for (cpu = 0; cpu < NR_CPUS; cpu++) { | ||
| 1632 | struct neigh_statistics *st; | ||
| 1633 | |||
| 1634 | if (!cpu_possible(cpu)) | ||
| 1635 | continue; | ||
| 1636 | |||
| 1637 | st = per_cpu_ptr(tbl->stats, cpu); | ||
| 1638 | ndst.ndts_allocs += st->allocs; | ||
| 1639 | ndst.ndts_destroys += st->destroys; | ||
| 1640 | ndst.ndts_hash_grows += st->hash_grows; | ||
| 1641 | ndst.ndts_res_failed += st->res_failed; | ||
| 1642 | ndst.ndts_lookups += st->lookups; | ||
| 1643 | ndst.ndts_hits += st->hits; | ||
| 1644 | ndst.ndts_rcv_probes_mcast += st->rcv_probes_mcast; | ||
| 1645 | ndst.ndts_rcv_probes_ucast += st->rcv_probes_ucast; | ||
| 1646 | ndst.ndts_periodic_gc_runs += st->periodic_gc_runs; | ||
| 1647 | ndst.ndts_forced_gc_runs += st->forced_gc_runs; | ||
| 1648 | } | ||
| 1649 | |||
| 1650 | RTA_PUT(skb, NDTA_STATS, sizeof(ndst), &ndst); | ||
| 1651 | } | ||
| 1652 | |||
| 1653 | BUG_ON(tbl->parms.dev); | ||
| 1654 | if (neightbl_fill_parms(skb, &tbl->parms) < 0) | ||
| 1655 | goto rtattr_failure; | ||
| 1656 | |||
| 1657 | read_unlock_bh(&tbl->lock); | ||
| 1658 | return NLMSG_END(skb, nlh); | ||
| 1659 | |||
| 1660 | rtattr_failure: | ||
| 1661 | read_unlock_bh(&tbl->lock); | ||
| 1662 | return NLMSG_CANCEL(skb, nlh); | ||
| 1663 | |||
| 1664 | nlmsg_failure: | ||
| 1665 | return -1; | ||
| 1666 | } | ||
| 1667 | |||
| 1668 | static int neightbl_fill_param_info(struct neigh_table *tbl, | ||
| 1669 | struct neigh_parms *parms, | ||
| 1670 | struct sk_buff *skb, | ||
| 1671 | struct netlink_callback *cb) | ||
| 1672 | { | ||
| 1673 | struct ndtmsg *ndtmsg; | ||
| 1674 | struct nlmsghdr *nlh; | ||
| 1675 | |||
| 1676 | nlh = NLMSG_PUT_ANSWER(skb, cb, RTM_NEWNEIGHTBL, sizeof(struct ndtmsg)); | ||
| 1677 | ndtmsg = NLMSG_DATA(nlh); | ||
| 1678 | |||
| 1679 | NLMSG_SET_MULTIPART(nlh); | ||
| 1680 | |||
| 1681 | read_lock_bh(&tbl->lock); | ||
| 1682 | ndtmsg->ndtm_family = tbl->family; | ||
| 1683 | RTA_PUT_STRING(skb, NDTA_NAME, tbl->id); | ||
| 1684 | |||
| 1685 | if (neightbl_fill_parms(skb, parms) < 0) | ||
| 1686 | goto rtattr_failure; | ||
| 1687 | |||
| 1688 | read_unlock_bh(&tbl->lock); | ||
| 1689 | return NLMSG_END(skb, nlh); | ||
| 1690 | |||
| 1691 | rtattr_failure: | ||
| 1692 | read_unlock_bh(&tbl->lock); | ||
| 1693 | return NLMSG_CANCEL(skb, nlh); | ||
| 1694 | |||
| 1695 | nlmsg_failure: | ||
| 1696 | return -1; | ||
| 1697 | } | ||
| 1698 | |||
| 1699 | static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl, | ||
| 1700 | int ifindex) | ||
| 1701 | { | ||
| 1702 | struct neigh_parms *p; | ||
| 1703 | |||
| 1704 | for (p = &tbl->parms; p; p = p->next) | ||
| 1705 | if ((p->dev && p->dev->ifindex == ifindex) || | ||
| 1706 | (!p->dev && !ifindex)) | ||
| 1707 | return p; | ||
| 1708 | |||
| 1709 | return NULL; | ||
| 1710 | } | ||
| 1711 | |||
| 1712 | int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | ||
| 1713 | { | ||
| 1714 | struct neigh_table *tbl; | ||
| 1715 | struct ndtmsg *ndtmsg = NLMSG_DATA(nlh); | ||
| 1716 | struct rtattr **tb = arg; | ||
| 1717 | int err = -EINVAL; | ||
| 1718 | |||
| 1719 | if (!tb[NDTA_NAME - 1] || !RTA_PAYLOAD(tb[NDTA_NAME - 1])) | ||
| 1720 | return -EINVAL; | ||
| 1721 | |||
| 1722 | read_lock(&neigh_tbl_lock); | ||
| 1723 | for (tbl = neigh_tables; tbl; tbl = tbl->next) { | ||
| 1724 | if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family) | ||
| 1725 | continue; | ||
| 1726 | |||
| 1727 | if (!rtattr_strcmp(tb[NDTA_NAME - 1], tbl->id)) | ||
| 1728 | break; | ||
| 1729 | } | ||
| 1730 | |||
| 1731 | if (tbl == NULL) { | ||
| 1732 | err = -ENOENT; | ||
| 1733 | goto errout; | ||
| 1734 | } | ||
| 1735 | |||
| 1736 | /* | ||
| 1737 | * We acquire tbl->lock to be nice to the periodic timers and | ||
| 1738 | * make sure they always see a consistent set of values. | ||
| 1739 | */ | ||
| 1740 | write_lock_bh(&tbl->lock); | ||
| 1741 | |||
| 1742 | if (tb[NDTA_THRESH1 - 1]) | ||
| 1743 | tbl->gc_thresh1 = RTA_GET_U32(tb[NDTA_THRESH1 - 1]); | ||
| 1744 | |||
| 1745 | if (tb[NDTA_THRESH2 - 1]) | ||
| 1746 | tbl->gc_thresh2 = RTA_GET_U32(tb[NDTA_THRESH2 - 1]); | ||
| 1747 | |||
| 1748 | if (tb[NDTA_THRESH3 - 1]) | ||
| 1749 | tbl->gc_thresh3 = RTA_GET_U32(tb[NDTA_THRESH3 - 1]); | ||
| 1750 | |||
| 1751 | if (tb[NDTA_GC_INTERVAL - 1]) | ||
| 1752 | tbl->gc_interval = RTA_GET_MSECS(tb[NDTA_GC_INTERVAL - 1]); | ||
| 1753 | |||
| 1754 | if (tb[NDTA_PARMS - 1]) { | ||
| 1755 | struct rtattr *tbp[NDTPA_MAX]; | ||
| 1756 | struct neigh_parms *p; | ||
| 1757 | u32 ifindex = 0; | ||
| 1758 | |||
| 1759 | if (rtattr_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS - 1]) < 0) | ||
| 1760 | goto rtattr_failure; | ||
| 1761 | |||
| 1762 | if (tbp[NDTPA_IFINDEX - 1]) | ||
| 1763 | ifindex = RTA_GET_U32(tbp[NDTPA_IFINDEX - 1]); | ||
| 1764 | |||
| 1765 | p = lookup_neigh_params(tbl, ifindex); | ||
| 1766 | if (p == NULL) { | ||
| 1767 | err = -ENOENT; | ||
| 1768 | goto rtattr_failure; | ||
| 1769 | } | ||
| 1770 | |||
| 1771 | if (tbp[NDTPA_QUEUE_LEN - 1]) | ||
| 1772 | p->queue_len = RTA_GET_U32(tbp[NDTPA_QUEUE_LEN - 1]); | ||
| 1773 | |||
| 1774 | if (tbp[NDTPA_PROXY_QLEN - 1]) | ||
| 1775 | p->proxy_qlen = RTA_GET_U32(tbp[NDTPA_PROXY_QLEN - 1]); | ||
| 1776 | |||
| 1777 | if (tbp[NDTPA_APP_PROBES - 1]) | ||
| 1778 | p->app_probes = RTA_GET_U32(tbp[NDTPA_APP_PROBES - 1]); | ||
| 1779 | |||
| 1780 | if (tbp[NDTPA_UCAST_PROBES - 1]) | ||
| 1781 | p->ucast_probes = | ||
| 1782 | RTA_GET_U32(tbp[NDTPA_UCAST_PROBES - 1]); | ||
| 1783 | |||
| 1784 | if (tbp[NDTPA_MCAST_PROBES - 1]) | ||
| 1785 | p->mcast_probes = | ||
| 1786 | RTA_GET_U32(tbp[NDTPA_MCAST_PROBES - 1]); | ||
| 1787 | |||
| 1788 | if (tbp[NDTPA_BASE_REACHABLE_TIME - 1]) | ||
| 1789 | p->base_reachable_time = | ||
| 1790 | RTA_GET_MSECS(tbp[NDTPA_BASE_REACHABLE_TIME - 1]); | ||
| 1791 | |||
| 1792 | if (tbp[NDTPA_GC_STALETIME - 1]) | ||
| 1793 | p->gc_staletime = | ||
| 1794 | RTA_GET_MSECS(tbp[NDTPA_GC_STALETIME - 1]); | ||
| 1795 | |||
| 1796 | if (tbp[NDTPA_DELAY_PROBE_TIME - 1]) | ||
| 1797 | p->delay_probe_time = | ||
| 1798 | RTA_GET_MSECS(tbp[NDTPA_DELAY_PROBE_TIME - 1]); | ||
| 1799 | |||
| 1800 | if (tbp[NDTPA_RETRANS_TIME - 1]) | ||
| 1801 | p->retrans_time = | ||
| 1802 | RTA_GET_MSECS(tbp[NDTPA_RETRANS_TIME - 1]); | ||
| 1803 | |||
| 1804 | if (tbp[NDTPA_ANYCAST_DELAY - 1]) | ||
| 1805 | p->anycast_delay = | ||
| 1806 | RTA_GET_MSECS(tbp[NDTPA_ANYCAST_DELAY - 1]); | ||
| 1807 | |||
| 1808 | if (tbp[NDTPA_PROXY_DELAY - 1]) | ||
| 1809 | p->proxy_delay = | ||
| 1810 | RTA_GET_MSECS(tbp[NDTPA_PROXY_DELAY - 1]); | ||
| 1811 | |||
| 1812 | if (tbp[NDTPA_LOCKTIME - 1]) | ||
| 1813 | p->locktime = RTA_GET_MSECS(tbp[NDTPA_LOCKTIME - 1]); | ||
| 1814 | } | ||
| 1815 | |||
| 1816 | err = 0; | ||
| 1817 | |||
| 1818 | rtattr_failure: | ||
| 1819 | write_unlock_bh(&tbl->lock); | ||
| 1820 | errout: | ||
| 1821 | read_unlock(&neigh_tbl_lock); | ||
| 1822 | return err; | ||
| 1823 | } | ||
| 1824 | |||
| 1825 | int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb) | ||
| 1826 | { | ||
| 1827 | int idx, family; | ||
| 1828 | int s_idx = cb->args[0]; | ||
| 1829 | struct neigh_table *tbl; | ||
| 1830 | |||
| 1831 | family = ((struct rtgenmsg *)NLMSG_DATA(cb->nlh))->rtgen_family; | ||
| 1832 | |||
| 1833 | read_lock(&neigh_tbl_lock); | ||
| 1834 | for (tbl = neigh_tables, idx = 0; tbl; tbl = tbl->next) { | ||
| 1835 | struct neigh_parms *p; | ||
| 1836 | |||
| 1837 | if (idx < s_idx || (family && tbl->family != family)) | ||
| 1838 | continue; | ||
| 1839 | |||
| 1840 | if (neightbl_fill_info(tbl, skb, cb) <= 0) | ||
| 1841 | break; | ||
| 1842 | |||
| 1843 | for (++idx, p = tbl->parms.next; p; p = p->next, idx++) { | ||
| 1844 | if (idx < s_idx) | ||
| 1845 | continue; | ||
| 1846 | |||
| 1847 | if (neightbl_fill_param_info(tbl, p, skb, cb) <= 0) | ||
| 1848 | goto out; | ||
| 1849 | } | ||
| 1850 | |||
| 1851 | } | ||
| 1852 | out: | ||
| 1853 | read_unlock(&neigh_tbl_lock); | ||
| 1854 | cb->args[0] = idx; | ||
| 1855 | |||
| 1856 | return skb->len; | ||
| 1857 | } | ||
| 1549 | 1858 | ||
| 1550 | static int neigh_fill_info(struct sk_buff *skb, struct neighbour *n, | 1859 | static int neigh_fill_info(struct sk_buff *skb, struct neighbour *n, |
| 1551 | u32 pid, u32 seq, int event) | 1860 | u32 pid, u32 seq, int event) |
| @@ -2352,6 +2661,8 @@ EXPORT_SYMBOL(neigh_update); | |||
| 2352 | EXPORT_SYMBOL(neigh_update_hhs); | 2661 | EXPORT_SYMBOL(neigh_update_hhs); |
| 2353 | EXPORT_SYMBOL(pneigh_enqueue); | 2662 | EXPORT_SYMBOL(pneigh_enqueue); |
| 2354 | EXPORT_SYMBOL(pneigh_lookup); | 2663 | EXPORT_SYMBOL(pneigh_lookup); |
| 2664 | EXPORT_SYMBOL(neightbl_dump_info); | ||
| 2665 | EXPORT_SYMBOL(neightbl_set); | ||
| 2355 | 2666 | ||
| 2356 | #ifdef CONFIG_ARPD | 2667 | #ifdef CONFIG_ARPD |
| 2357 | EXPORT_SYMBOL(neigh_app_ns); | 2668 | EXPORT_SYMBOL(neigh_app_ns); |
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 00caf4b318b2..56a20f014b8a 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
| @@ -100,6 +100,7 @@ static const int rtm_min[RTM_NR_FAMILIES] = | |||
| 100 | [RTM_FAM(RTM_NEWPREFIX)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), | 100 | [RTM_FAM(RTM_NEWPREFIX)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), |
| 101 | [RTM_FAM(RTM_GETMULTICAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), | 101 | [RTM_FAM(RTM_GETMULTICAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), |
| 102 | [RTM_FAM(RTM_GETANYCAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), | 102 | [RTM_FAM(RTM_GETANYCAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), |
| 103 | [RTM_FAM(RTM_NEWNEIGHTBL)] = NLMSG_LENGTH(sizeof(struct ndtmsg)), | ||
| 103 | }; | 104 | }; |
| 104 | 105 | ||
| 105 | static const int rta_max[RTM_NR_FAMILIES] = | 106 | static const int rta_max[RTM_NR_FAMILIES] = |
| @@ -113,6 +114,7 @@ static const int rta_max[RTM_NR_FAMILIES] = | |||
| 113 | [RTM_FAM(RTM_NEWTCLASS)] = TCA_MAX, | 114 | [RTM_FAM(RTM_NEWTCLASS)] = TCA_MAX, |
| 114 | [RTM_FAM(RTM_NEWTFILTER)] = TCA_MAX, | 115 | [RTM_FAM(RTM_NEWTFILTER)] = TCA_MAX, |
| 115 | [RTM_FAM(RTM_NEWACTION)] = TCAA_MAX, | 116 | [RTM_FAM(RTM_NEWACTION)] = TCAA_MAX, |
| 117 | [RTM_FAM(RTM_NEWNEIGHTBL)] = NDTA_MAX, | ||
| 116 | }; | 118 | }; |
| 117 | 119 | ||
| 118 | void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data) | 120 | void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data) |
| @@ -649,14 +651,16 @@ static void rtnetlink_rcv(struct sock *sk, int len) | |||
| 649 | 651 | ||
| 650 | static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] = | 652 | static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] = |
| 651 | { | 653 | { |
| 652 | [RTM_GETLINK - RTM_BASE] = { .dumpit = rtnetlink_dump_ifinfo }, | 654 | [RTM_GETLINK - RTM_BASE] = { .dumpit = rtnetlink_dump_ifinfo }, |
| 653 | [RTM_SETLINK - RTM_BASE] = { .doit = do_setlink }, | 655 | [RTM_SETLINK - RTM_BASE] = { .doit = do_setlink }, |
| 654 | [RTM_GETADDR - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, | 656 | [RTM_GETADDR - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, |
| 655 | [RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, | 657 | [RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, |
| 656 | [RTM_NEWNEIGH - RTM_BASE] = { .doit = neigh_add }, | 658 | [RTM_NEWNEIGH - RTM_BASE] = { .doit = neigh_add }, |
| 657 | [RTM_DELNEIGH - RTM_BASE] = { .doit = neigh_delete }, | 659 | [RTM_DELNEIGH - RTM_BASE] = { .doit = neigh_delete }, |
| 658 | [RTM_GETNEIGH - RTM_BASE] = { .dumpit = neigh_dump_info }, | 660 | [RTM_GETNEIGH - RTM_BASE] = { .dumpit = neigh_dump_info }, |
| 659 | [RTM_GETRULE - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, | 661 | [RTM_GETRULE - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, |
| 662 | [RTM_GETNEIGHTBL - RTM_BASE] = { .dumpit = neightbl_dump_info }, | ||
| 663 | [RTM_SETNEIGHTBL - RTM_BASE] = { .doit = neightbl_set }, | ||
| 660 | }; | 664 | }; |
| 661 | 665 | ||
| 662 | static int rtnetlink_event(struct notifier_block *this, unsigned long event, void *ptr) | 666 | static int rtnetlink_event(struct notifier_block *this, unsigned long event, void *ptr) |
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index f0fb6d76f7c5..92b057becb4b 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c | |||
| @@ -63,6 +63,8 @@ static struct nlmsg_perm nlmsg_route_perms[] = | |||
| 63 | { RTM_GETPREFIX, NETLINK_ROUTE_SOCKET__NLMSG_READ }, | 63 | { RTM_GETPREFIX, NETLINK_ROUTE_SOCKET__NLMSG_READ }, |
| 64 | { RTM_GETMULTICAST, NETLINK_ROUTE_SOCKET__NLMSG_READ }, | 64 | { RTM_GETMULTICAST, NETLINK_ROUTE_SOCKET__NLMSG_READ }, |
| 65 | { RTM_GETANYCAST, NETLINK_ROUTE_SOCKET__NLMSG_READ }, | 65 | { RTM_GETANYCAST, NETLINK_ROUTE_SOCKET__NLMSG_READ }, |
| 66 | { RTM_GETNEIGHTBL, NETLINK_ROUTE_SOCKET__NLMSG_READ }, | ||
| 67 | { RTM_SETNEIGHTBL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, | ||
| 66 | }; | 68 | }; |
| 67 | 69 | ||
| 68 | static struct nlmsg_perm nlmsg_firewall_perms[] = | 70 | static struct nlmsg_perm nlmsg_firewall_perms[] = |
