aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2011-02-15 04:24:31 -0500
committerJiri Kosina <jkosina@suse.cz>2011-02-15 04:24:31 -0500
commit0a9d59a2461477bd9ed143c01af9df3f8f00fa81 (patch)
treedf997d1cfb0786427a0df1fbd6f0640fa4248cf4 /net/ipv6
parenta23ce6da9677d245aa0aadc99f4197030350ab54 (diff)
parent795abaf1e4e188c4171e3cd3dbb11a9fcacaf505 (diff)
Merge branch 'master' into for-next
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/addrconf.c84
-rw-r--r--net/ipv6/ip6_output.c3
-rw-r--r--net/ipv6/ip6mr.c75
-rw-r--r--net/ipv6/netfilter/nf_defrag_ipv6_hooks.c8
-rw-r--r--net/ipv6/raw.c19
-rw-r--r--net/ipv6/route.c19
-rw-r--r--net/ipv6/sysctl_net_ipv6.c9
-rw-r--r--net/ipv6/xfrm6_policy.c6
8 files changed, 158 insertions, 65 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 5b189c97c2fc..fd6782e3a038 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -420,9 +420,6 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
420 dev->type == ARPHRD_TUNNEL6 || 420 dev->type == ARPHRD_TUNNEL6 ||
421 dev->type == ARPHRD_SIT || 421 dev->type == ARPHRD_SIT ||
422 dev->type == ARPHRD_NONE) { 422 dev->type == ARPHRD_NONE) {
423 printk(KERN_INFO
424 "%s: Disabled Privacy Extensions\n",
425 dev->name);
426 ndev->cnf.use_tempaddr = -1; 423 ndev->cnf.use_tempaddr = -1;
427 } else { 424 } else {
428 in6_dev_hold(ndev); 425 in6_dev_hold(ndev);
@@ -2664,14 +2661,12 @@ static int addrconf_ifdown(struct net_device *dev, int how)
2664 struct net *net = dev_net(dev); 2661 struct net *net = dev_net(dev);
2665 struct inet6_dev *idev; 2662 struct inet6_dev *idev;
2666 struct inet6_ifaddr *ifa; 2663 struct inet6_ifaddr *ifa;
2667 LIST_HEAD(keep_list); 2664 int state, i;
2668 int state;
2669 2665
2670 ASSERT_RTNL(); 2666 ASSERT_RTNL();
2671 2667
2672 /* Flush routes if device is being removed or it is not loopback */ 2668 rt6_ifdown(net, dev);
2673 if (how || !(dev->flags & IFF_LOOPBACK)) 2669 neigh_ifdown(&nd_tbl, dev);
2674 rt6_ifdown(net, dev);
2675 2670
2676 idev = __in6_dev_get(dev); 2671 idev = __in6_dev_get(dev);
2677 if (idev == NULL) 2672 if (idev == NULL)
@@ -2692,6 +2687,23 @@ static int addrconf_ifdown(struct net_device *dev, int how)
2692 2687
2693 } 2688 }
2694 2689
2690 /* Step 2: clear hash table */
2691 for (i = 0; i < IN6_ADDR_HSIZE; i++) {
2692 struct hlist_head *h = &inet6_addr_lst[i];
2693 struct hlist_node *n;
2694
2695 spin_lock_bh(&addrconf_hash_lock);
2696 restart:
2697 hlist_for_each_entry_rcu(ifa, n, h, addr_lst) {
2698 if (ifa->idev == idev) {
2699 hlist_del_init_rcu(&ifa->addr_lst);
2700 addrconf_del_timer(ifa);
2701 goto restart;
2702 }
2703 }
2704 spin_unlock_bh(&addrconf_hash_lock);
2705 }
2706
2695 write_lock_bh(&idev->lock); 2707 write_lock_bh(&idev->lock);
2696 2708
2697 /* Step 2: clear flags for stateless addrconf */ 2709 /* Step 2: clear flags for stateless addrconf */
@@ -2725,52 +2737,23 @@ static int addrconf_ifdown(struct net_device *dev, int how)
2725 struct inet6_ifaddr, if_list); 2737 struct inet6_ifaddr, if_list);
2726 addrconf_del_timer(ifa); 2738 addrconf_del_timer(ifa);
2727 2739
2728 /* If just doing link down, and address is permanent 2740 list_del(&ifa->if_list);
2729 and not link-local, then retain it. */
2730 if (!how &&
2731 (ifa->flags&IFA_F_PERMANENT) &&
2732 !(ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) {
2733 list_move_tail(&ifa->if_list, &keep_list);
2734
2735 /* If not doing DAD on this address, just keep it. */
2736 if ((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) ||
2737 idev->cnf.accept_dad <= 0 ||
2738 (ifa->flags & IFA_F_NODAD))
2739 continue;
2740 2741
2741 /* If it was tentative already, no need to notify */ 2742 write_unlock_bh(&idev->lock);
2742 if (ifa->flags & IFA_F_TENTATIVE)
2743 continue;
2744 2743
2745 /* Flag it for later restoration when link comes up */ 2744 spin_lock_bh(&ifa->state_lock);
2746 ifa->flags |= IFA_F_TENTATIVE; 2745 state = ifa->state;
2747 ifa->state = INET6_IFADDR_STATE_DAD; 2746 ifa->state = INET6_IFADDR_STATE_DEAD;
2748 } else { 2747 spin_unlock_bh(&ifa->state_lock);
2749 list_del(&ifa->if_list);
2750
2751 /* clear hash table */
2752 spin_lock_bh(&addrconf_hash_lock);
2753 hlist_del_init_rcu(&ifa->addr_lst);
2754 spin_unlock_bh(&addrconf_hash_lock);
2755
2756 write_unlock_bh(&idev->lock);
2757 spin_lock_bh(&ifa->state_lock);
2758 state = ifa->state;
2759 ifa->state = INET6_IFADDR_STATE_DEAD;
2760 spin_unlock_bh(&ifa->state_lock);
2761
2762 if (state != INET6_IFADDR_STATE_DEAD) {
2763 __ipv6_ifa_notify(RTM_DELADDR, ifa);
2764 atomic_notifier_call_chain(&inet6addr_chain,
2765 NETDEV_DOWN, ifa);
2766 }
2767 2748
2768 in6_ifa_put(ifa); 2749 if (state != INET6_IFADDR_STATE_DEAD) {
2769 write_lock_bh(&idev->lock); 2750 __ipv6_ifa_notify(RTM_DELADDR, ifa);
2751 atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
2770 } 2752 }
2771 } 2753 in6_ifa_put(ifa);
2772 2754
2773 list_splice(&keep_list, &idev->addr_list); 2755 write_lock_bh(&idev->lock);
2756 }
2774 2757
2775 write_unlock_bh(&idev->lock); 2758 write_unlock_bh(&idev->lock);
2776 2759
@@ -4159,8 +4142,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
4159 addrconf_leave_solict(ifp->idev, &ifp->addr); 4142 addrconf_leave_solict(ifp->idev, &ifp->addr);
4160 dst_hold(&ifp->rt->dst); 4143 dst_hold(&ifp->rt->dst);
4161 4144
4162 if (ifp->state == INET6_IFADDR_STATE_DEAD && 4145 if (ip6_del_rt(ifp->rt))
4163 ip6_del_rt(ifp->rt))
4164 dst_free(&ifp->rt->dst); 4146 dst_free(&ifp->rt->dst);
4165 break; 4147 break;
4166 } 4148 }
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 94b5bf132b2e..5f8d242be3f3 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -401,6 +401,9 @@ int ip6_forward(struct sk_buff *skb)
401 goto drop; 401 goto drop;
402 } 402 }
403 403
404 if (skb->pkt_type != PACKET_HOST)
405 goto drop;
406
404 skb_forward_csum(skb); 407 skb_forward_csum(skb);
405 408
406 /* 409 /*
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 9fab274019c0..0e1d53bcf1e0 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -34,6 +34,7 @@
34#include <linux/seq_file.h> 34#include <linux/seq_file.h>
35#include <linux/init.h> 35#include <linux/init.h>
36#include <linux/slab.h> 36#include <linux/slab.h>
37#include <linux/compat.h>
37#include <net/protocol.h> 38#include <net/protocol.h>
38#include <linux/skbuff.h> 39#include <linux/skbuff.h>
39#include <net/sock.h> 40#include <net/sock.h>
@@ -1804,6 +1805,80 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
1804 } 1805 }
1805} 1806}
1806 1807
1808#ifdef CONFIG_COMPAT
1809struct compat_sioc_sg_req6 {
1810 struct sockaddr_in6 src;
1811 struct sockaddr_in6 grp;
1812 compat_ulong_t pktcnt;
1813 compat_ulong_t bytecnt;
1814 compat_ulong_t wrong_if;
1815};
1816
1817struct compat_sioc_mif_req6 {
1818 mifi_t mifi;
1819 compat_ulong_t icount;
1820 compat_ulong_t ocount;
1821 compat_ulong_t ibytes;
1822 compat_ulong_t obytes;
1823};
1824
1825int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
1826{
1827 struct compat_sioc_sg_req6 sr;
1828 struct compat_sioc_mif_req6 vr;
1829 struct mif_device *vif;
1830 struct mfc6_cache *c;
1831 struct net *net = sock_net(sk);
1832 struct mr6_table *mrt;
1833
1834 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
1835 if (mrt == NULL)
1836 return -ENOENT;
1837
1838 switch (cmd) {
1839 case SIOCGETMIFCNT_IN6:
1840 if (copy_from_user(&vr, arg, sizeof(vr)))
1841 return -EFAULT;
1842 if (vr.mifi >= mrt->maxvif)
1843 return -EINVAL;
1844 read_lock(&mrt_lock);
1845 vif = &mrt->vif6_table[vr.mifi];
1846 if (MIF_EXISTS(mrt, vr.mifi)) {
1847 vr.icount = vif->pkt_in;
1848 vr.ocount = vif->pkt_out;
1849 vr.ibytes = vif->bytes_in;
1850 vr.obytes = vif->bytes_out;
1851 read_unlock(&mrt_lock);
1852
1853 if (copy_to_user(arg, &vr, sizeof(vr)))
1854 return -EFAULT;
1855 return 0;
1856 }
1857 read_unlock(&mrt_lock);
1858 return -EADDRNOTAVAIL;
1859 case SIOCGETSGCNT_IN6:
1860 if (copy_from_user(&sr, arg, sizeof(sr)))
1861 return -EFAULT;
1862
1863 read_lock(&mrt_lock);
1864 c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
1865 if (c) {
1866 sr.pktcnt = c->mfc_un.res.pkt;
1867 sr.bytecnt = c->mfc_un.res.bytes;
1868 sr.wrong_if = c->mfc_un.res.wrong_if;
1869 read_unlock(&mrt_lock);
1870
1871 if (copy_to_user(arg, &sr, sizeof(sr)))
1872 return -EFAULT;
1873 return 0;
1874 }
1875 read_unlock(&mrt_lock);
1876 return -EADDRNOTAVAIL;
1877 default:
1878 return -ENOIOCTLCMD;
1879 }
1880}
1881#endif
1807 1882
1808static inline int ip6mr_forward2_finish(struct sk_buff *skb) 1883static inline int ip6mr_forward2_finish(struct sk_buff *skb)
1809{ 1884{
diff --git a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
index 99abfb53bab9..97c5b21b9674 100644
--- a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
+++ b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
@@ -19,13 +19,15 @@
19 19
20#include <linux/netfilter_ipv6.h> 20#include <linux/netfilter_ipv6.h>
21#include <linux/netfilter_bridge.h> 21#include <linux/netfilter_bridge.h>
22#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
22#include <net/netfilter/nf_conntrack.h> 23#include <net/netfilter/nf_conntrack.h>
23#include <net/netfilter/nf_conntrack_helper.h> 24#include <net/netfilter/nf_conntrack_helper.h>
24#include <net/netfilter/nf_conntrack_l4proto.h> 25#include <net/netfilter/nf_conntrack_l4proto.h>
25#include <net/netfilter/nf_conntrack_l3proto.h> 26#include <net/netfilter/nf_conntrack_l3proto.h>
26#include <net/netfilter/nf_conntrack_core.h> 27#include <net/netfilter/nf_conntrack_core.h>
27#include <net/netfilter/nf_conntrack_zones.h>
28#include <net/netfilter/ipv6/nf_conntrack_ipv6.h> 28#include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
29#endif
30#include <net/netfilter/nf_conntrack_zones.h>
29#include <net/netfilter/ipv6/nf_defrag_ipv6.h> 31#include <net/netfilter/ipv6/nf_defrag_ipv6.h>
30 32
31static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, 33static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum,
@@ -33,8 +35,10 @@ static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum,
33{ 35{
34 u16 zone = NF_CT_DEFAULT_ZONE; 36 u16 zone = NF_CT_DEFAULT_ZONE;
35 37
38#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
36 if (skb->nfct) 39 if (skb->nfct)
37 zone = nf_ct_zone((struct nf_conn *)skb->nfct); 40 zone = nf_ct_zone((struct nf_conn *)skb->nfct);
41#endif
38 42
39#ifdef CONFIG_BRIDGE_NETFILTER 43#ifdef CONFIG_BRIDGE_NETFILTER
40 if (skb->nf_bridge && 44 if (skb->nf_bridge &&
@@ -56,9 +60,11 @@ static unsigned int ipv6_defrag(unsigned int hooknum,
56{ 60{
57 struct sk_buff *reasm; 61 struct sk_buff *reasm;
58 62
63#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
59 /* Previously seen (loopback)? */ 64 /* Previously seen (loopback)? */
60 if (skb->nfct && !nf_ct_is_template((struct nf_conn *)skb->nfct)) 65 if (skb->nfct && !nf_ct_is_template((struct nf_conn *)skb->nfct))
61 return NF_ACCEPT; 66 return NF_ACCEPT;
67#endif
62 68
63 reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(hooknum, skb)); 69 reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(hooknum, skb));
64 /* queued */ 70 /* queued */
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 86c39526ba5e..c5b0915d106b 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -31,6 +31,7 @@
31#include <linux/netfilter.h> 31#include <linux/netfilter.h>
32#include <linux/netfilter_ipv6.h> 32#include <linux/netfilter_ipv6.h>
33#include <linux/skbuff.h> 33#include <linux/skbuff.h>
34#include <linux/compat.h>
34#include <asm/uaccess.h> 35#include <asm/uaccess.h>
35#include <asm/ioctls.h> 36#include <asm/ioctls.h>
36 37
@@ -1157,6 +1158,23 @@ static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg)
1157 } 1158 }
1158} 1159}
1159 1160
1161#ifdef CONFIG_COMPAT
1162static int compat_rawv6_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
1163{
1164 switch (cmd) {
1165 case SIOCOUTQ:
1166 case SIOCINQ:
1167 return -ENOIOCTLCMD;
1168 default:
1169#ifdef CONFIG_IPV6_MROUTE
1170 return ip6mr_compat_ioctl(sk, cmd, compat_ptr(arg));
1171#else
1172 return -ENOIOCTLCMD;
1173#endif
1174 }
1175}
1176#endif
1177
1160static void rawv6_close(struct sock *sk, long timeout) 1178static void rawv6_close(struct sock *sk, long timeout)
1161{ 1179{
1162 if (inet_sk(sk)->inet_num == IPPROTO_RAW) 1180 if (inet_sk(sk)->inet_num == IPPROTO_RAW)
@@ -1215,6 +1233,7 @@ struct proto rawv6_prot = {
1215#ifdef CONFIG_COMPAT 1233#ifdef CONFIG_COMPAT
1216 .compat_setsockopt = compat_rawv6_setsockopt, 1234 .compat_setsockopt = compat_rawv6_setsockopt,
1217 .compat_getsockopt = compat_rawv6_getsockopt, 1235 .compat_getsockopt = compat_rawv6_getsockopt,
1236 .compat_ioctl = compat_rawv6_ioctl,
1218#endif 1237#endif
1219}; 1238};
1220 1239
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 373bd0416f69..1c29f95695de 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -72,8 +72,6 @@
72#define RT6_TRACE(x...) do { ; } while (0) 72#define RT6_TRACE(x...) do { ; } while (0)
73#endif 73#endif
74 74
75#define CLONE_OFFLINK_ROUTE 0
76
77static struct rt6_info * ip6_rt_copy(struct rt6_info *ort); 75static struct rt6_info * ip6_rt_copy(struct rt6_info *ort);
78static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie); 76static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie);
79static unsigned int ip6_default_advmss(const struct dst_entry *dst); 77static unsigned int ip6_default_advmss(const struct dst_entry *dst);
@@ -115,6 +113,11 @@ static struct dst_ops ip6_dst_ops_template = {
115 .local_out = __ip6_local_out, 113 .local_out = __ip6_local_out,
116}; 114};
117 115
116static unsigned int ip6_blackhole_default_mtu(const struct dst_entry *dst)
117{
118 return 0;
119}
120
118static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) 121static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu)
119{ 122{
120} 123}
@@ -124,6 +127,7 @@ static struct dst_ops ip6_dst_blackhole_ops = {
124 .protocol = cpu_to_be16(ETH_P_IPV6), 127 .protocol = cpu_to_be16(ETH_P_IPV6),
125 .destroy = ip6_dst_destroy, 128 .destroy = ip6_dst_destroy,
126 .check = ip6_dst_check, 129 .check = ip6_dst_check,
130 .default_mtu = ip6_blackhole_default_mtu,
127 .update_pmtu = ip6_rt_blackhole_update_pmtu, 131 .update_pmtu = ip6_rt_blackhole_update_pmtu,
128}; 132};
129 133
@@ -196,7 +200,6 @@ static void ip6_dst_destroy(struct dst_entry *dst)
196 in6_dev_put(idev); 200 in6_dev_put(idev);
197 } 201 }
198 if (peer) { 202 if (peer) {
199 BUG_ON(!(rt->rt6i_flags & RTF_CACHE));
200 rt->rt6i_peer = NULL; 203 rt->rt6i_peer = NULL;
201 inet_putpeer(peer); 204 inet_putpeer(peer);
202 } 205 }
@@ -206,9 +209,6 @@ void rt6_bind_peer(struct rt6_info *rt, int create)
206{ 209{
207 struct inet_peer *peer; 210 struct inet_peer *peer;
208 211
209 if (WARN_ON(!(rt->rt6i_flags & RTF_CACHE)))
210 return;
211
212 peer = inet_getpeer_v6(&rt->rt6i_dst.addr, create); 212 peer = inet_getpeer_v6(&rt->rt6i_dst.addr, create);
213 if (peer && cmpxchg(&rt->rt6i_peer, NULL, peer) != NULL) 213 if (peer && cmpxchg(&rt->rt6i_peer, NULL, peer) != NULL)
214 inet_putpeer(peer); 214 inet_putpeer(peer);
@@ -738,13 +738,8 @@ restart:
738 738
739 if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) 739 if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP))
740 nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src); 740 nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src);
741 else { 741 else
742#if CLONE_OFFLINK_ROUTE
743 nrt = rt6_alloc_clone(rt, &fl->fl6_dst); 742 nrt = rt6_alloc_clone(rt, &fl->fl6_dst);
744#else
745 goto out2;
746#endif
747 }
748 743
749 dst_release(&rt->dst); 744 dst_release(&rt->dst);
750 rt = nrt ? : net->ipv6.ip6_null_entry; 745 rt = nrt ? : net->ipv6.ip6_null_entry;
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
index fa1d8f4e0051..7cb65ef79f9c 100644
--- a/net/ipv6/sysctl_net_ipv6.c
+++ b/net/ipv6/sysctl_net_ipv6.c
@@ -15,6 +15,8 @@
15#include <net/addrconf.h> 15#include <net/addrconf.h>
16#include <net/inet_frag.h> 16#include <net/inet_frag.h>
17 17
18static struct ctl_table empty[1];
19
18static ctl_table ipv6_table_template[] = { 20static ctl_table ipv6_table_template[] = {
19 { 21 {
20 .procname = "route", 22 .procname = "route",
@@ -35,6 +37,12 @@ static ctl_table ipv6_table_template[] = {
35 .mode = 0644, 37 .mode = 0644,
36 .proc_handler = proc_dointvec 38 .proc_handler = proc_dointvec
37 }, 39 },
40 {
41 .procname = "neigh",
42 .maxlen = 0,
43 .mode = 0555,
44 .child = empty,
45 },
38 { } 46 { }
39}; 47};
40 48
@@ -152,7 +160,6 @@ static struct ctl_table_header *ip6_base;
152 160
153int ipv6_static_sysctl_register(void) 161int ipv6_static_sysctl_register(void)
154{ 162{
155 static struct ctl_table empty[1];
156 ip6_base = register_sysctl_paths(net_ipv6_ctl_path, empty); 163 ip6_base = register_sysctl_paths(net_ipv6_ctl_path, empty);
157 if (ip6_base == NULL) 164 if (ip6_base == NULL)
158 return -ENOMEM; 165 return -ENOMEM;
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 7e74023ea6e4..da87428681cc 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -98,6 +98,10 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
98 if (!xdst->u.rt6.rt6i_idev) 98 if (!xdst->u.rt6.rt6i_idev)
99 return -ENODEV; 99 return -ENODEV;
100 100
101 xdst->u.rt6.rt6i_peer = rt->rt6i_peer;
102 if (rt->rt6i_peer)
103 atomic_inc(&rt->rt6i_peer->refcnt);
104
101 /* Sheit... I remember I did this right. Apparently, 105 /* Sheit... I remember I did this right. Apparently,
102 * it was magically lost, so this code needs audit */ 106 * it was magically lost, so this code needs audit */
103 xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST | 107 xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST |
@@ -216,6 +220,8 @@ static void xfrm6_dst_destroy(struct dst_entry *dst)
216 220
217 if (likely(xdst->u.rt6.rt6i_idev)) 221 if (likely(xdst->u.rt6.rt6i_idev))
218 in6_dev_put(xdst->u.rt6.rt6i_idev); 222 in6_dev_put(xdst->u.rt6.rt6i_idev);
223 if (likely(xdst->u.rt6.rt6i_peer))
224 inet_putpeer(xdst->u.rt6.rt6i_peer);
219 xfrm_dst_destroy(xdst); 225 xfrm_dst_destroy(xdst);
220} 226}
221 227