diff options
Diffstat (limited to 'net/ipv6/xfrm6_output.c')
-rw-r--r-- | net/ipv6/xfrm6_output.c | 39 |
1 files changed, 37 insertions, 2 deletions
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index 16e84254a252..48fccb1eca08 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c | |||
@@ -94,7 +94,7 @@ error_nolock: | |||
94 | goto out_exit; | 94 | goto out_exit; |
95 | } | 95 | } |
96 | 96 | ||
97 | static int xfrm6_output_finish(struct sk_buff *skb) | 97 | static int xfrm6_output_finish2(struct sk_buff *skb) |
98 | { | 98 | { |
99 | int err; | 99 | int err; |
100 | 100 | ||
@@ -110,7 +110,7 @@ static int xfrm6_output_finish(struct sk_buff *skb) | |||
110 | return dst_output(skb); | 110 | return dst_output(skb); |
111 | 111 | ||
112 | err = nf_hook(PF_INET6, NF_IP6_POST_ROUTING, &skb, NULL, | 112 | err = nf_hook(PF_INET6, NF_IP6_POST_ROUTING, &skb, NULL, |
113 | skb->dst->dev, xfrm6_output_finish); | 113 | skb->dst->dev, xfrm6_output_finish2); |
114 | if (unlikely(err != 1)) | 114 | if (unlikely(err != 1)) |
115 | break; | 115 | break; |
116 | } | 116 | } |
@@ -118,6 +118,41 @@ static int xfrm6_output_finish(struct sk_buff *skb) | |||
118 | return err; | 118 | return err; |
119 | } | 119 | } |
120 | 120 | ||
121 | static int xfrm6_output_finish(struct sk_buff *skb) | ||
122 | { | ||
123 | struct sk_buff *segs; | ||
124 | |||
125 | if (!skb_shinfo(skb)->gso_size) | ||
126 | return xfrm6_output_finish2(skb); | ||
127 | |||
128 | skb->protocol = htons(ETH_P_IP); | ||
129 | segs = skb_gso_segment(skb, 0); | ||
130 | kfree_skb(skb); | ||
131 | if (unlikely(IS_ERR(segs))) | ||
132 | return PTR_ERR(segs); | ||
133 | |||
134 | do { | ||
135 | struct sk_buff *nskb = segs->next; | ||
136 | int err; | ||
137 | |||
138 | segs->next = NULL; | ||
139 | err = xfrm6_output_finish2(segs); | ||
140 | |||
141 | if (unlikely(err)) { | ||
142 | while ((segs = nskb)) { | ||
143 | nskb = segs->next; | ||
144 | segs->next = NULL; | ||
145 | kfree_skb(segs); | ||
146 | } | ||
147 | return err; | ||
148 | } | ||
149 | |||
150 | segs = nskb; | ||
151 | } while (segs); | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
121 | int xfrm6_output(struct sk_buff *skb) | 156 | int xfrm6_output(struct sk_buff *skb) |
122 | { | 157 | { |
123 | return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb, NULL, skb->dst->dev, | 158 | return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb, NULL, skb->dst->dev, |