#include "ecdh_helper.h"
 
 #include <linux/scatterlist.h>
-#include <crypto/kpp.h>
 #include <crypto/ecdh.h>
 
 struct ecdh_completion {
                out[i] = __swab64(in[ndigits - 1 - i]);
 }
 
-bool compute_ecdh_secret(const u8 public_key[64], const u8 private_key[32],
-                        u8 secret[32])
+bool compute_ecdh_secret(struct crypto_kpp *tfm, const u8 public_key[64],
+                        const u8 private_key[32], u8 secret[32])
 {
-       struct crypto_kpp *tfm;
        struct kpp_request *req;
        struct ecdh p;
        struct ecdh_completion result;
        if (!tmp)
                return false;
 
-       tfm = crypto_alloc_kpp("ecdh", CRYPTO_ALG_INTERNAL, 0);
-       if (IS_ERR(tfm)) {
-               pr_err("alg: kpp: Failed to load tfm for kpp: %ld\n",
-                      PTR_ERR(tfm));
-               goto free_tmp;
-       }
-
        req = kpp_request_alloc(tfm, GFP_KERNEL);
        if (!req)
-               goto free_kpp;
+               goto free_tmp;
 
        init_completion(&result.completion);
 
        kzfree(buf);
 free_req:
        kpp_request_free(req);
-free_kpp:
-       crypto_free_kpp(tfm);
 free_tmp:
        kfree(tmp);
        return (err == 0);
 }
 
-bool generate_ecdh_keys(u8 public_key[64], u8 private_key[32])
+bool generate_ecdh_keys(struct crypto_kpp *tfm, u8 public_key[64],
+                       u8 private_key[32])
 {
-       struct crypto_kpp *tfm;
        struct kpp_request *req;
        struct ecdh p;
        struct ecdh_completion result;
        if (!tmp)
                return false;
 
-       tfm = crypto_alloc_kpp("ecdh", CRYPTO_ALG_INTERNAL, 0);
-       if (IS_ERR(tfm)) {
-               pr_err("alg: kpp: Failed to load tfm for kpp: %ld\n",
-                      PTR_ERR(tfm));
-               goto free_tmp;
-       }
-
        req = kpp_request_alloc(tfm, GFP_KERNEL);
        if (!req)
-               goto free_kpp;
+               goto free_tmp;
 
        init_completion(&result.completion);
 
        kzfree(buf);
 free_req:
        kpp_request_free(req);
-free_kpp:
-       crypto_free_kpp(tfm);
 free_tmp:
        kfree(tmp);
        return (err == 0);
 
        0x7c, 0x1c, 0xf9, 0x49, 0xe6, 0xd7, 0xaa, 0x70,
 };
 
-static int __init test_ecdh_sample(const u8 priv_a[32], const u8 priv_b[32],
-                                  const u8 pub_a[64], const u8 pub_b[64],
-                                  const u8 dhkey[32])
+static int __init test_ecdh_sample(struct crypto_kpp *tfm, const u8 priv_a[32],
+                                  const u8 priv_b[32], const u8 pub_a[64],
+                                  const u8 pub_b[64], const u8 dhkey[32])
 {
        u8 *tmp, *dhkey_a, *dhkey_b;
        int ret = 0;
        dhkey_a = &tmp[0];
        dhkey_b = &tmp[32];
 
-       compute_ecdh_secret(pub_b, priv_a, dhkey_a);
-       compute_ecdh_secret(pub_a, priv_b, dhkey_b);
+       compute_ecdh_secret(tfm, pub_b, priv_a, dhkey_a);
+       compute_ecdh_secret(tfm, pub_a, priv_b, dhkey_b);
 
        if (memcmp(dhkey_a, dhkey, 32)) {
                ret = -EINVAL;
 
 static int __init test_ecdh(void)
 {
+       struct crypto_kpp *tfm;
        ktime_t calltime, delta, rettime;
        unsigned long long duration;
        int err;
 
        calltime = ktime_get();
 
-       err = test_ecdh_sample(priv_a_1, priv_b_1, pub_a_1, pub_b_1, dhkey_1);
+       tfm = crypto_alloc_kpp("ecdh", CRYPTO_ALG_INTERNAL, 0);
+       if (IS_ERR(tfm)) {
+               BT_ERR("Unable to create ECDH crypto context");
+               err = PTR_ERR(tfm);
+               goto done;
+       }
+
+       err = test_ecdh_sample(tfm, priv_a_1, priv_b_1, pub_a_1, pub_b_1,
+                              dhkey_1);
        if (err) {
                BT_ERR("ECDH sample 1 failed");
                goto done;
        }
 
-       err = test_ecdh_sample(priv_a_2, priv_b_2, pub_a_2, pub_b_2, dhkey_2);
+       err = test_ecdh_sample(tfm, priv_a_2, priv_b_2, pub_a_2, pub_b_2,
+                              dhkey_2);
        if (err) {
                BT_ERR("ECDH sample 2 failed");
                goto done;
        }
 
-       err = test_ecdh_sample(priv_a_3, priv_a_3, pub_a_3, pub_a_3, dhkey_3);
+       err = test_ecdh_sample(tfm, priv_a_3, priv_a_3, pub_a_3, pub_a_3,
+                              dhkey_3);
        if (err) {
                BT_ERR("ECDH sample 3 failed");
                goto done;
        }
 
+       crypto_free_kpp(tfm);
+
        rettime = ktime_get();
        delta = ktime_sub(rettime, calltime);
        duration = (unsigned long long) ktime_to_ns(delta) >> 10;
 
 #include <crypto/algapi.h>
 #include <crypto/b128ops.h>
 #include <crypto/hash.h>
+#include <crypto/kpp.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
        struct crypto_cipher    *tfm_aes;
        struct crypto_shash     *tfm_cmac;
+       struct crypto_kpp       *tfm_ecdh;
 };
 
 struct smp_chan {
 
        struct crypto_cipher    *tfm_aes;
        struct crypto_shash     *tfm_cmac;
+       struct crypto_kpp       *tfm_ecdh;
 };
 
 /* These debug key values are defined in the SMP section of the core
                        get_random_bytes(smp->local_sk, 32);
 
                        /* Generate local key pair for Secure Connections */
-                       if (!generate_ecdh_keys(smp->local_pk, smp->local_sk))
+                       if (!generate_ecdh_keys(smp->tfm_ecdh, smp->local_pk,
+                                               smp->local_sk))
                                return -EIO;
 
                        /* This is unlikely, but we need to check that
 
        crypto_free_cipher(smp->tfm_aes);
        crypto_free_shash(smp->tfm_cmac);
+       crypto_free_kpp(smp->tfm_ecdh);
 
        /* Ensure that we don't leave any debug key around if debug key
         * support hasn't been explicitly enabled.
        smp->tfm_aes = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
        if (IS_ERR(smp->tfm_aes)) {
                BT_ERR("Unable to create AES crypto context");
-               kzfree(smp);
-               return NULL;
+               goto zfree_smp;
        }
 
        smp->tfm_cmac = crypto_alloc_shash("cmac(aes)", 0, 0);
        if (IS_ERR(smp->tfm_cmac)) {
                BT_ERR("Unable to create CMAC crypto context");
-               crypto_free_cipher(smp->tfm_aes);
-               kzfree(smp);
-               return NULL;
+               goto free_cipher;
+       }
+
+       smp->tfm_ecdh = crypto_alloc_kpp("ecdh", CRYPTO_ALG_INTERNAL, 0);
+       if (IS_ERR(smp->tfm_ecdh)) {
+               BT_ERR("Unable to create ECDH crypto context");
+               goto free_shash;
        }
 
        smp->conn = conn;
        hci_conn_hold(conn->hcon);
 
        return smp;
+
+free_shash:
+       crypto_free_shash(smp->tfm_cmac);
+free_cipher:
+       crypto_free_cipher(smp->tfm_aes);
+zfree_smp:
+       kzfree(smp);
+       return NULL;
 }
 
 static int sc_mackey_and_ltk(struct smp_chan *smp, u8 mackey[16], u8 ltk[16])
                        get_random_bytes(smp->local_sk, 32);
 
                        /* Generate local key pair for Secure Connections */
-                       if (!generate_ecdh_keys(smp->local_pk, smp->local_sk))
+                       if (!generate_ecdh_keys(smp->tfm_ecdh, smp->local_pk,
+                                               smp->local_sk))
                                return SMP_UNSPECIFIED;
 
                        /* This is unlikely, but we need to check that
        SMP_DBG("Remote Public Key X: %32phN", smp->remote_pk);
        SMP_DBG("Remote Public Key Y: %32phN", smp->remote_pk + 32);
 
-       if (!compute_ecdh_secret(smp->remote_pk, smp->local_sk, smp->dhkey))
+       if (!compute_ecdh_secret(smp->tfm_ecdh, smp->remote_pk, smp->local_sk,
+                                smp->dhkey))
                return SMP_UNSPECIFIED;
 
        SMP_DBG("DHKey %32phN", smp->dhkey);
        struct smp_dev *smp;
        struct crypto_cipher *tfm_aes;
        struct crypto_shash *tfm_cmac;
+       struct crypto_kpp *tfm_ecdh;
 
        if (cid == L2CAP_CID_SMP_BREDR) {
                smp = NULL;
                return ERR_CAST(tfm_cmac);
        }
 
+       tfm_ecdh = crypto_alloc_kpp("ecdh", CRYPTO_ALG_INTERNAL, 0);
+       if (IS_ERR(tfm_ecdh)) {
+               BT_ERR("Unable to create ECDH crypto context");
+               crypto_free_shash(tfm_cmac);
+               crypto_free_cipher(tfm_aes);
+               kzfree(smp);
+               return ERR_CAST(tfm_ecdh);
+       }
+
        smp->tfm_aes = tfm_aes;
        smp->tfm_cmac = tfm_cmac;
+       smp->tfm_ecdh = tfm_ecdh;
        smp->min_key_size = SMP_MIN_ENC_KEY_SIZE;
        smp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
 
                if (smp) {
                        crypto_free_cipher(smp->tfm_aes);
                        crypto_free_shash(smp->tfm_cmac);
+                       crypto_free_kpp(smp->tfm_ecdh);
                        kzfree(smp);
                }
                return ERR_PTR(-ENOMEM);
                chan->data = NULL;
                crypto_free_cipher(smp->tfm_aes);
                crypto_free_shash(smp->tfm_cmac);
+               crypto_free_kpp(smp->tfm_ecdh);
                kzfree(smp);
        }
 
                out[i] = __swab64(in[ndigits - 1 - i]);
 }
 
-static int __init test_debug_key(void)
+static int __init test_debug_key(struct crypto_kpp *tfm_ecdh)
 {
        u8 pk[64], sk[32];
 
        swap_digits((u64 *)debug_sk, (u64 *)sk, 4);
 
-       if (!generate_ecdh_keys(pk, sk))
+       if (!generate_ecdh_keys(tfm_ecdh, pk, sk))
                return -EINVAL;
 
        if (crypto_memneq(sk, debug_sk, 32))
 };
 
 static int __init run_selftests(struct crypto_cipher *tfm_aes,
-                               struct crypto_shash *tfm_cmac)
+                               struct crypto_shash *tfm_cmac,
+                               struct crypto_kpp *tfm_ecdh)
 {
        ktime_t calltime, delta, rettime;
        unsigned long long duration;
 
        calltime = ktime_get();
 
-       err = test_debug_key();
+       err = test_debug_key(tfm_ecdh);
        if (err) {
                BT_ERR("debug_key test failed");
                goto done;
 {
        struct crypto_cipher *tfm_aes;
        struct crypto_shash *tfm_cmac;
+       struct crypto_kpp *tfm_ecdh;
        int err;
 
        tfm_aes = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
                return PTR_ERR(tfm_cmac);
        }
 
-       err = run_selftests(tfm_aes, tfm_cmac);
+       tfm_ecdh = crypto_alloc_kpp("ecdh", CRYPTO_ALG_INTERNAL, 0);
+       if (IS_ERR(tfm_ecdh)) {
+               BT_ERR("Unable to create ECDH crypto context");
+               crypto_free_shash(tfm_cmac);
+               crypto_free_cipher(tfm_aes);
+               return PTR_ERR(tfm_ecdh);
+       }
+
+       err = run_selftests(tfm_aes, tfm_cmac, tfm_ecdh);
 
        crypto_free_shash(tfm_cmac);
        crypto_free_cipher(tfm_aes);
+       crypto_free_kpp(tfm_ecdh);
 
        return err;
 }