Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[linux-2.6-microblaze.git] / net / tls / tls_device.c
index 879b902..b3e2a30 100644 (file)
@@ -38,6 +38,7 @@
 #include <net/tcp.h>
 #include <net/tls.h>
 
+#include "tls.h"
 #include "trace.h"
 
 /* device_offload_lock is used to synchronize tls_dev_add
@@ -564,7 +565,7 @@ int tls_device_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
        lock_sock(sk);
 
        if (unlikely(msg->msg_controllen)) {
-               rc = tls_proccess_cmsg(sk, msg, &record_type);
+               rc = tls_process_cmsg(sk, msg, &record_type);
                if (rc)
                        goto out;
        }
@@ -890,25 +891,29 @@ static void tls_device_core_ctrl_rx_resync(struct tls_context *tls_ctx,
        }
 }
 
-static int tls_device_reencrypt(struct sock *sk, struct sk_buff *skb)
+static int
+tls_device_reencrypt(struct sock *sk, struct tls_sw_context_rx *sw_ctx)
 {
-       struct strp_msg *rxm = strp_msg(skb);
-       int err = 0, offset = rxm->offset, copy, nsg, data_len, pos;
-       struct sk_buff *skb_iter, *unused;
+       int err, offset, copy, data_len, pos;
+       struct sk_buff *skb, *skb_iter;
        struct scatterlist sg[1];
+       struct strp_msg *rxm;
        char *orig_buf, *buf;
 
+       rxm = strp_msg(tls_strp_msg(sw_ctx));
        orig_buf = kmalloc(rxm->full_len + TLS_HEADER_SIZE +
                           TLS_CIPHER_AES_GCM_128_IV_SIZE, sk->sk_allocation);
        if (!orig_buf)
                return -ENOMEM;
        buf = orig_buf;
 
-       nsg = skb_cow_data(skb, 0, &unused);
-       if (unlikely(nsg < 0)) {
-               err = nsg;
+       err = tls_strp_msg_cow(sw_ctx);
+       if (unlikely(err))
                goto free_buf;
-       }
+
+       skb = tls_strp_msg(sw_ctx);
+       rxm = strp_msg(skb);
+       offset = rxm->offset;
 
        sg_init_table(sg, 1);
        sg_set_buf(&sg[0], buf,
@@ -920,7 +925,7 @@ static int tls_device_reencrypt(struct sock *sk, struct sk_buff *skb)
                goto free_buf;
 
        /* We are interested only in the decrypted data not the auth */
-       err = decrypt_skb(sk, skb, sg);
+       err = decrypt_skb(sk, sg);
        if (err != -EBADMSG)
                goto free_buf;
        else
@@ -975,10 +980,12 @@ free_buf:
        return err;
 }
 
-int tls_device_decrypted(struct sock *sk, struct tls_context *tls_ctx,
-                        struct sk_buff *skb, struct strp_msg *rxm)
+int tls_device_decrypted(struct sock *sk, struct tls_context *tls_ctx)
 {
        struct tls_offload_context_rx *ctx = tls_offload_ctx_rx(tls_ctx);
+       struct tls_sw_context_rx *sw_ctx = tls_sw_ctx_rx(tls_ctx);
+       struct sk_buff *skb = tls_strp_msg(sw_ctx);
+       struct strp_msg *rxm = strp_msg(skb);
        int is_decrypted = skb->decrypted;
        int is_encrypted = !is_decrypted;
        struct sk_buff *skb_iter;
@@ -1001,7 +1008,7 @@ int tls_device_decrypted(struct sock *sk, struct tls_context *tls_ctx,
                 * likely have initial fragments decrypted, and final ones not
                 * decrypted. We need to reencrypt that single SKB.
                 */
-               return tls_device_reencrypt(sk, skb);
+               return tls_device_reencrypt(sk, sw_ctx);
        }
 
        /* Return immediately if the record is either entirely plaintext or
@@ -1018,7 +1025,7 @@ int tls_device_decrypted(struct sock *sk, struct tls_context *tls_ctx,
        }
 
        ctx->resync_nh_reset = 1;
-       return tls_device_reencrypt(sk, skb);
+       return tls_device_reencrypt(sk, sw_ctx);
 }
 
 static void tls_device_attach(struct tls_context *ctx, struct sock *sk,
@@ -1376,8 +1383,13 @@ static int tls_device_down(struct net_device *netdev)
                 * by tls_device_free_ctx. rx_conf and tx_conf stay in TLS_HW.
                 * Now release the ref taken above.
                 */
-               if (refcount_dec_and_test(&ctx->refcount))
+               if (refcount_dec_and_test(&ctx->refcount)) {
+                       /* sk_destruct ran after tls_device_down took a ref, and
+                        * it returned early. Complete the destruction here.
+                        */
+                       list_del(&ctx->list);
                        tls_device_free_ctx(ctx);
+               }
        }
 
        up_write(&device_offload_lock);