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[] = |