diff options
author | David S. Miller <davem@davemloft.net> | 2012-07-12 03:05:02 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-07-12 03:05:02 -0400 |
commit | 6e157b6ac61aa7758ccd643d4aafdf3cc17b9f04 (patch) | |
tree | f3048f6bd8d18711b7e6aa3686289d56fb97225c /net/ipv6 | |
parent | e8599ff4b1d6b0d61e1074ae4ba9fca8dd0c41d0 (diff) |
ipv6: Pull main logic of rt6_redirect() into rt6_do_redirect().
Hook it into dst_ops->redirect as well.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/route.c | 80 |
1 files changed, 49 insertions, 31 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 73cf3f78aaa8..545b1526c143 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -79,6 +79,7 @@ static int ip6_pkt_discard(struct sk_buff *skb); | |||
79 | static int ip6_pkt_discard_out(struct sk_buff *skb); | 79 | static int ip6_pkt_discard_out(struct sk_buff *skb); |
80 | static void ip6_link_failure(struct sk_buff *skb); | 80 | static void ip6_link_failure(struct sk_buff *skb); |
81 | static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu); | 81 | static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu); |
82 | static void rt6_do_redirect(struct dst_entry *dst, struct sk_buff *skb); | ||
82 | 83 | ||
83 | #ifdef CONFIG_IPV6_ROUTE_INFO | 84 | #ifdef CONFIG_IPV6_ROUTE_INFO |
84 | static struct rt6_info *rt6_add_route_info(struct net *net, | 85 | static struct rt6_info *rt6_add_route_info(struct net *net, |
@@ -174,6 +175,7 @@ static struct dst_ops ip6_dst_ops_template = { | |||
174 | .negative_advice = ip6_negative_advice, | 175 | .negative_advice = ip6_negative_advice, |
175 | .link_failure = ip6_link_failure, | 176 | .link_failure = ip6_link_failure, |
176 | .update_pmtu = ip6_rt_update_pmtu, | 177 | .update_pmtu = ip6_rt_update_pmtu, |
178 | .redirect = rt6_do_redirect, | ||
177 | .local_out = __ip6_local_out, | 179 | .local_out = __ip6_local_out, |
178 | .neigh_lookup = ip6_neigh_lookup, | 180 | .neigh_lookup = ip6_neigh_lookup, |
179 | }; | 181 | }; |
@@ -1690,28 +1692,26 @@ static struct rt6_info *ip6_route_redirect(const struct in6_addr *dest, | |||
1690 | flags, __ip6_route_redirect); | 1692 | flags, __ip6_route_redirect); |
1691 | } | 1693 | } |
1692 | 1694 | ||
1693 | void rt6_redirect(struct sk_buff *skb) | 1695 | static void rt6_do_redirect(struct dst_entry *dst, struct sk_buff *skb) |
1694 | { | 1696 | { |
1695 | struct net *net = dev_net(skb->dev); | 1697 | struct net *net = dev_net(skb->dev); |
1696 | struct netevent_redirect netevent; | 1698 | struct netevent_redirect netevent; |
1697 | struct rt6_info *rt, *nrt = NULL; | 1699 | struct rt6_info *rt, *nrt = NULL; |
1698 | const struct in6_addr *target; | 1700 | const struct in6_addr *target; |
1699 | struct neighbour *old_neigh; | ||
1700 | const struct in6_addr *dest; | ||
1701 | const struct in6_addr *src; | ||
1702 | const struct in6_addr *saddr; | ||
1703 | struct ndisc_options ndopts; | 1701 | struct ndisc_options ndopts; |
1702 | const struct in6_addr *dest; | ||
1703 | struct neighbour *old_neigh; | ||
1704 | struct inet6_dev *in6_dev; | 1704 | struct inet6_dev *in6_dev; |
1705 | struct neighbour *neigh; | 1705 | struct neighbour *neigh; |
1706 | struct icmp6hdr *icmph; | 1706 | struct icmp6hdr *icmph; |
1707 | int on_link, optlen; | 1707 | int optlen, on_link; |
1708 | u8 *lladdr = NULL; | 1708 | u8 *lladdr; |
1709 | 1709 | ||
1710 | optlen = skb->tail - skb->transport_header; | 1710 | optlen = skb->tail - skb->transport_header; |
1711 | optlen -= sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr); | 1711 | optlen -= sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr); |
1712 | 1712 | ||
1713 | if (optlen < 0) { | 1713 | if (optlen < 0) { |
1714 | net_dbg_ratelimited("rt6_redirect: packet too short\n"); | 1714 | net_dbg_ratelimited("rt6_do_redirect: packet too short\n"); |
1715 | return; | 1715 | return; |
1716 | } | 1716 | } |
1717 | 1717 | ||
@@ -1720,15 +1720,16 @@ void rt6_redirect(struct sk_buff *skb) | |||
1720 | dest = target + 1; | 1720 | dest = target + 1; |
1721 | 1721 | ||
1722 | if (ipv6_addr_is_multicast(dest)) { | 1722 | if (ipv6_addr_is_multicast(dest)) { |
1723 | net_dbg_ratelimited("rt6_redirect: destination address is multicast\n"); | 1723 | net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n"); |
1724 | return; | 1724 | return; |
1725 | } | 1725 | } |
1726 | 1726 | ||
1727 | on_link = 0; | ||
1727 | if (ipv6_addr_equal(dest, target)) { | 1728 | if (ipv6_addr_equal(dest, target)) { |
1728 | on_link = 1; | 1729 | on_link = 1; |
1729 | } else if (ipv6_addr_type(target) != | 1730 | } else if (ipv6_addr_type(target) != |
1730 | (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) { | 1731 | (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) { |
1731 | net_dbg_ratelimited("rt6_redirect: target address is not link-local unicast\n"); | 1732 | net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n"); |
1732 | return; | 1733 | return; |
1733 | } | 1734 | } |
1734 | 1735 | ||
@@ -1747,6 +1748,8 @@ void rt6_redirect(struct sk_buff *skb) | |||
1747 | net_dbg_ratelimited("rt6_redirect: invalid ND options\n"); | 1748 | net_dbg_ratelimited("rt6_redirect: invalid ND options\n"); |
1748 | return; | 1749 | return; |
1749 | } | 1750 | } |
1751 | |||
1752 | lladdr = NULL; | ||
1750 | if (ndopts.nd_opts_tgt_lladdr) { | 1753 | if (ndopts.nd_opts_tgt_lladdr) { |
1751 | lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, | 1754 | lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, |
1752 | skb->dev); | 1755 | skb->dev); |
@@ -1756,19 +1759,26 @@ void rt6_redirect(struct sk_buff *skb) | |||
1756 | } | 1759 | } |
1757 | } | 1760 | } |
1758 | 1761 | ||
1759 | neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1); | 1762 | rt = (struct rt6_info *) dst; |
1760 | if (!neigh) | 1763 | if (rt == net->ipv6.ip6_null_entry) { |
1764 | net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n"); | ||
1761 | return; | 1765 | return; |
1766 | } | ||
1762 | 1767 | ||
1763 | src = &ipv6_hdr(skb)->daddr; | 1768 | /* Redirect received -> path was valid. |
1764 | saddr = &ipv6_hdr(skb)->saddr; | 1769 | * Look, redirects are sent only in response to data packets, |
1770 | * so that this nexthop apparently is reachable. --ANK | ||
1771 | */ | ||
1772 | dst_confirm(&rt->dst); | ||
1765 | 1773 | ||
1766 | rt = ip6_route_redirect(dest, src, saddr, neigh->dev); | 1774 | neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1); |
1775 | if (!neigh) | ||
1776 | return; | ||
1767 | 1777 | ||
1768 | if (rt == net->ipv6.ip6_null_entry) { | 1778 | /* Duplicate redirect: silently ignore. */ |
1769 | net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n"); | 1779 | old_neigh = rt->n; |
1780 | if (neigh == old_neigh) | ||
1770 | goto out; | 1781 | goto out; |
1771 | } | ||
1772 | 1782 | ||
1773 | /* | 1783 | /* |
1774 | * We have finally decided to accept it. | 1784 | * We have finally decided to accept it. |
@@ -1781,18 +1791,6 @@ void rt6_redirect(struct sk_buff *skb) | |||
1781 | NEIGH_UPDATE_F_ISROUTER)) | 1791 | NEIGH_UPDATE_F_ISROUTER)) |
1782 | ); | 1792 | ); |
1783 | 1793 | ||
1784 | /* | ||
1785 | * Redirect received -> path was valid. | ||
1786 | * Look, redirects are sent only in response to data packets, | ||
1787 | * so that this nexthop apparently is reachable. --ANK | ||
1788 | */ | ||
1789 | dst_confirm(&rt->dst); | ||
1790 | |||
1791 | /* Duplicate redirect: silently ignore. */ | ||
1792 | old_neigh = rt->n; | ||
1793 | if (neigh == old_neigh) | ||
1794 | goto out; | ||
1795 | |||
1796 | nrt = ip6_rt_copy(rt, dest); | 1794 | nrt = ip6_rt_copy(rt, dest); |
1797 | if (!nrt) | 1795 | if (!nrt) |
1798 | goto out; | 1796 | goto out; |
@@ -1815,12 +1813,32 @@ void rt6_redirect(struct sk_buff *skb) | |||
1815 | call_netevent_notifiers(NETEVENT_REDIRECT, &netevent); | 1813 | call_netevent_notifiers(NETEVENT_REDIRECT, &netevent); |
1816 | 1814 | ||
1817 | if (rt->rt6i_flags & RTF_CACHE) { | 1815 | if (rt->rt6i_flags & RTF_CACHE) { |
1816 | rt = (struct rt6_info *) dst_clone(&rt->dst); | ||
1818 | ip6_del_rt(rt); | 1817 | ip6_del_rt(rt); |
1819 | return; | ||
1820 | } | 1818 | } |
1821 | 1819 | ||
1822 | out: | 1820 | out: |
1823 | neigh_release(neigh); | 1821 | neigh_release(neigh); |
1822 | } | ||
1823 | |||
1824 | void rt6_redirect(struct sk_buff *skb) | ||
1825 | { | ||
1826 | const struct in6_addr *target; | ||
1827 | const struct in6_addr *dest; | ||
1828 | const struct in6_addr *src; | ||
1829 | const struct in6_addr *saddr; | ||
1830 | struct icmp6hdr *icmph; | ||
1831 | struct rt6_info *rt; | ||
1832 | |||
1833 | icmph = icmp6_hdr(skb); | ||
1834 | target = (const struct in6_addr *) (icmph + 1); | ||
1835 | dest = target + 1; | ||
1836 | |||
1837 | src = &ipv6_hdr(skb)->daddr; | ||
1838 | saddr = &ipv6_hdr(skb)->saddr; | ||
1839 | |||
1840 | rt = ip6_route_redirect(dest, src, saddr, skb->dev); | ||
1841 | rt6_do_redirect(&rt->dst, skb); | ||
1824 | dst_release(&rt->dst); | 1842 | dst_release(&rt->dst); |
1825 | } | 1843 | } |
1826 | 1844 | ||