aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/ipv4/esp4.c87
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
245out: 244out: