diff options
author | WANG Cong <xiyou.wangcong@gmail.com> | 2014-11-10 18:59:36 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-11-11 15:23:54 -0500 |
commit | d7480fd3b1738a8eae6a76098b17af318cf9b9cc (patch) | |
tree | 559ba1e8e583fec97c223f31b3657023e71febfb /net/core/neighbour.c | |
parent | b2e2f0c779fefede3a871781c8827bd8e76c7c0f (diff) |
neigh: remove dynamic neigh table registration support
Currently there are only three neigh tables in the whole kernel:
arp table, ndisc table and decnet neigh table. What's more,
we don't support registering multiple tables per family.
Therefore we can just make these tables statically built-in.
Cc: David S. Miller <davem@davemloft.net>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/neighbour.c')
-rw-r--r-- | net/core/neighbour.c | 247 |
1 files changed, 112 insertions, 135 deletions
diff --git a/net/core/neighbour.c b/net/core/neighbour.c index edd04116ecb7..8e38f17288d3 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c | |||
@@ -56,7 +56,6 @@ static void __neigh_notify(struct neighbour *n, int type, int flags); | |||
56 | static void neigh_update_notify(struct neighbour *neigh); | 56 | static void neigh_update_notify(struct neighbour *neigh); |
57 | static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev); | 57 | static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev); |
58 | 58 | ||
59 | static struct neigh_table *neigh_tables; | ||
60 | #ifdef CONFIG_PROC_FS | 59 | #ifdef CONFIG_PROC_FS |
61 | static const struct file_operations neigh_stat_seq_fops; | 60 | static const struct file_operations neigh_stat_seq_fops; |
62 | #endif | 61 | #endif |
@@ -87,13 +86,8 @@ static const struct file_operations neigh_stat_seq_fops; | |||
87 | the most complicated procedure, which we allow is dev->hard_header. | 86 | the most complicated procedure, which we allow is dev->hard_header. |
88 | It is supposed, that dev->hard_header is simplistic and does | 87 | It is supposed, that dev->hard_header is simplistic and does |
89 | not make callbacks to neighbour tables. | 88 | not make callbacks to neighbour tables. |
90 | |||
91 | The last lock is neigh_tbl_lock. It is pure SMP lock, protecting | ||
92 | list of neighbour tables. This list is used only in process context, | ||
93 | */ | 89 | */ |
94 | 90 | ||
95 | static DEFINE_RWLOCK(neigh_tbl_lock); | ||
96 | |||
97 | static int neigh_blackhole(struct neighbour *neigh, struct sk_buff *skb) | 91 | static int neigh_blackhole(struct neighbour *neigh, struct sk_buff *skb) |
98 | { | 92 | { |
99 | kfree_skb(skb); | 93 | kfree_skb(skb); |
@@ -1520,7 +1514,9 @@ static void neigh_parms_destroy(struct neigh_parms *parms) | |||
1520 | 1514 | ||
1521 | static struct lock_class_key neigh_table_proxy_queue_class; | 1515 | static struct lock_class_key neigh_table_proxy_queue_class; |
1522 | 1516 | ||
1523 | static void neigh_table_init_no_netlink(struct neigh_table *tbl) | 1517 | static struct neigh_table *neigh_tables[NEIGH_NR_TABLES] __read_mostly; |
1518 | |||
1519 | void neigh_table_init(int index, struct neigh_table *tbl) | ||
1524 | { | 1520 | { |
1525 | unsigned long now = jiffies; | 1521 | unsigned long now = jiffies; |
1526 | unsigned long phsize; | 1522 | unsigned long phsize; |
@@ -1566,34 +1562,14 @@ static void neigh_table_init_no_netlink(struct neigh_table *tbl) | |||
1566 | 1562 | ||
1567 | tbl->last_flush = now; | 1563 | tbl->last_flush = now; |
1568 | tbl->last_rand = now + tbl->parms.reachable_time * 20; | 1564 | tbl->last_rand = now + tbl->parms.reachable_time * 20; |
1569 | } | ||
1570 | |||
1571 | void neigh_table_init(struct neigh_table *tbl) | ||
1572 | { | ||
1573 | struct neigh_table *tmp; | ||
1574 | 1565 | ||
1575 | neigh_table_init_no_netlink(tbl); | 1566 | neigh_tables[index] = tbl; |
1576 | write_lock(&neigh_tbl_lock); | ||
1577 | for (tmp = neigh_tables; tmp; tmp = tmp->next) { | ||
1578 | if (tmp->family == tbl->family) | ||
1579 | break; | ||
1580 | } | ||
1581 | tbl->next = neigh_tables; | ||
1582 | neigh_tables = tbl; | ||
1583 | write_unlock(&neigh_tbl_lock); | ||
1584 | |||
1585 | if (unlikely(tmp)) { | ||
1586 | pr_err("Registering multiple tables for family %d\n", | ||
1587 | tbl->family); | ||
1588 | dump_stack(); | ||
1589 | } | ||
1590 | } | 1567 | } |
1591 | EXPORT_SYMBOL(neigh_table_init); | 1568 | EXPORT_SYMBOL(neigh_table_init); |
1592 | 1569 | ||
1593 | int neigh_table_clear(struct neigh_table *tbl) | 1570 | int neigh_table_clear(int index, struct neigh_table *tbl) |
1594 | { | 1571 | { |
1595 | struct neigh_table **tp; | 1572 | neigh_tables[index] = NULL; |
1596 | |||
1597 | /* It is not clean... Fix it to unload IPv6 module safely */ | 1573 | /* It is not clean... Fix it to unload IPv6 module safely */ |
1598 | cancel_delayed_work_sync(&tbl->gc_work); | 1574 | cancel_delayed_work_sync(&tbl->gc_work); |
1599 | del_timer_sync(&tbl->proxy_timer); | 1575 | del_timer_sync(&tbl->proxy_timer); |
@@ -1601,14 +1577,6 @@ int neigh_table_clear(struct neigh_table *tbl) | |||
1601 | neigh_ifdown(tbl, NULL); | 1577 | neigh_ifdown(tbl, NULL); |
1602 | if (atomic_read(&tbl->entries)) | 1578 | if (atomic_read(&tbl->entries)) |
1603 | pr_crit("neighbour leakage\n"); | 1579 | pr_crit("neighbour leakage\n"); |
1604 | write_lock(&neigh_tbl_lock); | ||
1605 | for (tp = &neigh_tables; *tp; tp = &(*tp)->next) { | ||
1606 | if (*tp == tbl) { | ||
1607 | *tp = tbl->next; | ||
1608 | break; | ||
1609 | } | ||
1610 | } | ||
1611 | write_unlock(&neigh_tbl_lock); | ||
1612 | 1580 | ||
1613 | call_rcu(&rcu_dereference_protected(tbl->nht, 1)->rcu, | 1581 | call_rcu(&rcu_dereference_protected(tbl->nht, 1)->rcu, |
1614 | neigh_hash_free_rcu); | 1582 | neigh_hash_free_rcu); |
@@ -1626,12 +1594,32 @@ int neigh_table_clear(struct neigh_table *tbl) | |||
1626 | } | 1594 | } |
1627 | EXPORT_SYMBOL(neigh_table_clear); | 1595 | EXPORT_SYMBOL(neigh_table_clear); |
1628 | 1596 | ||
1597 | static struct neigh_table *neigh_find_table(int family) | ||
1598 | { | ||
1599 | struct neigh_table *tbl = NULL; | ||
1600 | |||
1601 | switch (family) { | ||
1602 | case AF_INET: | ||
1603 | tbl = neigh_tables[NEIGH_ARP_TABLE]; | ||
1604 | break; | ||
1605 | case AF_INET6: | ||
1606 | tbl = neigh_tables[NEIGH_ND_TABLE]; | ||
1607 | break; | ||
1608 | case AF_DECnet: | ||
1609 | tbl = neigh_tables[NEIGH_DN_TABLE]; | ||
1610 | break; | ||
1611 | } | ||
1612 | |||
1613 | return tbl; | ||
1614 | } | ||
1615 | |||
1629 | static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh) | 1616 | static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh) |
1630 | { | 1617 | { |
1631 | struct net *net = sock_net(skb->sk); | 1618 | struct net *net = sock_net(skb->sk); |
1632 | struct ndmsg *ndm; | 1619 | struct ndmsg *ndm; |
1633 | struct nlattr *dst_attr; | 1620 | struct nlattr *dst_attr; |
1634 | struct neigh_table *tbl; | 1621 | struct neigh_table *tbl; |
1622 | struct neighbour *neigh; | ||
1635 | struct net_device *dev = NULL; | 1623 | struct net_device *dev = NULL; |
1636 | int err = -EINVAL; | 1624 | int err = -EINVAL; |
1637 | 1625 | ||
@@ -1652,39 +1640,31 @@ static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1652 | } | 1640 | } |
1653 | } | 1641 | } |
1654 | 1642 | ||
1655 | read_lock(&neigh_tbl_lock); | 1643 | tbl = neigh_find_table(ndm->ndm_family); |
1656 | for (tbl = neigh_tables; tbl; tbl = tbl->next) { | 1644 | if (tbl == NULL) |
1657 | struct neighbour *neigh; | 1645 | return -EAFNOSUPPORT; |
1658 | |||
1659 | if (tbl->family != ndm->ndm_family) | ||
1660 | continue; | ||
1661 | read_unlock(&neigh_tbl_lock); | ||
1662 | |||
1663 | if (nla_len(dst_attr) < tbl->key_len) | ||
1664 | goto out; | ||
1665 | 1646 | ||
1666 | if (ndm->ndm_flags & NTF_PROXY) { | 1647 | if (nla_len(dst_attr) < tbl->key_len) |
1667 | err = pneigh_delete(tbl, net, nla_data(dst_attr), dev); | 1648 | goto out; |
1668 | goto out; | ||
1669 | } | ||
1670 | 1649 | ||
1671 | if (dev == NULL) | 1650 | if (ndm->ndm_flags & NTF_PROXY) { |
1672 | goto out; | 1651 | err = pneigh_delete(tbl, net, nla_data(dst_attr), dev); |
1652 | goto out; | ||
1653 | } | ||
1673 | 1654 | ||
1674 | neigh = neigh_lookup(tbl, nla_data(dst_attr), dev); | 1655 | if (dev == NULL) |
1675 | if (neigh == NULL) { | 1656 | goto out; |
1676 | err = -ENOENT; | ||
1677 | goto out; | ||
1678 | } | ||
1679 | 1657 | ||
1680 | err = neigh_update(neigh, NULL, NUD_FAILED, | 1658 | neigh = neigh_lookup(tbl, nla_data(dst_attr), dev); |
1681 | NEIGH_UPDATE_F_OVERRIDE | | 1659 | if (neigh == NULL) { |
1682 | NEIGH_UPDATE_F_ADMIN); | 1660 | err = -ENOENT; |
1683 | neigh_release(neigh); | ||
1684 | goto out; | 1661 | goto out; |
1685 | } | 1662 | } |
1686 | read_unlock(&neigh_tbl_lock); | 1663 | |
1687 | err = -EAFNOSUPPORT; | 1664 | err = neigh_update(neigh, NULL, NUD_FAILED, |
1665 | NEIGH_UPDATE_F_OVERRIDE | | ||
1666 | NEIGH_UPDATE_F_ADMIN); | ||
1667 | neigh_release(neigh); | ||
1688 | 1668 | ||
1689 | out: | 1669 | out: |
1690 | return err; | 1670 | return err; |
@@ -1692,11 +1672,14 @@ out: | |||
1692 | 1672 | ||
1693 | static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh) | 1673 | static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh) |
1694 | { | 1674 | { |
1675 | int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE; | ||
1695 | struct net *net = sock_net(skb->sk); | 1676 | struct net *net = sock_net(skb->sk); |
1696 | struct ndmsg *ndm; | 1677 | struct ndmsg *ndm; |
1697 | struct nlattr *tb[NDA_MAX+1]; | 1678 | struct nlattr *tb[NDA_MAX+1]; |
1698 | struct neigh_table *tbl; | 1679 | struct neigh_table *tbl; |
1699 | struct net_device *dev = NULL; | 1680 | struct net_device *dev = NULL; |
1681 | struct neighbour *neigh; | ||
1682 | void *dst, *lladdr; | ||
1700 | int err; | 1683 | int err; |
1701 | 1684 | ||
1702 | ASSERT_RTNL(); | 1685 | ASSERT_RTNL(); |
@@ -1720,70 +1703,60 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1720 | goto out; | 1703 | goto out; |
1721 | } | 1704 | } |
1722 | 1705 | ||
1723 | read_lock(&neigh_tbl_lock); | 1706 | tbl = neigh_find_table(ndm->ndm_family); |
1724 | for (tbl = neigh_tables; tbl; tbl = tbl->next) { | 1707 | if (tbl == NULL) |
1725 | int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE; | 1708 | return -EAFNOSUPPORT; |
1726 | struct neighbour *neigh; | ||
1727 | void *dst, *lladdr; | ||
1728 | 1709 | ||
1729 | if (tbl->family != ndm->ndm_family) | 1710 | if (nla_len(tb[NDA_DST]) < tbl->key_len) |
1730 | continue; | 1711 | goto out; |
1731 | read_unlock(&neigh_tbl_lock); | 1712 | dst = nla_data(tb[NDA_DST]); |
1713 | lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL; | ||
1732 | 1714 | ||
1733 | if (nla_len(tb[NDA_DST]) < tbl->key_len) | 1715 | if (ndm->ndm_flags & NTF_PROXY) { |
1734 | goto out; | 1716 | struct pneigh_entry *pn; |
1735 | dst = nla_data(tb[NDA_DST]); | 1717 | |
1736 | lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL; | 1718 | err = -ENOBUFS; |
1719 | pn = pneigh_lookup(tbl, net, dst, dev, 1); | ||
1720 | if (pn) { | ||
1721 | pn->flags = ndm->ndm_flags; | ||
1722 | err = 0; | ||
1723 | } | ||
1724 | goto out; | ||
1725 | } | ||
1737 | 1726 | ||
1738 | if (ndm->ndm_flags & NTF_PROXY) { | 1727 | if (dev == NULL) |
1739 | struct pneigh_entry *pn; | 1728 | goto out; |
1740 | 1729 | ||
1741 | err = -ENOBUFS; | 1730 | neigh = neigh_lookup(tbl, dst, dev); |
1742 | pn = pneigh_lookup(tbl, net, dst, dev, 1); | 1731 | if (neigh == NULL) { |
1743 | if (pn) { | 1732 | if (!(nlh->nlmsg_flags & NLM_F_CREATE)) { |
1744 | pn->flags = ndm->ndm_flags; | 1733 | err = -ENOENT; |
1745 | err = 0; | ||
1746 | } | ||
1747 | goto out; | 1734 | goto out; |
1748 | } | 1735 | } |
1749 | 1736 | ||
1750 | if (dev == NULL) | 1737 | neigh = __neigh_lookup_errno(tbl, dst, dev); |
1738 | if (IS_ERR(neigh)) { | ||
1739 | err = PTR_ERR(neigh); | ||
1740 | goto out; | ||
1741 | } | ||
1742 | } else { | ||
1743 | if (nlh->nlmsg_flags & NLM_F_EXCL) { | ||
1744 | err = -EEXIST; | ||
1745 | neigh_release(neigh); | ||
1751 | goto out; | 1746 | goto out; |
1752 | |||
1753 | neigh = neigh_lookup(tbl, dst, dev); | ||
1754 | if (neigh == NULL) { | ||
1755 | if (!(nlh->nlmsg_flags & NLM_F_CREATE)) { | ||
1756 | err = -ENOENT; | ||
1757 | goto out; | ||
1758 | } | ||
1759 | |||
1760 | neigh = __neigh_lookup_errno(tbl, dst, dev); | ||
1761 | if (IS_ERR(neigh)) { | ||
1762 | err = PTR_ERR(neigh); | ||
1763 | goto out; | ||
1764 | } | ||
1765 | } else { | ||
1766 | if (nlh->nlmsg_flags & NLM_F_EXCL) { | ||
1767 | err = -EEXIST; | ||
1768 | neigh_release(neigh); | ||
1769 | goto out; | ||
1770 | } | ||
1771 | |||
1772 | if (!(nlh->nlmsg_flags & NLM_F_REPLACE)) | ||
1773 | flags &= ~NEIGH_UPDATE_F_OVERRIDE; | ||
1774 | } | 1747 | } |
1775 | 1748 | ||
1776 | if (ndm->ndm_flags & NTF_USE) { | 1749 | if (!(nlh->nlmsg_flags & NLM_F_REPLACE)) |
1777 | neigh_event_send(neigh, NULL); | 1750 | flags &= ~NEIGH_UPDATE_F_OVERRIDE; |
1778 | err = 0; | ||
1779 | } else | ||
1780 | err = neigh_update(neigh, lladdr, ndm->ndm_state, flags); | ||
1781 | neigh_release(neigh); | ||
1782 | goto out; | ||
1783 | } | 1751 | } |
1784 | 1752 | ||
1785 | read_unlock(&neigh_tbl_lock); | 1753 | if (ndm->ndm_flags & NTF_USE) { |
1786 | err = -EAFNOSUPPORT; | 1754 | neigh_event_send(neigh, NULL); |
1755 | err = 0; | ||
1756 | } else | ||
1757 | err = neigh_update(neigh, lladdr, ndm->ndm_state, flags); | ||
1758 | neigh_release(neigh); | ||
1759 | |||
1787 | out: | 1760 | out: |
1788 | return err; | 1761 | return err; |
1789 | } | 1762 | } |
@@ -1982,7 +1955,8 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1982 | struct neigh_table *tbl; | 1955 | struct neigh_table *tbl; |
1983 | struct ndtmsg *ndtmsg; | 1956 | struct ndtmsg *ndtmsg; |
1984 | struct nlattr *tb[NDTA_MAX+1]; | 1957 | struct nlattr *tb[NDTA_MAX+1]; |
1985 | int err; | 1958 | bool found = false; |
1959 | int err, tidx; | ||
1986 | 1960 | ||
1987 | err = nlmsg_parse(nlh, sizeof(*ndtmsg), tb, NDTA_MAX, | 1961 | err = nlmsg_parse(nlh, sizeof(*ndtmsg), tb, NDTA_MAX, |
1988 | nl_neightbl_policy); | 1962 | nl_neightbl_policy); |
@@ -1995,19 +1969,21 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1995 | } | 1969 | } |
1996 | 1970 | ||
1997 | ndtmsg = nlmsg_data(nlh); | 1971 | ndtmsg = nlmsg_data(nlh); |
1998 | read_lock(&neigh_tbl_lock); | 1972 | |
1999 | for (tbl = neigh_tables; tbl; tbl = tbl->next) { | 1973 | for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) { |
1974 | tbl = neigh_tables[tidx]; | ||
1975 | if (!tbl) | ||
1976 | continue; | ||
2000 | if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family) | 1977 | if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family) |
2001 | continue; | 1978 | continue; |
2002 | 1979 | if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0) { | |
2003 | if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0) | 1980 | found = true; |
2004 | break; | 1981 | break; |
1982 | } | ||
2005 | } | 1983 | } |
2006 | 1984 | ||
2007 | if (tbl == NULL) { | 1985 | if (!found) |
2008 | err = -ENOENT; | 1986 | return -ENOENT; |
2009 | goto errout_locked; | ||
2010 | } | ||
2011 | 1987 | ||
2012 | /* | 1988 | /* |
2013 | * We acquire tbl->lock to be nice to the periodic timers and | 1989 | * We acquire tbl->lock to be nice to the periodic timers and |
@@ -2118,8 +2094,6 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
2118 | 2094 | ||
2119 | errout_tbl_lock: | 2095 | errout_tbl_lock: |
2120 | write_unlock_bh(&tbl->lock); | 2096 | write_unlock_bh(&tbl->lock); |
2121 | errout_locked: | ||
2122 | read_unlock(&neigh_tbl_lock); | ||
2123 | errout: | 2097 | errout: |
2124 | return err; | 2098 | return err; |
2125 | } | 2099 | } |
@@ -2134,10 +2108,13 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb) | |||
2134 | 2108 | ||
2135 | family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family; | 2109 | family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family; |
2136 | 2110 | ||
2137 | read_lock(&neigh_tbl_lock); | 2111 | for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) { |
2138 | for (tbl = neigh_tables, tidx = 0; tbl; tbl = tbl->next, tidx++) { | ||
2139 | struct neigh_parms *p; | 2112 | struct neigh_parms *p; |
2140 | 2113 | ||
2114 | tbl = neigh_tables[tidx]; | ||
2115 | if (!tbl) | ||
2116 | continue; | ||
2117 | |||
2141 | if (tidx < tbl_skip || (family && tbl->family != family)) | 2118 | if (tidx < tbl_skip || (family && tbl->family != family)) |
2142 | continue; | 2119 | continue; |
2143 | 2120 | ||
@@ -2168,7 +2145,6 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb) | |||
2168 | neigh_skip = 0; | 2145 | neigh_skip = 0; |
2169 | } | 2146 | } |
2170 | out: | 2147 | out: |
2171 | read_unlock(&neigh_tbl_lock); | ||
2172 | cb->args[0] = tidx; | 2148 | cb->args[0] = tidx; |
2173 | cb->args[1] = nidx; | 2149 | cb->args[1] = nidx; |
2174 | 2150 | ||
@@ -2351,7 +2327,6 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb) | |||
2351 | int proxy = 0; | 2327 | int proxy = 0; |
2352 | int err; | 2328 | int err; |
2353 | 2329 | ||
2354 | read_lock(&neigh_tbl_lock); | ||
2355 | family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family; | 2330 | family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family; |
2356 | 2331 | ||
2357 | /* check for full ndmsg structure presence, family member is | 2332 | /* check for full ndmsg structure presence, family member is |
@@ -2363,8 +2338,11 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb) | |||
2363 | 2338 | ||
2364 | s_t = cb->args[0]; | 2339 | s_t = cb->args[0]; |
2365 | 2340 | ||
2366 | for (tbl = neigh_tables, t = 0; tbl; | 2341 | for (t = 0; t < NEIGH_NR_TABLES; t++) { |
2367 | tbl = tbl->next, t++) { | 2342 | tbl = neigh_tables[t]; |
2343 | |||
2344 | if (!tbl) | ||
2345 | continue; | ||
2368 | if (t < s_t || (family && tbl->family != family)) | 2346 | if (t < s_t || (family && tbl->family != family)) |
2369 | continue; | 2347 | continue; |
2370 | if (t > s_t) | 2348 | if (t > s_t) |
@@ -2377,7 +2355,6 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb) | |||
2377 | if (err < 0) | 2355 | if (err < 0) |
2378 | break; | 2356 | break; |
2379 | } | 2357 | } |
2380 | read_unlock(&neigh_tbl_lock); | ||
2381 | 2358 | ||
2382 | cb->args[0] = t; | 2359 | cb->args[0] = t; |
2383 | return skb->len; | 2360 | return skb->len; |