Bluetooth: Add LE Secure Connections tests for SMP
[cascardo/linux.git] / net / bluetooth / smp.c
index 135e725..3a4333b 100644 (file)
 #include "ecc.h"
 #include "smp.h"
 
+/* Low-level debug macros to be used for stuff that we don't want
+ * accidentially in dmesg, i.e. the values of the various crypto keys
+ * and the inputs & outputs of crypto functions.
+ */
+#ifdef DEBUG
+#define SMP_DBG(fmt, ...) printk(KERN_DEBUG "%s: " fmt, __func__, \
+                                ##__VA_ARGS__)
+#else
+#define SMP_DBG(fmt, ...) no_printk(KERN_DEBUG "%s: " fmt, __func__, \
+                                   ##__VA_ARGS__)
+#endif
+
 #define SMP_ALLOW_CMD(smp, code)       set_bit(code, &smp->allow_cmd)
 
 /* Keys which are not distributed with Secure Connections */
@@ -57,6 +69,7 @@ enum {
        SMP_FLAG_DEBUG_KEY,
        SMP_FLAG_WAIT_USER,
        SMP_FLAG_DHKEY_PENDING,
+       SMP_FLAG_OOB,
 };
 
 struct smp_chan {
@@ -70,6 +83,7 @@ struct smp_chan {
        u8              rrnd[16]; /* SMP Pairing Random (remote) */
        u8              pcnf[16]; /* SMP Pairing Confirm */
        u8              tk[16]; /* SMP Temporary Key */
+       u8              rr[16];
        u8              enc_key_size;
        u8              remote_key_dist;
        bdaddr_t        id_addr;
@@ -127,6 +141,10 @@ static inline void swap_buf(const u8 *src, u8 *dst, size_t len)
                dst[len - 1 - i] = src[i];
 }
 
+/* The following functions map to the LE SC SMP crypto functions
+ * AES-CMAC, f4, f5, f6, g2 and h6.
+ */
+
 static int aes_cmac(struct crypto_hash *tfm, const u8 k[16], const u8 *m,
                    size_t len, u8 mac[16])
 {
@@ -152,8 +170,8 @@ static int aes_cmac(struct crypto_hash *tfm, const u8 k[16], const u8 *m,
        swap_buf(k, tmp, 16);
        swap_buf(m, msg_msb, len);
 
-       BT_DBG("msg (len %zu) %*phN", len, (int) len, m);
-       BT_DBG("key %16phN", k);
+       SMP_DBG("msg (len %zu) %*phN", len, (int) len, m);
+       SMP_DBG("key %16phN", k);
 
        err = crypto_hash_setkey(tfm, tmp, 16);
        if (err) {
@@ -177,7 +195,7 @@ static int aes_cmac(struct crypto_hash *tfm, const u8 k[16], const u8 *m,
 
        swap_buf(mac_msb, mac, 16);
 
-       BT_DBG("mac %16phN", mac);
+       SMP_DBG("mac %16phN", mac);
 
        return 0;
 }
@@ -188,9 +206,9 @@ static int smp_f4(struct crypto_hash *tfm_cmac, const u8 u[32], const u8 v[32],
        u8 m[65];
        int err;
 
-       BT_DBG("u %32phN", u);
-       BT_DBG("v %32phN", v);
-       BT_DBG("x %16phN z %02x", x, z);
+       SMP_DBG("u %32phN", u);
+       SMP_DBG("v %32phN", v);
+       SMP_DBG("x %16phN z %02x", x, z);
 
        m[0] = z;
        memcpy(m + 1, v, 32);
@@ -200,13 +218,14 @@ static int smp_f4(struct crypto_hash *tfm_cmac, const u8 u[32], const u8 v[32],
        if (err)
                return err;
 
-       BT_DBG("res %16phN", res);
+       SMP_DBG("res %16phN", res);
 
        return err;
 }
 
-static int smp_f5(struct crypto_hash *tfm_cmac, u8 w[32], u8 n1[16], u8 n2[16],
-                 u8 a1[7], u8 a2[7], u8 mackey[16], u8 ltk[16])
+static int smp_f5(struct crypto_hash *tfm_cmac, const u8 w[32],
+                 const u8 n1[16], const u8 n2[16], const u8 a1[7],
+                 const u8 a2[7], u8 mackey[16], u8 ltk[16])
 {
        /* The btle, salt and length "magic" values are as defined in
         * the SMP section of the Bluetooth core specification. In ASCII
@@ -221,15 +240,15 @@ static int smp_f5(struct crypto_hash *tfm_cmac, u8 w[32], u8 n1[16], u8 n2[16],
        u8 m[53], t[16];
        int err;
 
-       BT_DBG("w %32phN", w);
-       BT_DBG("n1 %16phN n2 %16phN", n1, n2);
-       BT_DBG("a1 %7phN a2 %7phN", a1, a2);
+       SMP_DBG("w %32phN", w);
+       SMP_DBG("n1 %16phN n2 %16phN", n1, n2);
+       SMP_DBG("a1 %7phN a2 %7phN", a1, a2);
 
        err = aes_cmac(tfm_cmac, salt, w, 32, t);
        if (err)
                return err;
 
-       BT_DBG("t %16phN", t);
+       SMP_DBG("t %16phN", t);
 
        memcpy(m, length, 2);
        memcpy(m + 2, a2, 7);
@@ -244,7 +263,7 @@ static int smp_f5(struct crypto_hash *tfm_cmac, u8 w[32], u8 n1[16], u8 n2[16],
        if (err)
                return err;
 
-       BT_DBG("mackey %16phN", mackey);
+       SMP_DBG("mackey %16phN", mackey);
 
        m[52] = 1; /* Counter */
 
@@ -252,22 +271,22 @@ static int smp_f5(struct crypto_hash *tfm_cmac, u8 w[32], u8 n1[16], u8 n2[16],
        if (err)
                return err;
 
-       BT_DBG("ltk %16phN", ltk);
+       SMP_DBG("ltk %16phN", ltk);
 
        return 0;
 }
 
 static int smp_f6(struct crypto_hash *tfm_cmac, const u8 w[16],
-                 const u8 n1[16], u8 n2[16], const u8 r[16],
+                 const u8 n1[16], const u8 n2[16], const u8 r[16],
                  const u8 io_cap[3], const u8 a1[7], const u8 a2[7],
                  u8 res[16])
 {
        u8 m[65];
        int err;
 
-       BT_DBG("w %16phN", w);
-       BT_DBG("n1 %16phN n2 %16phN", n1, n2);
-       BT_DBG("r %16phN io_cap %3phN a1 %7phN a2 %7phN", r, io_cap, a1, a2);
+       SMP_DBG("w %16phN", w);
+       SMP_DBG("n1 %16phN n2 %16phN", n1, n2);
+       SMP_DBG("r %16phN io_cap %3phN a1 %7phN a2 %7phN", r, io_cap, a1, a2);
 
        memcpy(m, a2, 7);
        memcpy(m + 7, a1, 7);
@@ -291,9 +310,9 @@ static int smp_g2(struct crypto_hash *tfm_cmac, const u8 u[32], const u8 v[32],
        u8 m[80], tmp[16];
        int err;
 
-       BT_DBG("u %32phN", u);
-       BT_DBG("v %32phN", v);
-       BT_DBG("x %16phN y %16phN", x, y);
+       SMP_DBG("u %32phN", u);
+       SMP_DBG("v %32phN", v);
+       SMP_DBG("x %16phN y %16phN", x, y);
 
        memcpy(m, y, 16);
        memcpy(m + 16, v, 32);
@@ -306,11 +325,31 @@ static int smp_g2(struct crypto_hash *tfm_cmac, const u8 u[32], const u8 v[32],
        *val = get_unaligned_le32(tmp);
        *val %= 1000000;
 
-       BT_DBG("val %06u", *val);
+       SMP_DBG("val %06u", *val);
 
        return 0;
 }
 
+static int smp_h6(struct crypto_hash *tfm_cmac, const u8 w[16],
+                 const u8 key_id[4], u8 res[16])
+{
+       int err;
+
+       SMP_DBG("w %16phN key_id %4phN", w, key_id);
+
+       err = aes_cmac(tfm_cmac, w, key_id, 4, res);
+       if (err)
+               return err;
+
+       SMP_DBG("res %16phN", res);
+
+       return err;
+}
+
+/* The following functions map to the legacy SMP crypto functions e, c1,
+ * s1 and ah.
+ */
+
 static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
 {
        struct blkcipher_desc desc;
@@ -318,7 +357,7 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
        uint8_t tmp[16], data[16];
        int err;
 
-       if (tfm == NULL) {
+       if (!tfm) {
                BT_ERR("tfm %p", tfm);
                return -EINVAL;
        }
@@ -350,23 +389,65 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
        return err;
 }
 
-static int smp_h6(struct crypto_hash *tfm_cmac, const u8 w[16],
-                 const u8 key_id[4], u8 res[16])
+static int smp_c1(struct crypto_blkcipher *tfm_aes, const u8 k[16],
+                 const u8 r[16], const u8 preq[7], const u8 pres[7], u8 _iat,
+                 const bdaddr_t *ia, u8 _rat, const bdaddr_t *ra, u8 res[16])
 {
+       u8 p1[16], p2[16];
        int err;
 
-       BT_DBG("w %16phN key_id %4phN", w, key_id);
+       memset(p1, 0, 16);
 
-       err = aes_cmac(tfm_cmac, w, key_id, 4, res);
-       if (err)
+       /* p1 = pres || preq || _rat || _iat */
+       p1[0] = _iat;
+       p1[1] = _rat;
+       memcpy(p1 + 2, preq, 7);
+       memcpy(p1 + 9, pres, 7);
+
+       /* p2 = padding || ia || ra */
+       memcpy(p2, ra, 6);
+       memcpy(p2 + 6, ia, 6);
+       memset(p2 + 12, 0, 4);
+
+       /* res = r XOR p1 */
+       u128_xor((u128 *) res, (u128 *) r, (u128 *) p1);
+
+       /* res = e(k, res) */
+       err = smp_e(tfm_aes, k, res);
+       if (err) {
+               BT_ERR("Encrypt data error");
                return err;
+       }
 
-       BT_DBG("res %16phN", res);
+       /* res = res XOR p2 */
+       u128_xor((u128 *) res, (u128 *) res, (u128 *) p2);
+
+       /* res = e(k, res) */
+       err = smp_e(tfm_aes, k, res);
+       if (err)
+               BT_ERR("Encrypt data error");
+
+       return err;
+}
+
+static int smp_s1(struct crypto_blkcipher *tfm_aes, const u8 k[16],
+                 const u8 r1[16], const u8 r2[16], u8 _r[16])
+{
+       int err;
+
+       /* Just least significant octets from r1 and r2 are considered */
+       memcpy(_r, r2, 8);
+       memcpy(_r + 8, r1, 8);
+
+       err = smp_e(tfm_aes, k, _r);
+       if (err)
+               BT_ERR("Encrypt data error");
 
        return err;
 }
 
-static int smp_ah(struct crypto_blkcipher *tfm, u8 irk[16], u8 r[3], u8 res[3])
+static int smp_ah(struct crypto_blkcipher *tfm, const u8 irk[16],
+                 const u8 r[3], u8 res[3])
 {
        u8 _res[16];
        int err;
@@ -392,7 +473,8 @@ static int smp_ah(struct crypto_blkcipher *tfm, u8 irk[16], u8 r[3], u8 res[3])
        return 0;
 }
 
-bool smp_irk_matches(struct hci_dev *hdev, u8 irk[16], bdaddr_t *bdaddr)
+bool smp_irk_matches(struct hci_dev *hdev, const u8 irk[16],
+                    const bdaddr_t *bdaddr)
 {
        struct l2cap_chan *chan = hdev->smp_data;
        struct crypto_blkcipher *tfm;
@@ -413,7 +495,7 @@ bool smp_irk_matches(struct hci_dev *hdev, u8 irk[16], bdaddr_t *bdaddr)
        return !memcmp(bdaddr->b, hash, 3);
 }
 
-int smp_generate_rpa(struct hci_dev *hdev, u8 irk[16], bdaddr_t *rpa)
+int smp_generate_rpa(struct hci_dev *hdev, const u8 irk[16], bdaddr_t *rpa)
 {
        struct l2cap_chan *chan = hdev->smp_data;
        struct crypto_blkcipher *tfm;
@@ -438,63 +520,6 @@ int smp_generate_rpa(struct hci_dev *hdev, u8 irk[16], bdaddr_t *rpa)
        return 0;
 }
 
-static int smp_c1(struct crypto_blkcipher *tfm_aes, u8 k[16], u8 r[16],
-                 u8 preq[7], u8 pres[7], u8 _iat, bdaddr_t *ia, u8 _rat,
-                 bdaddr_t *ra, u8 res[16])
-{
-       u8 p1[16], p2[16];
-       int err;
-
-       memset(p1, 0, 16);
-
-       /* p1 = pres || preq || _rat || _iat */
-       p1[0] = _iat;
-       p1[1] = _rat;
-       memcpy(p1 + 2, preq, 7);
-       memcpy(p1 + 9, pres, 7);
-
-       /* p2 = padding || ia || ra */
-       memcpy(p2, ra, 6);
-       memcpy(p2 + 6, ia, 6);
-       memset(p2 + 12, 0, 4);
-
-       /* res = r XOR p1 */
-       u128_xor((u128 *) res, (u128 *) r, (u128 *) p1);
-
-       /* res = e(k, res) */
-       err = smp_e(tfm_aes, k, res);
-       if (err) {
-               BT_ERR("Encrypt data error");
-               return err;
-       }
-
-       /* res = res XOR p2 */
-       u128_xor((u128 *) res, (u128 *) res, (u128 *) p2);
-
-       /* res = e(k, res) */
-       err = smp_e(tfm_aes, k, res);
-       if (err)
-               BT_ERR("Encrypt data error");
-
-       return err;
-}
-
-static int smp_s1(struct crypto_blkcipher *tfm_aes, u8 k[16], u8 r1[16],
-                 u8 r2[16], u8 _r[16])
-{
-       int err;
-
-       /* Just least significant octets from r1 and r2 are considered */
-       memcpy(_r, r2, 8);
-       memcpy(_r + 8, r1, 8);
-
-       err = smp_e(tfm_aes, k, _r);
-       if (err)
-               BT_ERR("Encrypt data error");
-
-       return err;
-}
-
 static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
 {
        struct l2cap_chan *chan = conn->smp;
@@ -515,8 +540,7 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
 
        memset(&msg, 0, sizeof(msg));
 
-       msg.msg_iov = (struct iovec *) &iv;
-       msg.msg_iovlen = 2;
+       iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, iv, 2, 1 + len);
 
        l2cap_chan_send(chan, &msg, 1 + len);
 
@@ -562,7 +586,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
        struct smp_chan *smp = chan->data;
        struct hci_conn *hcon = conn->hcon;
        struct hci_dev *hdev = hcon->hdev;
-       u8 local_dist = 0, remote_dist = 0;
+       u8 local_dist = 0, remote_dist = 0, oob_flag = SMP_OOB_NOT_PRESENT;
 
        if (test_bit(HCI_BONDABLE, &conn->hcon->hdev->dev_flags)) {
                local_dist = SMP_DIST_ENC_KEY | SMP_DIST_SIGN;
@@ -578,19 +602,37 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
        if (test_bit(HCI_PRIVACY, &hdev->dev_flags))
                local_dist |= SMP_DIST_ID_KEY;
 
-       if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) {
-               if ((authreq & SMP_AUTH_SC) &&
-                   test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
+       if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
+           (authreq & SMP_AUTH_SC)) {
+               struct oob_data *oob_data;
+               u8 bdaddr_type;
+
+               if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
                        local_dist |= SMP_DIST_LINK_KEY;
                        remote_dist |= SMP_DIST_LINK_KEY;
                }
+
+               if (hcon->dst_type == ADDR_LE_DEV_PUBLIC)
+                       bdaddr_type = BDADDR_LE_PUBLIC;
+               else
+                       bdaddr_type = BDADDR_LE_RANDOM;
+
+               oob_data = hci_find_remote_oob_data(hdev, &hcon->dst,
+                                                   bdaddr_type);
+               if (oob_data) {
+                       set_bit(SMP_FLAG_OOB, &smp->flags);
+                       oob_flag = SMP_OOB_PRESENT;
+                       memcpy(smp->rr, oob_data->rand256, 16);
+                       memcpy(smp->pcnf, oob_data->hash256, 16);
+               }
+
        } else {
                authreq &= ~SMP_AUTH_SC;
        }
 
        if (rsp == NULL) {
                req->io_capability = conn->hcon->io_capability;
-               req->oob_flag = SMP_OOB_NOT_PRESENT;
+               req->oob_flag = oob_flag;
                req->max_key_size = SMP_MAX_ENC_KEY_SIZE;
                req->init_key_dist = local_dist;
                req->resp_key_dist = remote_dist;
@@ -601,7 +643,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
        }
 
        rsp->io_capability = conn->hcon->io_capability;
-       rsp->oob_flag = SMP_OOB_NOT_PRESENT;
+       rsp->oob_flag = oob_flag;
        rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
        rsp->init_key_dist = req->init_key_dist & remote_dist;
        rsp->resp_key_dist = req->resp_key_dist & local_dist;
@@ -628,6 +670,7 @@ static void smp_chan_destroy(struct l2cap_conn *conn)
 {
        struct l2cap_chan *chan = conn->smp;
        struct smp_chan *smp = chan->data;
+       struct hci_conn *hcon = conn->hcon;
        bool complete;
 
        BUG_ON(!smp);
@@ -635,7 +678,7 @@ static void smp_chan_destroy(struct l2cap_conn *conn)
        cancel_delayed_work_sync(&smp->security_timer);
 
        complete = test_bit(SMP_FLAG_COMPLETE, &smp->flags);
-       mgmt_smp_complete(conn->hcon, complete);
+       mgmt_smp_complete(hcon, complete);
 
        kfree(smp->csrk);
        kfree(smp->slave_csrk);
@@ -644,6 +687,16 @@ static void smp_chan_destroy(struct l2cap_conn *conn)
        crypto_free_blkcipher(smp->tfm_aes);
        crypto_free_hash(smp->tfm_cmac);
 
+       /* Ensure that we don't leave any debug key around if debug key
+        * support hasn't been explicitly enabled.
+        */
+       if (smp->ltk && smp->ltk->type == SMP_LTK_P256_DEBUG &&
+           !test_bit(HCI_KEEP_DEBUG_KEYS, &hcon->hdev->dev_flags)) {
+               list_del_rcu(&smp->ltk->list);
+               kfree_rcu(smp->ltk, rcu);
+               smp->ltk = NULL;
+       }
+
        /* If pairing failed clean up any keys we might have */
        if (!complete) {
                if (smp->ltk) {
@@ -664,7 +717,7 @@ static void smp_chan_destroy(struct l2cap_conn *conn)
 
        chan->data = NULL;
        kfree(smp);
-       hci_conn_drop(conn->hcon);
+       hci_conn_drop(hcon);
 }
 
 static void smp_failure(struct l2cap_conn *conn, u8 reason)
@@ -915,11 +968,13 @@ static void smp_notify_keys(struct l2cap_conn *conn)
                mgmt_new_irk(hdev, smp->remote_irk);
                /* Now that user space can be considered to know the
                 * identity address track the connection based on it
-                * from now on.
+                * from now on (assuming this is an LE link).
                 */
-               bacpy(&hcon->dst, &smp->remote_irk->bdaddr);
-               hcon->dst_type = smp->remote_irk->addr_type;
-               queue_work(hdev->workqueue, &conn->id_addr_update_work);
+               if (hcon->type == LE_LINK) {
+                       bacpy(&hcon->dst, &smp->remote_irk->bdaddr);
+                       hcon->dst_type = smp->remote_irk->addr_type;
+                       queue_work(hdev->workqueue, &conn->id_addr_update_work);
+               }
 
                /* When receiving an indentity resolving key for
                 * a remote device that does not use a resolvable
@@ -938,10 +993,20 @@ static void smp_notify_keys(struct l2cap_conn *conn)
                }
        }
 
-       /* The LTKs and CSRKs should be persistent only if both sides
-        * had the bonding bit set in their authentication requests.
-        */
-       persistent = !!((req->auth_req & rsp->auth_req) & SMP_AUTH_BONDING);
+       if (hcon->type == ACL_LINK) {
+               if (hcon->key_type == HCI_LK_DEBUG_COMBINATION)
+                       persistent = false;
+               else
+                       persistent = !test_bit(HCI_CONN_FLUSH_KEY,
+                                              &hcon->flags);
+       } else {
+               /* The LTKs and CSRKs should be persistent only if both sides
+                * had the bonding bit set in their authentication requests.
+                */
+               persistent = !!((req->auth_req & rsp->auth_req) &
+                               SMP_AUTH_BONDING);
+       }
+
 
        if (smp->csrk) {
                smp->csrk->bdaddr_type = hcon->dst_type;
@@ -1057,6 +1122,35 @@ static void smp_allow_key_dist(struct smp_chan *smp)
                SMP_ALLOW_CMD(smp, SMP_CMD_SIGN_INFO);
 }
 
+static void sc_generate_ltk(struct smp_chan *smp)
+{
+       /* These constants are as specified in the core specification.
+        * In ASCII they spell out to 'tmp2' and 'brle'.
+        */
+       const u8 tmp2[4] = { 0x32, 0x70, 0x6d, 0x74 };
+       const u8 brle[4] = { 0x65, 0x6c, 0x72, 0x62 };
+       struct hci_conn *hcon = smp->conn->hcon;
+       struct hci_dev *hdev = hcon->hdev;
+       struct link_key *key;
+
+       key = hci_find_link_key(hdev, &hcon->dst);
+       if (!key) {
+               BT_ERR("%s No Link Key found to generate LTK", hdev->name);
+               return;
+       }
+
+       if (key->type == HCI_LK_DEBUG_COMBINATION)
+               set_bit(SMP_FLAG_DEBUG_KEY, &smp->flags);
+
+       if (smp_h6(smp->tfm_cmac, key->val, tmp2, smp->tk))
+               return;
+
+       if (smp_h6(smp->tfm_cmac, smp->tk, brle, smp->tk))
+               return;
+
+       sc_add_ltk(smp);
+}
+
 static void smp_distribute_keys(struct smp_chan *smp)
 {
        struct smp_cmd_pairing *req, *rsp;
@@ -1086,8 +1180,10 @@ static void smp_distribute_keys(struct smp_chan *smp)
        }
 
        if (test_bit(SMP_FLAG_SC, &smp->flags)) {
-               if (*keydist & SMP_DIST_LINK_KEY)
+               if (hcon->type == LE_LINK && (*keydist & SMP_DIST_LINK_KEY))
                        sc_generate_link_key(smp);
+               if (hcon->type == ACL_LINK && (*keydist & SMP_DIST_ENC_KEY))
+                       sc_generate_ltk(smp);
 
                /* Clear the keys which are generated but not distributed */
                *keydist &= ~SMP_SC_NO_DIST;
@@ -1272,6 +1368,9 @@ static void sc_dhkey_check(struct smp_chan *smp)
        if (smp->method == REQ_PASSKEY || smp->method == DSP_PASSKEY)
                put_unaligned_le32(hcon->passkey_notify, r);
 
+       if (smp->method == REQ_OOB)
+               memcpy(r, smp->rr, 16);
+
        smp_f6(smp->tfm_cmac, smp->mackey, smp->prnd, smp->rrnd, r, io_cap,
               local_addr, remote_addr, check.e);
 
@@ -1493,6 +1592,46 @@ unlock:
        return err;
 }
 
+static void build_bredr_pairing_cmd(struct smp_chan *smp,
+                                   struct smp_cmd_pairing *req,
+                                   struct smp_cmd_pairing *rsp)
+{
+       struct l2cap_conn *conn = smp->conn;
+       struct hci_dev *hdev = conn->hcon->hdev;
+       u8 local_dist = 0, remote_dist = 0;
+
+       if (test_bit(HCI_BONDABLE, &hdev->dev_flags)) {
+               local_dist = SMP_DIST_ENC_KEY | SMP_DIST_SIGN;
+               remote_dist = SMP_DIST_ENC_KEY | SMP_DIST_SIGN;
+       }
+
+       if (test_bit(HCI_RPA_RESOLVING, &hdev->dev_flags))
+               remote_dist |= SMP_DIST_ID_KEY;
+
+       if (test_bit(HCI_PRIVACY, &hdev->dev_flags))
+               local_dist |= SMP_DIST_ID_KEY;
+
+       if (!rsp) {
+               memset(req, 0, sizeof(*req));
+
+               req->init_key_dist   = local_dist;
+               req->resp_key_dist   = remote_dist;
+               req->max_key_size    = SMP_MAX_ENC_KEY_SIZE;
+
+               smp->remote_key_dist = remote_dist;
+
+               return;
+       }
+
+       memset(rsp, 0, sizeof(*rsp));
+
+       rsp->max_key_size    = SMP_MAX_ENC_KEY_SIZE;
+       rsp->init_key_dist   = req->init_key_dist & remote_dist;
+       rsp->resp_key_dist   = req->resp_key_dist & local_dist;
+
+       smp->remote_key_dist = rsp->init_key_dist;
+}
+
 static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
 {
        struct smp_cmd_pairing rsp, *req = (void *) skb->data;
@@ -1525,10 +1664,39 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
            (auth & SMP_AUTH_BONDING))
                return SMP_PAIRING_NOTSUPP;
 
+       if (test_bit(HCI_SC_ONLY, &hdev->dev_flags) && !(auth & SMP_AUTH_SC))
+               return SMP_AUTH_REQUIREMENTS;
+
        smp->preq[0] = SMP_CMD_PAIRING_REQ;
        memcpy(&smp->preq[1], req, sizeof(*req));
        skb_pull(skb, sizeof(*req));
 
+       /* SMP over BR/EDR requires special treatment */
+       if (conn->hcon->type == ACL_LINK) {
+               /* We must have a BR/EDR SC link */
+               if (!test_bit(HCI_CONN_AES_CCM, &conn->hcon->flags) &&
+                   !test_bit(HCI_FORCE_LESC, &hdev->dbg_flags))
+                       return SMP_CROSS_TRANSP_NOT_ALLOWED;
+
+               set_bit(SMP_FLAG_SC, &smp->flags);
+
+               build_bredr_pairing_cmd(smp, req, &rsp);
+
+               key_size = min(req->max_key_size, rsp.max_key_size);
+               if (check_enc_key_size(conn, key_size))
+                       return SMP_ENC_KEY_SIZE;
+
+               /* Clear bits which are generated but not distributed */
+               smp->remote_key_dist &= ~SMP_SC_NO_DIST;
+
+               smp->prsp[0] = SMP_CMD_PAIRING_RSP;
+               memcpy(&smp->prsp[1], &rsp, sizeof(rsp));
+               smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp);
+
+               smp_distribute_keys(smp);
+               return 0;
+       }
+
        build_pairing_cmd(conn, req, &rsp, auth);
 
        if (rsp.auth_req & SMP_AUTH_SC)
@@ -1608,9 +1776,9 @@ static u8 sc_send_public_key(struct smp_chan *smp)
                }
        }
 
-       BT_DBG("Local Public Key X: %32phN", smp->local_pk);
-       BT_DBG("Local Public Key Y: %32phN", &smp->local_pk[32]);
-       BT_DBG("Local Private Key:  %32phN", smp->local_sk);
+       SMP_DBG("Local Public Key X: %32phN", smp->local_pk);
+       SMP_DBG("Local Public Key Y: %32phN", &smp->local_pk[32]);
+       SMP_DBG("Local Private Key:  %32phN", smp->local_sk);
 
        smp_send_cmd(smp->conn, SMP_CMD_PUBLIC_KEY, 64, smp->local_pk);
 
@@ -1644,6 +1812,25 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
 
        auth = rsp->auth_req & AUTH_REQ_MASK(hdev);
 
+       if (test_bit(HCI_SC_ONLY, &hdev->dev_flags) && !(auth & SMP_AUTH_SC))
+               return SMP_AUTH_REQUIREMENTS;
+
+       smp->prsp[0] = SMP_CMD_PAIRING_RSP;
+       memcpy(&smp->prsp[1], rsp, sizeof(*rsp));
+
+       /* Update remote key distribution in case the remote cleared
+        * some bits that we had enabled in our request.
+        */
+       smp->remote_key_dist &= rsp->resp_key_dist;
+
+       /* For BR/EDR this means we're done and can start phase 3 */
+       if (conn->hcon->type == ACL_LINK) {
+               /* Clear bits which are generated but not distributed */
+               smp->remote_key_dist &= ~SMP_SC_NO_DIST;
+               smp_distribute_keys(smp);
+               return 0;
+       }
+
        if ((req->auth_req & SMP_AUTH_SC) && (auth & SMP_AUTH_SC))
                set_bit(SMP_FLAG_SC, &smp->flags);
        else if (conn->hcon->pending_sec_level > BT_SECURITY_HIGH)
@@ -1661,9 +1848,6 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
 
        get_random_bytes(smp->prnd, sizeof(smp->prnd));
 
-       smp->prsp[0] = SMP_CMD_PAIRING_RSP;
-       memcpy(&smp->prsp[1], rsp, sizeof(*rsp));
-
        /* Update remote key distribution in case the remote cleared
         * some bits that we had enabled in our request.
         */
@@ -1764,6 +1948,26 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
        if (!test_bit(SMP_FLAG_SC, &smp->flags))
                return smp_random(smp);
 
+       if (hcon->out) {
+               pkax = smp->local_pk;
+               pkbx = smp->remote_pk;
+               na   = smp->prnd;
+               nb   = smp->rrnd;
+       } else {
+               pkax = smp->remote_pk;
+               pkbx = smp->local_pk;
+               na   = smp->rrnd;
+               nb   = smp->prnd;
+       }
+
+       if (smp->method == REQ_OOB) {
+               if (!hcon->out)
+                       smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM,
+                                    sizeof(smp->prnd), smp->prnd);
+               SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK);
+               goto mackey_and_ltk;
+       }
+
        /* Passkey entry has special treatment */
        if (smp->method == REQ_PASSKEY || smp->method == DSP_PASSKEY)
                return sc_passkey_round(smp, SMP_CMD_PAIRING_RANDOM);
@@ -1778,28 +1982,19 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 
                if (memcmp(smp->pcnf, cfm, 16))
                        return SMP_CONFIRM_FAILED;
-
-               pkax = smp->local_pk;
-               pkbx = smp->remote_pk;
-               na   = smp->prnd;
-               nb   = smp->rrnd;
        } else {
                smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd),
                             smp->prnd);
                SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK);
-
-               pkax = smp->remote_pk;
-               pkbx = smp->local_pk;
-               na   = smp->rrnd;
-               nb   = smp->prnd;
        }
 
+mackey_and_ltk:
        /* Generate MacKey and LTK */
        err = sc_mackey_and_ltk(smp, smp->mackey, smp->tk);
        if (err)
                return SMP_UNSPECIFIED;
 
-       if (smp->method == JUST_WORKS) {
+       if (smp->method == JUST_WORKS || smp->method == REQ_OOB) {
                if (hcon->out) {
                        sc_dhkey_check(smp);
                        SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK);
@@ -1887,6 +2082,9 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
 
        auth = rp->auth_req & AUTH_REQ_MASK(hdev);
 
+       if (test_bit(HCI_SC_ONLY, &hdev->dev_flags) && !(auth & SMP_AUTH_SC))
+               return SMP_AUTH_REQUIREMENTS;
+
        if (hcon->io_capability == HCI_IO_NO_INPUT_OUTPUT)
                sec_level = BT_SECURITY_MEDIUM;
        else
@@ -2165,6 +2363,9 @@ static u8 sc_select_method(struct smp_chan *smp)
        struct smp_cmd_pairing *local, *remote;
        u8 local_mitm, remote_mitm, local_io, remote_io, method;
 
+       if (test_bit(SMP_FLAG_OOB, &smp->flags))
+               return REQ_OOB;
+
        /* The preq/prsp contain the raw Pairing Request/Response PDUs
         * which are needed as inputs to some crypto functions. To get
         * the "struct smp_cmd_pairing" from them we need to skip the
@@ -2225,13 +2426,13 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
                        return err;
        }
 
-       BT_DBG("Remote Public Key X: %32phN", smp->remote_pk);
-       BT_DBG("Remote Public Key Y: %32phN", &smp->remote_pk[32]);
+       SMP_DBG("Remote Public Key X: %32phN", smp->remote_pk);
+       SMP_DBG("Remote Public Key Y: %32phN", &smp->remote_pk[32]);
 
        if (!ecdh_shared_secret(smp->remote_pk, smp->local_sk, smp->dhkey))
                return SMP_UNSPECIFIED;
 
-       BT_DBG("DHKey %32phN", smp->dhkey);
+       SMP_DBG("DHKey %32phN", smp->dhkey);
 
        set_bit(SMP_FLAG_REMOTE_PK, &smp->flags);
 
@@ -2263,6 +2464,24 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
                return sc_passkey_round(smp, SMP_CMD_PUBLIC_KEY);
        }
 
+       if (smp->method == REQ_OOB) {
+               err = smp_f4(smp->tfm_cmac, smp->remote_pk, smp->remote_pk,
+                            smp->rr, 0, cfm.confirm_val);
+               if (err)
+                       return SMP_UNSPECIFIED;
+
+               if (memcmp(cfm.confirm_val, smp->pcnf, 16))
+                       return SMP_CONFIRM_FAILED;
+
+               if (hcon->out)
+                       smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM,
+                                    sizeof(smp->prnd), smp->prnd);
+
+               SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RANDOM);
+
+               return 0;
+       }
+
        if (hcon->out)
                SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM);
 
@@ -2373,11 +2592,6 @@ static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb)
        __u8 code, reason;
        int err = 0;
 
-       if (hcon->type != LE_LINK) {
-               kfree_skb(skb);
-               return 0;
-       }
-
        if (skb->len < 1)
                return -EILSEQ;
 
@@ -2496,6 +2710,74 @@ static void smp_teardown_cb(struct l2cap_chan *chan, int err)
        l2cap_chan_put(chan);
 }
 
+static void bredr_pairing(struct l2cap_chan *chan)
+{
+       struct l2cap_conn *conn = chan->conn;
+       struct hci_conn *hcon = conn->hcon;
+       struct hci_dev *hdev = hcon->hdev;
+       struct smp_cmd_pairing req;
+       struct smp_chan *smp;
+
+       BT_DBG("chan %p", chan);
+
+       /* Only new pairings are interesting */
+       if (!test_bit(HCI_CONN_NEW_LINK_KEY, &hcon->flags))
+               return;
+
+       /* Don't bother if we're not encrypted */
+       if (!test_bit(HCI_CONN_ENCRYPT, &hcon->flags))
+               return;
+
+       /* Only master may initiate SMP over BR/EDR */
+       if (hcon->role != HCI_ROLE_MASTER)
+               return;
+
+       /* Secure Connections support must be enabled */
+       if (!test_bit(HCI_SC_ENABLED, &hdev->dev_flags))
+               return;
+
+       /* BR/EDR must use Secure Connections for SMP */
+       if (!test_bit(HCI_CONN_AES_CCM, &hcon->flags) &&
+           !test_bit(HCI_FORCE_LESC, &hdev->dbg_flags))
+               return;
+
+       /* If our LE support is not enabled don't do anything */
+       if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
+               return;
+
+       /* Don't bother if remote LE support is not enabled */
+       if (!lmp_host_le_capable(hcon))
+               return;
+
+       /* Remote must support SMP fixed chan for BR/EDR */
+       if (!(conn->remote_fixed_chan & L2CAP_FC_SMP_BREDR))
+               return;
+
+       /* Don't bother if SMP is already ongoing */
+       if (chan->data)
+               return;
+
+       smp = smp_chan_create(conn);
+       if (!smp) {
+               BT_ERR("%s unable to create SMP context for BR/EDR",
+                      hdev->name);
+               return;
+       }
+
+       set_bit(SMP_FLAG_SC, &smp->flags);
+
+       BT_DBG("%s starting SMP over BR/EDR", hdev->name);
+
+       /* Prepare and send the BR/EDR SMP Pairing Request */
+       build_bredr_pairing_cmd(smp, &req, NULL);
+
+       smp->preq[0] = SMP_CMD_PAIRING_REQ;
+       memcpy(&smp->preq[1], &req, sizeof(req));
+
+       smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(req), &req);
+       SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RSP);
+}
+
 static void smp_resume_cb(struct l2cap_chan *chan)
 {
        struct smp_chan *smp = chan->data;
@@ -2504,8 +2786,10 @@ static void smp_resume_cb(struct l2cap_chan *chan)
 
        BT_DBG("chan %p", chan);
 
-       if (hcon->type == ACL_LINK)
+       if (hcon->type == ACL_LINK) {
+               bredr_pairing(chan);
                return;
+       }
 
        if (!smp)
                return;
@@ -2521,23 +2805,23 @@ static void smp_resume_cb(struct l2cap_chan *chan)
 static void smp_ready_cb(struct l2cap_chan *chan)
 {
        struct l2cap_conn *conn = chan->conn;
+       struct hci_conn *hcon = conn->hcon;
 
        BT_DBG("chan %p", chan);
 
        conn->smp = chan;
        l2cap_chan_hold(chan);
+
+       if (hcon->type == ACL_LINK && test_bit(HCI_CONN_ENCRYPT, &hcon->flags))
+               bredr_pairing(chan);
 }
 
 static int smp_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
 {
-       struct hci_conn *hcon = chan->conn->hcon;
        int err;
 
        BT_DBG("chan %p", chan);
 
-       if (hcon->type == ACL_LINK)
-               return -EOPNOTSUPP;
-
        err = smp_sig_channel(chan, skb);
        if (err) {
                struct smp_chan *smp = chan->data;
@@ -2582,7 +2866,6 @@ static const struct l2cap_ops smp_chan_ops = {
        .suspend                = l2cap_chan_no_suspend,
        .set_shutdown           = l2cap_chan_no_set_shutdown,
        .get_sndtimeo           = l2cap_chan_no_get_sndtimeo,
-       .memcpy_fromiovec       = l2cap_chan_no_memcpy_fromiovec,
 };
 
 static inline struct l2cap_chan *smp_new_conn_cb(struct l2cap_chan *pchan)
@@ -2631,7 +2914,6 @@ static const struct l2cap_ops smp_root_chan_ops = {
        .resume                 = l2cap_chan_no_resume,
        .set_shutdown           = l2cap_chan_no_set_shutdown,
        .get_sndtimeo           = l2cap_chan_no_get_sndtimeo,
-       .memcpy_fromiovec       = l2cap_chan_no_memcpy_fromiovec,
 };
 
 static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid)
@@ -2647,7 +2929,7 @@ static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid)
        tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, 0);
        if (IS_ERR(tfm_aes)) {
                BT_ERR("Unable to create crypto context");
-               return ERR_PTR(PTR_ERR(tfm_aes));
+               return ERR_CAST(tfm_aes);
        }
 
 create_chan:
@@ -2740,3 +3022,323 @@ void smp_unregister(struct hci_dev *hdev)
                smp_del_chan(chan);
        }
 }
+
+#if IS_ENABLED(CONFIG_BT_SELFTEST_SMP)
+
+static int __init test_ah(struct crypto_blkcipher *tfm_aes)
+{
+       const u8 irk[16] = {
+                       0x9b, 0x7d, 0x39, 0x0a, 0xa6, 0x10, 0x10, 0x34,
+                       0x05, 0xad, 0xc8, 0x57, 0xa3, 0x34, 0x02, 0xec };
+       const u8 r[3] = { 0x94, 0x81, 0x70 };
+       const u8 exp[3] = { 0xaa, 0xfb, 0x0d };
+       u8 res[3];
+       int err;
+
+       err = smp_ah(tfm_aes, irk, r, res);
+       if (err)
+               return err;
+
+       if (memcmp(res, exp, 3))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int __init test_c1(struct crypto_blkcipher *tfm_aes)
+{
+       const u8 k[16] = {
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+       const u8 r[16] = {
+                       0xe0, 0x2e, 0x70, 0xc6, 0x4e, 0x27, 0x88, 0x63,
+                       0x0e, 0x6f, 0xad, 0x56, 0x21, 0xd5, 0x83, 0x57 };
+       const u8 preq[7] = { 0x01, 0x01, 0x00, 0x00, 0x10, 0x07, 0x07 };
+       const u8 pres[7] = { 0x02, 0x03, 0x00, 0x00, 0x08, 0x00, 0x05 };
+       const u8 _iat = 0x01;
+       const u8 _rat = 0x00;
+       const bdaddr_t ra = { { 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1 } };
+       const bdaddr_t ia = { { 0xa6, 0xa5, 0xa4, 0xa3, 0xa2, 0xa1 } };
+       const u8 exp[16] = {
+                       0x86, 0x3b, 0xf1, 0xbe, 0xc5, 0x4d, 0xa7, 0xd2,
+                       0xea, 0x88, 0x89, 0x87, 0xef, 0x3f, 0x1e, 0x1e };
+       u8 res[16];
+       int err;
+
+       err = smp_c1(tfm_aes, k, r, preq, pres, _iat, &ia, _rat, &ra, res);
+       if (err)
+               return err;
+
+       if (memcmp(res, exp, 16))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int __init test_s1(struct crypto_blkcipher *tfm_aes)
+{
+       const u8 k[16] = {
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+       const u8 r1[16] = {
+                       0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11 };
+       const u8 r2[16] = {
+                       0x00, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99 };
+       const u8 exp[16] = {
+                       0x62, 0xa0, 0x6d, 0x79, 0xae, 0x16, 0x42, 0x5b,
+                       0x9b, 0xf4, 0xb0, 0xe8, 0xf0, 0xe1, 0x1f, 0x9a };
+       u8 res[16];
+       int err;
+
+       err = smp_s1(tfm_aes, k, r1, r2, res);
+       if (err)
+               return err;
+
+       if (memcmp(res, exp, 16))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int __init test_f4(struct crypto_hash *tfm_cmac)
+{
+       const u8 u[32] = {
+                       0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc,
+                       0xdb, 0xfd, 0xf4, 0xac, 0x11, 0x91, 0xf4, 0xef,
+                       0xb9, 0xa5, 0xf9, 0xe9, 0xa7, 0x83, 0x2c, 0x5e,
+                       0x2c, 0xbe, 0x97, 0xf2, 0xd2, 0x03, 0xb0, 0x20 };
+       const u8 v[32] = {
+                       0xfd, 0xc5, 0x7f, 0xf4, 0x49, 0xdd, 0x4f, 0x6b,
+                       0xfb, 0x7c, 0x9d, 0xf1, 0xc2, 0x9a, 0xcb, 0x59,
+                       0x2a, 0xe7, 0xd4, 0xee, 0xfb, 0xfc, 0x0a, 0x90,
+                       0x9a, 0xbb, 0xf6, 0x32, 0x3d, 0x8b, 0x18, 0x55 };
+       const u8 x[16] = {
+                       0xab, 0xae, 0x2b, 0x71, 0xec, 0xb2, 0xff, 0xff,
+                       0x3e, 0x73, 0x77, 0xd1, 0x54, 0x84, 0xcb, 0xd5 };
+       const u8 z = 0x00;
+       const u8 exp[16] = {
+                       0x2d, 0x87, 0x74, 0xa9, 0xbe, 0xa1, 0xed, 0xf1,
+                       0x1c, 0xbd, 0xa9, 0x07, 0xf1, 0x16, 0xc9, 0xf2 };
+       u8 res[16];
+       int err;
+
+       err = smp_f4(tfm_cmac, u, v, x, z, res);
+       if (err)
+               return err;
+
+       if (memcmp(res, exp, 16))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int __init test_f5(struct crypto_hash *tfm_cmac)
+{
+       const u8 w[32] = {
+                       0x98, 0xa6, 0xbf, 0x73, 0xf3, 0x34, 0x8d, 0x86,
+                       0xf1, 0x66, 0xf8, 0xb4, 0x13, 0x6b, 0x79, 0x99,
+                       0x9b, 0x7d, 0x39, 0x0a, 0xa6, 0x10, 0x10, 0x34,
+                       0x05, 0xad, 0xc8, 0x57, 0xa3, 0x34, 0x02, 0xec };
+       const u8 n1[16] = {
+                       0xab, 0xae, 0x2b, 0x71, 0xec, 0xb2, 0xff, 0xff,
+                       0x3e, 0x73, 0x77, 0xd1, 0x54, 0x84, 0xcb, 0xd5 };
+       const u8 n2[16] = {
+                       0xcf, 0xc4, 0x3d, 0xff, 0xf7, 0x83, 0x65, 0x21,
+                       0x6e, 0x5f, 0xa7, 0x25, 0xcc, 0xe7, 0xe8, 0xa6 };
+       const u8 a1[7] = { 0xce, 0xbf, 0x37, 0x37, 0x12, 0x56, 0x00 };
+       const u8 a2[7] = { 0xc1, 0xcf, 0x2d, 0x70, 0x13, 0xa7, 0x00 };
+       const u8 exp_ltk[16] = {
+                       0x38, 0x0a, 0x75, 0x94, 0xb5, 0x22, 0x05, 0x98,
+                       0x23, 0xcd, 0xd7, 0x69, 0x11, 0x79, 0x86, 0x69 };
+       const u8 exp_mackey[16] = {
+                       0x20, 0x6e, 0x63, 0xce, 0x20, 0x6a, 0x3f, 0xfd,
+                       0x02, 0x4a, 0x08, 0xa1, 0x76, 0xf1, 0x65, 0x29 };
+       u8 mackey[16], ltk[16];
+       int err;
+
+       err = smp_f5(tfm_cmac, w, n1, n2, a1, a2, mackey, ltk);
+       if (err)
+               return err;
+
+       if (memcmp(mackey, exp_mackey, 16))
+               return -EINVAL;
+
+       if (memcmp(ltk, exp_ltk, 16))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int __init test_f6(struct crypto_hash *tfm_cmac)
+{
+       const u8 w[16] = {
+                       0x20, 0x6e, 0x63, 0xce, 0x20, 0x6a, 0x3f, 0xfd,
+                       0x02, 0x4a, 0x08, 0xa1, 0x76, 0xf1, 0x65, 0x29 };
+       const u8 n1[16] = {
+                       0xab, 0xae, 0x2b, 0x71, 0xec, 0xb2, 0xff, 0xff,
+                       0x3e, 0x73, 0x77, 0xd1, 0x54, 0x84, 0xcb, 0xd5 };
+       const u8 n2[16] = {
+                       0xcf, 0xc4, 0x3d, 0xff, 0xf7, 0x83, 0x65, 0x21,
+                       0x6e, 0x5f, 0xa7, 0x25, 0xcc, 0xe7, 0xe8, 0xa6 };
+       const u8 r[16] = {
+                       0xc8, 0x0f, 0x2d, 0x0c, 0xd2, 0x42, 0xda, 0x08,
+                       0x54, 0xbb, 0x53, 0xb4, 0x3b, 0x34, 0xa3, 0x12 };
+       const u8 io_cap[3] = { 0x02, 0x01, 0x01 };
+       const u8 a1[7] = { 0xce, 0xbf, 0x37, 0x37, 0x12, 0x56, 0x00 };
+       const u8 a2[7] = { 0xc1, 0xcf, 0x2d, 0x70, 0x13, 0xa7, 0x00 };
+       const u8 exp[16] = {
+                       0x61, 0x8f, 0x95, 0xda, 0x09, 0x0b, 0x6c, 0xd2,
+                       0xc5, 0xe8, 0xd0, 0x9c, 0x98, 0x73, 0xc4, 0xe3 };
+       u8 res[16];
+       int err;
+
+       err = smp_f6(tfm_cmac, w, n1, n2, r, io_cap, a1, a2, res);
+       if (err)
+               return err;
+
+       if (memcmp(res, exp, 16))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int __init test_g2(struct crypto_hash *tfm_cmac)
+{
+       const u8 u[32] = {
+                       0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc,
+                       0xdb, 0xfd, 0xf4, 0xac, 0x11, 0x91, 0xf4, 0xef,
+                       0xb9, 0xa5, 0xf9, 0xe9, 0xa7, 0x83, 0x2c, 0x5e,
+                       0x2c, 0xbe, 0x97, 0xf2, 0xd2, 0x03, 0xb0, 0x20 };
+       const u8 v[32] = {
+                       0xfd, 0xc5, 0x7f, 0xf4, 0x49, 0xdd, 0x4f, 0x6b,
+                       0xfb, 0x7c, 0x9d, 0xf1, 0xc2, 0x9a, 0xcb, 0x59,
+                       0x2a, 0xe7, 0xd4, 0xee, 0xfb, 0xfc, 0x0a, 0x90,
+                       0x9a, 0xbb, 0xf6, 0x32, 0x3d, 0x8b, 0x18, 0x55 };
+       const u8 x[16] = {
+                       0xab, 0xae, 0x2b, 0x71, 0xec, 0xb2, 0xff, 0xff,
+                       0x3e, 0x73, 0x77, 0xd1, 0x54, 0x84, 0xcb, 0xd5 };
+       const u8 y[16] = {
+                       0xcf, 0xc4, 0x3d, 0xff, 0xf7, 0x83, 0x65, 0x21,
+                       0x6e, 0x5f, 0xa7, 0x25, 0xcc, 0xe7, 0xe8, 0xa6 };
+       const u32 exp_val = 0x2f9ed5ba % 1000000;
+       u32 val;
+       int err;
+
+       err = smp_g2(tfm_cmac, u, v, x, y, &val);
+       if (err)
+               return err;
+
+       if (val != exp_val)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int __init test_h6(struct crypto_hash *tfm_cmac)
+{
+       const u8 w[16] = {
+                       0x9b, 0x7d, 0x39, 0x0a, 0xa6, 0x10, 0x10, 0x34,
+                       0x05, 0xad, 0xc8, 0x57, 0xa3, 0x34, 0x02, 0xec };
+       const u8 key_id[4] = { 0x72, 0x62, 0x65, 0x6c };
+       const u8 exp[16] = {
+                       0x99, 0x63, 0xb1, 0x80, 0xe2, 0xa9, 0xd3, 0xe8,
+                       0x1c, 0xc9, 0x6d, 0xe7, 0x02, 0xe1, 0x9a, 0x2d };
+       u8 res[16];
+       int err;
+
+       err = smp_h6(tfm_cmac, w, key_id, res);
+       if (err)
+               return err;
+
+       if (memcmp(res, exp, 16))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int __init run_selftests(struct crypto_blkcipher *tfm_aes,
+                               struct crypto_hash *tfm_cmac)
+{
+       int err;
+
+       err = test_ah(tfm_aes);
+       if (err) {
+               BT_ERR("smp_ah test failed");
+               return err;
+       }
+
+       err = test_c1(tfm_aes);
+       if (err) {
+               BT_ERR("smp_c1 test failed");
+               return err;
+       }
+
+       err = test_s1(tfm_aes);
+       if (err) {
+               BT_ERR("smp_s1 test failed");
+               return err;
+       }
+
+       err = test_f4(tfm_cmac);
+       if (err) {
+               BT_ERR("smp_f4 test failed");
+               return err;
+       }
+
+       err = test_f5(tfm_cmac);
+       if (err) {
+               BT_ERR("smp_f5 test failed");
+               return err;
+       }
+
+       err = test_f6(tfm_cmac);
+       if (err) {
+               BT_ERR("smp_f6 test failed");
+               return err;
+       }
+
+       err = test_g2(tfm_cmac);
+       if (err) {
+               BT_ERR("smp_g2 test failed");
+               return err;
+       }
+
+       err = test_h6(tfm_cmac);
+       if (err) {
+               BT_ERR("smp_h6 test failed");
+               return err;
+       }
+
+       BT_INFO("SMP test passed");
+
+       return 0;
+}
+
+int __init bt_selftest_smp(void)
+{
+       struct crypto_blkcipher *tfm_aes;
+       struct crypto_hash *tfm_cmac;
+       int err;
+
+       tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(tfm_aes)) {
+               BT_ERR("Unable to create ECB crypto context");
+               return PTR_ERR(tfm_aes);
+       }
+
+       tfm_cmac = crypto_alloc_hash("cmac(aes)", 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(tfm_cmac)) {
+               BT_ERR("Unable to create CMAC crypto context");
+               crypto_free_blkcipher(tfm_aes);
+               return PTR_ERR(tfm_cmac);
+       }
+
+       err = run_selftests(tfm_aes, tfm_cmac);
+
+       crypto_free_hash(tfm_cmac);
+       crypto_free_blkcipher(tfm_aes);
+
+       return err;
+}
+
+#endif