]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/ipv4/esp4.c
[IP]: Introduce ip_hdrlen()
[linux-2.6-omap-h63xx.git] / net / ipv4 / esp4.c
index e87377e1d6b64cd299a215ee32d60a9d139a317d..222d21e5bbeb10afb41609f98c0943990b4af7b2 100644 (file)
@@ -57,9 +57,10 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
        *(u8*)(trailer->tail + clen-skb->len - 2) = (clen - skb->len)-2;
        pskb_put(skb, trailer, clen - skb->len);
 
-       __skb_push(skb, skb->data - skb->nh.raw);
+       __skb_push(skb, skb->data - skb_network_header(skb));
        top_iph = skb->nh.iph;
-       esph = (struct ip_esp_hdr *)(skb->nh.raw + top_iph->ihl*4);
+       esph = (struct ip_esp_hdr *)(skb_network_header(skb) +
+                                    top_iph->ihl * 4);
        top_iph->tot_len = htons(skb->len + alen);
        *(u8*)(trailer->tail - 1) = top_iph->protocol;
 
@@ -67,7 +68,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
        if (x->encap) {
                struct xfrm_encap_tmpl *encap = x->encap;
                struct udphdr *uh;
-               u32 *udpdata32;
+               __be32 *udpdata32;
 
                uh = (struct udphdr *)esph;
                uh->source = encap->encap_sport;
@@ -81,7 +82,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
                        esph = (struct ip_esp_hdr *)(uh + 1);
                        break;
                case UDP_ENCAP_ESPINUDP_NON_IKE:
-                       udpdata32 = (u32 *)(uh + 1);
+                       udpdata32 = (__be32 *)(uh + 1);
                        udpdata32[0] = udpdata32[1] = 0;
                        esph = (struct ip_esp_hdr *)(udpdata32 + 2);
                        break;
@@ -95,8 +96,13 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
        esph->seq_no = htonl(++x->replay.oseq);
        xfrm_aevent_doreplay(x);
 
-       if (esp->conf.ivlen)
+       if (esp->conf.ivlen) {
+               if (unlikely(!esp->conf.ivinitted)) {
+                       get_random_bytes(esp->conf.ivec, esp->conf.ivlen);
+                       esp->conf.ivinitted = 1;
+               }
                crypto_blkcipher_set_iv(tfm, esp->conf.ivec, esp->conf.ivlen);
+       }
 
        do {
                struct scatterlist *sg = &esp->sgbuf[0];
@@ -210,14 +216,14 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
        if (padlen+2 >= elen)
                goto out;
 
-       /* ... check padding bits here. Silly. :-) */ 
+       /* ... check padding bits here. Silly. :-) */
 
        iph = skb->nh.iph;
        ihl = iph->ihl * 4;
 
        if (x->encap) {
                struct xfrm_encap_tmpl *encap = x->encap;
-               struct udphdr *uh = (void *)(skb->nh.raw + ihl);
+               struct udphdr *uh = (void *)(skb_network_header(skb) + ihl);
 
                /*
                 * 1) if the NAT-T peer's IP or port changed then
@@ -231,7 +237,7 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
 
                        ipaddr.a4 = iph->saddr;
                        km_new_mapping(x, &ipaddr, uh->source);
-                               
+
                        /* XXX: perhaps add an extra
                         * policy check here, to see
                         * if we should allow or
@@ -240,7 +246,7 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
                         * address/port.
                         */
                }
-       
+
                /*
                 * 2) ignore UDP/TCP checksums in case
                 *    of NAT-T in Transport Mode, or
@@ -248,7 +254,8 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
                 *    as per draft-ietf-ipsec-udp-encaps-06,
                 *    section 3.1.2
                 */
-               if (x->props.mode == XFRM_MODE_TRANSPORT)
+               if (x->props.mode == XFRM_MODE_TRANSPORT ||
+                   x->props.mode == XFRM_MODE_BEET)
                        skb->ip_summed = CHECKSUM_UNNECESSARY;
        }
 
@@ -266,17 +273,28 @@ static u32 esp4_get_max_size(struct xfrm_state *x, int mtu)
 {
        struct esp_data *esp = x->data;
        u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4);
-
-       if (x->props.mode == XFRM_MODE_TUNNEL) {
-               mtu = ALIGN(mtu + 2, blksize);
-       } else {
-               /* The worst case. */
+       int enclen = 0;
+
+       switch (x->props.mode) {
+       case XFRM_MODE_TUNNEL:
+               mtu = ALIGN(mtu +2, blksize);
+               break;
+       default:
+       case XFRM_MODE_TRANSPORT:
+               /* The worst case */
                mtu = ALIGN(mtu + 2, 4) + blksize - 4;
+               break;
+       case XFRM_MODE_BEET:
+               /* The worst case. */
+               enclen = IPV4_BEET_PHMAXLEN;
+               mtu = ALIGN(mtu + enclen + 2, blksize);
+               break;
        }
+
        if (esp->conf.padlen)
                mtu = ALIGN(mtu, esp->conf.padlen);
 
-       return mtu + x->props.header_len + esp->auth.icv_trunc_len;
+       return mtu + x->props.header_len + esp->auth.icv_trunc_len - enclen;
 }
 
 static void esp4_err(struct sk_buff *skb, u32 info)
@@ -378,7 +396,7 @@ static int esp_init_state(struct xfrm_state *x)
                esp->conf.ivec = kmalloc(esp->conf.ivlen, GFP_KERNEL);
                if (unlikely(esp->conf.ivec == NULL))
                        goto error;
-               get_random_bytes(esp->conf.ivec, esp->conf.ivlen);
+               esp->conf.ivinitted = 0;
        }
        if (crypto_blkcipher_setkey(tfm, esp->conf.key, esp->conf.key_len))
                goto error;