diff options
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/esp4.c | 87 |
1 files changed, 43 insertions, 44 deletions
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 73bfcae8af9c..3f47419cb9c5 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c | |||
@@ -150,6 +150,10 @@ static int esp_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struc | |||
150 | int elen = skb->len - sizeof(struct ip_esp_hdr) - esp->conf.ivlen - alen; | 150 | int elen = skb->len - sizeof(struct ip_esp_hdr) - esp->conf.ivlen - alen; |
151 | int nfrags; | 151 | int nfrags; |
152 | int encap_len = 0; | 152 | int encap_len = 0; |
153 | u8 nexthdr[2]; | ||
154 | struct scatterlist *sg; | ||
155 | u8 workbuf[60]; | ||
156 | int padlen; | ||
153 | 157 | ||
154 | if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr))) | 158 | if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr))) |
155 | goto out; | 159 | goto out; |
@@ -185,61 +189,56 @@ static int esp_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struc | |||
185 | if (esp->conf.ivlen) | 189 | if (esp->conf.ivlen) |
186 | crypto_cipher_set_iv(esp->conf.tfm, esph->enc_data, crypto_tfm_alg_ivsize(esp->conf.tfm)); | 190 | crypto_cipher_set_iv(esp->conf.tfm, esph->enc_data, crypto_tfm_alg_ivsize(esp->conf.tfm)); |
187 | 191 | ||
188 | { | 192 | sg = &esp->sgbuf[0]; |
189 | u8 nexthdr[2]; | ||
190 | struct scatterlist *sg = &esp->sgbuf[0]; | ||
191 | u8 workbuf[60]; | ||
192 | int padlen; | ||
193 | 193 | ||
194 | if (unlikely(nfrags > ESP_NUM_FAST_SG)) { | 194 | if (unlikely(nfrags > ESP_NUM_FAST_SG)) { |
195 | sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); | 195 | sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); |
196 | if (!sg) | 196 | if (!sg) |
197 | goto out; | 197 | goto out; |
198 | } | 198 | } |
199 | skb_to_sgvec(skb, sg, sizeof(struct ip_esp_hdr) + esp->conf.ivlen, elen); | 199 | skb_to_sgvec(skb, sg, sizeof(struct ip_esp_hdr) + esp->conf.ivlen, elen); |
200 | crypto_cipher_decrypt(esp->conf.tfm, sg, sg, elen); | 200 | crypto_cipher_decrypt(esp->conf.tfm, sg, sg, elen); |
201 | if (unlikely(sg != &esp->sgbuf[0])) | 201 | if (unlikely(sg != &esp->sgbuf[0])) |
202 | kfree(sg); | 202 | kfree(sg); |
203 | 203 | ||
204 | if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2)) | 204 | if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2)) |
205 | BUG(); | 205 | BUG(); |
206 | 206 | ||
207 | padlen = nexthdr[0]; | 207 | padlen = nexthdr[0]; |
208 | if (padlen+2 >= elen) | 208 | if (padlen+2 >= elen) |
209 | goto out; | 209 | goto out; |
210 | 210 | ||
211 | /* ... check padding bits here. Silly. :-) */ | 211 | /* ... check padding bits here. Silly. :-) */ |
212 | 212 | ||
213 | if (x->encap && decap && decap->decap_type) { | 213 | if (x->encap && decap && decap->decap_type) { |
214 | struct esp_decap_data *encap_data; | 214 | struct esp_decap_data *encap_data; |
215 | struct udphdr *uh = (struct udphdr *) (iph+1); | 215 | struct udphdr *uh = (struct udphdr *) (iph+1); |
216 | 216 | ||
217 | encap_data = (struct esp_decap_data *) (decap->decap_data); | 217 | encap_data = (struct esp_decap_data *) (decap->decap_data); |
218 | encap_data->proto = 0; | 218 | encap_data->proto = 0; |
219 | 219 | ||
220 | switch (decap->decap_type) { | 220 | switch (decap->decap_type) { |
221 | case UDP_ENCAP_ESPINUDP: | 221 | case UDP_ENCAP_ESPINUDP: |
222 | case UDP_ENCAP_ESPINUDP_NON_IKE: | 222 | case UDP_ENCAP_ESPINUDP_NON_IKE: |
223 | encap_data->proto = AF_INET; | 223 | encap_data->proto = AF_INET; |
224 | encap_data->saddr.a4 = iph->saddr; | 224 | encap_data->saddr.a4 = iph->saddr; |
225 | encap_data->sport = uh->source; | 225 | encap_data->sport = uh->source; |
226 | encap_len = (void*)esph - (void*)uh; | 226 | encap_len = (void*)esph - (void*)uh; |
227 | break; | 227 | break; |
228 | 228 | ||
229 | default: | 229 | default: |
230 | goto out; | 230 | goto out; |
231 | } | ||
232 | } | 231 | } |
233 | |||
234 | iph->protocol = nexthdr[1]; | ||
235 | pskb_trim(skb, skb->len - alen - padlen - 2); | ||
236 | memcpy(workbuf, skb->nh.raw, iph->ihl*4); | ||
237 | skb->h.raw = skb_pull(skb, sizeof(struct ip_esp_hdr) + esp->conf.ivlen); | ||
238 | skb->nh.raw += encap_len + sizeof(struct ip_esp_hdr) + esp->conf.ivlen; | ||
239 | memcpy(skb->nh.raw, workbuf, iph->ihl*4); | ||
240 | skb->nh.iph->tot_len = htons(skb->len); | ||
241 | } | 232 | } |
242 | 233 | ||
234 | iph->protocol = nexthdr[1]; | ||
235 | pskb_trim(skb, skb->len - alen - padlen - 2); | ||
236 | memcpy(workbuf, skb->nh.raw, iph->ihl*4); | ||
237 | skb->h.raw = skb_pull(skb, sizeof(struct ip_esp_hdr) + esp->conf.ivlen); | ||
238 | skb->nh.raw += encap_len + sizeof(struct ip_esp_hdr) + esp->conf.ivlen; | ||
239 | memcpy(skb->nh.raw, workbuf, iph->ihl*4); | ||
240 | skb->nh.iph->tot_len = htons(skb->len); | ||
241 | |||
243 | return 0; | 242 | return 0; |
244 | 243 | ||
245 | out: | 244 | out: |