diff options
Diffstat (limited to 'net/ipv4/xfrm4_output.c')
-rw-r--r-- | net/ipv4/xfrm4_output.c | 76 |
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 | } |
68 | EXPORT_SYMBOL(xfrm4_prepare_output); | 68 | EXPORT_SYMBOL(xfrm4_prepare_output); |
69 | 69 | ||
70 | static 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 | |||
81 | out_exit: | ||
82 | return err; | ||
83 | error_nolock: | ||
84 | kfree_skb(skb); | ||
85 | goto out_exit; | ||
86 | } | ||
87 | |||
88 | static 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 | |||
111 | static int xfrm4_output_finish(struct sk_buff *skb) | 70 | static 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 | ||
153 | int xfrm4_output(struct sk_buff *skb) | 85 | int xfrm4_output(struct sk_buff *skb) |