|
@@ -49,6 +49,8 @@ struct esp_skb_cb {
|
|
|
|
|
|
#define ESP_SKB_CB(__skb) ((struct esp_skb_cb *)&((__skb)->cb[0]))
|
|
|
|
|
|
+static u32 esp6_get_mtu(struct xfrm_state *x, int mtu);
|
|
|
+
|
|
|
/*
|
|
|
* Allocate an AEAD request structure with extra space for SG and IV.
|
|
|
*
|
|
@@ -140,6 +142,8 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
|
|
|
int blksize;
|
|
|
int clen;
|
|
|
int alen;
|
|
|
+ int plen;
|
|
|
+ int tfclen;
|
|
|
int nfrags;
|
|
|
u8 *iv;
|
|
|
u8 *tail;
|
|
@@ -148,18 +152,26 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
|
|
|
/* skb is pure payload to encrypt */
|
|
|
err = -ENOMEM;
|
|
|
|
|
|
- /* Round to block size */
|
|
|
- clen = skb->len;
|
|
|
-
|
|
|
aead = esp->aead;
|
|
|
alen = crypto_aead_authsize(aead);
|
|
|
|
|
|
+ tfclen = 0;
|
|
|
+ if (x->tfcpad) {
|
|
|
+ struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb);
|
|
|
+ u32 padto;
|
|
|
+
|
|
|
+ padto = min(x->tfcpad, esp6_get_mtu(x, dst->child_mtu_cached));
|
|
|
+ if (skb->len < padto)
|
|
|
+ tfclen = padto - skb->len;
|
|
|
+ }
|
|
|
blksize = ALIGN(crypto_aead_blocksize(aead), 4);
|
|
|
- clen = ALIGN(clen + 2, blksize);
|
|
|
+ clen = ALIGN(skb->len + 2 + tfclen, blksize);
|
|
|
if (esp->padlen)
|
|
|
clen = ALIGN(clen, esp->padlen);
|
|
|
+ plen = clen - skb->len - tfclen;
|
|
|
|
|
|
- if ((err = skb_cow_data(skb, clen - skb->len + alen, &trailer)) < 0)
|
|
|
+ err = skb_cow_data(skb, tfclen + plen + alen, &trailer);
|
|
|
+ if (err < 0)
|
|
|
goto error;
|
|
|
nfrags = err;
|
|
|
|
|
@@ -174,13 +186,17 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
|
|
|
|
|
|
/* Fill padding... */
|
|
|
tail = skb_tail_pointer(trailer);
|
|
|
+ if (tfclen) {
|
|
|
+ memset(tail, 0, tfclen);
|
|
|
+ tail += tfclen;
|
|
|
+ }
|
|
|
do {
|
|
|
int i;
|
|
|
- for (i=0; i<clen-skb->len - 2; i++)
|
|
|
+ for (i = 0; i < plen - 2; i++)
|
|
|
tail[i] = i + 1;
|
|
|
} while (0);
|
|
|
- tail[clen-skb->len - 2] = (clen - skb->len) - 2;
|
|
|
- tail[clen - skb->len - 1] = *skb_mac_header(skb);
|
|
|
+ tail[plen - 2] = plen - 2;
|
|
|
+ tail[plen - 1] = *skb_mac_header(skb);
|
|
|
pskb_put(skb, trailer, clen - skb->len + alen);
|
|
|
|
|
|
skb_push(skb, -skb_network_offset(skb));
|