diff options
| -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: |
