]> git.ipfire.org Git - thirdparty/kernel/stable.git/blobdiff - net/xfrm/xfrm_input.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
[thirdparty/kernel/stable.git] / net / xfrm / xfrm_input.c
index e23570b647ae721516997130d7abebeaf3f8bb03..9de4b1dbc0aea3f768a8d98eeab456c0c8e0fa61 100644 (file)
@@ -107,6 +107,8 @@ struct sec_path *secpath_dup(struct sec_path *src)
        sp->len = 0;
        sp->olen = 0;
 
+       memset(sp->ovec, 0, sizeof(sp->ovec[XFRM_MAX_OFFLOAD_DEPTH]));
+
        if (src) {
                int i;
 
@@ -207,8 +209,9 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
        unsigned int family;
        int decaps = 0;
        int async = 0;
-       struct xfrm_offload *xo;
        bool xfrm_gro = false;
+       bool crypto_done = false;
+       struct xfrm_offload *xo = xfrm_offload(skb);
 
        if (encap_type < 0) {
                x = xfrm_input_state(skb);
@@ -220,9 +223,40 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
                        seq = XFRM_SKB_CB(skb)->seq.input.low;
                        goto resume;
                }
+
                /* encap_type < -1 indicates a GRO call. */
                encap_type = 0;
                seq = XFRM_SPI_SKB_CB(skb)->seq;
+
+               if (xo && (xo->flags & CRYPTO_DONE)) {
+                       crypto_done = true;
+                       x = xfrm_input_state(skb);
+                       family = XFRM_SPI_SKB_CB(skb)->family;
+
+                       if (!(xo->status & CRYPTO_SUCCESS)) {
+                               if (xo->status &
+                                   (CRYPTO_TRANSPORT_AH_AUTH_FAILED |
+                                    CRYPTO_TRANSPORT_ESP_AUTH_FAILED |
+                                    CRYPTO_TUNNEL_AH_AUTH_FAILED |
+                                    CRYPTO_TUNNEL_ESP_AUTH_FAILED)) {
+
+                                       xfrm_audit_state_icvfail(x, skb,
+                                                                x->type->proto);
+                                       x->stats.integrity_failed++;
+                                       XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEPROTOERROR);
+                                       goto drop;
+                               }
+
+                               XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
+                               goto drop;
+                       }
+
+                       if ((err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) {
+                               XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
+                               goto drop;
+                       }
+               }
+
                goto lock;
        }
 
@@ -311,7 +345,10 @@ lock:
                skb_dst_force(skb);
                dev_hold(skb->dev);
 
-               nexthdr = x->type->input(x, skb);
+               if (crypto_done)
+                       nexthdr = x->type_offload->input_tail(x, skb);
+               else
+                       nexthdr = x->type->input(x, skb);
 
                if (nexthdr == -EINPROGRESS)
                        return 0;