diff options
-rw-r--r-- | include/net/route.h | 8 | ||||
-rw-r--r-- | include/net/xfrm.h | 6 | ||||
-rw-r--r-- | net/ipv4/ip_output.c | 8 | ||||
-rw-r--r-- | net/ipv4/xfrm4_output.c | 16 | ||||
-rw-r--r-- | net/ipv4/xfrm4_state.c | 1 | ||||
-rw-r--r-- | net/ipv6/ip6_gre.c | 5 | ||||
-rw-r--r-- | net/ipv6/ip6_output.c | 3 | ||||
-rw-r--r-- | net/ipv6/ip6_tunnel.c | 6 | ||||
-rw-r--r-- | net/ipv6/raw.c | 1 | ||||
-rw-r--r-- | net/ipv6/sit.c | 5 | ||||
-rw-r--r-- | net/ipv6/xfrm6_output.c | 21 | ||||
-rw-r--r-- | net/ipv6/xfrm6_state.c | 1 | ||||
-rw-r--r-- | net/xfrm/xfrm_output.c | 21 | ||||
-rw-r--r-- | net/xfrm/xfrm_policy.c | 9 | ||||
-rw-r--r-- | net/xfrm/xfrm_state.c | 7 |
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 | ||
320 | static 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 | ||
346 | extern int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo); | 347 | extern int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo); |
347 | extern int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo); | 348 | extern int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo); |
349 | extern struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); | ||
350 | extern void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); | ||
348 | 351 | ||
349 | extern void xfrm_state_delete_tunnel(struct xfrm_state *x); | 352 | extern 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); | |||
1477 | extern int xfrm_output_resume(struct sk_buff *skb, int err); | 1480 | extern int xfrm_output_resume(struct sk_buff *skb, int err); |
1478 | extern int xfrm_output(struct sk_buff *skb); | 1481 | extern int xfrm_output(struct sk_buff *skb); |
1479 | extern int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb); | 1482 | extern int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb); |
1483 | extern void xfrm_local_error(struct sk_buff *skb, int mtu); | ||
1480 | extern int xfrm4_extract_header(struct sk_buff *skb); | 1484 | extern int xfrm4_extract_header(struct sk_buff *skb); |
1481 | extern int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb); | 1485 | extern int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb); |
1482 | extern int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi, | 1486 | extern 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 | |||
1497 | extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family); | 1501 | extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family); |
1498 | extern int xfrm4_mode_tunnel_input_register(struct xfrm_tunnel *handler); | 1502 | extern int xfrm4_mode_tunnel_input_register(struct xfrm_tunnel *handler); |
1499 | extern int xfrm4_mode_tunnel_input_deregister(struct xfrm_tunnel *handler); | 1503 | extern int xfrm4_mode_tunnel_input_deregister(struct xfrm_tunnel *handler); |
1504 | extern void xfrm4_local_error(struct sk_buff *skb, u32 mtu); | ||
1500 | extern int xfrm6_extract_header(struct sk_buff *skb); | 1505 | extern int xfrm6_extract_header(struct sk_buff *skb); |
1501 | extern int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb); | 1506 | extern int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb); |
1502 | extern int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi); | 1507 | extern int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi); |
@@ -1514,6 +1519,7 @@ extern int xfrm6_output(struct sk_buff *skb); | |||
1514 | extern int xfrm6_output_finish(struct sk_buff *skb); | 1519 | extern int xfrm6_output_finish(struct sk_buff *skb); |
1515 | extern int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb, | 1520 | extern int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb, |
1516 | u8 **prevhdr); | 1521 | u8 **prevhdr); |
1522 | extern void xfrm6_local_error(struct sk_buff *skb, u32 mtu); | ||
1517 | 1523 | ||
1518 | #ifdef CONFIG_XFRM | 1524 | #ifdef CONFIG_XFRM |
1519 | extern int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb); | 1525 | extern 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 | ||
214 | static 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 | |||
222 | static int ip_finish_output(struct sk_buff *skb) | 214 | static 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 @@ | |||
21 | static int xfrm4_tunnel_check_size(struct sk_buff *skb) | 21 | static 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 | |||
100 | void 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 | ||
88 | void __init xfrm4_state_init(void) | 89 | void __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 | ||
57 | static void xfrm6_local_error(struct sk_buff *skb, u32 mtu) | 59 | void 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 | ||
188 | int __init xfrm6_state_init(void) | 189 | int __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 | ||
217 | void 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 | |||
217 | EXPORT_SYMBOL_GPL(xfrm_output); | 237 | EXPORT_SYMBOL_GPL(xfrm_output); |
218 | EXPORT_SYMBOL_GPL(xfrm_inner_extract_output); | 238 | EXPORT_SYMBOL_GPL(xfrm_inner_extract_output); |
239 | EXPORT_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 | ||
40 | static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; | 40 | static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; |
41 | 41 | ||
42 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); | ||
43 | static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); | ||
44 | |||
45 | static inline unsigned int xfrm_dst_hash(struct net *net, | 42 | static 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 | } |
1861 | EXPORT_SYMBOL(xfrm_state_unregister_afinfo); | 1858 | EXPORT_SYMBOL(xfrm_state_unregister_afinfo); |
1862 | 1859 | ||
1863 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family) | 1860 | struct 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 | ||
1875 | static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) | 1872 | void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) |
1876 | { | 1873 | { |
1877 | rcu_read_unlock(); | 1874 | rcu_read_unlock(); |
1878 | } | 1875 | } |