aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/route.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2012-07-12 03:05:02 -0400
committerDavid S. Miller <davem@davemloft.net>2012-07-12 03:05:02 -0400
commit6e157b6ac61aa7758ccd643d4aafdf3cc17b9f04 (patch)
treef3048f6bd8d18711b7e6aa3686289d56fb97225c /net/ipv6/route.c
parente8599ff4b1d6b0d61e1074ae4ba9fca8dd0c41d0 (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/route.c')
-rw-r--r--net/ipv6/route.c80
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);
79static int ip6_pkt_discard_out(struct sk_buff *skb); 79static int ip6_pkt_discard_out(struct sk_buff *skb);
80static void ip6_link_failure(struct sk_buff *skb); 80static void ip6_link_failure(struct sk_buff *skb);
81static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu); 81static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu);
82static 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
84static struct rt6_info *rt6_add_route_info(struct net *net, 85static 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
1693void rt6_redirect(struct sk_buff *skb) 1695static 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
1822out: 1820out:
1823 neigh_release(neigh); 1821 neigh_release(neigh);
1822}
1823
1824void 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