aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/ip6_route.h10
-rw-r--r--net/ipv6/ip6_output.c12
-rw-r--r--net/ipv6/xfrm6_output.c16
3 files changed, 27 insertions, 11 deletions
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index 278312c95f9..2ab926860cd 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -164,5 +164,15 @@ static inline int ipv6_unicast_destination(struct sk_buff *skb)
164 return rt->rt6i_flags & RTF_LOCAL; 164 return rt->rt6i_flags & RTF_LOCAL;
165} 165}
166 166
167int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *));
168
169static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
170{
171 struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL;
172
173 return (np && np->pmtudisc == IPV6_PMTUDISC_PROBE) ?
174 skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
175}
176
167#endif 177#endif
168#endif 178#endif
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 99157b4cd56..94b5bf132b2 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -56,7 +56,7 @@
56#include <net/checksum.h> 56#include <net/checksum.h>
57#include <linux/mroute6.h> 57#include <linux/mroute6.h>
58 58
59static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)); 59int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *));
60 60
61int __ip6_local_out(struct sk_buff *skb) 61int __ip6_local_out(struct sk_buff *skb)
62{ 62{
@@ -145,14 +145,6 @@ static int ip6_finish_output2(struct sk_buff *skb)
145 return -EINVAL; 145 return -EINVAL;
146} 146}
147 147
148static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
149{
150 struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL;
151
152 return (np && np->pmtudisc == IPV6_PMTUDISC_PROBE) ?
153 skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
154}
155
156static int ip6_finish_output(struct sk_buff *skb) 148static int ip6_finish_output(struct sk_buff *skb)
157{ 149{
158 if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) || 150 if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
@@ -601,7 +593,7 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
601 return offset; 593 return offset;
602} 594}
603 595
604static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) 596int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
605{ 597{
606 struct sk_buff *frag; 598 struct sk_buff *frag;
607 struct rt6_info *rt = (struct rt6_info*)skb_dst(skb); 599 struct rt6_info *rt = (struct rt6_info*)skb_dst(skb);
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
index 6434bd5ce08..8e688b3de9a 100644
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -17,6 +17,7 @@
17#include <linux/netfilter_ipv6.h> 17#include <linux/netfilter_ipv6.h>
18#include <net/dst.h> 18#include <net/dst.h>
19#include <net/ipv6.h> 19#include <net/ipv6.h>
20#include <net/ip6_route.h>
20#include <net/xfrm.h> 21#include <net/xfrm.h>
21 22
22int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb, 23int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb,
@@ -88,8 +89,21 @@ static int xfrm6_output_finish(struct sk_buff *skb)
88 return xfrm_output(skb); 89 return xfrm_output(skb);
89} 90}
90 91
92static int __xfrm6_output(struct sk_buff *skb)
93{
94 struct dst_entry *dst = skb_dst(skb);
95 struct xfrm_state *x = dst->xfrm;
96
97 if ((x && x->props.mode == XFRM_MODE_TUNNEL) &&
98 ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
99 dst_allfrag(skb_dst(skb)))) {
100 return ip6_fragment(skb, xfrm6_output_finish);
101 }
102 return xfrm6_output_finish(skb);
103}
104
91int xfrm6_output(struct sk_buff *skb) 105int xfrm6_output(struct sk_buff *skb)
92{ 106{
93 return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL, 107 return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL,
94 skb_dst(skb)->dev, xfrm6_output_finish); 108 skb_dst(skb)->dev, __xfrm6_output);
95} 109}