aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/xfrm6_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/xfrm6_output.c')
-rw-r--r--net/ipv6/xfrm6_output.c77
1 files changed, 7 insertions, 70 deletions
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
index 0f0ff51f6dba..a0a924991c4f 100644
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -66,6 +66,9 @@ int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
66 return err; 66 return err;
67 67
68 memset(IP6CB(skb), 0, sizeof(*IP6CB(skb))); 68 memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
69#ifdef CONFIG_NETFILTER
70 IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
71#endif
69 72
70 skb->protocol = htons(ETH_P_IPV6); 73 skb->protocol = htons(ETH_P_IPV6);
71 74
@@ -73,80 +76,14 @@ int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
73} 76}
74EXPORT_SYMBOL(xfrm6_prepare_output); 77EXPORT_SYMBOL(xfrm6_prepare_output);
75 78
76static inline int xfrm6_output_one(struct sk_buff *skb)
77{
78 int err;
79
80 err = xfrm_output(skb);
81 if (err)
82 goto error_nolock;
83
84 IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
85 err = 0;
86
87out_exit:
88 return err;
89error_nolock:
90 kfree_skb(skb);
91 goto out_exit;
92}
93
94static int xfrm6_output_finish2(struct sk_buff *skb)
95{
96 int err;
97
98 while (likely((err = xfrm6_output_one(skb)) == 0)) {
99 nf_reset(skb);
100
101 err = __ip6_local_out(skb);
102 if (unlikely(err != 1))
103 break;
104
105 if (!skb->dst->xfrm)
106 return dst_output(skb);
107
108 err = nf_hook(PF_INET6, NF_IP6_POST_ROUTING, skb, NULL,
109 skb->dst->dev, xfrm6_output_finish2);
110 if (unlikely(err != 1))
111 break;
112 }
113
114 return err;
115}
116
117static int xfrm6_output_finish(struct sk_buff *skb) 79static int xfrm6_output_finish(struct sk_buff *skb)
118{ 80{
119 struct sk_buff *segs; 81#ifdef CONFIG_NETFILTER
120 82 IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
121 if (!skb_is_gso(skb)) 83#endif
122 return xfrm6_output_finish2(skb);
123 84
124 skb->protocol = htons(ETH_P_IPV6); 85 skb->protocol = htons(ETH_P_IPV6);
125 segs = skb_gso_segment(skb, 0); 86 return xfrm_output(skb);
126 kfree_skb(skb);
127 if (unlikely(IS_ERR(segs)))
128 return PTR_ERR(segs);
129
130 do {
131 struct sk_buff *nskb = segs->next;
132 int err;
133
134 segs->next = NULL;
135 err = xfrm6_output_finish2(segs);
136
137 if (unlikely(err)) {
138 while ((segs = nskb)) {
139 nskb = segs->next;
140 segs->next = NULL;
141 kfree_skb(segs);
142 }
143 return err;
144 }
145
146 segs = nskb;
147 } while (segs);
148
149 return 0;
150} 87}
151 88
152int xfrm6_output(struct sk_buff *skb) 89int xfrm6_output(struct sk_buff *skb)