aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2013-08-29 16:05:30 -0400
committerDavid S. Miller <davem@davemloft.net>2013-08-29 16:05:30 -0400
commit79f9ab7e0a8ec452e58b5a5267b9eb019ff493d0 (patch)
tree650d432ab57882fa022b0edaee058fe8044e68c0
parent1f324e38870cc09659cf23bc626f1b8869e201f2 (diff)
parent302a50bc941010d7a67f288fd0db31981e4d722d (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec
Steffen Klassert says: ==================== This pull request fixes some issues that arise when 6in4 or 4in6 tunnels are used in combination with IPsec, all from Hannes Frederic Sowa and a null pointer dereference when queueing packets to the policy hold queue. 1) We might access the local error handler of the wrong address family if 6in4 or 4in6 tunnel is protected by ipsec. Fix this by addind a pointer to the correct local_error to xfrm_state_afinet. 2) Add a helper function to always refer to the correct interpretation of skb->sk. 3) Call skb_reset_inner_headers to record the position of the inner headers when adding a new one in various ipv6 tunnels. This is needed to identify the addresses where to send back errors in the xfrm layer. 4) Dereference inner ipv6 header if encapsulated to always call the right error handler. 5) Choose protocol family by skb protocol to not call the wrong xfrm{4,6}_local_error handler in case an ipv6 sockets is used in ipv4 mode. 6) Partly revert "xfrm: introduce helper for safe determination of mtu" because this introduced pmtu discovery problems. 7) Set skb->protocol on tcp, raw and ip6_append_data genereated skbs. We need this to get the correct mtu informations in xfrm. 8) Fix null pointer dereference in xdst_queue_output. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/route.h8
-rw-r--r--include/net/xfrm.h6
-rw-r--r--net/ipv4/ip_output.c8
-rw-r--r--net/ipv4/xfrm4_output.c16
-rw-r--r--net/ipv4/xfrm4_state.c1
-rw-r--r--net/ipv6/ip6_gre.c5
-rw-r--r--net/ipv6/ip6_output.c3
-rw-r--r--net/ipv6/ip6_tunnel.c6
-rw-r--r--net/ipv6/raw.c1
-rw-r--r--net/ipv6/sit.c5
-rw-r--r--net/ipv6/xfrm6_output.c21
-rw-r--r--net/ipv6/xfrm6_state.c1
-rw-r--r--net/xfrm/xfrm_output.c21
-rw-r--r--net/xfrm/xfrm_policy.c9
-rw-r--r--net/xfrm/xfrm_state.c7
15 files changed, 86 insertions, 32 deletions
diff --git a/include/net/route.h b/include/net/route.h
index 2ea40c1b5e00..afdeeb5bec25 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -317,4 +317,12 @@ static inline int ip4_dst_hoplimit(const struct dst_entry *dst)
317 return hoplimit; 317 return hoplimit;
318} 318}
319 319
320static inline int ip_skb_dst_mtu(struct sk_buff *skb)
321{
322 struct inet_sock *inet = skb->sk ? inet_sk(skb->sk) : NULL;
323
324 return (inet && inet->pmtudisc == IP_PMTUDISC_PROBE) ?
325 skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
326}
327
320#endif /* _ROUTE_H */ 328#endif /* _ROUTE_H */
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 94ce082b29dc..e823786e7c66 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -341,10 +341,13 @@ struct xfrm_state_afinfo {
341 struct sk_buff *skb); 341 struct sk_buff *skb);
342 int (*transport_finish)(struct sk_buff *skb, 342 int (*transport_finish)(struct sk_buff *skb,
343 int async); 343 int async);
344 void (*local_error)(struct sk_buff *skb, u32 mtu);
344}; 345};
345 346
346extern int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo); 347extern int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo);
347extern int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo); 348extern int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo);
349extern struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
350extern void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
348 351
349extern void xfrm_state_delete_tunnel(struct xfrm_state *x); 352extern void xfrm_state_delete_tunnel(struct xfrm_state *x);
350 353
@@ -1477,6 +1480,7 @@ extern int xfrm_input_resume(struct sk_buff *skb, int nexthdr);
1477extern int xfrm_output_resume(struct sk_buff *skb, int err); 1480extern int xfrm_output_resume(struct sk_buff *skb, int err);
1478extern int xfrm_output(struct sk_buff *skb); 1481extern int xfrm_output(struct sk_buff *skb);
1479extern int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb); 1482extern int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb);
1483extern void xfrm_local_error(struct sk_buff *skb, int mtu);
1480extern int xfrm4_extract_header(struct sk_buff *skb); 1484extern int xfrm4_extract_header(struct sk_buff *skb);
1481extern int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb); 1485extern int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb);
1482extern int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi, 1486extern int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
@@ -1497,6 +1501,7 @@ extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short fam
1497extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family); 1501extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family);
1498extern int xfrm4_mode_tunnel_input_register(struct xfrm_tunnel *handler); 1502extern int xfrm4_mode_tunnel_input_register(struct xfrm_tunnel *handler);
1499extern int xfrm4_mode_tunnel_input_deregister(struct xfrm_tunnel *handler); 1503extern int xfrm4_mode_tunnel_input_deregister(struct xfrm_tunnel *handler);
1504extern void xfrm4_local_error(struct sk_buff *skb, u32 mtu);
1500extern int xfrm6_extract_header(struct sk_buff *skb); 1505extern int xfrm6_extract_header(struct sk_buff *skb);
1501extern int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb); 1506extern int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb);
1502extern int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi); 1507extern int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi);
@@ -1514,6 +1519,7 @@ extern int xfrm6_output(struct sk_buff *skb);
1514extern int xfrm6_output_finish(struct sk_buff *skb); 1519extern int xfrm6_output_finish(struct sk_buff *skb);
1515extern int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb, 1520extern int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb,
1516 u8 **prevhdr); 1521 u8 **prevhdr);
1522extern void xfrm6_local_error(struct sk_buff *skb, u32 mtu);
1517 1523
1518#ifdef CONFIG_XFRM 1524#ifdef CONFIG_XFRM
1519extern int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb); 1525extern int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb);
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 4bcabf3ab4ca..9ee17e3d11c3 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -211,14 +211,6 @@ static inline int ip_finish_output2(struct sk_buff *skb)
211 return -EINVAL; 211 return -EINVAL;
212} 212}
213 213
214static inline int ip_skb_dst_mtu(struct sk_buff *skb)
215{
216 struct inet_sock *inet = skb->sk ? inet_sk(skb->sk) : NULL;
217
218 return (inet && inet->pmtudisc == IP_PMTUDISC_PROBE) ?
219 skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
220}
221
222static int ip_finish_output(struct sk_buff *skb) 214static int ip_finish_output(struct sk_buff *skb)
223{ 215{
224#if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM) 216#if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
index 327a617d594c..baa0f63731fd 100644
--- a/net/ipv4/xfrm4_output.c
+++ b/net/ipv4/xfrm4_output.c
@@ -21,7 +21,6 @@
21static int xfrm4_tunnel_check_size(struct sk_buff *skb) 21static int xfrm4_tunnel_check_size(struct sk_buff *skb)
22{ 22{
23 int mtu, ret = 0; 23 int mtu, ret = 0;
24 struct dst_entry *dst;
25 24
26 if (IPCB(skb)->flags & IPSKB_XFRM_TUNNEL_SIZE) 25 if (IPCB(skb)->flags & IPSKB_XFRM_TUNNEL_SIZE)
27 goto out; 26 goto out;
@@ -29,12 +28,10 @@ static int xfrm4_tunnel_check_size(struct sk_buff *skb)
29 if (!(ip_hdr(skb)->frag_off & htons(IP_DF)) || skb->local_df) 28 if (!(ip_hdr(skb)->frag_off & htons(IP_DF)) || skb->local_df)
30 goto out; 29 goto out;
31 30
32 dst = skb_dst(skb); 31 mtu = dst_mtu(skb_dst(skb));
33 mtu = dst_mtu(dst);
34 if (skb->len > mtu) { 32 if (skb->len > mtu) {
35 if (skb->sk) 33 if (skb->sk)
36 ip_local_error(skb->sk, EMSGSIZE, ip_hdr(skb)->daddr, 34 xfrm_local_error(skb, mtu);
37 inet_sk(skb->sk)->inet_dport, mtu);
38 else 35 else
39 icmp_send(skb, ICMP_DEST_UNREACH, 36 icmp_send(skb, ICMP_DEST_UNREACH,
40 ICMP_FRAG_NEEDED, htonl(mtu)); 37 ICMP_FRAG_NEEDED, htonl(mtu));
@@ -99,3 +96,12 @@ int xfrm4_output(struct sk_buff *skb)
99 x->outer_mode->afinfo->output_finish, 96 x->outer_mode->afinfo->output_finish,
100 !(IPCB(skb)->flags & IPSKB_REROUTED)); 97 !(IPCB(skb)->flags & IPSKB_REROUTED));
101} 98}
99
100void xfrm4_local_error(struct sk_buff *skb, u32 mtu)
101{
102 struct iphdr *hdr;
103
104 hdr = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb);
105 ip_local_error(skb->sk, EMSGSIZE, hdr->daddr,
106 inet_sk(skb->sk)->inet_dport, mtu);
107}
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c
index 9258e751baba..0b2a0641526a 100644
--- a/net/ipv4/xfrm4_state.c
+++ b/net/ipv4/xfrm4_state.c
@@ -83,6 +83,7 @@ static struct xfrm_state_afinfo xfrm4_state_afinfo = {
83 .extract_input = xfrm4_extract_input, 83 .extract_input = xfrm4_extract_input,
84 .extract_output = xfrm4_extract_output, 84 .extract_output = xfrm4_extract_output,
85 .transport_finish = xfrm4_transport_finish, 85 .transport_finish = xfrm4_transport_finish,
86 .local_error = xfrm4_local_error,
86}; 87};
87 88
88void __init xfrm4_state_init(void) 89void __init xfrm4_state_init(void)
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index ecd60733e5e2..90747f1973fe 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -724,6 +724,11 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
724 ipv6_push_nfrag_opts(skb, &opt.ops, &proto, NULL); 724 ipv6_push_nfrag_opts(skb, &opt.ops, &proto, NULL);
725 } 725 }
726 726
727 if (likely(!skb->encapsulation)) {
728 skb_reset_inner_headers(skb);
729 skb->encapsulation = 1;
730 }
731
727 skb_push(skb, gre_hlen); 732 skb_push(skb, gre_hlen);
728 skb_reset_network_header(skb); 733 skb_reset_network_header(skb);
729 skb_set_transport_header(skb, sizeof(*ipv6h)); 734 skb_set_transport_header(skb, sizeof(*ipv6h));
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 6e3ddf806ec2..e7ceb6c871d1 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -238,6 +238,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
238 hdr->saddr = fl6->saddr; 238 hdr->saddr = fl6->saddr;
239 hdr->daddr = *first_hop; 239 hdr->daddr = *first_hop;
240 240
241 skb->protocol = htons(ETH_P_IPV6);
241 skb->priority = sk->sk_priority; 242 skb->priority = sk->sk_priority;
242 skb->mark = sk->sk_mark; 243 skb->mark = sk->sk_mark;
243 244
@@ -1057,6 +1058,7 @@ static inline int ip6_ufo_append_data(struct sock *sk,
1057 /* initialize protocol header pointer */ 1058 /* initialize protocol header pointer */
1058 skb->transport_header = skb->network_header + fragheaderlen; 1059 skb->transport_header = skb->network_header + fragheaderlen;
1059 1060
1061 skb->protocol = htons(ETH_P_IPV6);
1060 skb->ip_summed = CHECKSUM_PARTIAL; 1062 skb->ip_summed = CHECKSUM_PARTIAL;
1061 skb->csum = 0; 1063 skb->csum = 0;
1062 } 1064 }
@@ -1359,6 +1361,7 @@ alloc_new_skb:
1359 /* 1361 /*
1360 * Fill in the control structures 1362 * Fill in the control structures
1361 */ 1363 */
1364 skb->protocol = htons(ETH_P_IPV6);
1362 skb->ip_summed = CHECKSUM_NONE; 1365 skb->ip_summed = CHECKSUM_NONE;
1363 skb->csum = 0; 1366 skb->csum = 0;
1364 /* reserve for fragmentation and ipsec header */ 1367 /* reserve for fragmentation and ipsec header */
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 1e55866cead7..46ba243605a3 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -1027,6 +1027,12 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
1027 init_tel_txopt(&opt, encap_limit); 1027 init_tel_txopt(&opt, encap_limit);
1028 ipv6_push_nfrag_opts(skb, &opt.ops, &proto, NULL); 1028 ipv6_push_nfrag_opts(skb, &opt.ops, &proto, NULL);
1029 } 1029 }
1030
1031 if (likely(!skb->encapsulation)) {
1032 skb_reset_inner_headers(skb);
1033 skb->encapsulation = 1;
1034 }
1035
1030 skb_push(skb, sizeof(struct ipv6hdr)); 1036 skb_push(skb, sizeof(struct ipv6hdr));
1031 skb_reset_network_header(skb); 1037 skb_reset_network_header(skb);
1032 ipv6h = ipv6_hdr(skb); 1038 ipv6h = ipv6_hdr(skb);
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index c45f7a5c36e9..cdaed47ba932 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -628,6 +628,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
628 goto error; 628 goto error;
629 skb_reserve(skb, hlen); 629 skb_reserve(skb, hlen);
630 630
631 skb->protocol = htons(ETH_P_IPV6);
631 skb->priority = sk->sk_priority; 632 skb->priority = sk->sk_priority;
632 skb->mark = sk->sk_mark; 633 skb->mark = sk->sk_mark;
633 skb_dst_set(skb, &rt->dst); 634 skb_dst_set(skb, &rt->dst);
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index a3437a4cd07e..fbfc5a83867f 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -888,6 +888,11 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
888 ttl = iph6->hop_limit; 888 ttl = iph6->hop_limit;
889 tos = INET_ECN_encapsulate(tos, ipv6_get_dsfield(iph6)); 889 tos = INET_ECN_encapsulate(tos, ipv6_get_dsfield(iph6));
890 890
891 if (likely(!skb->encapsulation)) {
892 skb_reset_inner_headers(skb);
893 skb->encapsulation = 1;
894 }
895
891 err = iptunnel_xmit(dev_net(dev), rt, skb, fl4.saddr, fl4.daddr, 896 err = iptunnel_xmit(dev_net(dev), rt, skb, fl4.saddr, fl4.daddr,
892 IPPROTO_IPV6, tos, ttl, df); 897 IPPROTO_IPV6, tos, ttl, df);
893 iptunnel_xmit_stats(err, &dev->stats, dev->tstats); 898 iptunnel_xmit_stats(err, &dev->stats, dev->tstats);
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
index 8755a3079d0f..6cd625e37706 100644
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -34,8 +34,10 @@ static int xfrm6_local_dontfrag(struct sk_buff *skb)
34 struct sock *sk = skb->sk; 34 struct sock *sk = skb->sk;
35 35
36 if (sk) { 36 if (sk) {
37 proto = sk->sk_protocol; 37 if (sk->sk_family != AF_INET6)
38 return 0;
38 39
40 proto = sk->sk_protocol;
39 if (proto == IPPROTO_UDP || proto == IPPROTO_RAW) 41 if (proto == IPPROTO_UDP || proto == IPPROTO_RAW)
40 return inet6_sk(sk)->dontfrag; 42 return inet6_sk(sk)->dontfrag;
41 } 43 }
@@ -54,13 +56,15 @@ static void xfrm6_local_rxpmtu(struct sk_buff *skb, u32 mtu)
54 ipv6_local_rxpmtu(sk, &fl6, mtu); 56 ipv6_local_rxpmtu(sk, &fl6, mtu);
55} 57}
56 58
57static void xfrm6_local_error(struct sk_buff *skb, u32 mtu) 59void xfrm6_local_error(struct sk_buff *skb, u32 mtu)
58{ 60{
59 struct flowi6 fl6; 61 struct flowi6 fl6;
62 const struct ipv6hdr *hdr;
60 struct sock *sk = skb->sk; 63 struct sock *sk = skb->sk;
61 64
65 hdr = skb->encapsulation ? inner_ipv6_hdr(skb) : ipv6_hdr(skb);
62 fl6.fl6_dport = inet_sk(sk)->inet_dport; 66 fl6.fl6_dport = inet_sk(sk)->inet_dport;
63 fl6.daddr = ipv6_hdr(skb)->daddr; 67 fl6.daddr = hdr->daddr;
64 68
65 ipv6_local_error(sk, EMSGSIZE, &fl6, mtu); 69 ipv6_local_error(sk, EMSGSIZE, &fl6, mtu);
66} 70}
@@ -80,7 +84,7 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb)
80 if (xfrm6_local_dontfrag(skb)) 84 if (xfrm6_local_dontfrag(skb))
81 xfrm6_local_rxpmtu(skb, mtu); 85 xfrm6_local_rxpmtu(skb, mtu);
82 else if (skb->sk) 86 else if (skb->sk)
83 xfrm6_local_error(skb, mtu); 87 xfrm_local_error(skb, mtu);
84 else 88 else
85 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); 89 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
86 ret = -EMSGSIZE; 90 ret = -EMSGSIZE;
@@ -136,13 +140,18 @@ static int __xfrm6_output(struct sk_buff *skb)
136{ 140{
137 struct dst_entry *dst = skb_dst(skb); 141 struct dst_entry *dst = skb_dst(skb);
138 struct xfrm_state *x = dst->xfrm; 142 struct xfrm_state *x = dst->xfrm;
139 int mtu = ip6_skb_dst_mtu(skb); 143 int mtu;
144
145 if (skb->protocol == htons(ETH_P_IPV6))
146 mtu = ip6_skb_dst_mtu(skb);
147 else
148 mtu = dst_mtu(skb_dst(skb));
140 149
141 if (skb->len > mtu && xfrm6_local_dontfrag(skb)) { 150 if (skb->len > mtu && xfrm6_local_dontfrag(skb)) {
142 xfrm6_local_rxpmtu(skb, mtu); 151 xfrm6_local_rxpmtu(skb, mtu);
143 return -EMSGSIZE; 152 return -EMSGSIZE;
144 } else if (!skb->local_df && skb->len > mtu && skb->sk) { 153 } else if (!skb->local_df && skb->len > mtu && skb->sk) {
145 xfrm6_local_error(skb, mtu); 154 xfrm_local_error(skb, mtu);
146 return -EMSGSIZE; 155 return -EMSGSIZE;
147 } 156 }
148 157
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
index d8c70b8efc24..3fc970135fc6 100644
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -183,6 +183,7 @@ static struct xfrm_state_afinfo xfrm6_state_afinfo = {
183 .extract_input = xfrm6_extract_input, 183 .extract_input = xfrm6_extract_input,
184 .extract_output = xfrm6_extract_output, 184 .extract_output = xfrm6_extract_output,
185 .transport_finish = xfrm6_transport_finish, 185 .transport_finish = xfrm6_transport_finish,
186 .local_error = xfrm6_local_error,
186}; 187};
187 188
188int __init xfrm6_state_init(void) 189int __init xfrm6_state_init(void)
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
index eb4a84288648..3bb2cdc13b46 100644
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -214,5 +214,26 @@ int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb)
214 return inner_mode->afinfo->extract_output(x, skb); 214 return inner_mode->afinfo->extract_output(x, skb);
215} 215}
216 216
217void xfrm_local_error(struct sk_buff *skb, int mtu)
218{
219 unsigned int proto;
220 struct xfrm_state_afinfo *afinfo;
221
222 if (skb->protocol == htons(ETH_P_IP))
223 proto = AF_INET;
224 else if (skb->protocol == htons(ETH_P_IPV6))
225 proto = AF_INET6;
226 else
227 return;
228
229 afinfo = xfrm_state_get_afinfo(proto);
230 if (!afinfo)
231 return;
232
233 afinfo->local_error(skb, mtu);
234 xfrm_state_put_afinfo(afinfo);
235}
236
217EXPORT_SYMBOL_GPL(xfrm_output); 237EXPORT_SYMBOL_GPL(xfrm_output);
218EXPORT_SYMBOL_GPL(xfrm_inner_extract_output); 238EXPORT_SYMBOL_GPL(xfrm_inner_extract_output);
239EXPORT_SYMBOL_GPL(xfrm_local_error);
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index e52cab3591dd..f77c371ea72b 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -320,10 +320,8 @@ static void xfrm_queue_purge(struct sk_buff_head *list)
320{ 320{
321 struct sk_buff *skb; 321 struct sk_buff *skb;
322 322
323 while ((skb = skb_dequeue(list)) != NULL) { 323 while ((skb = skb_dequeue(list)) != NULL)
324 dev_put(skb->dev);
325 kfree_skb(skb); 324 kfree_skb(skb);
326 }
327} 325}
328 326
329/* Rule must be locked. Release descentant resources, announce 327/* Rule must be locked. Release descentant resources, announce
@@ -1758,7 +1756,6 @@ static void xfrm_policy_queue_process(unsigned long arg)
1758 struct sk_buff *skb; 1756 struct sk_buff *skb;
1759 struct sock *sk; 1757 struct sock *sk;
1760 struct dst_entry *dst; 1758 struct dst_entry *dst;
1761 struct net_device *dev;
1762 struct xfrm_policy *pol = (struct xfrm_policy *)arg; 1759 struct xfrm_policy *pol = (struct xfrm_policy *)arg;
1763 struct xfrm_policy_queue *pq = &pol->polq; 1760 struct xfrm_policy_queue *pq = &pol->polq;
1764 struct flowi fl; 1761 struct flowi fl;
@@ -1805,7 +1802,6 @@ static void xfrm_policy_queue_process(unsigned long arg)
1805 dst = xfrm_lookup(xp_net(pol), skb_dst(skb)->path, 1802 dst = xfrm_lookup(xp_net(pol), skb_dst(skb)->path,
1806 &fl, skb->sk, 0); 1803 &fl, skb->sk, 0);
1807 if (IS_ERR(dst)) { 1804 if (IS_ERR(dst)) {
1808 dev_put(skb->dev);
1809 kfree_skb(skb); 1805 kfree_skb(skb);
1810 continue; 1806 continue;
1811 } 1807 }
@@ -1814,9 +1810,7 @@ static void xfrm_policy_queue_process(unsigned long arg)
1814 skb_dst_drop(skb); 1810 skb_dst_drop(skb);
1815 skb_dst_set(skb, dst); 1811 skb_dst_set(skb, dst);
1816 1812
1817 dev = skb->dev;
1818 err = dst_output(skb); 1813 err = dst_output(skb);
1819 dev_put(dev);
1820 } 1814 }
1821 1815
1822 return; 1816 return;
@@ -1839,7 +1833,6 @@ static int xdst_queue_output(struct sk_buff *skb)
1839 } 1833 }
1840 1834
1841 skb_dst_force(skb); 1835 skb_dst_force(skb);
1842 dev_hold(skb->dev);
1843 1836
1844 spin_lock_bh(&pq->hold_queue.lock); 1837 spin_lock_bh(&pq->hold_queue.lock);
1845 1838
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 78f66fa92449..54c0acd29468 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -39,9 +39,6 @@ static DEFINE_SPINLOCK(xfrm_state_lock);
39 39
40static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; 40static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
41 41
42static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
43static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
44
45static inline unsigned int xfrm_dst_hash(struct net *net, 42static inline unsigned int xfrm_dst_hash(struct net *net,
46 const xfrm_address_t *daddr, 43 const xfrm_address_t *daddr,
47 const xfrm_address_t *saddr, 44 const xfrm_address_t *saddr,
@@ -1860,7 +1857,7 @@ int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo)
1860} 1857}
1861EXPORT_SYMBOL(xfrm_state_unregister_afinfo); 1858EXPORT_SYMBOL(xfrm_state_unregister_afinfo);
1862 1859
1863static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family) 1860struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
1864{ 1861{
1865 struct xfrm_state_afinfo *afinfo; 1862 struct xfrm_state_afinfo *afinfo;
1866 if (unlikely(family >= NPROTO)) 1863 if (unlikely(family >= NPROTO))
@@ -1872,7 +1869,7 @@ static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
1872 return afinfo; 1869 return afinfo;
1873} 1870}
1874 1871
1875static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) 1872void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo)
1876{ 1873{
1877 rcu_read_unlock(); 1874 rcu_read_unlock();
1878} 1875}