aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/xfrm4_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/xfrm4_output.c')
-rw-r--r--net/ipv4/xfrm4_output.c76
1 files changed, 4 insertions, 72 deletions
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
index 0ffc3d078489..2fb4efa3ff2c 100644
--- a/net/ipv4/xfrm4_output.c
+++ b/net/ipv4/xfrm4_output.c
@@ -59,7 +59,7 @@ int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
59 return err; 59 return err;
60 60
61 memset(IPCB(skb), 0, sizeof(*IPCB(skb))); 61 memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
62 IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE; 62 IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED;
63 63
64 skb->protocol = htons(ETH_P_IP); 64 skb->protocol = htons(ETH_P_IP);
65 65
@@ -67,87 +67,19 @@ int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
67} 67}
68EXPORT_SYMBOL(xfrm4_prepare_output); 68EXPORT_SYMBOL(xfrm4_prepare_output);
69 69
70static inline int xfrm4_output_one(struct sk_buff *skb)
71{
72 int err;
73
74 err = xfrm_output(skb);
75 if (err)
76 goto error_nolock;
77
78 IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
79 err = 0;
80
81out_exit:
82 return err;
83error_nolock:
84 kfree_skb(skb);
85 goto out_exit;
86}
87
88static int xfrm4_output_finish2(struct sk_buff *skb)
89{
90 int err;
91
92 while (likely((err = xfrm4_output_one(skb)) == 0)) {
93 nf_reset(skb);
94
95 err = __ip_local_out(skb);
96 if (unlikely(err != 1))
97 break;
98
99 if (!skb->dst->xfrm)
100 return dst_output(skb);
101
102 err = nf_hook(PF_INET, NF_IP_POST_ROUTING, skb, NULL,
103 skb->dst->dev, xfrm4_output_finish2);
104 if (unlikely(err != 1))
105 break;
106 }
107
108 return err;
109}
110
111static int xfrm4_output_finish(struct sk_buff *skb) 70static int xfrm4_output_finish(struct sk_buff *skb)
112{ 71{
113 struct sk_buff *segs;
114
115#ifdef CONFIG_NETFILTER 72#ifdef CONFIG_NETFILTER
116 if (!skb->dst->xfrm) { 73 if (!skb->dst->xfrm) {
117 IPCB(skb)->flags |= IPSKB_REROUTED; 74 IPCB(skb)->flags |= IPSKB_REROUTED;
118 return dst_output(skb); 75 return dst_output(skb);
119 } 76 }
120#endif
121 77
122 if (!skb_is_gso(skb)) 78 IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
123 return xfrm4_output_finish2(skb); 79#endif
124 80
125 skb->protocol = htons(ETH_P_IP); 81 skb->protocol = htons(ETH_P_IP);
126 segs = skb_gso_segment(skb, 0); 82 return xfrm_output(skb);
127 kfree_skb(skb);
128 if (unlikely(IS_ERR(segs)))
129 return PTR_ERR(segs);
130
131 do {
132 struct sk_buff *nskb = segs->next;
133 int err;
134
135 segs->next = NULL;
136 err = xfrm4_output_finish2(segs);
137
138 if (unlikely(err)) {
139 while ((segs = nskb)) {
140 nskb = segs->next;
141 segs->next = NULL;
142 kfree_skb(segs);
143 }
144 return err;
145 }
146
147 segs = nskb;
148 } while (segs);
149
150 return 0;
151} 83}
152 84
153int xfrm4_output(struct sk_buff *skb) 85int xfrm4_output(struct sk_buff *skb)