summaryrefslogtreecommitdiff
path: root/lib/bt/host/bluedroid/stack/smp
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2024-03-28 14:32:49 +1100
committerjacqueline <me@jacqueline.id.au>2024-03-28 14:32:49 +1100
commitee29c25b29eaa4fac4e897442634b69ecc8d8125 (patch)
tree8c5f1a140463f20f104316fa3492984e191154e9 /lib/bt/host/bluedroid/stack/smp
parent239e6d89507a24c849385f4bfa93ac4ad58e5de5 (diff)
downloadtangara-fw-ee29c25b29eaa4fac4e897442634b69ecc8d8125.tar.gz
Fork ESP-IDF's bluetooth component
i want better sbc encoding, and no cla will stop me
Diffstat (limited to 'lib/bt/host/bluedroid/stack/smp')
-rw-r--r--lib/bt/host/bluedroid/stack/smp/aes.c938
-rw-r--r--lib/bt/host/bluedroid/stack/smp/include/aes.h162
-rw-r--r--lib/bt/host/bluedroid/stack/smp/include/p_256_ecc_pp.h74
-rw-r--r--lib/bt/host/bluedroid/stack/smp/include/p_256_multprecision.h60
-rw-r--r--lib/bt/host/bluedroid/stack/smp/include/smp_int.h545
-rw-r--r--lib/bt/host/bluedroid/stack/smp/p_256_curvepara.c78
-rw-r--r--lib/bt/host/bluedroid/stack/smp/p_256_ecc_pp.c283
-rw-r--r--lib/bt/host/bluedroid/stack/smp/p_256_multprecision.c647
-rw-r--r--lib/bt/host/bluedroid/stack/smp/smp_act.c2194
-rw-r--r--lib/bt/host/bluedroid/stack/smp/smp_api.c615
-rw-r--r--lib/bt/host/bluedroid/stack/smp/smp_br_main.c369
-rw-r--r--lib/bt/host/bluedroid/stack/smp/smp_cmac.c369
-rw-r--r--lib/bt/host/bluedroid/stack/smp/smp_keys.c2293
-rw-r--r--lib/bt/host/bluedroid/stack/smp/smp_l2c.c344
-rw-r--r--lib/bt/host/bluedroid/stack/smp/smp_main.c810
-rw-r--r--lib/bt/host/bluedroid/stack/smp/smp_utils.c1645
16 files changed, 11426 insertions, 0 deletions
diff --git a/lib/bt/host/bluedroid/stack/smp/aes.c b/lib/bt/host/bluedroid/stack/smp/aes.c
new file mode 100644
index 00000000..18b56b87
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/smp/aes.c
@@ -0,0 +1,938 @@
+/*
+ ---------------------------------------------------------------------------
+ Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
+
+ LICENSE TERMS
+
+ The redistribution and use of this software (with or without changes)
+ is allowed without the payment of fees or royalties provided that:
+
+ 1. source code distributions include the above copyright notice, this
+ list of conditions and the following disclaimer;
+
+ 2. binary distributions include the above copyright notice, this list
+ of conditions and the following disclaimer in their documentation;
+
+ 3. the name of the copyright holder is not used to endorse products
+ built using this software without specific written permission.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
+ Issue 09/09/2006
+
+ This is an AES implementation that uses only 8-bit byte operations on the
+ cipher state (there are options to use 32-bit types if available).
+
+ The combination of mix columns and byte substitution used here is based on
+ that developed by Karl Malbrain. His contribution is acknowledged.
+ */
+
+/* define if you have a fast memcpy function on your system */
+#if 1
+# define HAVE_MEMCPY
+# include <string.h>
+#if 0
+# if defined( _MSC_VER )
+# include <intrin.h>
+# pragma intrinsic( memcpy )
+# endif
+#endif
+#endif
+
+#include <stdlib.h>
+
+/* add the target configuration to allow using internal data types and compilation options */
+#include "common/bt_target.h"
+
+/* define if you have fast 32-bit types on your system */
+#if 1
+# define HAVE_UINT_32T
+#endif
+
+/* define if you don't want any tables */
+#if 1
+# define USE_TABLES
+#endif
+
+/* On Intel Core 2 duo VERSION_1 is faster */
+
+/* alternative versions (test for performance on your system) */
+#if 1
+# define VERSION_1
+#endif
+
+#include "aes.h"
+
+#if defined( HAVE_UINT_32T )
+typedef UINT32 uint_32t;
+#endif
+
+/* functions for finite field multiplication in the AES Galois field */
+
+#define WPOLY 0x011b
+#define BPOLY 0x1b
+#define DPOLY 0x008d
+
+#define f1(x) (x)
+#define f2(x) ((x << 1) ^ (((x >> 7) & 1) * WPOLY))
+#define f4(x) ((x << 2) ^ (((x >> 6) & 1) * WPOLY) ^ (((x >> 6) & 2) * WPOLY))
+#define f8(x) ((x << 3) ^ (((x >> 5) & 1) * WPOLY) ^ (((x >> 5) & 2) * WPOLY) \
+ ^ (((x >> 5) & 4) * WPOLY))
+#define d2(x) (((x) >> 1) ^ ((x) & 1 ? DPOLY : 0))
+
+#define f3(x) (f2(x) ^ x)
+#define f9(x) (f8(x) ^ x)
+#define fb(x) (f8(x) ^ f2(x) ^ x)
+#define fd(x) (f8(x) ^ f4(x) ^ x)
+#define fe(x) (f8(x) ^ f4(x) ^ f2(x))
+
+#if defined( USE_TABLES )
+
+#define sb_data(w) { /* S Box data values */ \
+ w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\
+ w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\
+ w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\
+ w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\
+ w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\
+ w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\
+ w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\
+ w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\
+ w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\
+ w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\
+ w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\
+ w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\
+ w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\
+ w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\
+ w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\
+ w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\
+ w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\
+ w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\
+ w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\
+ w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\
+ w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\
+ w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\
+ w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\
+ w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\
+ w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\
+ w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\
+ w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\
+ w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\
+ w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\
+ w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\
+ w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\
+ w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) }
+
+#define isb_data(w) { /* inverse S Box data values */ \
+ w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\
+ w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\
+ w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\
+ w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\
+ w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\
+ w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\
+ w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\
+ w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\
+ w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\
+ w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\
+ w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\
+ w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\
+ w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\
+ w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\
+ w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\
+ w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\
+ w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\
+ w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\
+ w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\
+ w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\
+ w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\
+ w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\
+ w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\
+ w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\
+ w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\
+ w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\
+ w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\
+ w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\
+ w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\
+ w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\
+ w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\
+ w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d) }
+
+#define mm_data(w) { /* basic data for forming finite field tables */ \
+ w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\
+ w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\
+ w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\
+ w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\
+ w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\
+ w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\
+ w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\
+ w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\
+ w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\
+ w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\
+ w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\
+ w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\
+ w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\
+ w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\
+ w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\
+ w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\
+ w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\
+ w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\
+ w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\
+ w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\
+ w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\
+ w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\
+ w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\
+ w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\
+ w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\
+ w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\
+ w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\
+ w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\
+ w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\
+ w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\
+ w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\
+ w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) }
+
+static const uint_8t sbox[256] = sb_data(f1);
+static const uint_8t isbox[256] = isb_data(f1);
+
+static const uint_8t gfm2_sbox[256] = sb_data(f2);
+static const uint_8t gfm3_sbox[256] = sb_data(f3);
+
+static const uint_8t gfmul_9[256] = mm_data(f9);
+static const uint_8t gfmul_b[256] = mm_data(fb);
+static const uint_8t gfmul_d[256] = mm_data(fd);
+static const uint_8t gfmul_e[256] = mm_data(fe);
+
+#define s_box(x) sbox[(x)]
+#define is_box(x) isbox[(x)]
+#define gfm2_sb(x) gfm2_sbox[(x)]
+#define gfm3_sb(x) gfm3_sbox[(x)]
+#define gfm_9(x) gfmul_9[(x)]
+#define gfm_b(x) gfmul_b[(x)]
+#define gfm_d(x) gfmul_d[(x)]
+#define gfm_e(x) gfmul_e[(x)]
+
+#else
+
+/* this is the high bit of x right shifted by 1 */
+/* position. Since the starting polynomial has */
+/* 9 bits (0x11b), this right shift keeps the */
+/* values of all top bits within a byte */
+
+static uint_8t hibit(const uint_8t x)
+{
+ uint_8t r = (uint_8t)((x >> 1) | (x >> 2));
+
+ r |= (r >> 2);
+ r |= (r >> 4);
+ return (r + 1) >> 1;
+}
+
+/* return the inverse of the finite field element x */
+
+static uint_8t gf_inv(const uint_8t x)
+{
+ uint_8t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0;
+
+ if (x < 2) {
+ return x;
+ }
+
+ for ( ; ; ) {
+ if (n1) {
+ while (n2 >= n1) { /* divide polynomial p2 by p1 */
+ n2 /= n1; /* shift smaller polynomial left */
+ p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */
+ v2 ^= (v1 * n2); /* shift accumulated value and */
+ n2 = hibit(p2); /* add into result */
+ }
+ } else {
+ return v1;
+ }
+
+ if (n2) { /* repeat with values swapped */
+ while (n1 >= n2) {
+ n1 /= n2;
+ p1 ^= p2 * n1;
+ v1 ^= v2 * n1;
+ n1 = hibit(p1);
+ }
+ } else {
+ return v2;
+ }
+ }
+}
+
+/* The forward and inverse affine transformations used in the S-box */
+uint_8t fwd_affine(const uint_8t x)
+{
+#if defined( HAVE_UINT_32T )
+ uint_32t w = x;
+ w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4);
+ return 0x63 ^ ((w ^ (w >> 8)) & 0xff);
+#else
+ return 0x63 ^ x ^ (x << 1) ^ (x << 2) ^ (x << 3) ^ (x << 4)
+ ^ (x >> 7) ^ (x >> 6) ^ (x >> 5) ^ (x >> 4);
+#endif
+}
+
+uint_8t inv_affine(const uint_8t x)
+{
+#if defined( HAVE_UINT_32T )
+ uint_32t w = x;
+ w = (w << 1) ^ (w << 3) ^ (w << 6);
+ return 0x05 ^ ((w ^ (w >> 8)) & 0xff);
+#else
+ return 0x05 ^ (x << 1) ^ (x << 3) ^ (x << 6)
+ ^ (x >> 7) ^ (x >> 5) ^ (x >> 2);
+#endif
+}
+
+#define s_box(x) fwd_affine(gf_inv(x))
+#define is_box(x) gf_inv(inv_affine(x))
+#define gfm2_sb(x) f2(s_box(x))
+#define gfm3_sb(x) f3(s_box(x))
+#define gfm_9(x) f9(x)
+#define gfm_b(x) fb(x)
+#define gfm_d(x) fd(x)
+#define gfm_e(x) fe(x)
+
+#endif
+
+#if defined( HAVE_MEMCPY )
+# define block_copy_nn(d, s, l) memcpy(d, s, l)
+# define block_copy(d, s) memcpy(d, s, N_BLOCK)
+#else
+# define block_copy_nn(d, s, l) copy_block_nn(d, s, l)
+# define block_copy(d, s) copy_block(d, s)
+#endif
+
+#if !defined( HAVE_MEMCPY )
+static void copy_block( void *d, const void *s )
+{
+#if defined( HAVE_UINT_32T )
+ ((uint_32t *)d)[ 0] = ((uint_32t *)s)[ 0];
+ ((uint_32t *)d)[ 1] = ((uint_32t *)s)[ 1];
+ ((uint_32t *)d)[ 2] = ((uint_32t *)s)[ 2];
+ ((uint_32t *)d)[ 3] = ((uint_32t *)s)[ 3];
+#else
+ ((uint_8t *)d)[ 0] = ((uint_8t *)s)[ 0];
+ ((uint_8t *)d)[ 1] = ((uint_8t *)s)[ 1];
+ ((uint_8t *)d)[ 2] = ((uint_8t *)s)[ 2];
+ ((uint_8t *)d)[ 3] = ((uint_8t *)s)[ 3];
+ ((uint_8t *)d)[ 4] = ((uint_8t *)s)[ 4];
+ ((uint_8t *)d)[ 5] = ((uint_8t *)s)[ 5];
+ ((uint_8t *)d)[ 6] = ((uint_8t *)s)[ 6];
+ ((uint_8t *)d)[ 7] = ((uint_8t *)s)[ 7];
+ ((uint_8t *)d)[ 8] = ((uint_8t *)s)[ 8];
+ ((uint_8t *)d)[ 9] = ((uint_8t *)s)[ 9];
+ ((uint_8t *)d)[10] = ((uint_8t *)s)[10];
+ ((uint_8t *)d)[11] = ((uint_8t *)s)[11];
+ ((uint_8t *)d)[12] = ((uint_8t *)s)[12];
+ ((uint_8t *)d)[13] = ((uint_8t *)s)[13];
+ ((uint_8t *)d)[14] = ((uint_8t *)s)[14];
+ ((uint_8t *)d)[15] = ((uint_8t *)s)[15];
+#endif
+}
+
+static void copy_block_nn( void *d, const void *s, uint_8t nn )
+{
+ while ( nn-- ) {
+ *((uint_8t *)d)++ = *((uint_8t *)s)++;
+ }
+}
+#endif
+
+static void xor_block( void *d, const void *s )
+{
+#if defined( HAVE_UINT_32T )
+ ((uint_32t *)d)[ 0] ^= ((uint_32t *)s)[ 0];
+ ((uint_32t *)d)[ 1] ^= ((uint_32t *)s)[ 1];
+ ((uint_32t *)d)[ 2] ^= ((uint_32t *)s)[ 2];
+ ((uint_32t *)d)[ 3] ^= ((uint_32t *)s)[ 3];
+#else
+ ((uint_8t *)d)[ 0] ^= ((uint_8t *)s)[ 0];
+ ((uint_8t *)d)[ 1] ^= ((uint_8t *)s)[ 1];
+ ((uint_8t *)d)[ 2] ^= ((uint_8t *)s)[ 2];
+ ((uint_8t *)d)[ 3] ^= ((uint_8t *)s)[ 3];
+ ((uint_8t *)d)[ 4] ^= ((uint_8t *)s)[ 4];
+ ((uint_8t *)d)[ 5] ^= ((uint_8t *)s)[ 5];
+ ((uint_8t *)d)[ 6] ^= ((uint_8t *)s)[ 6];
+ ((uint_8t *)d)[ 7] ^= ((uint_8t *)s)[ 7];
+ ((uint_8t *)d)[ 8] ^= ((uint_8t *)s)[ 8];
+ ((uint_8t *)d)[ 9] ^= ((uint_8t *)s)[ 9];
+ ((uint_8t *)d)[10] ^= ((uint_8t *)s)[10];
+ ((uint_8t *)d)[11] ^= ((uint_8t *)s)[11];
+ ((uint_8t *)d)[12] ^= ((uint_8t *)s)[12];
+ ((uint_8t *)d)[13] ^= ((uint_8t *)s)[13];
+ ((uint_8t *)d)[14] ^= ((uint_8t *)s)[14];
+ ((uint_8t *)d)[15] ^= ((uint_8t *)s)[15];
+#endif
+}
+
+static void copy_and_key( void *d, const void *s, const void *k )
+{
+#if defined( HAVE_UINT_32T )
+ ((uint_32t *)d)[ 0] = ((uint_32t *)s)[ 0] ^ ((uint_32t *)k)[ 0];
+ ((uint_32t *)d)[ 1] = ((uint_32t *)s)[ 1] ^ ((uint_32t *)k)[ 1];
+ ((uint_32t *)d)[ 2] = ((uint_32t *)s)[ 2] ^ ((uint_32t *)k)[ 2];
+ ((uint_32t *)d)[ 3] = ((uint_32t *)s)[ 3] ^ ((uint_32t *)k)[ 3];
+#elif 1
+ ((uint_8t *)d)[ 0] = ((uint_8t *)s)[ 0] ^ ((uint_8t *)k)[ 0];
+ ((uint_8t *)d)[ 1] = ((uint_8t *)s)[ 1] ^ ((uint_8t *)k)[ 1];
+ ((uint_8t *)d)[ 2] = ((uint_8t *)s)[ 2] ^ ((uint_8t *)k)[ 2];
+ ((uint_8t *)d)[ 3] = ((uint_8t *)s)[ 3] ^ ((uint_8t *)k)[ 3];
+ ((uint_8t *)d)[ 4] = ((uint_8t *)s)[ 4] ^ ((uint_8t *)k)[ 4];
+ ((uint_8t *)d)[ 5] = ((uint_8t *)s)[ 5] ^ ((uint_8t *)k)[ 5];
+ ((uint_8t *)d)[ 6] = ((uint_8t *)s)[ 6] ^ ((uint_8t *)k)[ 6];
+ ((uint_8t *)d)[ 7] = ((uint_8t *)s)[ 7] ^ ((uint_8t *)k)[ 7];
+ ((uint_8t *)d)[ 8] = ((uint_8t *)s)[ 8] ^ ((uint_8t *)k)[ 8];
+ ((uint_8t *)d)[ 9] = ((uint_8t *)s)[ 9] ^ ((uint_8t *)k)[ 9];
+ ((uint_8t *)d)[10] = ((uint_8t *)s)[10] ^ ((uint_8t *)k)[10];
+ ((uint_8t *)d)[11] = ((uint_8t *)s)[11] ^ ((uint_8t *)k)[11];
+ ((uint_8t *)d)[12] = ((uint_8t *)s)[12] ^ ((uint_8t *)k)[12];
+ ((uint_8t *)d)[13] = ((uint_8t *)s)[13] ^ ((uint_8t *)k)[13];
+ ((uint_8t *)d)[14] = ((uint_8t *)s)[14] ^ ((uint_8t *)k)[14];
+ ((uint_8t *)d)[15] = ((uint_8t *)s)[15] ^ ((uint_8t *)k)[15];
+#else
+ block_copy(d, s);
+ xor_block(d, k);
+#endif
+}
+
+static void add_round_key( uint_8t d[N_BLOCK], const uint_8t k[N_BLOCK] )
+{
+ xor_block(d, k);
+}
+
+static void shift_sub_rows( uint_8t st[N_BLOCK] )
+{
+ uint_8t tt;
+
+ st[ 0] = s_box(st[ 0]); st[ 4] = s_box(st[ 4]);
+ st[ 8] = s_box(st[ 8]); st[12] = s_box(st[12]);
+
+ tt = st[1]; st[ 1] = s_box(st[ 5]); st[ 5] = s_box(st[ 9]);
+ st[ 9] = s_box(st[13]); st[13] = s_box( tt );
+
+ tt = st[2]; st[ 2] = s_box(st[10]); st[10] = s_box( tt );
+ tt = st[6]; st[ 6] = s_box(st[14]); st[14] = s_box( tt );
+
+ tt = st[15]; st[15] = s_box(st[11]); st[11] = s_box(st[ 7]);
+ st[ 7] = s_box(st[ 3]); st[ 3] = s_box( tt );
+}
+
+static void inv_shift_sub_rows( uint_8t st[N_BLOCK] )
+{
+ uint_8t tt;
+
+ st[ 0] = is_box(st[ 0]); st[ 4] = is_box(st[ 4]);
+ st[ 8] = is_box(st[ 8]); st[12] = is_box(st[12]);
+
+ tt = st[13]; st[13] = is_box(st[9]); st[ 9] = is_box(st[5]);
+ st[ 5] = is_box(st[1]); st[ 1] = is_box( tt );
+
+ tt = st[2]; st[ 2] = is_box(st[10]); st[10] = is_box( tt );
+ tt = st[6]; st[ 6] = is_box(st[14]); st[14] = is_box( tt );
+
+ tt = st[3]; st[ 3] = is_box(st[ 7]); st[ 7] = is_box(st[11]);
+ st[11] = is_box(st[15]); st[15] = is_box( tt );
+}
+
+#if defined( VERSION_1 )
+static void mix_sub_columns( uint_8t dt[N_BLOCK] )
+{
+ uint_8t st[N_BLOCK];
+ block_copy(st, dt);
+#else
+static void mix_sub_columns( uint_8t dt[N_BLOCK], uint_8t st[N_BLOCK] )
+{
+#endif
+ dt[ 0] = gfm2_sb(st[0]) ^ gfm3_sb(st[5]) ^ s_box(st[10]) ^ s_box(st[15]);
+ dt[ 1] = s_box(st[0]) ^ gfm2_sb(st[5]) ^ gfm3_sb(st[10]) ^ s_box(st[15]);
+ dt[ 2] = s_box(st[0]) ^ s_box(st[5]) ^ gfm2_sb(st[10]) ^ gfm3_sb(st[15]);
+ dt[ 3] = gfm3_sb(st[0]) ^ s_box(st[5]) ^ s_box(st[10]) ^ gfm2_sb(st[15]);
+
+ dt[ 4] = gfm2_sb(st[4]) ^ gfm3_sb(st[9]) ^ s_box(st[14]) ^ s_box(st[3]);
+ dt[ 5] = s_box(st[4]) ^ gfm2_sb(st[9]) ^ gfm3_sb(st[14]) ^ s_box(st[3]);
+ dt[ 6] = s_box(st[4]) ^ s_box(st[9]) ^ gfm2_sb(st[14]) ^ gfm3_sb(st[3]);
+ dt[ 7] = gfm3_sb(st[4]) ^ s_box(st[9]) ^ s_box(st[14]) ^ gfm2_sb(st[3]);
+
+ dt[ 8] = gfm2_sb(st[8]) ^ gfm3_sb(st[13]) ^ s_box(st[2]) ^ s_box(st[7]);
+ dt[ 9] = s_box(st[8]) ^ gfm2_sb(st[13]) ^ gfm3_sb(st[2]) ^ s_box(st[7]);
+ dt[10] = s_box(st[8]) ^ s_box(st[13]) ^ gfm2_sb(st[2]) ^ gfm3_sb(st[7]);
+ dt[11] = gfm3_sb(st[8]) ^ s_box(st[13]) ^ s_box(st[2]) ^ gfm2_sb(st[7]);
+
+ dt[12] = gfm2_sb(st[12]) ^ gfm3_sb(st[1]) ^ s_box(st[6]) ^ s_box(st[11]);
+ dt[13] = s_box(st[12]) ^ gfm2_sb(st[1]) ^ gfm3_sb(st[6]) ^ s_box(st[11]);
+ dt[14] = s_box(st[12]) ^ s_box(st[1]) ^ gfm2_sb(st[6]) ^ gfm3_sb(st[11]);
+ dt[15] = gfm3_sb(st[12]) ^ s_box(st[1]) ^ s_box(st[6]) ^ gfm2_sb(st[11]);
+}
+
+#if defined( VERSION_1 )
+static void inv_mix_sub_columns( uint_8t dt[N_BLOCK] )
+{
+ uint_8t st[N_BLOCK];
+ block_copy(st, dt);
+#else
+static void inv_mix_sub_columns( uint_8t dt[N_BLOCK], uint_8t st[N_BLOCK] )
+{
+#endif
+ dt[ 0] = is_box(gfm_e(st[ 0]) ^ gfm_b(st[ 1]) ^ gfm_d(st[ 2]) ^ gfm_9(st[ 3]));
+ dt[ 5] = is_box(gfm_9(st[ 0]) ^ gfm_e(st[ 1]) ^ gfm_b(st[ 2]) ^ gfm_d(st[ 3]));
+ dt[10] = is_box(gfm_d(st[ 0]) ^ gfm_9(st[ 1]) ^ gfm_e(st[ 2]) ^ gfm_b(st[ 3]));
+ dt[15] = is_box(gfm_b(st[ 0]) ^ gfm_d(st[ 1]) ^ gfm_9(st[ 2]) ^ gfm_e(st[ 3]));
+
+ dt[ 4] = is_box(gfm_e(st[ 4]) ^ gfm_b(st[ 5]) ^ gfm_d(st[ 6]) ^ gfm_9(st[ 7]));
+ dt[ 9] = is_box(gfm_9(st[ 4]) ^ gfm_e(st[ 5]) ^ gfm_b(st[ 6]) ^ gfm_d(st[ 7]));
+ dt[14] = is_box(gfm_d(st[ 4]) ^ gfm_9(st[ 5]) ^ gfm_e(st[ 6]) ^ gfm_b(st[ 7]));
+ dt[ 3] = is_box(gfm_b(st[ 4]) ^ gfm_d(st[ 5]) ^ gfm_9(st[ 6]) ^ gfm_e(st[ 7]));
+
+ dt[ 8] = is_box(gfm_e(st[ 8]) ^ gfm_b(st[ 9]) ^ gfm_d(st[10]) ^ gfm_9(st[11]));
+ dt[13] = is_box(gfm_9(st[ 8]) ^ gfm_e(st[ 9]) ^ gfm_b(st[10]) ^ gfm_d(st[11]));
+ dt[ 2] = is_box(gfm_d(st[ 8]) ^ gfm_9(st[ 9]) ^ gfm_e(st[10]) ^ gfm_b(st[11]));
+ dt[ 7] = is_box(gfm_b(st[ 8]) ^ gfm_d(st[ 9]) ^ gfm_9(st[10]) ^ gfm_e(st[11]));
+
+ dt[12] = is_box(gfm_e(st[12]) ^ gfm_b(st[13]) ^ gfm_d(st[14]) ^ gfm_9(st[15]));
+ dt[ 1] = is_box(gfm_9(st[12]) ^ gfm_e(st[13]) ^ gfm_b(st[14]) ^ gfm_d(st[15]));
+ dt[ 6] = is_box(gfm_d(st[12]) ^ gfm_9(st[13]) ^ gfm_e(st[14]) ^ gfm_b(st[15]));
+ dt[11] = is_box(gfm_b(st[12]) ^ gfm_d(st[13]) ^ gfm_9(st[14]) ^ gfm_e(st[15]));
+}
+
+#if defined( AES_ENC_PREKEYED ) || defined( AES_DEC_PREKEYED )
+
+/* Set the cipher key for the pre-keyed version */
+/* NOTE: If the length_type used for the key length is an
+ unsigned 8-bit character, a key length of 256 bits must
+ be entered as a length in bytes (valid inputs are hence
+ 128, 192, 16, 24 and 32).
+*/
+
+return_type aes_set_key( const unsigned char key[], length_type keylen, aes_context ctx[1] )
+{
+ uint_8t cc, rc, hi;
+
+ switch ( keylen ) {
+ case 16:
+ case 128: /* length in bits (128 = 8*16) */
+ keylen = 16;
+ break;
+ case 24:
+ case 192: /* length in bits (192 = 8*24) */
+ keylen = 24;
+ break;
+ case 32:
+ /* case 256: length in bits (256 = 8*32) */
+ keylen = 32;
+ break;
+ default:
+ ctx->rnd = 0;
+ return (return_type) - 1;
+ }
+ block_copy_nn(ctx->ksch, key, keylen);
+ hi = (keylen + 28) << 2;
+ ctx->rnd = (hi >> 4) - 1;
+ for ( cc = keylen, rc = 1; cc < hi; cc += 4 ) {
+ uint_8t tt, t0, t1, t2, t3;
+
+ t0 = ctx->ksch[cc - 4];
+ t1 = ctx->ksch[cc - 3];
+ t2 = ctx->ksch[cc - 2];
+ t3 = ctx->ksch[cc - 1];
+ if ( cc % keylen == 0 ) {
+ tt = t0;
+ t0 = s_box(t1) ^ rc;
+ t1 = s_box(t2);
+ t2 = s_box(t3);
+ t3 = s_box(tt);
+ rc = f2(rc);
+ } else if ( keylen > 24 && cc % keylen == 16 ) {
+ t0 = s_box(t0);
+ t1 = s_box(t1);
+ t2 = s_box(t2);
+ t3 = s_box(t3);
+ }
+ tt = cc - keylen;
+ ctx->ksch[cc + 0] = ctx->ksch[tt + 0] ^ t0;
+ ctx->ksch[cc + 1] = ctx->ksch[tt + 1] ^ t1;
+ ctx->ksch[cc + 2] = ctx->ksch[tt + 2] ^ t2;
+ ctx->ksch[cc + 3] = ctx->ksch[tt + 3] ^ t3;
+ }
+ return 0;
+}
+
+#endif
+
+#if defined( AES_ENC_PREKEYED )
+
+/* Encrypt a single block of 16 bytes */
+
+/* @breif change the name by snake for avoid the conflict with libcrypto */
+return_type bluedroid_aes_encrypt( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], const aes_context ctx[1] )
+{
+ if ( ctx->rnd ) {
+ uint_8t s1[N_BLOCK], r;
+ copy_and_key( s1, in, ctx->ksch );
+
+ for ( r = 1 ; r < ctx->rnd ; ++r )
+#if defined( VERSION_1 )
+ {
+ mix_sub_columns( s1 );
+ add_round_key( s1, ctx->ksch + r * N_BLOCK);
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ mix_sub_columns( s2, s1 );
+ copy_and_key( s1, s2, ctx->ksch + r * N_BLOCK);
+ }
+#endif
+ shift_sub_rows( s1 );
+ copy_and_key( out, s1, ctx->ksch + r * N_BLOCK );
+ } else {
+ return (return_type) - 1;
+ }
+ return 0;
+}
+
+/* CBC encrypt a number of blocks (input and return an IV) */
+
+return_type aes_cbc_encrypt( const unsigned char *in, unsigned char *out,
+ int n_block, unsigned char iv[N_BLOCK], const aes_context ctx[1] )
+{
+
+ while (n_block--) {
+ xor_block(iv, in);
+ if (bluedroid_aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) {
+ return EXIT_FAILURE;
+ }
+ memcpy(out, iv, N_BLOCK);
+ in += N_BLOCK;
+ out += N_BLOCK;
+ }
+ return EXIT_SUCCESS;
+}
+
+#endif
+
+#if defined( AES_DEC_PREKEYED )
+
+/* Decrypt a single block of 16 bytes */
+
+return_type bluedroid_aes_decrypt( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], const aes_context ctx[1] )
+{
+ if ( ctx->rnd ) {
+ uint_8t s1[N_BLOCK], r;
+ copy_and_key( s1, in, ctx->ksch + ctx->rnd * N_BLOCK );
+ inv_shift_sub_rows( s1 );
+
+ for ( r = ctx->rnd ; --r ; )
+#if defined( VERSION_1 )
+ {
+ add_round_key( s1, ctx->ksch + r * N_BLOCK );
+ inv_mix_sub_columns( s1 );
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ copy_and_key( s2, s1, ctx->ksch + r * N_BLOCK );
+ inv_mix_sub_columns( s1, s2 );
+ }
+#endif
+ copy_and_key( out, s1, ctx->ksch );
+ } else {
+ return (return_type) - 1;
+ }
+ return 0;
+}
+
+/* CBC decrypt a number of blocks (input and return an IV) */
+
+return_type aes_cbc_decrypt( const unsigned char *in, unsigned char *out,
+ int n_block, unsigned char iv[N_BLOCK], const aes_context ctx[1] )
+{
+ while (n_block--) {
+ uint_8t tmp[N_BLOCK];
+
+ memcpy(tmp, in, N_BLOCK);
+ if (bluedroid_aes_decrypt(in, out, ctx) != EXIT_SUCCESS) {
+ return EXIT_FAILURE;
+ }
+ xor_block(out, iv);
+ memcpy(iv, tmp, N_BLOCK);
+ in += N_BLOCK;
+ out += N_BLOCK;
+ }
+ return EXIT_SUCCESS;
+}
+
+#endif
+
+#if defined( AES_ENC_128_OTFK )
+
+/* The 'on the fly' encryption key update for for 128 bit keys */
+
+static void update_encrypt_key_128( uint_8t k[N_BLOCK], uint_8t *rc )
+{
+ uint_8t cc;
+
+ k[0] ^= s_box(k[13]) ^ *rc;
+ k[1] ^= s_box(k[14]);
+ k[2] ^= s_box(k[15]);
+ k[3] ^= s_box(k[12]);
+ *rc = f2( *rc );
+
+ for (cc = 4; cc < 16; cc += 4 ) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+}
+
+/* Encrypt a single block of 16 bytes with 'on the fly' 128 bit keying */
+
+void bluedroid_aes_encrypt_128( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK],
+ const unsigned char key[N_BLOCK], unsigned char o_key[N_BLOCK] )
+{
+ uint_8t s1[N_BLOCK], r, rc = 1;
+
+ if (o_key != key) {
+ block_copy( o_key, key );
+ }
+ copy_and_key( s1, in, o_key );
+
+ for ( r = 1 ; r < 10 ; ++r )
+#if defined( VERSION_1 )
+ {
+ mix_sub_columns( s1 );
+ update_encrypt_key_128( o_key, &rc );
+ add_round_key( s1, o_key );
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ mix_sub_columns( s2, s1 );
+ update_encrypt_key_128( o_key, &rc );
+ copy_and_key( s1, s2, o_key );
+ }
+#endif
+
+ shift_sub_rows( s1 );
+ update_encrypt_key_128( o_key, &rc );
+ copy_and_key( out, s1, o_key );
+}
+
+#endif
+
+#if defined( AES_DEC_128_OTFK )
+
+/* The 'on the fly' decryption key update for for 128 bit keys */
+
+static void update_decrypt_key_128( uint_8t k[N_BLOCK], uint_8t *rc )
+{
+ uint_8t cc;
+
+ for ( cc = 12; cc > 0; cc -= 4 ) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+ *rc = d2(*rc);
+ k[0] ^= s_box(k[13]) ^ *rc;
+ k[1] ^= s_box(k[14]);
+ k[2] ^= s_box(k[15]);
+ k[3] ^= s_box(k[12]);
+}
+
+/* Decrypt a single block of 16 bytes with 'on the fly' 128 bit keying */
+
+void bluedroid_aes_decrypt_128( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK],
+ const unsigned char key[N_BLOCK], unsigned char o_key[N_BLOCK] )
+{
+ uint_8t s1[N_BLOCK], r, rc = 0x6c;
+ if (o_key != key) {
+ block_copy( o_key, key );
+ }
+
+ copy_and_key( s1, in, o_key );
+ inv_shift_sub_rows( s1 );
+
+ for ( r = 10 ; --r ; )
+#if defined( VERSION_1 )
+ {
+ update_decrypt_key_128( o_key, &rc );
+ add_round_key( s1, o_key );
+ inv_mix_sub_columns( s1 );
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ update_decrypt_key_128( o_key, &rc );
+ copy_and_key( s2, s1, o_key );
+ inv_mix_sub_columns( s1, s2 );
+ }
+#endif
+ update_decrypt_key_128( o_key, &rc );
+ copy_and_key( out, s1, o_key );
+}
+
+#endif
+
+#if defined( AES_ENC_256_OTFK )
+
+/* The 'on the fly' encryption key update for for 256 bit keys */
+
+static void update_encrypt_key_256( uint_8t k[2 * N_BLOCK], uint_8t *rc )
+{
+ uint_8t cc;
+
+ k[0] ^= s_box(k[29]) ^ *rc;
+ k[1] ^= s_box(k[30]);
+ k[2] ^= s_box(k[31]);
+ k[3] ^= s_box(k[28]);
+ *rc = f2( *rc );
+
+ for (cc = 4; cc < 16; cc += 4) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+
+ k[16] ^= s_box(k[12]);
+ k[17] ^= s_box(k[13]);
+ k[18] ^= s_box(k[14]);
+ k[19] ^= s_box(k[15]);
+
+ for ( cc = 20; cc < 32; cc += 4 ) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+}
+
+/* Encrypt a single block of 16 bytes with 'on the fly' 256 bit keying */
+
+void bluedroid_aes_encrypt_256( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK],
+ const unsigned char key[2 * N_BLOCK], unsigned char o_key[2 * N_BLOCK] )
+{
+ uint_8t s1[N_BLOCK], r, rc = 1;
+ if (o_key != key) {
+ block_copy( o_key, key );
+ block_copy( o_key + 16, key + 16 );
+ }
+ copy_and_key( s1, in, o_key );
+
+ for ( r = 1 ; r < 14 ; ++r )
+#if defined( VERSION_1 )
+ {
+ mix_sub_columns(s1);
+ if ( r & 1 ) {
+ add_round_key( s1, o_key + 16 );
+ } else {
+ update_encrypt_key_256( o_key, &rc );
+ add_round_key( s1, o_key );
+ }
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ mix_sub_columns( s2, s1 );
+ if ( r & 1 ) {
+ copy_and_key( s1, s2, o_key + 16 );
+ } else {
+ update_encrypt_key_256( o_key, &rc );
+ copy_and_key( s1, s2, o_key );
+ }
+ }
+#endif
+
+ shift_sub_rows( s1 );
+ update_encrypt_key_256( o_key, &rc );
+ copy_and_key( out, s1, o_key );
+}
+
+#endif
+
+#if defined( AES_DEC_256_OTFK )
+
+/* The 'on the fly' encryption key update for for 256 bit keys */
+
+static void update_decrypt_key_256( uint_8t k[2 * N_BLOCK], uint_8t *rc )
+{
+ uint_8t cc;
+
+ for (cc = 28; cc > 16; cc -= 4) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+
+ k[16] ^= s_box(k[12]);
+ k[17] ^= s_box(k[13]);
+ k[18] ^= s_box(k[14]);
+ k[19] ^= s_box(k[15]);
+
+ for (cc = 12; cc > 0; cc -= 4) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+
+ *rc = d2(*rc);
+ k[0] ^= s_box(k[29]) ^ *rc;
+ k[1] ^= s_box(k[30]);
+ k[2] ^= s_box(k[31]);
+ k[3] ^= s_box(k[28]);
+}
+
+/* Decrypt a single block of 16 bytes with 'on the fly'
+ 256 bit keying
+*/
+void bluedroid_aes_decrypt_256( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK],
+ const unsigned char key[2 * N_BLOCK], unsigned char o_key[2 * N_BLOCK] )
+{
+ uint_8t s1[N_BLOCK], r, rc = 0x80;
+
+ if (o_key != key) {
+ block_copy( o_key, key );
+ block_copy( o_key + 16, key + 16 );
+ }
+
+ copy_and_key( s1, in, o_key );
+ inv_shift_sub_rows( s1 );
+
+ for ( r = 14 ; --r ; )
+#if defined( VERSION_1 )
+ {
+ if ( ( r & 1 ) ) {
+ update_decrypt_key_256( o_key, &rc );
+ add_round_key( s1, o_key + 16 );
+ } else {
+ add_round_key( s1, o_key );
+ }
+ inv_mix_sub_columns( s1 );
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ if ( ( r & 1 ) ) {
+ update_decrypt_key_256( o_key, &rc );
+ copy_and_key( s2, s1, o_key + 16 );
+ } else {
+ copy_and_key( s2, s1, o_key );
+ }
+ inv_mix_sub_columns( s1, s2 );
+ }
+#endif
+ copy_and_key( out, s1, o_key );
+}
+
+#endif
diff --git a/lib/bt/host/bluedroid/stack/smp/include/aes.h b/lib/bt/host/bluedroid/stack/smp/include/aes.h
new file mode 100644
index 00000000..48495bb1
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/smp/include/aes.h
@@ -0,0 +1,162 @@
+/*
+ ---------------------------------------------------------------------------
+ Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
+
+ LICENSE TERMS
+
+ The redistribution and use of this software (with or without changes)
+ is allowed without the payment of fees or royalties provided that:
+
+ 1. source code distributions include the above copyright notice, this
+ list of conditions and the following disclaimer;
+
+ 2. binary distributions include the above copyright notice, this list
+ of conditions and the following disclaimer in their documentation;
+
+ 3. the name of the copyright holder is not used to endorse products
+ built using this software without specific written permission.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
+ Issue 09/09/2006
+
+ This is an AES implementation that uses only 8-bit byte operations on the
+ cipher state.
+ */
+
+#ifndef AES_H
+#define AES_H
+
+#if 1
+# define AES_ENC_PREKEYED /* AES encryption with a precomputed key schedule */
+#endif
+#if 1
+# define AES_DEC_PREKEYED /* AES decryption with a precomputed key schedule */
+#endif
+#if 1
+# define AES_ENC_128_OTFK /* AES encryption with 'on the fly' 128 bit keying */
+#endif
+#if 1
+# define AES_DEC_128_OTFK /* AES decryption with 'on the fly' 128 bit keying */
+#endif
+#if 1
+# define AES_ENC_256_OTFK /* AES encryption with 'on the fly' 256 bit keying */
+#endif
+#if 1
+# define AES_DEC_256_OTFK /* AES decryption with 'on the fly' 256 bit keying */
+#endif
+
+#define N_ROW 4
+#define N_COL 4
+#define N_BLOCK (N_ROW * N_COL)
+#define N_MAX_ROUNDS 14
+
+typedef unsigned char uint_8t;
+
+typedef uint_8t return_type;
+
+/* Warning: The key length for 256 bit keys overflows a byte
+ (see comment below)
+*/
+
+typedef uint_8t length_type;
+
+typedef struct {
+ uint_8t ksch[(N_MAX_ROUNDS + 1) * N_BLOCK];
+ uint_8t rnd;
+} aes_context;
+
+/* The following calls are for a precomputed key schedule
+
+ NOTE: If the length_type used for the key length is an
+ unsigned 8-bit character, a key length of 256 bits must
+ be entered as a length in bytes (valid inputs are hence
+ 128, 192, 16, 24 and 32).
+*/
+
+#if defined( AES_ENC_PREKEYED ) || defined( AES_DEC_PREKEYED )
+
+return_type aes_set_key( const unsigned char key[],
+ length_type keylen,
+ aes_context ctx[1] );
+#endif
+
+#if defined( AES_ENC_PREKEYED )
+
+return_type bluedroid_aes_encrypt( const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const aes_context ctx[1] );
+
+return_type aes_cbc_encrypt( const unsigned char *in,
+ unsigned char *out,
+ int n_block,
+ unsigned char iv[N_BLOCK],
+ const aes_context ctx[1] );
+#endif
+
+#if defined( AES_DEC_PREKEYED )
+
+return_type bluedroid_aes_decrypt( const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const aes_context ctx[1] );
+
+return_type aes_cbc_decrypt( const unsigned char *in,
+ unsigned char *out,
+ int n_block,
+ unsigned char iv[N_BLOCK],
+ const aes_context ctx[1] );
+#endif
+
+/* The following calls are for 'on the fly' keying. In this case the
+ encryption and decryption keys are different.
+
+ The encryption subroutines take a key in an array of bytes in
+ key[L] where L is 16, 24 or 32 bytes for key lengths of 128,
+ 192, and 256 bits respectively. They then encrypts the input
+ data, in[] with this key and put the reult in the output array
+ out[]. In addition, the second key array, o_key[L], is used
+ to output the key that is needed by the decryption subroutine
+ to reverse the encryption operation. The two key arrays can
+ be the same array but in this case the original key will be
+ overwritten.
+
+ In the same way, the decryption subroutines output keys that
+ can be used to reverse their effect when used for encryption.
+
+ Only 128 and 256 bit keys are supported in these 'on the fly'
+ modes.
+*/
+
+#if defined( AES_ENC_128_OTFK )
+void bluedroid_aes_encrypt_128( const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[N_BLOCK],
+ uint_8t o_key[N_BLOCK] );
+#endif
+
+#if defined( AES_DEC_128_OTFK )
+void bluedroid_aes_decrypt_128( const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[N_BLOCK],
+ unsigned char o_key[N_BLOCK] );
+#endif
+
+#if defined( AES_ENC_256_OTFK )
+void bluedroid_aes_encrypt_256( const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[2 * N_BLOCK],
+ unsigned char o_key[2 * N_BLOCK] );
+#endif
+
+#if defined( AES_DEC_256_OTFK )
+void bluedroid_aes_decrypt_256( const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[2 * N_BLOCK],
+ unsigned char o_key[2 * N_BLOCK] );
+#endif
+
+#endif
diff --git a/lib/bt/host/bluedroid/stack/smp/include/p_256_ecc_pp.h b/lib/bt/host/bluedroid/stack/smp/include/p_256_ecc_pp.h
new file mode 100644
index 00000000..3b28e0c9
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/smp/include/p_256_ecc_pp.h
@@ -0,0 +1,74 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2006-2015 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains simple pairing algorithms using Elliptic Curve Cryptography for private public key
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include "p_256_multprecision.h"
+#include "common/bt_target.h"
+
+typedef unsigned long DWORD;
+
+typedef struct {
+ DWORD x[KEY_LENGTH_DWORDS_P256];
+ DWORD y[KEY_LENGTH_DWORDS_P256];
+ DWORD z[KEY_LENGTH_DWORDS_P256];
+} Point;
+
+typedef struct {
+ // curve's coefficients
+ DWORD a[KEY_LENGTH_DWORDS_P256];
+ DWORD b[KEY_LENGTH_DWORDS_P256];
+
+ //whether a is -3
+ int a_minus3;
+
+ // prime modulus
+ DWORD p[KEY_LENGTH_DWORDS_P256];
+
+ // Omega, p = 2^m -omega
+ DWORD omega[KEY_LENGTH_DWORDS_P256];
+
+ // base point, a point on E of order r
+ Point G;
+
+} elliptic_curve_t;
+
+#if SMP_DYNAMIC_MEMORY == FALSE
+extern elliptic_curve_t curve;
+extern elliptic_curve_t curve_p256;
+#else
+extern elliptic_curve_t *curve_ptr;
+extern elliptic_curve_t *curve_p256_ptr;
+#define curve (*curve_ptr)
+#define curve_p256 (*curve_p256_ptr)
+#endif
+
+
+void ECC_PointMult_Bin_NAF(Point *q, Point *p, DWORD *n, uint32_t keyLength);
+
+bool ECC_CheckPointIsInElliCur_P256(Point *p);
+
+#define ECC_PointMult(q, p, n, keyLength) ECC_PointMult_Bin_NAF(q, p, n, keyLength)
+
+void p_256_init_curve(UINT32 keyLength);
diff --git a/lib/bt/host/bluedroid/stack/smp/include/p_256_multprecision.h b/lib/bt/host/bluedroid/stack/smp/include/p_256_multprecision.h
new file mode 100644
index 00000000..0a33b4e2
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/smp/include/p_256_multprecision.h
@@ -0,0 +1,60 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2006-2015 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains simple pairing algorithms
+ *
+ ******************************************************************************/
+#pragma once
+
+#include "stack/bt_types.h"
+
+/* Type definitions */
+typedef unsigned long DWORD;
+
+#define DWORD_BITS 32
+#define DWORD_BYTES 4
+#define DWORD_BITS_SHIFT 5
+
+#define KEY_LENGTH_DWORDS_P192 6
+#define KEY_LENGTH_DWORDS_P256 8
+/* Arithmetic Operations */
+
+int multiprecision_compare(DWORD *a, DWORD *b, uint32_t keyLength);
+int multiprecision_iszero(DWORD *a, uint32_t keyLength);
+void multiprecision_init(DWORD *c, uint32_t keyLength);
+void multiprecision_copy(DWORD *c, DWORD *a, uint32_t keyLength);
+UINT32 multiprecision_dword_bits (DWORD a);
+UINT32 multiprecision_most_signdwords(DWORD *a, uint32_t keyLength);
+UINT32 multiprecision_most_signbits(DWORD *a, uint32_t keyLength);
+void multiprecision_inv_mod(DWORD *aminus, DWORD *a, uint32_t keyLength);
+DWORD multiprecision_add(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength); // c=a+b
+void multiprecision_add_mod(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength);
+DWORD multiprecision_sub(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength); // c=a-b
+void multiprecision_sub_mod(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength);
+void multiprecision_rshift(DWORD *c, DWORD *a, uint32_t keyLength); // c=a>>1, return carrier
+void multiprecision_lshift_mod(DWORD *c, DWORD *a, uint32_t keyLength); // c=a<<b, return carrier
+DWORD multiprecision_lshift(DWORD *c, DWORD *a, uint32_t keyLength); // c=a<<b, return carrier
+void multiprecision_mult(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength); // c=a*b
+void multiprecision_mersenns_mult_mod(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength);
+void multiprecision_mersenns_squa_mod(DWORD *c, DWORD *a, uint32_t keyLength);
+DWORD multiprecision_lshift(DWORD *c, DWORD *a, uint32_t keyLength);
+void multiprecision_mult(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength);
+void multiprecision_fast_mod(DWORD *c, DWORD *a);
+void multiprecision_fast_mod_P256(DWORD *c, DWORD *a);
diff --git a/lib/bt/host/bluedroid/stack/smp/include/smp_int.h b/lib/bt/host/bluedroid/stack/smp/include/smp_int.h
new file mode 100644
index 00000000..f3ab7ad4
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/smp/include/smp_int.h
@@ -0,0 +1,545 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains internally used SMP definitions
+ *
+ ******************************************************************************/
+#ifndef SMP_INT_H
+#define SMP_INT_H
+
+// #if (SMP_INCLUDED == TRUE)
+
+#include "stack/btu.h"
+#include "stack/btm_ble_api.h"
+#include "stack/btm_api.h"
+#include "stack/smp_api.h"
+
+#define SMP_MODEL_ENCRYPTION_ONLY 0 /* Legacy mode, Just Works model */
+#define SMP_MODEL_PASSKEY 1 /* Legacy mode, Passkey Entry model, this side inputs the key */
+#define SMP_MODEL_OOB 2 /* Legacy mode, OOB model */
+#define SMP_MODEL_KEY_NOTIF 3 /* Legacy mode, Passkey Entry model, this side displays the key */
+#define SMP_MODEL_SEC_CONN_JUSTWORKS 4 /* Secure Connections mode, Just Works model */
+#define SMP_MODEL_SEC_CONN_NUM_COMP 5 /* Secure Connections mode, Numeric Comparison model */
+#define SMP_MODEL_SEC_CONN_PASSKEY_ENT 6 /* Secure Connections mode, Passkey Entry model, */
+/* this side inputs the key */
+#define SMP_MODEL_SEC_CONN_PASSKEY_DISP 7 /* Secure Connections mode, Passkey Entry model, */
+/* this side displays the key */
+#define SMP_MODEL_SEC_CONN_OOB 8 /* Secure Connections mode, OOB model */
+#define SMP_MODEL_OUT_OF_RANGE 9
+typedef UINT8 tSMP_ASSO_MODEL;
+
+
+#ifndef SMP_MAX_CONN
+#define SMP_MAX_CONN 2
+#endif
+
+#define SMP_WAIT_FOR_RSP_TOUT 30
+
+#define SMP_OPCODE_INIT 0x04
+
+/* SMP events */
+#define SMP_PAIRING_REQ_EVT SMP_OPCODE_PAIRING_REQ
+#define SMP_PAIRING_RSP_EVT SMP_OPCODE_PAIRING_RSP
+#define SMP_CONFIRM_EVT SMP_OPCODE_CONFIRM
+#define SMP_RAND_EVT SMP_OPCODE_RAND
+#define SMP_PAIRING_FAILED_EVT SMP_OPCODE_PAIRING_FAILED
+#define SMP_ENCRPTION_INFO_EVT SMP_OPCODE_ENCRYPT_INFO
+#define SMP_MASTER_ID_EVT SMP_OPCODE_MASTER_ID
+#define SMP_ID_INFO_EVT SMP_OPCODE_IDENTITY_INFO
+#define SMP_ID_ADDR_EVT SMP_OPCODE_ID_ADDR
+#define SMP_SIGN_INFO_EVT SMP_OPCODE_SIGN_INFO
+#define SMP_SECURITY_REQ_EVT SMP_OPCODE_SEC_REQ
+
+#define SMP_PAIR_PUBLIC_KEY_EVT SMP_OPCODE_PAIR_PUBLIC_KEY
+#define SMP_PAIR_KEYPRESS_NOTIFICATION_EVT SMP_OPCODE_PAIR_KEYPR_NOTIF
+
+#define SMP_PAIR_COMMITM_EVT SMP_OPCODE_PAIR_COMMITM
+
+#define SMP_SELF_DEF_EVT (SMP_PAIR_COMMITM_EVT + 1)
+#define SMP_KEY_READY_EVT (SMP_SELF_DEF_EVT)
+#define SMP_ENCRYPTED_EVT (SMP_SELF_DEF_EVT + 1)
+#define SMP_L2CAP_CONN_EVT (SMP_SELF_DEF_EVT + 2)
+#define SMP_L2CAP_DISCONN_EVT (SMP_SELF_DEF_EVT + 3)
+#define SMP_IO_RSP_EVT (SMP_SELF_DEF_EVT + 4)
+#define SMP_API_SEC_GRANT_EVT (SMP_SELF_DEF_EVT + 5)
+#define SMP_TK_REQ_EVT (SMP_SELF_DEF_EVT + 6)
+#define SMP_AUTH_CMPL_EVT (SMP_SELF_DEF_EVT + 7)
+#define SMP_ENC_REQ_EVT (SMP_SELF_DEF_EVT + 8)
+#define SMP_BOND_REQ_EVT (SMP_SELF_DEF_EVT + 9)
+#define SMP_DISCARD_SEC_REQ_EVT (SMP_SELF_DEF_EVT + 10)
+
+#define SMP_PAIR_DHKEY_CHCK_EVT SMP_OPCODE_PAIR_DHKEY_CHECK
+
+#define SMP_PUBL_KEY_EXCH_REQ_EVT (SMP_SELF_DEF_EVT + 11) /* request to start public */
+/* key exchange */
+
+#define SMP_LOC_PUBL_KEY_CRTD_EVT (SMP_SELF_DEF_EVT + 12) /* local public key created */
+
+#define SMP_BOTH_PUBL_KEYS_RCVD_EVT (SMP_SELF_DEF_EVT + 13) /* both local and peer public */
+/* keys are saved in cb */
+
+#define SMP_SC_DHKEY_CMPLT_EVT (SMP_SELF_DEF_EVT + 14) /* DHKey computation is completed,*/
+/* time to start SC phase1 */
+
+#define SMP_HAVE_LOC_NONCE_EVT (SMP_SELF_DEF_EVT + 15) /* new local nonce is generated */
+/*and saved in p_cb->rand */
+
+#define SMP_SC_PHASE1_CMPLT_EVT (SMP_SELF_DEF_EVT + 16) /* time to start SC phase2 */
+
+#define SMP_SC_CALC_NC_EVT (SMP_SELF_DEF_EVT + 17) /* request to calculate number */
+/* for user check. Used only in the */
+/* numeric compare protocol */
+
+/* Request to display the number for user check to the user.*/
+/* Used only in the numeric compare protocol */
+#define SMP_SC_DSPL_NC_EVT (SMP_SELF_DEF_EVT + 18)
+
+#define SMP_SC_NC_OK_EVT (SMP_SELF_DEF_EVT + 19) /* user confirms 'OK' numeric */
+/*comparison request */
+
+/* both local and peer DHKey Checks are already present - it is used on slave to prevent race condition */
+#define SMP_SC_2_DHCK_CHKS_PRES_EVT (SMP_SELF_DEF_EVT + 20)
+
+/* same meaning as SMP_KEY_READY_EVT to separate between SC and legacy actions */
+#define SMP_SC_KEY_READY_EVT (SMP_SELF_DEF_EVT + 21)
+#define SMP_KEYPRESS_NOTIFICATION_EVENT (SMP_SELF_DEF_EVT + 22)
+
+#define SMP_SC_OOB_DATA_EVT (SMP_SELF_DEF_EVT + 23) /* SC OOB data from some */
+/* repository is provided */
+
+#define SMP_CR_LOC_SC_OOB_DATA_EVT (SMP_SELF_DEF_EVT + 24)
+#define SMP_MAX_EVT SMP_CR_LOC_SC_OOB_DATA_EVT
+
+typedef UINT8 tSMP_EVENT;
+
+/* Assumption it's only using the low 8 bits, if bigger than that, need to expand it to 16 bits */
+#define SMP_SEC_KEY_MASK 0x00ff
+
+#define SMP_PASSKEY_MASK 0xfff00000
+
+/* SMP pairing state */
+enum {
+ SMP_STATE_IDLE,
+ SMP_STATE_WAIT_APP_RSP,
+ SMP_STATE_SEC_REQ_PENDING,
+ SMP_STATE_PAIR_REQ_RSP,
+ SMP_STATE_WAIT_CONFIRM,
+ SMP_STATE_CONFIRM,
+ SMP_STATE_RAND,
+ SMP_STATE_PUBLIC_KEY_EXCH,
+ SMP_STATE_SEC_CONN_PHS1_START,
+ SMP_STATE_WAIT_COMMITMENT,
+ SMP_STATE_WAIT_NONCE,
+ SMP_STATE_SEC_CONN_PHS2_START,
+ SMP_STATE_WAIT_DHK_CHECK,
+ SMP_STATE_DHK_CHECK,
+ SMP_STATE_ENCRYPTION_PENDING,
+ SMP_STATE_BOND_PENDING,
+ SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA,
+ SMP_STATE_MAX
+};
+typedef UINT8 tSMP_STATE;
+
+/* SMP over BR/EDR events */
+#define SMP_BR_PAIRING_REQ_EVT SMP_OPCODE_PAIRING_REQ
+#define SMP_BR_PAIRING_RSP_EVT SMP_OPCODE_PAIRING_RSP
+#define SMP_BR_CONFIRM_EVT SMP_OPCODE_CONFIRM /* not expected over BR/EDR */
+#define SMP_BR_RAND_EVT SMP_OPCODE_RAND /* not expected over BR/EDR */
+#define SMP_BR_PAIRING_FAILED_EVT SMP_OPCODE_PAIRING_FAILED
+#define SMP_BR_ENCRPTION_INFO_EVT SMP_OPCODE_ENCRYPT_INFO /* not expected over BR/EDR */
+#define SMP_BR_MASTER_ID_EVT SMP_OPCODE_MASTER_ID /* not expected over BR/EDR */
+#define SMP_BR_ID_INFO_EVT SMP_OPCODE_IDENTITY_INFO
+#define SMP_BR_ID_ADDR_EVT SMP_OPCODE_ID_ADDR
+#define SMP_BR_SIGN_INFO_EVT SMP_OPCODE_SIGN_INFO
+#define SMP_BR_SECURITY_REQ_EVT SMP_OPCODE_SEC_REQ /* not expected over BR/EDR */
+#define SMP_BR_PAIR_PUBLIC_KEY_EVT SMP_OPCODE_PAIR_PUBLIC_KEY /* not expected over BR/EDR */
+#define SMP_BR_PAIR_DHKEY_CHCK_EVT SMP_OPCODE_PAIR_DHKEY_CHECK /* not expected over BR/EDR */
+#define SMP_BR_PAIR_KEYPR_NOTIF_EVT SMP_OPCODE_PAIR_KEYPR_NOTIF /* not expected over BR/EDR */
+#define SMP_BR_SELF_DEF_EVT SMP_BR_PAIR_KEYPR_NOTIF_EVT
+#define SMP_BR_KEY_READY_EVT (SMP_BR_SELF_DEF_EVT + 1)
+#define SMP_BR_ENCRYPTED_EVT (SMP_BR_SELF_DEF_EVT + 2)
+#define SMP_BR_L2CAP_CONN_EVT (SMP_BR_SELF_DEF_EVT + 3)
+#define SMP_BR_L2CAP_DISCONN_EVT (SMP_BR_SELF_DEF_EVT + 4)
+#define SMP_BR_KEYS_RSP_EVT (SMP_BR_SELF_DEF_EVT + 5)
+#define SMP_BR_API_SEC_GRANT_EVT (SMP_BR_SELF_DEF_EVT + 6)
+#define SMP_BR_TK_REQ_EVT (SMP_BR_SELF_DEF_EVT + 7)
+#define SMP_BR_AUTH_CMPL_EVT (SMP_BR_SELF_DEF_EVT + 8)
+#define SMP_BR_ENC_REQ_EVT (SMP_BR_SELF_DEF_EVT + 9)
+#define SMP_BR_BOND_REQ_EVT (SMP_BR_SELF_DEF_EVT + 10)
+#define SMP_BR_DISCARD_SEC_REQ_EVT (SMP_BR_SELF_DEF_EVT + 11)
+#define SMP_BR_MAX_EVT (SMP_BR_SELF_DEF_EVT + 12)
+typedef UINT8 tSMP_BR_EVENT;
+
+/* SMP over BR/EDR pairing states */
+enum {
+ SMP_BR_STATE_IDLE = SMP_STATE_IDLE,
+ SMP_BR_STATE_WAIT_APP_RSP,
+ SMP_BR_STATE_PAIR_REQ_RSP,
+ SMP_BR_STATE_BOND_PENDING,
+ SMP_BR_STATE_MAX
+};
+typedef UINT8 tSMP_BR_STATE;
+
+/* random and encrption activity state */
+enum {
+ SMP_GEN_COMPARE = 1,
+ SMP_GEN_CONFIRM,
+
+ SMP_GEN_DIV_LTK,
+ SMP_GEN_DIV_CSRK,
+ SMP_GEN_RAND_V,
+ SMP_GEN_TK,
+ SMP_GEN_SRAND_MRAND,
+ SMP_GEN_SRAND_MRAND_CONT,
+ SMP_GENERATE_PRIVATE_KEY_0_7,
+ SMP_GENERATE_PRIVATE_KEY_8_15,
+ SMP_GENERATE_PRIVATE_KEY_16_23,
+ SMP_GENERATE_PRIVATE_KEY_24_31,
+ SMP_GEN_NONCE_0_7,
+ SMP_GEN_NONCE_8_15
+};
+
+enum {
+ SMP_KEY_TYPE_TK,
+ SMP_KEY_TYPE_CFM,
+ SMP_KEY_TYPE_CMP,
+ SMP_KEY_TYPE_PEER_DHK_CHCK,
+ SMP_KEY_TYPE_STK,
+ SMP_KEY_TYPE_LTK
+};
+typedef struct {
+ UINT8 key_type;
+ UINT8 *p_data;
+} tSMP_KEY;
+
+typedef union {
+ UINT8 *p_data; /* UINT8 type data pointer */
+ tSMP_KEY key;
+ UINT16 reason;
+ UINT32 passkey;
+ tSMP_OOB_DATA_TYPE req_oob_type;
+} tSMP_INT_DATA;
+
+/* internal status mask */
+#define SMP_PAIR_FLAGS_WE_STARTED_DD (1)
+#define SMP_PAIR_FLAGS_PEER_STARTED_DD (1 << 1)
+#define SMP_PAIR_FLAGS_CMD_CONFIRM (1 << SMP_OPCODE_CONFIRM) /* 1 << 3 */
+#define SMP_PAIR_FLAG_ENC_AFTER_PAIR (1 << 4)
+#define SMP_PAIR_FLAG_HAVE_PEER_DHK_CHK (1 << 5) /* used on slave to resolve race condition */
+#define SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY (1 << 6) /* used on slave to resolve race condition */
+#define SMP_PAIR_FLAG_HAVE_PEER_COMM (1 << 7) /* used to resolve race condition */
+#define SMP_PAIR_FLAG_HAVE_LOCAL_PUBL_KEY (1 << 8) /* used on slave to resolve race condition */
+
+/* check if authentication requirement need MITM protection */
+#define SMP_NO_MITM_REQUIRED(x) (((x) & SMP_AUTH_YN_BIT) == 0)
+
+#define SMP_ENCRYT_KEY_SIZE 16
+#define SMP_ENCRYT_DATA_SIZE 16
+#define SMP_ECNCRPYT_STATUS HCI_SUCCESS
+
+typedef struct {
+ BD_ADDR bd_addr;
+ BT_HDR *p_copy;
+} tSMP_REQ_Q_ENTRY;
+
+/* SMP control block */
+typedef struct {
+ tSMP_CALLBACK *p_callback;
+ TIMER_LIST_ENT rsp_timer_ent;
+ UINT8 trace_level;
+ BD_ADDR pairing_bda;
+ tSMP_STATE state;
+ BOOLEAN derive_lk;
+ BOOLEAN id_addr_rcvd;
+ tBLE_ADDR_TYPE id_addr_type;
+ BD_ADDR id_addr;
+ BOOLEAN smp_over_br;
+ tSMP_BR_STATE br_state; /* if SMP over BR/ERD has priority over SMP */
+ UINT8 failure;
+ UINT8 status;
+ UINT8 role;
+ UINT16 flags;
+ UINT8 cb_evt;
+ tSMP_SEC_LEVEL sec_level;
+ BOOLEAN connect_initialized;
+ BT_OCTET16 confirm;
+ BT_OCTET16 rconfirm;
+ BT_OCTET16 rrand; /* for SC this is peer nonce */
+ BT_OCTET16 rand; /* for SC this is local nonce */
+ BT_OCTET32 private_key;
+ BT_OCTET32 dhkey;
+ BT_OCTET16 commitment;
+ BT_OCTET16 remote_commitment;
+ BT_OCTET16 local_random; /* local randomizer - passkey or OOB randomizer */
+ BT_OCTET16 peer_random; /* peer randomizer - passkey or OOB randomizer */
+ BT_OCTET16 dhkey_check;
+ BT_OCTET16 remote_dhkey_check;
+ tSMP_PUBLIC_KEY loc_publ_key;
+ tSMP_PUBLIC_KEY peer_publ_key;
+ tSMP_OOB_DATA_TYPE req_oob_type;
+ tSMP_SC_OOB_DATA sc_oob_data;
+ tSMP_IO_CAP peer_io_caps;
+ tSMP_IO_CAP local_io_capability;
+ tSMP_OOB_FLAG peer_oob_flag;
+ tSMP_OOB_FLAG loc_oob_flag;
+ tSMP_AUTH_REQ peer_auth_req;
+ tSMP_AUTH_REQ loc_auth_req;
+ tSMP_AUTH_REQ auth_mode;
+ BOOLEAN secure_connections_only_mode_required;/* TRUE if locally SM is required to operate */
+ /* either in Secure Connections mode or not at all */
+ tSMP_ASSO_MODEL selected_association_model;
+ BOOLEAN le_secure_connections_mode_is_used;
+ BOOLEAN le_sc_kp_notif_is_used;
+ tSMP_SC_KEY_TYPE local_keypress_notification;
+ tSMP_SC_KEY_TYPE peer_keypress_notification;
+ UINT8 round; /* authentication stage 1 round for passkey association model */
+ UINT32 number_to_display;
+ BT_OCTET16 mac_key;
+ UINT8 peer_enc_size;
+ UINT8 loc_enc_size;
+ UINT8 peer_i_key;
+ UINT8 peer_r_key;
+ UINT8 local_i_key;
+ UINT8 local_r_key;
+
+ BT_OCTET16 tk;
+ BT_OCTET16 ltk;
+ UINT16 div;
+ BT_OCTET16 csrk; /* storage for local CSRK */
+ UINT16 ediv;
+ BT_OCTET8 enc_rand;
+ UINT8 rand_enc_proc_state;
+ UINT8 addr_type;
+ BD_ADDR local_bda;
+ BOOLEAN is_pair_cancel;
+ BOOLEAN discard_sec_req;
+ UINT8 rcvd_cmd_code;
+ UINT8 rcvd_cmd_len;
+ UINT16 total_tx_unacked;
+ BOOLEAN wait_for_authorization_complete;
+ BOOLEAN use_static_passkey;
+ UINT32 static_passkey;
+ BOOLEAN accept_specified_sec_auth;
+ tSMP_AUTH_REQ origin_loc_auth_req;
+} tSMP_CB;
+
+/* Server Action functions are of this type */
+typedef void (*tSMP_ACT)(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#if SMP_DYNAMIC_MEMORY == FALSE
+extern tSMP_CB smp_cb;
+#else
+extern tSMP_CB *smp_cb_ptr;
+#define smp_cb (*smp_cb_ptr)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Functions provided by att_main.c */
+extern void smp_init (void);
+
+/* smp main */
+extern void smp_sm_event(tSMP_CB *p_cb, tSMP_EVENT event, void *p_data);
+
+extern void smp_proc_sec_request(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_set_fail_nc (BOOLEAN enable);
+extern void smp_set_fail_conf (BOOLEAN enable);
+extern void smp_set_passk_entry_fail(BOOLEAN enable);
+extern void smp_set_oob_fail(BOOLEAN enable);
+extern void smp_set_peer_sc_notif(BOOLEAN enable);
+extern void smp_aes_cmac_rfc4493_chk (UINT8 *key, UINT8 *msg, UINT8 msg_len,
+ UINT8 mac_len, UINT8 *mac);
+extern void smp_f4_calc_chk (UINT8 *U, UINT8 *V, UINT8 *X, UINT8 *Z, UINT8 *mac);
+extern void smp_g2_calc_chk (UINT8 *U, UINT8 *V, UINT8 *X, UINT8 *Y);
+extern void smp_h6_calc_chk (UINT8 *key, UINT8 *key_id, UINT8 *mac);
+extern void smp_f5_key_calc_chk (UINT8 *w, UINT8 *mac);
+extern void smp_f5_mackey_or_ltk_calc_chk(UINT8 *t, UINT8 *counter,
+ UINT8 *key_id, UINT8 *n1,
+ UINT8 *n2, UINT8 *a1, UINT8 *a2,
+ UINT8 *length, UINT8 *mac);
+extern void smp_f5_calc_chk (UINT8 *w, UINT8 *n1, UINT8 *n2, UINT8 *a1, UINT8 *a2,
+ UINT8 *mac_key, UINT8 *ltk);
+extern void smp_f6_calc_chk (UINT8 *w, UINT8 *n1, UINT8 *n2, UINT8 *r,
+ UINT8 *iocap, UINT8 *a1, UINT8 *a2, UINT8 *mac);
+/* smp_main */
+extern void smp_sm_event(tSMP_CB *p_cb, tSMP_EVENT event, void *p_data);
+extern tSMP_STATE smp_get_state(void);
+extern void smp_set_state(tSMP_STATE state);
+
+/* smp_br_main */
+extern void smp_br_state_machine_event(tSMP_CB *p_cb, tSMP_BR_EVENT event, void *p_data);
+extern tSMP_BR_STATE smp_get_br_state(void);
+extern void smp_set_br_state(tSMP_BR_STATE state);
+
+
+/* smp_act.c */
+extern void smp_send_pair_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_pair_fail(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_rand(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_pair_public_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_keypress_notification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_pair_fail(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_rand(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_process_pairing_public_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_master_id(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_id_addr(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_sec_grant(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_sec_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_sl_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_start_enc(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_enc_cmpl(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_discard(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_pairing_cmpl(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_decide_association_model(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_app_cback(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_compare(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_check_auth_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_process_io_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_csrk_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_ltk_reply(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_pair_cmd(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_pair_terminate(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_idle_terminate(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_send_pair_rsp(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_key_distribution(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_srk_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_generate_csrk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_fast_conn_param(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_key_pick_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_both_have_public_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_start_secure_connection_phase1(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_process_local_nonce(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_process_pairing_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_process_peer_nonce(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_process_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_match_dhkey_checks(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_process_keypress_notification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_move_to_secure_connections_phase2(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_phase_2_dhkey_checks_are_present(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_wait_for_both_public_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_start_passkey_verification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_process_secure_connection_oob_data(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_process_secure_connection_long_term_key(void);
+extern void smp_set_local_oob_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_set_local_oob_random_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_set_derive_link_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_derive_link_key_from_long_term_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_br_process_pairing_command(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_br_process_security_grant(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_br_process_slave_keys_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_br_send_pair_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_br_check_authorization_request(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_br_select_next_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_br_process_link_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_key_distribution_by_transport(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_br_pairing_complete(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+
+/* smp_l2c */
+extern void smp_l2cap_if_init (void);
+extern void smp_data_ind (BD_ADDR bd_addr, BT_HDR *p_buf);
+
+/* smp_util.c */
+extern BOOLEAN smp_send_cmd(UINT8 cmd_code, tSMP_CB *p_cb);
+extern void smp_cb_cleanup(tSMP_CB *p_cb);
+extern void smp_reset_control_value(tSMP_CB *p_cb);
+extern void smp_proc_pairing_cmpl(tSMP_CB *p_cb);
+extern void smp_convert_string_to_tk(BT_OCTET16 tk, UINT32 passkey);
+extern void smp_mask_enc_key(UINT8 loc_enc_size, UINT8 *p_data);
+extern void smp_rsp_timeout(TIMER_LIST_ENT *p_tle);
+extern void smp_xor_128(BT_OCTET16 a, const BT_OCTET16 b);
+extern BOOLEAN smp_encrypt_data (UINT8 *key, UINT8 key_len,
+ UINT8 *plain_text, UINT8 pt_len,
+ tSMP_ENC *p_out);
+extern BOOLEAN smp_command_has_invalid_parameters(tSMP_CB *p_cb);
+extern void smp_reject_unexpected_pairing_command(BD_ADDR bd_addr);
+extern tSMP_ASSO_MODEL smp_select_association_model(tSMP_CB *p_cb);
+extern void smp_reverse_array(UINT8 *arr, UINT8 len);
+extern UINT8 smp_calculate_random_input(UINT8 *random, UINT8 round);
+extern void smp_collect_local_io_capabilities(UINT8 *iocap, tSMP_CB *p_cb);
+extern void smp_collect_peer_io_capabilities(UINT8 *iocap, tSMP_CB *p_cb);
+extern void smp_collect_local_ble_address(UINT8 *le_addr, tSMP_CB *p_cb);
+extern void smp_collect_peer_ble_address(UINT8 *le_addr, tSMP_CB *p_cb);
+extern BOOLEAN smp_check_commitment(tSMP_CB *p_cb);
+extern void smp_save_secure_connections_long_term_key(tSMP_CB *p_cb);
+extern BOOLEAN smp_calculate_f5_mackey_and_long_term_key(tSMP_CB *p_cb);
+extern void smp_remove_fixed_channel(tSMP_CB *p_cb);
+extern BOOLEAN smp_request_oob_data(tSMP_CB *p_cb);
+
+/* smp_keys.c */
+extern void smp_generate_srand_mrand_confirm (tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_generate_compare (tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_generate_stk (tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_generate_ltk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_generate_passkey (tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_generate_rand_cont(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_create_private_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_use_oob_private_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_compute_dhkey(tSMP_CB *p_cb);
+extern void smp_calculate_local_commitment(tSMP_CB *p_cb);
+extern void smp_calculate_peer_commitment(tSMP_CB *p_cb, BT_OCTET16 output_buf);
+extern void smp_calculate_numeric_comparison_display_number(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_calculate_local_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_calculate_peer_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_start_nonce_generation(tSMP_CB *p_cb);
+extern BOOLEAN smp_calculate_link_key_from_long_term_key(tSMP_CB *p_cb);
+extern BOOLEAN smp_calculate_long_term_key_from_link_key(tSMP_CB *p_cb);
+extern void smp_calculate_f4(UINT8 *u, UINT8 *v, UINT8 *x, UINT8 z, UINT8 *c);
+extern UINT32 smp_calculate_g2(UINT8 *u, UINT8 *v, UINT8 *x, UINT8 *y);
+extern BOOLEAN smp_calculate_f5(UINT8 *w, UINT8 *n1, UINT8 *n2, UINT8 *a1, UINT8 *a2,
+ UINT8 *mac_key, UINT8 *ltk);
+extern BOOLEAN smp_calculate_f5_mackey_or_long_term_key(UINT8 *t, UINT8 *counter,
+ UINT8 *key_id, UINT8 *n1, UINT8 *n2, UINT8 *a1,
+ UINT8 *a2, UINT8 *length, UINT8 *mac);
+extern BOOLEAN smp_calculate_f5_key(UINT8 *w, UINT8 *t);
+extern BOOLEAN smp_calculate_f6(UINT8 *w, UINT8 *n1, UINT8 *n2, UINT8 *r, UINT8 *iocap,
+ UINT8 *a1, UINT8 *a2, UINT8 *f3);
+extern BOOLEAN smp_calculate_h6(UINT8 *w, UINT8 *keyid, UINT8 *h2);
+extern void smp_save_local_oob_data(tSMP_CB *p_cb);
+extern void smp_clear_local_oob_data(void);
+extern tSMP_LOC_OOB_DATA *smp_get_local_oob_data(void);
+#if SMP_DEBUG == TRUE
+extern void smp_debug_print_nbyte_little_endian (UINT8 *p, const UINT8 *key_name,
+ UINT8 len);
+#endif
+
+/* smp_cmac.c */
+extern BOOLEAN aes_cipher_msg_auth_code(BT_OCTET16 key, UINT8 *input, UINT16 length,
+ UINT16 tlen, UINT8 *p_signature);
+extern void print128(BT_OCTET16 x, const UINT8 *key_name);
+
+// #endif ///BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
+
+#endif /* SMP_INT_H */
diff --git a/lib/bt/host/bluedroid/stack/smp/p_256_curvepara.c b/lib/bt/host/bluedroid/stack/smp/p_256_curvepara.c
new file mode 100644
index 00000000..abf9a8ee
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/smp/p_256_curvepara.c
@@ -0,0 +1,78 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2006-2015 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains simple pairing algorithms
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "p_256_ecc_pp.h"
+
+void p_256_init_curve(UINT32 keyLength)
+{
+ elliptic_curve_t *ec;
+
+ if (keyLength == KEY_LENGTH_DWORDS_P256) {
+ ec = &curve_p256;
+
+ ec->p[7] = 0xFFFFFFFF;
+ ec->p[6] = 0x00000001;
+ ec->p[5] = 0x0;
+ ec->p[4] = 0x0;
+ ec->p[3] = 0x0;
+ ec->p[2] = 0xFFFFFFFF;
+ ec->p[1] = 0xFFFFFFFF;
+ ec->p[0] = 0xFFFFFFFF;
+
+ memset(ec->omega, 0, KEY_LENGTH_DWORDS_P256 * sizeof(ec->omega[0]));
+ memset(ec->a, 0, KEY_LENGTH_DWORDS_P256 * sizeof(ec->a[0]));
+
+ ec->a_minus3 = TRUE;
+
+ //b
+ ec->b[7] = 0x5ac635d8;
+ ec->b[6] = 0xaa3a93e7;
+ ec->b[5] = 0xb3ebbd55;
+ ec->b[4] = 0x769886bc;
+ ec->b[3] = 0x651d06b0;
+ ec->b[2] = 0xcc53b0f6;
+ ec->b[1] = 0x3bce3c3e;
+ ec->b[0] = 0x27d2604b;
+
+ //base point
+ ec->G.x[7] = 0x6b17d1f2;
+ ec->G.x[6] = 0xe12c4247;
+ ec->G.x[5] = 0xf8bce6e5;
+ ec->G.x[4] = 0x63a440f2;
+ ec->G.x[3] = 0x77037d81;
+ ec->G.x[2] = 0x2deb33a0;
+ ec->G.x[1] = 0xf4a13945;
+ ec->G.x[0] = 0xd898c296;
+
+ ec->G.y[7] = 0x4fe342e2;
+ ec->G.y[6] = 0xfe1a7f9b;
+ ec->G.y[5] = 0x8ee7eb4a;
+ ec->G.y[4] = 0x7c0f9e16;
+ ec->G.y[3] = 0x2bce3357;
+ ec->G.y[2] = 0x6b315ece;
+ ec->G.y[1] = 0xcbb64068;
+ ec->G.y[0] = 0x37bf51f5;
+ }
+}
diff --git a/lib/bt/host/bluedroid/stack/smp/p_256_ecc_pp.c b/lib/bt/host/bluedroid/stack/smp/p_256_ecc_pp.c
new file mode 100644
index 00000000..1f49c652
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/smp/p_256_ecc_pp.c
@@ -0,0 +1,283 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2006-2015 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains simple pairing algorithms using Elliptic Curve Cryptography for private public key
+ *
+ ******************************************************************************/
+//#include <stdio.h>
+//#include <stdlib.h>
+#include <string.h>
+#include "p_256_ecc_pp.h"
+#include "p_256_multprecision.h"
+#include "common/bt_target.h"
+
+#if SMP_DYNAMIC_MEMORY == FALSE
+elliptic_curve_t curve;
+elliptic_curve_t curve_p256;
+#else
+elliptic_curve_t *curve_ptr;
+elliptic_curve_t *curve_p256_ptr;
+#endif
+
+static void p_256_init_point(Point *q)
+{
+ memset(q, 0, sizeof(Point));
+}
+
+static void p_256_copy_point(Point *q, Point *p)
+{
+ memcpy(q, p, sizeof(Point));
+}
+
+// q=2q
+static void ECC_Double(Point *q, Point *p, uint32_t keyLength)
+{
+ DWORD t1[KEY_LENGTH_DWORDS_P256];
+ DWORD t2[KEY_LENGTH_DWORDS_P256];
+ DWORD t3[KEY_LENGTH_DWORDS_P256];
+ DWORD *x1;
+ DWORD *x3;
+ DWORD *y1;
+ DWORD *y3;
+ DWORD *z1;
+ DWORD *z3;
+
+ if (multiprecision_iszero(p->z, keyLength)) {
+ multiprecision_init(q->z, keyLength);
+ return; // return infinity
+ }
+
+ x1 = p->x; y1 = p->y; z1 = p->z;
+ x3 = q->x; y3 = q->y; z3 = q->z;
+
+ multiprecision_mersenns_squa_mod(t1, z1, keyLength); // t1=z1^2
+ multiprecision_sub_mod(t2, x1, t1, keyLength); // t2=x1-t1
+ multiprecision_add_mod(t1, x1, t1, keyLength); // t1=x1+t1
+ multiprecision_mersenns_mult_mod(t2, t1, t2, keyLength); // t2=t2*t1
+ multiprecision_lshift_mod(t3, t2, keyLength);
+ multiprecision_add_mod(t2, t3, t2, keyLength); // t2=3t2
+
+ multiprecision_mersenns_mult_mod(z3, y1, z1, keyLength); // z3=y1*z1
+ multiprecision_lshift_mod(z3, z3, keyLength);
+
+ multiprecision_mersenns_squa_mod(y3, y1, keyLength); // y3=y1^2
+ multiprecision_lshift_mod(y3, y3, keyLength);
+ multiprecision_mersenns_mult_mod(t3, y3, x1, keyLength); // t3=y3*x1=x1*y1^2
+ multiprecision_lshift_mod(t3, t3, keyLength);
+ multiprecision_mersenns_squa_mod(y3, y3, keyLength); // y3=y3^2=y1^4
+ multiprecision_lshift_mod(y3, y3, keyLength);
+
+ multiprecision_mersenns_squa_mod(x3, t2, keyLength); // x3=t2^2
+ multiprecision_lshift_mod(t1, t3, keyLength); // t1=2t3
+ multiprecision_sub_mod(x3, x3, t1, keyLength); // x3=x3-t1
+ multiprecision_sub_mod(t1, t3, x3, keyLength); // t1=t3-x3
+ multiprecision_mersenns_mult_mod(t1, t1, t2, keyLength); // t1=t1*t2
+ multiprecision_sub_mod(y3, t1, y3, keyLength); // y3=t1-y3
+}
+
+// q=q+p, zp must be 1
+static void ECC_Add(Point *r, Point *p, Point *q, uint32_t keyLength)
+{
+ DWORD t1[KEY_LENGTH_DWORDS_P256];
+ DWORD t2[KEY_LENGTH_DWORDS_P256];
+ DWORD *x1;
+ DWORD *x2;
+ DWORD *x3;
+ DWORD *y1;
+ DWORD *y2;
+ DWORD *y3;
+ DWORD *z1;
+ DWORD *z2;
+ DWORD *z3;
+
+ x1 = p->x; y1 = p->y; z1 = p->z;
+ x2 = q->x; y2 = q->y; z2 = q->z;
+ x3 = r->x; y3 = r->y; z3 = r->z;
+
+ // if Q=infinity, return p
+ if (multiprecision_iszero(z2, keyLength)) {
+ p_256_copy_point(r, p);
+ return;
+ }
+
+ // if P=infinity, return q
+ if (multiprecision_iszero(z1, keyLength)) {
+ p_256_copy_point(r, q);
+ return;
+ }
+
+ multiprecision_mersenns_squa_mod(t1, z1, keyLength); // t1=z1^2
+ multiprecision_mersenns_mult_mod(t2, z1, t1, keyLength); // t2=t1*z1
+ multiprecision_mersenns_mult_mod(t1, x2, t1, keyLength); // t1=t1*x2
+ multiprecision_mersenns_mult_mod(t2, y2, t2, keyLength); // t2=t2*y2
+
+ multiprecision_sub_mod(t1, t1, x1, keyLength); // t1=t1-x1
+ multiprecision_sub_mod(t2, t2, y1, keyLength); // t2=t2-y1
+
+ if (multiprecision_iszero(t1, keyLength)) {
+ if (multiprecision_iszero(t2, keyLength)) {
+ ECC_Double(r, q, keyLength) ;
+ return;
+ } else {
+ multiprecision_init(z3, keyLength);
+ return; // return infinity
+ }
+ }
+
+ multiprecision_mersenns_mult_mod(z3, z1, t1, keyLength); // z3=z1*t1
+ multiprecision_mersenns_squa_mod(y3, t1, keyLength); // t3=t1^2
+ multiprecision_mersenns_mult_mod(z1, y3, t1, keyLength); // t4=t3*t1
+ multiprecision_mersenns_mult_mod(y3, y3, x1, keyLength); // t3=t3*x1
+ multiprecision_lshift_mod(t1, y3, keyLength); // t1=2*t3
+ multiprecision_mersenns_squa_mod(x3, t2, keyLength); // x3=t2^2
+ multiprecision_sub_mod(x3, x3, t1, keyLength); // x3=x3-t1
+ multiprecision_sub_mod(x3, x3, z1, keyLength); // x3=x3-t4
+ multiprecision_sub_mod(y3, y3, x3, keyLength); // t3=t3-x3
+ multiprecision_mersenns_mult_mod(y3, y3, t2, keyLength); // t3=t3*t2
+ multiprecision_mersenns_mult_mod(z1, z1, y1, keyLength); // t4=t4*t1
+ multiprecision_sub_mod(y3, y3, z1, keyLength);
+}
+
+// Computing the Non-Adjacent Form of a positive integer
+static void ECC_NAF(uint8_t *naf, uint32_t *NumNAF, DWORD *k, uint32_t keyLength)
+{
+ uint32_t sign;
+ int i = 0;
+ int j;
+ uint32_t var;
+
+ while ((var = multiprecision_most_signbits(k, keyLength)) >= 1) {
+ if (k[0] & 0x01) { // k is odd
+ sign = (k[0] & 0x03); // 1 or 3
+
+ // k = k-naf[i]
+ if (sign == 1) {
+ k[0] = k[0] & 0xFFFFFFFE;
+ } else {
+ k[0] = k[0] + 1;
+ if (k[0] == 0) { //overflow
+ j = 1;
+ do {
+ k[j]++;
+ } while (k[j++] == 0); //overflow
+ }
+ }
+ } else {
+ sign = 0;
+ }
+
+ multiprecision_rshift(k, k, keyLength);
+ naf[i / 4] |= (sign) << ((i % 4) * 2);
+ i++;
+ }
+
+ *NumNAF = i;
+}
+
+// Binary Non-Adjacent Form for point multiplication
+void ECC_PointMult_Bin_NAF(Point *q, Point *p, DWORD *n, uint32_t keyLength)
+{
+ uint32_t sign;
+ UINT8 naf[256 / 4 + 1];
+ uint32_t NumNaf;
+ Point minus_p;
+ Point r;
+ DWORD *modp;
+
+ if (keyLength == KEY_LENGTH_DWORDS_P256) {
+ modp = curve_p256.p;
+ } else {
+ modp = curve.p;
+ }
+
+ p_256_init_point(&r);
+ multiprecision_init(p->z, keyLength);
+ p->z[0] = 1;
+
+ // initialization
+ p_256_init_point(q);
+
+ // -p
+ multiprecision_copy(minus_p.x, p->x, keyLength);
+ multiprecision_sub(minus_p.y, modp, p->y, keyLength);
+
+ multiprecision_init(minus_p.z, keyLength);
+ minus_p.z[0] = 1;
+
+ // NAF
+ memset(naf, 0, sizeof(naf));
+ ECC_NAF(naf, &NumNaf, n, keyLength);
+
+ for (int i = NumNaf - 1; i >= 0; i--) {
+ p_256_copy_point(&r, q);
+ ECC_Double(q, &r, keyLength);
+ sign = (naf[i / 4] >> ((i % 4) * 2)) & 0x03;
+
+ if (sign == 1) {
+ p_256_copy_point(&r, q);
+ ECC_Add(q, &r, p, keyLength);
+ } else if (sign == 3) {
+ p_256_copy_point(&r, q);
+ ECC_Add(q, &r, &minus_p, keyLength);
+ }
+ }
+
+ multiprecision_inv_mod(minus_p.x, q->z, keyLength);
+ multiprecision_mersenns_squa_mod(q->z, minus_p.x, keyLength);
+ multiprecision_mersenns_mult_mod(q->x, q->x, q->z, keyLength);
+ multiprecision_mersenns_mult_mod(q->z, q->z, minus_p.x, keyLength);
+ multiprecision_mersenns_mult_mod(q->y, q->y, q->z, keyLength);
+}
+
+bool ECC_CheckPointIsInElliCur_P256(Point *p)
+{
+ /* y^2 % q */
+ DWORD y_y_q[KEY_LENGTH_DWORDS_P256] = {0x0};
+ /* x^2 % q */
+ DWORD x_x_q[KEY_LENGTH_DWORDS_P256] = {0x0};
+ /* x % q */
+ DWORD x_q[KEY_LENGTH_DWORDS_P256] = {0x0};
+ /* x^2, To prevent overflow, the length of the x square here needs to
+ be expanded to two times the original one. */
+ DWORD x_x[2*KEY_LENGTH_DWORDS_P256] = {0x0};
+ /* y_y_q =(p->y)^2(mod q) */
+ multiprecision_mersenns_squa_mod(y_y_q, p->y, KEY_LENGTH_DWORDS_P256);
+ /* Calculate the value of p->x square, x_x = (p->x)^2 */
+ multiprecision_mult(x_x, p->x, p->x, KEY_LENGTH_DWORDS_P256);
+ /* The function of the elliptic curve is y^2 = x^3 - 3x + b (mod q) ==>
+ y^2 = (x^2 - 3)*x + b (mod q),
+ so we calculate the x^2 - 3 value here */
+ x_x[0] -= 3;
+ /* Using math relations. (a*b) % q = ((a%q)*(b%q)) % q ==>
+ (x^2 - 3)*x = (((x^2 - 3) % q) * x % q) % q */
+ multiprecision_fast_mod_P256(x_x_q, x_x);
+ /* x_x = x_x_q * x_q */
+ multiprecision_mult(x_x, x_x_q, p->x, KEY_LENGTH_DWORDS_P256);
+ /* x_q = x_x % q */
+ multiprecision_fast_mod_P256(x_q, x_x);
+ /* Save the result in x_x_q */
+ multiprecision_add_mod(x_x_q, x_q, curve_p256.b, KEY_LENGTH_DWORDS_P256);
+ /* compare the y_y_q and x_x_q, see if they are on a given elliptic curve. */
+ if (multiprecision_compare(y_y_q, x_x_q, KEY_LENGTH_DWORDS_P256)) {
+ return false;
+ } else {
+ return true;
+ }
+}
diff --git a/lib/bt/host/bluedroid/stack/smp/p_256_multprecision.c b/lib/bt/host/bluedroid/stack/smp/p_256_multprecision.c
new file mode 100644
index 00000000..1dbca137
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/smp/p_256_multprecision.c
@@ -0,0 +1,647 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2006-2015 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains simple pairing algorithms
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "common/bt_target.h"
+#include "p_256_ecc_pp.h"
+#include "p_256_multprecision.h"
+
+void multiprecision_init(DWORD *c, uint32_t keyLength)
+{
+ for (uint32_t i = 0; i < keyLength; i++) {
+ c[i] = 0;
+ }
+}
+
+void multiprecision_copy(DWORD *c, DWORD *a, uint32_t keyLength)
+{
+ for (uint32_t i = 0; i < keyLength; i++) {
+ c[i] = a[i];
+ }
+}
+
+int multiprecision_compare(DWORD *a, DWORD *b, uint32_t keyLength)
+{
+ for (int i = keyLength - 1; i >= 0; i--) {
+ if (a[i] > b[i]) {
+ return 1;
+ }
+ if (a[i] < b[i]) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int multiprecision_iszero(DWORD *a, uint32_t keyLength)
+{
+ for (uint32_t i = 0; i < keyLength; i++)
+ if (a[i]) {
+ return 0;
+ }
+
+ return 1;
+}
+
+UINT32 multiprecision_dword_bits(DWORD a)
+{
+ uint32_t i;
+ for (i = 0; i < DWORD_BITS; i++, a >>= 1)
+ if (a == 0) {
+ break;
+ }
+
+ return i;
+}
+
+UINT32 multiprecision_most_signdwords(DWORD *a, uint32_t keyLength)
+{
+ int i;
+ for (i = keyLength - 1; i >= 0; i--)
+ if (a[i]) {
+ break;
+ }
+ return (i + 1);
+}
+
+UINT32 multiprecision_most_signbits(DWORD *a, uint32_t keyLength)
+{
+ int aMostSignDWORDs;
+
+ aMostSignDWORDs = multiprecision_most_signdwords(a, keyLength);
+ if (aMostSignDWORDs == 0) {
+ return 0;
+ }
+
+ return (((aMostSignDWORDs - 1) << DWORD_BITS_SHIFT) +
+ multiprecision_dword_bits(a[aMostSignDWORDs - 1]) );
+}
+
+DWORD multiprecision_add(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength)
+{
+ DWORD carrier;
+ DWORD temp;
+
+ carrier = 0;
+ for (uint32_t i = 0; i < keyLength; i++) {
+ temp = a[i] + carrier;
+ carrier = (temp < carrier);
+ temp += b[i];
+ carrier |= (temp < b[i]);
+ c[i] = temp;
+ }
+
+ return carrier;
+}
+
+//c=a-b
+DWORD multiprecision_sub(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength)
+{
+ DWORD borrow;
+ DWORD temp;
+
+ borrow = 0;
+ for (uint32_t i = 0; i < keyLength; i++) {
+ temp = a[i] - borrow;
+ borrow = (temp > a[i]);
+ c[i] = temp - b[i];
+ borrow |= (c[i] > temp);
+ }
+
+ return borrow;
+}
+
+// c = a << 1
+void multiprecision_lshift_mod(DWORD *c, DWORD *a, uint32_t keyLength)
+{
+ DWORD carrier;
+ DWORD *modp;
+
+ if (keyLength == KEY_LENGTH_DWORDS_P192) {
+ modp = curve.p;
+ } else if (keyLength == KEY_LENGTH_DWORDS_P256) {
+ modp = curve_p256.p;
+ } else {
+ return;
+ }
+
+ carrier = multiprecision_lshift(c, a, keyLength);
+ if (carrier) {
+ multiprecision_sub(c, c, modp, keyLength);
+ } else if (multiprecision_compare(c, modp, keyLength) >= 0) {
+ multiprecision_sub(c, c, modp, keyLength);
+ }
+}
+
+// c=a>>1
+void multiprecision_rshift(DWORD *c, DWORD *a, uint32_t keyLength)
+{
+ int j;
+ DWORD b = 1;
+
+ j = DWORD_BITS - b;
+
+ DWORD carrier = 0;
+ DWORD temp;
+ for (int i = keyLength - 1; i >= 0; i--) {
+ temp = a[i]; // in case of c==a
+ c[i] = (temp >> b) | carrier;
+ carrier = temp << j;
+ }
+}
+
+// Curve specific optimization when p is a pseudo-Mersenns prime, p=2^(KEY_LENGTH_BITS)-omega
+void multiprecision_mersenns_mult_mod(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength)
+{
+ DWORD cc[2 * KEY_LENGTH_DWORDS_P256];
+
+ multiprecision_mult(cc, a, b, keyLength);
+ if (keyLength == 6) {
+ multiprecision_fast_mod(c, cc);
+ } else if (keyLength == 8) {
+ multiprecision_fast_mod_P256(c, cc);
+ }
+}
+
+// Curve specific optimization when p is a pseudo-Mersenns prime
+void multiprecision_mersenns_squa_mod(DWORD *c, DWORD *a, uint32_t keyLength)
+{
+ multiprecision_mersenns_mult_mod(c, a, a, keyLength);
+}
+
+// c=(a+b) mod p, b<p, a<p
+void multiprecision_add_mod(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength)
+{
+ DWORD carrier;
+ DWORD *modp;
+
+ if (keyLength == KEY_LENGTH_DWORDS_P192) {
+ modp = curve.p;
+ } else if (keyLength == KEY_LENGTH_DWORDS_P256) {
+ modp = curve_p256.p;
+ } else {
+ return;
+ }
+
+ carrier = multiprecision_add(c, a, b, keyLength);
+ if (carrier) {
+ multiprecision_sub(c, c, modp, keyLength);
+ } else if (multiprecision_compare(c, modp, keyLength) >= 0) {
+ multiprecision_sub(c, c, modp, keyLength);
+ }
+}
+
+// c=(a-b) mod p, a<p, b<p
+void multiprecision_sub_mod(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength)
+{
+ DWORD borrow;
+ DWORD *modp;
+
+ if (keyLength == KEY_LENGTH_DWORDS_P192) {
+ modp = curve.p;
+ } else if (keyLength == KEY_LENGTH_DWORDS_P256) {
+ modp = curve_p256.p;
+ } else {
+ return;
+ }
+
+ borrow = multiprecision_sub(c, a, b, keyLength);
+ if (borrow) {
+ multiprecision_add(c, c, modp, keyLength);
+ }
+}
+
+// c=a<<b, b<DWORD_BITS, c has a buffer size of NumDWORDs+1
+DWORD multiprecision_lshift(DWORD *c, DWORD *a, uint32_t keyLength)
+{
+ int j;
+ uint32_t b = 1;
+ j = DWORD_BITS - b;
+
+ DWORD carrier = 0;
+ DWORD temp;
+
+ for (uint32_t i = 0; i < keyLength; i++) {
+ temp = a[i]; // in case c==a
+ c[i] = (temp << b) | carrier;
+ carrier = temp >> j;
+ }
+
+ return carrier;
+}
+
+// c=a*b; c must have a buffer of 2*Key_LENGTH_DWORDS, c != a != b
+void multiprecision_mult(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength)
+{
+ DWORD W;
+ DWORD U;
+ DWORD V;
+
+ U = V = W = 0;
+ multiprecision_init(c, keyLength);
+
+ //assume little endian right now
+ for (uint32_t i = 0; i < keyLength; i++) {
+ U = 0;
+ for (uint32_t j = 0; j < keyLength; j++) {
+ uint64_t result;
+ result = ((UINT64)a[i]) * ((uint64_t) b[j]);
+ W = result >> 32;
+ V = a[i] * b[j];
+ V = V + U;
+ U = (V < U);
+ U += W;
+ V = V + c[i + j];
+ U += (V < c[i + j]);
+ c[i + j] = V;
+ }
+ c[i + keyLength] = U;
+ }
+}
+
+void multiprecision_fast_mod(DWORD *c, DWORD *a)
+{
+ DWORD U;
+ DWORD V;
+ DWORD *modp = curve.p;
+
+ c[0] = a[0] + a[6];
+ U = c[0] < a[0];
+ c[0] += a[10];
+ U += c[0] < a[10];
+
+ c[1] = a[1] + U;
+ U = c[1] < a[1];
+ c[1] += a[7];
+ U += c[1] < a[7];
+ c[1] += a[11];
+ U += c[1] < a[11];
+
+ c[2] = a[2] + U;
+ U = c[2] < a[2];
+ c[2] += a[6];
+ U += c[2] < a[6];
+ c[2] += a[8];
+ U += c[2] < a[8];
+ c[2] += a[10];
+ U += c[2] < a[10];
+
+ c[3] = a[3] + U;
+ U = c[3] < a[3];
+ c[3] += a[7];
+ U += c[3] < a[7];
+ c[3] += a[9];
+ U += c[3] < a[9];
+ c[3] += a[11];
+ U += c[3] < a[11];
+
+ c[4] = a[4] + U;
+ U = c[4] < a[4];
+ c[4] += a[8];
+ U += c[4] < a[8];
+ c[4] += a[10];
+ U += c[4] < a[10];
+
+ c[5] = a[5] + U;
+ U = c[5] < a[5];
+ c[5] += a[9];
+ U += c[5] < a[9];
+ c[5] += a[11];
+ U += c[5] < a[11];
+
+ c[0] += U;
+ V = c[0] < U;
+ c[1] += V;
+ V = c[1] < V;
+ c[2] += V;
+ V = c[2] < V;
+ c[2] += U;
+ V = c[2] < U;
+ c[3] += V;
+ V = c[3] < V;
+ c[4] += V;
+ V = c[4] < V;
+ c[5] += V;
+ V = c[5] < V;
+
+ if (V) {
+ multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P192);
+ } else if (multiprecision_compare(c, modp, KEY_LENGTH_DWORDS_P192) >= 0) {
+ multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P192);
+ }
+}
+
+void multiprecision_fast_mod_P256(DWORD *c, DWORD *a)
+{
+ DWORD A;
+ DWORD B;
+ DWORD C;
+ DWORD D;
+ DWORD E;
+ DWORD F;
+ DWORD G;
+ uint8_t UA;
+ uint8_t UB;
+ uint8_t UC;
+ uint8_t UD;
+ uint8_t UE;
+ uint8_t UF;
+ uint8_t UG;
+ DWORD U;
+ DWORD *modp = curve_p256.p;
+
+ // C = a[13] + a[14] + a[15];
+ C = a[13];
+ C += a[14];
+ UC = (C < a[14]);
+ C += a[15];
+ UC += (C < a[15]);
+
+ // E = a[8] + a[9];
+ E = a[8];
+ E += a[9];
+ UE = (E < a[9]);
+
+ // F = a[9] + a[10];
+ F = a[9];
+ F += a[10];
+ UF = (F < a[10]);
+
+ // G = a[10] + a[11]
+ G = a[10];
+ G += a[11];
+ UG = (G < a[11]);
+
+ // B = a[12] + a[13] + a[14] + a[15] == C + a[12]
+ B = C;
+ UB = UC;
+ B += a[12];
+ UB += (B < a[12]);
+
+ // A = a[11] + a[12] + a[13] + a[14] == B + a[11] - a[15]
+ A = B;
+ UA = UB;
+ A += a[11];
+ UA += (A < a[11]);
+ UA -= (A < a[15]);
+ A -= a[15];
+
+ // D = a[10] + a[11] + a[12] + a[13] == A + a[10] - a[14]
+ D = A;
+ UD = UA;
+ D += a[10];
+ UD += (D < a[10]);
+ UD -= (D < a[14]);
+ D -= a[14];
+
+ c[0] = a[0];
+ c[0] += E;
+ U = (c[0] < E);
+ U += UE;
+ U -= (c[0] < A);
+ U -= UA;
+ c[0] -= A;
+
+ if (U & 0x80000000) {
+ DWORD UU;
+ UU = 0 - U;
+ U = (a[1] < UU);
+ c[1] = a[1] - UU;
+ } else {
+ c[1] = a[1] + U;
+ U = (c[1] < a[1]);
+ }
+
+ c[1] += F;
+ U += (c[1] < F);
+ U += UF;
+ U -= (c[1] < B);
+ U -= UB;
+ c[1] -= B;
+
+ if (U & 0x80000000) {
+ DWORD UU;
+ UU = 0 - U;
+ U = (a[2] < UU);
+ c[2] = a[2] - UU;
+ } else {
+ c[2] = a[2] + U;
+ U = (c[2] < a[2]);
+ }
+
+ c[2] += G;
+ U += (c[2] < G);
+ U += UG;
+ U -= (c[2] < C);
+ U -= UC;
+ c[2] -= C;
+
+ if (U & 0x80000000) {
+ DWORD UU;
+ UU = 0 - U;
+ U = (a[3] < UU);
+ c[3] = a[3] - UU;
+ } else {
+ c[3] = a[3] + U;
+ U = (c[3] < a[3]);
+ }
+
+ c[3] += A;
+ U += (c[3] < A);
+ U += UA;
+ c[3] += a[11];
+ U += (c[3] < a[11]);
+ c[3] += a[12];
+ U += (c[3] < a[12]);
+ U -= (c[3] < a[14]);
+ c[3] -= a[14];
+ U -= (c[3] < a[15]);
+ c[3] -= a[15];
+ U -= (c[3] < E);
+ U -= UE;
+ c[3] -= E;
+
+ if (U & 0x80000000) {
+ DWORD UU;
+ UU = 0 - U;
+ U = (a[4] < UU);
+ c[4] = a[4] - UU;
+ } else {
+ c[4] = a[4] + U;
+ U = (c[4] < a[4]);
+ }
+
+ c[4] += B;
+ U += (c[4] < B);
+ U += UB;
+ U -= (c[4] < a[15]);
+ c[4] -= a[15];
+ c[4] += a[12];
+ U += (c[4] < a[12]);
+ c[4] += a[13];
+ U += (c[4] < a[13]);
+ U -= (c[4] < F);
+ U -= UF;
+ c[4] -= F;
+
+ if (U & 0x80000000) {
+ DWORD UU;
+ UU = 0 - U;
+ U = (a[5] < UU);
+ c[5] = a[5] - UU;
+ } else {
+ c[5] = a[5] + U;
+ U = (c[5] < a[5]);
+ }
+
+ c[5] += C;
+ U += (c[5] < C);
+ U += UC;
+ c[5] += a[13];
+ U += (c[5] < a[13]);
+ c[5] += a[14];
+ U += (c[5] < a[14]);
+ U -= (c[5] < G);
+ U -= UG;
+ c[5] -= G;
+
+ if (U & 0x80000000) {
+ DWORD UU;
+ UU = 0 - U;
+ U = (a[6] < UU);
+ c[6] = a[6] - UU;
+ } else {
+ c[6] = a[6] + U;
+ U = (c[6] < a[6]);
+ }
+
+ c[6] += C;
+ U += (c[6] < C);
+ U += UC;
+ c[6] += a[14];
+ U += (c[6] < a[14]);
+ c[6] += a[14];
+ U += (c[6] < a[14]);
+ c[6] += a[15];
+ U += (c[6] < a[15]);
+ U -= (c[6] < E);
+ U -= UE;
+ c[6] -= E;
+
+ if (U & 0x80000000) {
+ DWORD UU;
+ UU = 0 - U;
+ U = (a[7] < UU);
+ c[7] = a[7] - UU;
+ } else {
+ c[7] = a[7] + U;
+ U = (c[7] < a[7]);
+ }
+
+ c[7] += a[15];
+ U += (c[7] < a[15]);
+ c[7] += a[15];
+ U += (c[7] < a[15]);
+ c[7] += a[15];
+ U += (c[7] < a[15]);
+ c[7] += a[8];
+ U += (c[7] < a[8]);
+ U -= (c[7] < D);
+ U -= UD;
+ c[7] -= D;
+
+ if (U & 0x80000000) {
+ while (U) {
+ multiprecision_add(c, c, modp, KEY_LENGTH_DWORDS_P256);
+ U++;
+ }
+ } else if (U) {
+ while (U) {
+ multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P256);
+ U--;
+ }
+ }
+
+ if (multiprecision_compare(c, modp, KEY_LENGTH_DWORDS_P256) >= 0) {
+ multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P256);
+ }
+
+}
+
+void multiprecision_inv_mod(DWORD *aminus, DWORD *u, uint32_t keyLength)
+{
+ DWORD v[KEY_LENGTH_DWORDS_P256];
+ DWORD A[KEY_LENGTH_DWORDS_P256 + 1];
+ DWORD C[KEY_LENGTH_DWORDS_P256 + 1];
+ DWORD *modp;
+
+ if (keyLength == KEY_LENGTH_DWORDS_P256) {
+ modp = curve_p256.p;
+ } else {
+ modp = curve.p;
+ }
+
+ multiprecision_copy(v, modp, keyLength);
+ multiprecision_init(A, keyLength);
+ multiprecision_init(C, keyLength);
+ A[0] = 1;
+
+ while (!multiprecision_iszero(u, keyLength)) {
+ while (!(u[0] & 0x01)) { // u is even
+ multiprecision_rshift(u, u, keyLength);
+ if (!(A[0] & 0x01)) { // A is even
+ multiprecision_rshift(A, A, keyLength);
+ } else {
+ A[keyLength] = multiprecision_add(A, A, modp, keyLength); // A =A+p
+ multiprecision_rshift(A, A, keyLength);
+ A[keyLength - 1] |= (A[keyLength] << 31);
+ }
+ }
+
+ while (!(v[0] & 0x01)) { // v is even
+ multiprecision_rshift(v, v, keyLength);
+ if (!(C[0] & 0x01)) { // C is even
+ multiprecision_rshift(C, C, keyLength);
+ } else {
+ C[keyLength] = multiprecision_add(C, C, modp, keyLength); // C =C+p
+ multiprecision_rshift(C, C, keyLength);
+ C[keyLength - 1] |= (C[keyLength] << 31);
+ }
+ }
+
+ if (multiprecision_compare(u, v, keyLength) >= 0) {
+ multiprecision_sub(u, u, v, keyLength);
+ multiprecision_sub_mod(A, A, C, keyLength);
+ } else {
+ multiprecision_sub(v, v, u, keyLength);
+ multiprecision_sub_mod(C, C, A, keyLength);
+ }
+ }
+
+ if (multiprecision_compare(C, modp, keyLength) >= 0) {
+ multiprecision_sub(aminus, C, modp, keyLength);
+ } else {
+ multiprecision_copy(aminus, C, keyLength);
+ }
+}
diff --git a/lib/bt/host/bluedroid/stack/smp/smp_act.c b/lib/bt/host/bluedroid/stack/smp/smp_act.c
new file mode 100644
index 00000000..0e7dcd5b
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/smp/smp_act.c
@@ -0,0 +1,2194 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "device/interop.h"
+#include "common/bt_target.h"
+#include "btm_int.h"
+#include "stack/l2c_api.h"
+#include "smp_int.h"
+#include "p_256_ecc_pp.h"
+//#include "utils/include/bt_utils.h"
+
+#if SMP_INCLUDED == TRUE
+const UINT8 smp_association_table[2][SMP_IO_CAP_MAX][SMP_IO_CAP_MAX] = {
+ /* initiator */
+ { {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY}, /* Display Only */
+ {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY}, /* SMP_CAP_IO = 1 */
+ {SMP_MODEL_KEY_NOTIF, SMP_MODEL_KEY_NOTIF, SMP_MODEL_PASSKEY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF}, /* keyboard only */
+ {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY},/* No Input No Output */
+ {SMP_MODEL_KEY_NOTIF, SMP_MODEL_KEY_NOTIF, SMP_MODEL_PASSKEY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF}
+ }, /* keyboard display */
+ /* responder */
+ { {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF}, /* Display Only */
+ {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF}, /* SMP_CAP_IO = 1 */
+ {SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY}, /* keyboard only */
+ {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY},/* No Input No Output */
+ {SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_KEY_NOTIF, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY}
+ } /* keyboard display */
+ /* display only */ /*SMP_CAP_IO = 1 */ /* keyboard only */ /* No InputOutput */ /* keyboard display */
+};
+
+#define SMP_KEY_DIST_TYPE_MAX 4
+const tSMP_ACT smp_distribute_act [] = {
+#if (BLE_INCLUDED == TRUE)
+ smp_generate_ltk,
+ smp_send_id_info,
+ smp_generate_csrk,
+ smp_set_derive_link_key
+#else
+ NULL,
+ NULL,
+ NULL,
+ NULL
+#endif ///BLE_INCLUDED == TRUE
+};
+
+extern UINT8 bta_dm_co_ble_get_accept_auth_enable(void);
+extern UINT8 bta_dm_co_ble_get_auth_req(void);
+
+static bool lmp_version_below(BD_ADDR bda, uint8_t version)
+{
+ tACL_CONN *acl = btm_bda_to_acl(bda, BT_TRANSPORT_LE);
+ if (acl == NULL || acl->lmp_version == 0) {
+ SMP_TRACE_WARNING("%s cannot retrieve LMP version...", __func__);
+ return false;
+ }
+ SMP_TRACE_DEBUG("%s LMP version %d < %d", __func__, acl->lmp_version, version);
+ return acl->lmp_version < version;
+}
+
+/*******************************************************************************
+** Function smp_update_key_mask
+** Description This function updates the key mask for sending or receiving.
+*******************************************************************************/
+static void smp_update_key_mask (tSMP_CB *p_cb, UINT8 key_type, BOOLEAN recv)
+{
+ SMP_TRACE_DEBUG("%s before update role=%d recv=%d local_i_key = %02x, local_r_key = %02x\n",
+ __func__, p_cb->role, recv, p_cb->local_i_key, p_cb->local_r_key);
+
+ if (((p_cb->le_secure_connections_mode_is_used) ||
+ (p_cb->smp_over_br)) &&
+ ((key_type == SMP_SEC_KEY_TYPE_ENC) || (key_type == SMP_SEC_KEY_TYPE_LK))) {
+ /* in LE SC mode LTK, CSRK and BR/EDR LK are derived locally instead of
+ ** being exchanged with the peer */
+ p_cb->local_i_key &= ~key_type;
+ p_cb->local_r_key &= ~key_type;
+ } else if (p_cb->role == HCI_ROLE_SLAVE) {
+ if (recv) {
+ p_cb->local_i_key &= ~key_type;
+ } else {
+ p_cb->local_r_key &= ~key_type;
+ }
+ } else {
+ if (recv) {
+ p_cb->local_r_key &= ~key_type;
+ } else {
+ p_cb->local_i_key &= ~key_type;
+ }
+ }
+
+ SMP_TRACE_DEBUG("updated local_i_key = %02x, local_r_key = %02x\n", p_cb->local_i_key,
+ p_cb->local_r_key);
+}
+
+/*******************************************************************************
+** Function smp_send_app_cback
+** Description notifies application about the events the application is interested in
+*******************************************************************************/
+void smp_send_app_cback(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ tSMP_EVT_DATA cb_data;
+ tSMP_STATUS callback_rc;
+ SMP_TRACE_DEBUG("%s p_cb->cb_evt=%d\n", __func__, p_cb->cb_evt);
+ if (p_cb->p_callback && p_cb->cb_evt != 0) {
+ switch (p_cb->cb_evt) {
+ case SMP_IO_CAP_REQ_EVT:
+ cb_data.io_req.auth_req = p_cb->peer_auth_req;
+ cb_data.io_req.oob_data = SMP_OOB_NONE;
+ cb_data.io_req.io_cap = SMP_DEFAULT_IO_CAPS;
+ cb_data.io_req.max_key_size = SMP_MAX_ENC_KEY_SIZE;
+ cb_data.io_req.init_keys = p_cb->local_i_key ;
+ cb_data.io_req.resp_keys = p_cb->local_r_key ;
+ SMP_TRACE_DEBUG ( "io_cap = %d", cb_data.io_req.io_cap);
+ break;
+
+ case SMP_NC_REQ_EVT:
+ cb_data.passkey = p_data->passkey;
+ break;
+ case SMP_SC_OOB_REQ_EVT:
+ cb_data.req_oob_type = p_data->req_oob_type;
+ break;
+ case SMP_SC_LOC_OOB_DATA_UP_EVT:
+ cb_data.loc_oob_data = p_cb->sc_oob_data.loc_oob_data;
+ break;
+
+ case SMP_BR_KEYS_REQ_EVT:
+ cb_data.io_req.auth_req = 0;
+ cb_data.io_req.oob_data = SMP_OOB_NONE;
+ cb_data.io_req.io_cap = 0;
+ cb_data.io_req.max_key_size = SMP_MAX_ENC_KEY_SIZE;
+ cb_data.io_req.init_keys = SMP_BR_SEC_DEFAULT_KEY;
+ cb_data.io_req.resp_keys = SMP_BR_SEC_DEFAULT_KEY;
+ break;
+
+ default:
+ break;
+ }
+
+ callback_rc = (*p_cb->p_callback)(p_cb->cb_evt, p_cb->pairing_bda, &cb_data);
+
+ SMP_TRACE_DEBUG("callback_rc=%d p_cb->cb_evt=%d\n", callback_rc, p_cb->cb_evt );
+
+ if (callback_rc == SMP_SUCCESS) {
+ switch (p_cb->cb_evt) {
+ case SMP_IO_CAP_REQ_EVT:
+ p_cb->loc_auth_req = cb_data.io_req.auth_req;
+ p_cb->local_io_capability = cb_data.io_req.io_cap;
+ p_cb->loc_oob_flag = cb_data.io_req.oob_data;
+ p_cb->loc_enc_size = cb_data.io_req.max_key_size;
+ p_cb->local_i_key = cb_data.io_req.init_keys;
+ p_cb->local_r_key = cb_data.io_req.resp_keys;
+
+ if (!(p_cb->loc_auth_req & SMP_AUTH_BOND)) {
+ SMP_TRACE_WARNING ("Non bonding: No keys will be exchanged");
+ p_cb->local_i_key = 0;
+ p_cb->local_r_key = 0;
+ }
+
+ SMP_TRACE_DEBUG ("rcvd auth_req: 0x%02x, io_cap: %d \
+ loc_oob_flag: %d loc_enc_size: %d,"
+ "local_i_key: 0x%02x, local_r_key: 0x%02x\n",
+ p_cb->loc_auth_req, p_cb->local_io_capability, p_cb->loc_oob_flag,
+ p_cb->loc_enc_size, p_cb->local_i_key, p_cb->local_r_key);
+
+ p_cb->secure_connections_only_mode_required =
+ (btm_cb.security_mode == BTM_SEC_MODE_SC) ? TRUE : FALSE;
+
+ if (p_cb->secure_connections_only_mode_required) {
+ p_cb->loc_auth_req |= SMP_SC_SUPPORT_BIT;
+ }
+
+ if (!(p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT)
+ || lmp_version_below(p_cb->pairing_bda, HCI_PROTO_VERSION_4_2)
+ || interop_match(INTEROP_DISABLE_LE_SECURE_CONNECTIONS,
+ (const bt_bdaddr_t *)&p_cb->pairing_bda)) {
+ p_cb->loc_auth_req &= ~SMP_KP_SUPPORT_BIT;
+ p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK;
+ p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK;
+ }
+
+ SMP_TRACE_DEBUG("set auth_req: 0x%02x, local_i_key: 0x%02x, local_r_key: 0x%02x\n",
+ p_cb->loc_auth_req, p_cb->local_i_key, p_cb->local_r_key);
+
+ smp_sm_event(p_cb, SMP_IO_RSP_EVT, NULL);
+ break;
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ case SMP_BR_KEYS_REQ_EVT:
+ p_cb->loc_enc_size = cb_data.io_req.max_key_size;
+ p_cb->local_i_key = cb_data.io_req.init_keys;
+ p_cb->local_r_key = cb_data.io_req.resp_keys;
+
+ p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK;
+ p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK;
+
+ SMP_TRACE_WARNING ( "for SMP over BR max_key_size: 0x%02x,\
+ local_i_key: 0x%02x, local_r_key: 0x%02x\n",
+ p_cb->loc_enc_size, p_cb->local_i_key, p_cb->local_r_key);
+
+ smp_br_state_machine_event(p_cb, SMP_BR_KEYS_RSP_EVT, NULL);
+ break;
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+ }
+ }
+ }
+
+ if (!p_cb->cb_evt && p_cb->discard_sec_req) {
+ p_cb->discard_sec_req = FALSE;
+ smp_sm_event(p_cb, SMP_DISCARD_SEC_REQ_EVT, NULL);
+ }
+
+ SMP_TRACE_DEBUG("%s return\n", __func__);
+}
+
+/*******************************************************************************
+** Function smp_send_pair_fail
+** Description pairing failure to peer device if needed.
+*******************************************************************************/
+void smp_send_pair_fail(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ p_cb->status = *(UINT8 *)p_data;
+ p_cb->failure = *(UINT8 *)p_data;
+
+ SMP_TRACE_DEBUG("%s status=%d failure=%d ", __func__, p_cb->status, p_cb->failure);
+
+ if (p_cb->status <= SMP_MAX_FAIL_RSN_PER_SPEC && p_cb->status != SMP_SUCCESS) {
+ smp_send_cmd(SMP_OPCODE_PAIRING_FAILED, p_cb);
+ p_cb->wait_for_authorization_complete = TRUE;
+ }
+}
+
+/*******************************************************************************
+** Function smp_send_pair_req
+** Description actions related to sending pairing request
+*******************************************************************************/
+void smp_send_pair_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG("%s\n", __func__);
+
+#if (BLE_INCLUDED == TRUE)
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (p_cb->pairing_bda);
+ /* erase all keys when master sends pairing req*/
+ if (p_dev_rec) {
+ btm_sec_clear_ble_keys(p_dev_rec);
+ }
+#endif ///BLE_INCLUDED == TRUE
+ /* do not manipulate the key, let app decide,
+ leave out to BTM to mandate key distribution for bonding case */
+ smp_send_cmd(SMP_OPCODE_PAIRING_REQ, p_cb);
+}
+
+/*******************************************************************************
+** Function smp_send_pair_rsp
+** Description actions related to sending pairing response
+*******************************************************************************/
+void smp_send_pair_rsp(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG("%s\n", __func__);
+
+#if (BLE_INCLUDED == TRUE)
+ p_cb->local_i_key &= p_cb->peer_i_key;
+ p_cb->local_r_key &= p_cb->peer_r_key;
+
+ if (smp_send_cmd (SMP_OPCODE_PAIRING_RSP, p_cb)) {
+ if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_OOB) {
+ smp_use_oob_private_key(p_cb, NULL);
+ } else {
+ smp_decide_association_model(p_cb, NULL);
+ }
+ }
+#endif ///BLE_INCLUDED == TRUE
+}
+
+/*******************************************************************************
+** Function smp_send_confirm
+** Description send confirmation to the peer
+*******************************************************************************/
+void smp_send_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG("%s\n", __func__);
+ smp_send_cmd(SMP_OPCODE_CONFIRM, p_cb);
+}
+
+#if 0 //Unused
+/*******************************************************************************
+** Function smp_send_init
+** Description process pairing initializer to slave device
+*******************************************************************************/
+void smp_send_init(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG("%s\n", __func__);
+ smp_send_cmd(SMP_OPCODE_INIT, p_cb);
+}
+#endif
+
+/*******************************************************************************
+** Function smp_send_rand
+** Description send pairing random to the peer
+*******************************************************************************/
+void smp_send_rand(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG("%s\n", __func__);
+ smp_send_cmd(SMP_OPCODE_RAND, p_cb);
+}
+
+/*******************************************************************************
+** Function smp_send_pair_public_key
+** Description send pairing public key command to the peer
+*******************************************************************************/
+void smp_send_pair_public_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG("%s\n", __func__);
+ smp_send_cmd(SMP_OPCODE_PAIR_PUBLIC_KEY, p_cb);
+}
+
+/*******************************************************************************
+** Function SMP_SEND_COMMITMENT
+** Description send commitment command to the peer
+*******************************************************************************/
+void smp_send_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG("%s", __func__);
+ smp_send_cmd(SMP_OPCODE_PAIR_COMMITM, p_cb);
+}
+
+/*******************************************************************************
+** Function smp_send_dhkey_check
+** Description send DHKey Check command to the peer
+*******************************************************************************/
+void smp_send_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG("%s", __func__);
+ smp_send_cmd(SMP_OPCODE_PAIR_DHKEY_CHECK, p_cb);
+}
+
+/*******************************************************************************
+** Function smp_send_keypress_notification
+** Description send Keypress Notification command to the peer
+*******************************************************************************/
+void smp_send_keypress_notification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ p_cb->local_keypress_notification = *(UINT8 *) p_data;
+ smp_send_cmd(SMP_OPCODE_PAIR_KEYPR_NOTIF, p_cb);
+}
+
+/*******************************************************************************
+** Function smp_send_enc_info
+** Description send encryption information command.
+*******************************************************************************/
+void smp_send_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ tBTM_LE_LENC_KEYS le_key;
+
+ SMP_TRACE_DEBUG("%s p_cb->loc_enc_size = %d\n", __func__, p_cb->loc_enc_size);
+ smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ENC, FALSE);
+
+ smp_send_cmd(SMP_OPCODE_ENCRYPT_INFO, p_cb);
+ smp_send_cmd(SMP_OPCODE_MASTER_ID, p_cb);
+
+ /* save the DIV and key size information when acting as slave device */
+ memcpy(le_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
+ le_key.div = p_cb->div;
+ le_key.key_size = p_cb->loc_enc_size;
+ le_key.sec_level = p_cb->sec_level;
+
+#if (BLE_INCLUDED == TRUE)
+ if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND)) {
+ btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LENC,
+ (tBTM_LE_KEY_VALUE *)&le_key, TRUE);
+ }
+
+ SMP_TRACE_DEBUG ("%s\n", __func__);
+
+ smp_key_distribution(p_cb, NULL);
+#endif ///BLE_INCLUDED == TRUE
+}
+
+/*******************************************************************************
+** Function smp_send_id_info
+** Description send ID information command.
+*******************************************************************************/
+void smp_send_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG("%s\n", __func__);
+ smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ID, FALSE);
+
+ smp_send_cmd(SMP_OPCODE_IDENTITY_INFO, p_cb);
+ smp_send_cmd(SMP_OPCODE_ID_ADDR, p_cb);
+
+#if (BLE_INCLUDED == TRUE)
+ tBTM_LE_KEY_VALUE le_key;
+ if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND)) {
+ btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LID,
+ &le_key, TRUE);
+ }
+#endif ///BLE_INCLUDED == TRUE
+
+ smp_key_distribution_by_transport(p_cb, NULL);
+}
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+** Function smp_send_csrk_info
+** Description send CSRK command.
+*******************************************************************************/
+void smp_send_csrk_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ tBTM_LE_LCSRK_KEYS key;
+ SMP_TRACE_DEBUG("%s\n", __func__);
+ smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_CSRK, FALSE);
+
+ if (smp_send_cmd(SMP_OPCODE_SIGN_INFO, p_cb)) {
+ key.div = p_cb->div;
+ key.sec_level = p_cb->sec_level;
+ key.counter = 0; /* initialize the local counter */
+ memcpy (key.csrk, p_cb->csrk, BT_OCTET16_LEN);
+ btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LCSRK, (tBTM_LE_KEY_VALUE *)&key, TRUE);
+ }
+
+ smp_key_distribution_by_transport(p_cb, NULL);
+}
+
+/*******************************************************************************
+** Function smp_send_ltk_reply
+** Description send LTK reply
+*******************************************************************************/
+void smp_send_ltk_reply(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG("%s", __func__);
+ /* send stk as LTK response */
+ btm_ble_ltk_request_reply(p_cb->pairing_bda, TRUE, p_data->key.p_data);
+}
+
+/*******************************************************************************
+** Function smp_proc_sec_req
+** Description process security request.
+*******************************************************************************/
+void smp_proc_sec_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ tBTM_LE_AUTH_REQ auth_req = *(tBTM_LE_AUTH_REQ *)p_data;
+ tBTM_BLE_SEC_REQ_ACT sec_req_act;
+ UINT8 reason;
+
+ SMP_TRACE_DEBUG("%s auth_req=0x%x", __func__, auth_req);
+
+ p_cb->cb_evt = 0;
+ btm_ble_link_sec_check(p_cb->pairing_bda, auth_req, &sec_req_act);
+
+ SMP_TRACE_DEBUG("%s sec_req_act=0x%x", __func__, sec_req_act);
+
+ switch (sec_req_act) {
+ case BTM_BLE_SEC_REQ_ACT_ENCRYPT:
+ SMP_TRACE_DEBUG("%s BTM_BLE_SEC_REQ_ACT_ENCRYPT", __func__);
+ smp_sm_event(p_cb, SMP_ENC_REQ_EVT, NULL);
+ break;
+
+ case BTM_BLE_SEC_REQ_ACT_PAIR:
+ p_cb->secure_connections_only_mode_required =
+ (btm_cb.security_mode == BTM_SEC_MODE_SC) ? TRUE : FALSE;
+
+ /* respond to non SC pairing request as failure in SC only mode */
+ if (p_cb->secure_connections_only_mode_required &&
+ (auth_req & SMP_SC_SUPPORT_BIT) == 0) {
+ reason = SMP_PAIR_AUTH_FAIL;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ } else {
+ /* initialize local i/r key to be default keys */
+ p_cb->peer_auth_req = auth_req;
+ p_cb->local_r_key = p_cb->local_i_key = SMP_SEC_DEFAULT_KEY ;
+ p_cb->cb_evt = SMP_SEC_REQUEST_EVT;
+ }
+ break;
+
+ case BTM_BLE_SEC_REQ_ACT_DISCARD:
+ p_cb->discard_sec_req = TRUE;
+ break;
+
+ default:
+ /* do nothing */
+ break;
+ }
+}
+#endif ///BLE_INCLUDED == TRUE
+
+/*******************************************************************************
+** Function smp_proc_sec_grant
+** Description process security grant.
+*******************************************************************************/
+void smp_proc_sec_grant(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 res = *(UINT8 *)p_data;
+ SMP_TRACE_DEBUG("%s", __func__);
+ if (res != SMP_SUCCESS) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, p_data);
+ } else { /*otherwise, start pairing */
+ /* send IO request callback */
+ p_cb->cb_evt = SMP_IO_CAP_REQ_EVT;
+ }
+}
+
+/*******************************************************************************
+** Function smp_proc_pair_fail
+** Description process pairing failure from peer device
+*******************************************************************************/
+void smp_proc_pair_fail(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG("%s", __func__);
+ p_cb->status = *(UINT8 *)p_data;
+}
+
+/*******************************************************************************
+** Function smp_get_auth_mode
+** Description Get the SMP pairing auth mode
+*******************************************************************************/
+uint16_t smp_get_auth_mode (tSMP_ASSO_MODEL model)
+{
+ SMP_TRACE_DEBUG("%s model %d", __func__, model);
+ uint16_t auth = 0;
+ if (model == SMP_MODEL_ENCRYPTION_ONLY || model == SMP_MODEL_SEC_CONN_JUSTWORKS) {
+ //No MITM
+ if(model == SMP_MODEL_SEC_CONN_JUSTWORKS) {
+ //SC SMP_SC_SUPPORT_BIT
+ auth |= SMP_SC_SUPPORT_BIT;
+ }
+ } else if (model <= SMP_MODEL_KEY_NOTIF) {
+ //NO SC, MITM
+ auth |= SMP_AUTH_YN_BIT;
+ } else if (model <= SMP_MODEL_SEC_CONN_OOB) {
+ //SC, MITM
+ auth |= SMP_SC_SUPPORT_BIT;
+ auth |= SMP_AUTH_YN_BIT;
+ } else {
+ auth = 0;
+ }
+ return auth;
+}
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+** Function smp_proc_pair_cmd
+** Description Process the SMP pairing request/response from peer device
+*******************************************************************************/
+void smp_proc_pair_cmd(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 *p = (UINT8 *)p_data;
+ UINT8 reason = SMP_ENC_KEY_SIZE;
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (p_cb->pairing_bda);
+
+ SMP_TRACE_DEBUG("%s\n", __func__);
+ /* erase all keys if it is slave proc pairing req*/
+ if (p_dev_rec && (p_cb->role == HCI_ROLE_SLAVE)) {
+ btm_sec_clear_ble_keys(p_dev_rec);
+ }
+
+ p_cb->flags |= SMP_PAIR_FLAG_ENC_AFTER_PAIR;
+
+ STREAM_TO_UINT8(p_cb->peer_io_caps, p);
+ STREAM_TO_UINT8(p_cb->peer_oob_flag, p);
+ STREAM_TO_UINT8(p_cb->peer_auth_req, p);
+ STREAM_TO_UINT8(p_cb->peer_enc_size, p);
+ STREAM_TO_UINT8(p_cb->peer_i_key, p);
+ STREAM_TO_UINT8(p_cb->peer_r_key, p);
+
+ if (smp_command_has_invalid_parameters(p_cb)) {
+ reason = SMP_INVALID_PARAMETERS;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+ p_cb->accept_specified_sec_auth = bta_dm_co_ble_get_accept_auth_enable();
+ p_cb->origin_loc_auth_req = bta_dm_co_ble_get_auth_req();
+ if (p_cb->role == HCI_ROLE_SLAVE) {
+ if (!(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)) {
+ /* peer (master) started pairing sending Pairing Request */
+ p_cb->local_i_key = p_cb->peer_i_key;
+ p_cb->local_r_key = p_cb->peer_r_key;
+
+ p_cb->cb_evt = SMP_SEC_REQUEST_EVT;
+ } else { /* update local i/r key according to pairing request */
+ /* pairing started with this side (slave) sending Security Request */
+ p_cb->local_i_key &= p_cb->peer_i_key;
+ p_cb->local_r_key &= p_cb->peer_r_key;
+ p_cb->selected_association_model = smp_select_association_model(p_cb);
+
+ if (p_cb->secure_connections_only_mode_required &&
+ (!(p_cb->le_secure_connections_mode_is_used) ||
+ (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS))) {
+ SMP_TRACE_ERROR("%s pairing failed - slave requires secure connection only mode",
+ __func__);
+ reason = SMP_PAIR_AUTH_FAIL;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+ uint16_t auth = smp_get_auth_mode(p_cb->selected_association_model);
+ if(p_cb->peer_auth_req & p_cb->loc_auth_req & SMP_AUTH_GEN_BOND) {
+ auth |= SMP_AUTH_GEN_BOND;
+ }
+ p_cb->auth_mode = auth;
+ if (p_cb->accept_specified_sec_auth) {
+ if ((auth & p_cb->origin_loc_auth_req) != p_cb->origin_loc_auth_req ) {
+ SMP_TRACE_ERROR("%s pairing failed - slave requires auth is 0x%x but peer auth is 0x%x local auth is 0x%x",
+ __func__, p_cb->origin_loc_auth_req, p_cb->peer_auth_req, p_cb->loc_auth_req);
+ if (BTM_IsAclConnectionUp(p_cb->pairing_bda, BT_TRANSPORT_LE)) {
+ btm_remove_acl (p_cb->pairing_bda, BT_TRANSPORT_LE);
+ }
+ reason = SMP_PAIR_AUTH_FAIL;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+ }
+
+ if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_OOB && p_cb->loc_oob_flag == SMP_OOB_PRESENT) {
+ if (smp_request_oob_data(p_cb)) {
+ return;
+ }
+ } else {
+ smp_send_pair_rsp(p_cb, NULL);
+ }
+ }
+ } else { /* Master receives pairing response */
+ p_cb->selected_association_model = smp_select_association_model(p_cb);
+
+ if (p_cb->secure_connections_only_mode_required &&
+ (!(p_cb->le_secure_connections_mode_is_used) ||
+ (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS))) {
+ SMP_TRACE_ERROR ("Master requires secure connection only mode \
+ but it can't be provided -> Master fails pairing");
+ reason = SMP_PAIR_AUTH_FAIL;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ uint16_t auth = smp_get_auth_mode(p_cb->selected_association_model);
+ if(p_cb->peer_auth_req & p_cb->loc_auth_req & SMP_AUTH_GEN_BOND) {
+ auth |= SMP_AUTH_GEN_BOND;
+ }
+ p_cb->auth_mode = auth;
+ if (p_cb->accept_specified_sec_auth) {
+ if ((auth & p_cb->origin_loc_auth_req) != p_cb->origin_loc_auth_req ) {
+ SMP_TRACE_ERROR("%s pairing failed - master requires auth is 0x%x but peer auth is 0x%x local auth is 0x%x",
+ __func__, p_cb->origin_loc_auth_req, p_cb->peer_auth_req, p_cb->loc_auth_req);
+ if (BTM_IsAclConnectionUp(p_cb->pairing_bda, BT_TRANSPORT_LE)) {
+ btm_remove_acl (p_cb->pairing_bda, BT_TRANSPORT_LE);
+ }
+ reason = SMP_PAIR_AUTH_FAIL;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+ }
+
+ /* Only if peer oob data present, then should request peer oob data */
+ if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_OOB && p_cb->loc_oob_flag == SMP_OOB_PRESENT) {
+ if (smp_request_oob_data(p_cb)) {
+ return;
+ }
+ } else {
+ smp_decide_association_model(p_cb, NULL);
+ }
+ }
+}
+#endif ///BLE_INCLUDED == TRUE
+
+/*******************************************************************************
+** Function smp_proc_confirm
+** Description process pairing confirm from peer device
+*******************************************************************************/
+void smp_proc_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 *p = (UINT8 *)p_data;
+ UINT8 reason = SMP_INVALID_PARAMETERS;
+
+ SMP_TRACE_DEBUG("%s\n", __func__);
+
+ if (smp_command_has_invalid_parameters(p_cb)) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ if (p != NULL) {
+ /* save the SConfirm for comparison later */
+ STREAM_TO_ARRAY(p_cb->rconfirm, p, BT_OCTET16_LEN);
+ }
+
+ p_cb->flags |= SMP_PAIR_FLAGS_CMD_CONFIRM;
+}
+
+#if 0 //Unused
+/*******************************************************************************
+** Function smp_proc_init
+** Description process pairing initializer from peer device
+*******************************************************************************/
+void smp_proc_init(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 *p = (UINT8 *)p_data;
+ UINT8 reason = SMP_INVALID_PARAMETERS;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ if (smp_command_has_invalid_parameters(p_cb)) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ /* save the SRand for comparison */
+ STREAM_TO_ARRAY(p_cb->rrand, p, BT_OCTET16_LEN);
+}
+#endif
+
+/*******************************************************************************
+** Function smp_proc_rand
+** Description process pairing random (nonce) from peer device
+*******************************************************************************/
+void smp_proc_rand(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 *p = (UINT8 *)p_data;
+ UINT8 reason = SMP_INVALID_PARAMETERS;
+
+ SMP_TRACE_DEBUG("%s\n", __func__);
+
+ if (smp_command_has_invalid_parameters(p_cb)) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ /* save the SRand for comparison */
+ STREAM_TO_ARRAY(p_cb->rrand, p, BT_OCTET16_LEN);
+}
+
+/*******************************************************************************
+** Function smp_process_pairing_public_key
+** Description process pairing public key command from the peer device
+** - saves the peer public key;
+** - sets the flag indicating that the peer public key is received;
+** - calls smp_wait_for_both_public_keys(...).
+**
+*******************************************************************************/
+void smp_process_pairing_public_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 *p = (UINT8 *)p_data;
+ UINT8 reason = SMP_INVALID_PARAMETERS;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ if (smp_command_has_invalid_parameters(p_cb)) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ STREAM_TO_ARRAY(p_cb->peer_publ_key.x, p, BT_OCTET32_LEN);
+ STREAM_TO_ARRAY(p_cb->peer_publ_key.y, p, BT_OCTET32_LEN);
+
+ /* Check if the peer device's and own public key are not same. If they are same then
+ * return pairing fail. This check is needed to avoid 'Impersonation in Passkey entry
+ * protocol' vulnerability (CVE-2020-26558).*/
+ if ((memcmp(p_cb->loc_publ_key.x, p_cb->peer_publ_key.x, sizeof(BT_OCTET32)) == 0)) {
+ p_cb->status = SMP_PAIR_AUTH_FAIL;
+ p_cb->failure = SMP_PAIR_AUTH_FAIL;
+ reason = SMP_PAIR_AUTH_FAIL;
+ SMP_TRACE_ERROR("%s, Peer and own device cannot have same public key.", __func__);
+ smp_sm_event(p_cb, SMP_PAIRING_FAILED_EVT, &reason);
+ return ;
+ }
+ /* In order to prevent the x and y coordinates of the public key from being modified,
+ we need to check whether the x and y coordinates are on the given elliptic curve. */
+ if (!ECC_CheckPointIsInElliCur_P256((Point *)&p_cb->peer_publ_key)) {
+ SMP_TRACE_ERROR("%s, Invalid Public key.", __func__);
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ }
+ p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY;
+
+ smp_wait_for_both_public_keys(p_cb, NULL);
+}
+
+/*******************************************************************************
+** Function smp_process_pairing_commitment
+** Description process pairing commitment from peer device
+*******************************************************************************/
+void smp_process_pairing_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 *p = (UINT8 *)p_data;
+ UINT8 reason = SMP_INVALID_PARAMETERS;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ if (smp_command_has_invalid_parameters(p_cb)) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_COMM;
+
+ if (p != NULL) {
+ STREAM_TO_ARRAY(p_cb->remote_commitment, p, BT_OCTET16_LEN);
+ }
+}
+
+/*******************************************************************************
+** Function smp_process_dhkey_check
+** Description process DHKey Check from peer device
+*******************************************************************************/
+void smp_process_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 *p = (UINT8 *)p_data;
+ UINT8 reason = SMP_INVALID_PARAMETERS;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ if (smp_command_has_invalid_parameters(p_cb)) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ if (p != NULL) {
+ STREAM_TO_ARRAY(p_cb->remote_dhkey_check, p, BT_OCTET16_LEN);
+ }
+
+ p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_DHK_CHK;
+}
+
+/*******************************************************************************
+** Function smp_process_keypress_notification
+** Description process pairing keypress notification from peer device
+*******************************************************************************/
+void smp_process_keypress_notification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 *p = (UINT8 *)p_data;
+ UINT8 reason = SMP_INVALID_PARAMETERS;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ p_cb->status = *(UINT8 *)p_data;
+
+ if (smp_command_has_invalid_parameters(p_cb)) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ if (p != NULL) {
+ STREAM_TO_UINT8(p_cb->peer_keypress_notification, p);
+ } else {
+ p_cb->peer_keypress_notification = BTM_SP_KEY_OUT_OF_RANGE;
+ }
+ p_cb->cb_evt = SMP_PEER_KEYPR_NOT_EVT;
+}
+
+#if (CLASSIC_BT_INCLUDED == TRUE)
+/*******************************************************************************
+** Function smp_br_process_pairing_command
+** Description Process the SMP pairing request/response from peer device via
+** BR/EDR transport.
+*******************************************************************************/
+void smp_br_process_pairing_command(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 *p = (UINT8 *)p_data;
+ UINT8 reason = SMP_ENC_KEY_SIZE;
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (p_cb->pairing_bda);
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ /* rejecting BR pairing request over non-SC BR link */
+ if (!p_dev_rec->new_encryption_key_is_p256 && p_cb->role == HCI_ROLE_SLAVE) {
+ reason = SMP_XTRANS_DERIVE_NOT_ALLOW;
+ smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+#if (BLE_INCLUDED == TRUE)
+ /* erase all keys if it is slave proc pairing req*/
+ if (p_dev_rec && (p_cb->role == HCI_ROLE_SLAVE)) {
+ btm_sec_clear_ble_keys(p_dev_rec);
+ }
+#endif ///BLE_INCLUDED == TRUE
+
+ p_cb->flags |= SMP_PAIR_FLAG_ENC_AFTER_PAIR;
+
+ STREAM_TO_UINT8(p_cb->peer_io_caps, p);
+ STREAM_TO_UINT8(p_cb->peer_oob_flag, p);
+ STREAM_TO_UINT8(p_cb->peer_auth_req, p);
+ STREAM_TO_UINT8(p_cb->peer_enc_size, p);
+ STREAM_TO_UINT8(p_cb->peer_i_key, p);
+ STREAM_TO_UINT8(p_cb->peer_r_key, p);
+
+ if (smp_command_has_invalid_parameters(p_cb)) {
+ reason = SMP_INVALID_PARAMETERS;
+ smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ /* peer (master) started pairing sending Pairing Request */
+ /* or being master device always use received i/r key as keys to distribute */
+ p_cb->local_i_key = p_cb->peer_i_key;
+ p_cb->local_r_key = p_cb->peer_r_key;
+
+ if (p_cb->role == HCI_ROLE_SLAVE) {
+ p_dev_rec->new_encryption_key_is_p256 = FALSE;
+ /* shortcut to skip Security Grant step */
+ p_cb->cb_evt = SMP_BR_KEYS_REQ_EVT;
+ } else { /* Master receives pairing response */
+ SMP_TRACE_DEBUG("%s master rcvs valid PAIRING RESPONSE."
+ " Supposed to move to key distribution phase. ", __func__);
+ }
+
+ /* auth_req received via BR/EDR SM channel is set to 0,
+ but everything derived/exchanged has to be saved */
+ p_cb->peer_auth_req |= SMP_AUTH_BOND;
+ p_cb->loc_auth_req |= SMP_AUTH_BOND;
+}
+
+/*******************************************************************************
+** Function smp_br_process_security_grant
+** Description process security grant in case of pairing over BR/EDR transport.
+*******************************************************************************/
+void smp_br_process_security_grant(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 res = *(UINT8 *)p_data;
+ SMP_TRACE_DEBUG("%s", __func__);
+ if (res != SMP_SUCCESS) {
+ smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, p_data);
+ } else { /*otherwise, start pairing */
+ /* send IO request callback */
+ p_cb->cb_evt = SMP_BR_KEYS_REQ_EVT;
+ }
+}
+
+/*******************************************************************************
+** Function smp_br_check_authorization_request
+** Description sets the SMP kes to be derived/distribute over BR/EDR transport
+** before starting the distribution/derivation
+*******************************************************************************/
+void smp_br_check_authorization_request(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 reason = SMP_SUCCESS;
+
+ SMP_TRACE_DEBUG("%s rcvs i_keys=0x%x r_keys=0x%x "
+ "(i-initiator r-responder)", __FUNCTION__, p_cb->local_i_key,
+ p_cb->local_r_key);
+
+ /* In LE SC mode LK field is ignored when BR/EDR transport is used */
+ p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK;
+ p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK;
+
+ /* In LE SC mode only IRK, IAI, CSRK are exchanged with the peer.
+ ** Set local_r_key on master to expect only these keys. */
+ if (p_cb->role == HCI_ROLE_MASTER) {
+ p_cb->local_r_key &= (SMP_SEC_KEY_TYPE_ID | SMP_SEC_KEY_TYPE_CSRK);
+ }
+
+ SMP_TRACE_DEBUG("%s rcvs upgrades: i_keys=0x%x r_keys=0x%x "
+ "(i-initiator r-responder)", __FUNCTION__, p_cb->local_i_key,
+ p_cb->local_r_key);
+
+ if (/*((p_cb->peer_auth_req & SMP_AUTH_BOND) ||
+ (p_cb->loc_auth_req & SMP_AUTH_BOND)) &&*/
+ (p_cb->local_i_key || p_cb->local_r_key)) {
+ smp_br_state_machine_event(p_cb, SMP_BR_BOND_REQ_EVT, NULL);
+
+ /* if no peer key is expected, start master key distribution */
+ if (p_cb->role == HCI_ROLE_MASTER && p_cb->local_r_key == 0) {
+ smp_key_distribution_by_transport(p_cb, NULL);
+ }
+ } else {
+ smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason);
+ }
+}
+
+/*******************************************************************************
+** Function smp_br_select_next_key
+** Description selects the next key to derive/send when BR/EDR transport is
+** used.
+*******************************************************************************/
+void smp_br_select_next_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 reason = SMP_SUCCESS;
+ SMP_TRACE_DEBUG("%s role=%d (0-master) r_keys=0x%x i_keys=0x%x",
+ __func__, p_cb->role, p_cb->local_r_key, p_cb->local_i_key);
+
+ if (p_cb->role == HCI_ROLE_SLAVE ||
+ (!p_cb->local_r_key && p_cb->role == HCI_ROLE_MASTER)) {
+ smp_key_pick_key(p_cb, p_data);
+ }
+
+ if (!p_cb->local_i_key && !p_cb->local_r_key) {
+ /* state check to prevent re-entrance */
+ if (smp_get_br_state() == SMP_BR_STATE_BOND_PENDING) {
+ if (p_cb->total_tx_unacked == 0) {
+ smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason);
+ } else {
+ p_cb->wait_for_authorization_complete = TRUE;
+ }
+ }
+ }
+}
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+** Function smp_proc_enc_info
+** Description process encryption information from peer device
+*******************************************************************************/
+void smp_proc_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 *p = (UINT8 *)p_data;
+
+ SMP_TRACE_DEBUG("%s\n", __func__);
+ STREAM_TO_ARRAY(p_cb->ltk, p, BT_OCTET16_LEN);
+
+ smp_key_distribution(p_cb, NULL);
+}
+#endif ///BLE_INCLUDED == TRUE
+
+/*******************************************************************************
+** Function smp_proc_master_id
+** Description process master ID from slave device
+*******************************************************************************/
+void smp_proc_master_id(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 *p = (UINT8 *)p_data;
+ tBTM_LE_PENC_KEYS le_key;
+
+ SMP_TRACE_DEBUG("%s\np_cb->peer_auth_req = %d,p_cb->loc_auth_req= %d\n", __func__,
+ p_cb->peer_auth_req, p_cb->loc_auth_req);
+ smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ENC, TRUE);
+
+ STREAM_TO_UINT16(le_key.ediv, p);
+ STREAM_TO_ARRAY(le_key.rand, p, BT_OCTET8_LEN );
+
+ /* store the encryption keys from peer device */
+ memcpy(le_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
+ le_key.sec_level = p_cb->sec_level;
+ le_key.key_size = p_cb->loc_enc_size;
+
+#if (BLE_INCLUDED == TRUE)
+ if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND)) {
+ btm_sec_save_le_key(p_cb->pairing_bda,
+ BTM_LE_KEY_PENC,
+ (tBTM_LE_KEY_VALUE *)&le_key, TRUE);
+ }
+
+ smp_key_distribution(p_cb, NULL);
+#endif ///BLE_INCLUDED == TRUE
+}
+
+/*******************************************************************************
+** Function smp_proc_enc_info
+** Description process identity information from peer device
+*******************************************************************************/
+void smp_proc_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 *p = (UINT8 *)p_data;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ STREAM_TO_ARRAY (p_cb->tk, p, BT_OCTET16_LEN); /* reuse TK for IRK */
+ smp_key_distribution_by_transport(p_cb, NULL);
+}
+
+/*******************************************************************************
+** Function smp_proc_id_addr
+** Description process identity address from peer device
+*******************************************************************************/
+void smp_proc_id_addr(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 *p = (UINT8 *)p_data;
+ tBTM_LE_PID_KEYS pid_key;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ID, TRUE);
+
+ STREAM_TO_UINT8(pid_key.addr_type, p);
+ STREAM_TO_BDADDR(pid_key.static_addr, p);
+ memcpy(pid_key.irk, p_cb->tk, BT_OCTET16_LEN);
+
+ /* to use as BD_ADDR for lk derived from ltk */
+ p_cb->id_addr_rcvd = TRUE;
+ p_cb->id_addr_type = pid_key.addr_type;
+ memcpy(p_cb->id_addr, pid_key.static_addr, BD_ADDR_LEN);
+
+#if (BLE_INCLUDED == TRUE)
+ /* store the ID key from peer device */
+ if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND)) {
+ btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PID,
+ (tBTM_LE_KEY_VALUE *)&pid_key, TRUE);
+ }
+#endif ///BLE_INCLUDED == TRUE
+
+ smp_key_distribution_by_transport(p_cb, NULL);
+}
+
+/*******************************************************************************
+** Function smp_proc_srk_info
+** Description process security information from peer device
+*******************************************************************************/
+void smp_proc_srk_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+#if (BLE_INCLUDED == TRUE)
+ tBTM_LE_PCSRK_KEYS le_key;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_CSRK, TRUE);
+
+ /* save CSRK to security record */
+ le_key.sec_level = p_cb->sec_level;
+ memcpy (le_key.csrk, p_data, BT_OCTET16_LEN); /* get peer CSRK */
+ le_key.counter = 0; /* initialize the peer counter */
+
+ if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND)) {
+ btm_sec_save_le_key(p_cb->pairing_bda,
+ BTM_LE_KEY_PCSRK,
+ (tBTM_LE_KEY_VALUE *)&le_key, TRUE);
+ }
+
+#endif ///BLE_INCLUDED == TRUE
+ smp_key_distribution_by_transport(p_cb, NULL);
+}
+
+/*******************************************************************************
+** Function smp_proc_compare
+** Description process compare value
+*******************************************************************************/
+void smp_proc_compare(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 reason;
+
+ SMP_TRACE_DEBUG("%s\n", __func__);
+ if (!memcmp(p_cb->rconfirm, p_data->key.p_data, BT_OCTET16_LEN)) {
+ /* compare the max encryption key size, and save the smaller one for the link */
+ if ( p_cb->peer_enc_size < p_cb->loc_enc_size) {
+ p_cb->loc_enc_size = p_cb->peer_enc_size;
+ }
+
+ if (p_cb->role == HCI_ROLE_SLAVE) {
+ smp_sm_event(p_cb, SMP_RAND_EVT, NULL);
+ } else {
+ /* master device always use received i/r key as keys to distribute */
+ p_cb->local_i_key = p_cb->peer_i_key;
+ p_cb->local_r_key = p_cb->peer_r_key;
+
+ smp_sm_event(p_cb, SMP_ENC_REQ_EVT, NULL);
+ }
+
+ } else {
+ reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ }
+}
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+** Function smp_proc_sl_key
+** Description process key ready events.
+*******************************************************************************/
+void smp_proc_sl_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 key_type = p_data->key.key_type;
+
+ SMP_TRACE_DEBUG("%s\n", __func__);
+ if (key_type == SMP_KEY_TYPE_TK) {
+ smp_generate_srand_mrand_confirm(p_cb, NULL);
+ } else if (key_type == SMP_KEY_TYPE_CFM) {
+ smp_set_state(SMP_STATE_WAIT_CONFIRM);
+
+ if (p_cb->flags & SMP_PAIR_FLAGS_CMD_CONFIRM) {
+ smp_sm_event(p_cb, SMP_CONFIRM_EVT, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+** Function smp_start_enc
+** Description start encryption
+*******************************************************************************/
+void smp_start_enc(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ tBTM_STATUS cmd;
+ UINT8 reason = SMP_ENC_FAIL;
+
+ SMP_TRACE_DEBUG("%s\n", __func__);
+ if (p_data != NULL) {
+ cmd = btm_ble_start_encrypt(p_cb->pairing_bda, TRUE, p_data->key.p_data);
+ } else {
+ cmd = btm_ble_start_encrypt(p_cb->pairing_bda, FALSE, NULL);
+ }
+
+ if (cmd != BTM_CMD_STARTED && cmd != BTM_BUSY) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ }
+}
+#endif ///BLE_INCLUDED == TRUE
+
+/*******************************************************************************
+** Function smp_proc_discard
+** Description processing for discard security request
+*******************************************************************************/
+void smp_proc_discard(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG("%s\n", __func__);
+ if (!(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)) {
+ smp_reset_control_value(p_cb);
+ }
+}
+
+/*******************************************************************************
+** Function smp_enc_cmpl
+** Description encryption success
+*******************************************************************************/
+void smp_enc_cmpl(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 enc_enable = *(UINT8 *)p_data;
+ UINT8 reason = enc_enable ? SMP_SUCCESS : SMP_ENC_FAIL;
+
+ SMP_TRACE_DEBUG("%s\n", __func__);
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+}
+
+/*******************************************************************************
+** Function smp_check_auth_req
+** Description check authentication request
+*******************************************************************************/
+void smp_check_auth_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 enc_enable = *(UINT8 *)p_data;
+ UINT8 reason = enc_enable ? SMP_SUCCESS : SMP_ENC_FAIL;
+
+ SMP_TRACE_DEBUG("%s rcvs enc_enable=%d i_keys=0x%x r_keys=0x%x "
+ "(i-initiator r-responder)\n",
+ __func__, enc_enable, p_cb->local_i_key, p_cb->local_r_key);
+ if (enc_enable == 1) {
+ if (p_cb->le_secure_connections_mode_is_used) {
+ /* In LE SC mode LTK is used instead of STK and has to be always saved */
+ p_cb->local_i_key |= SMP_SEC_KEY_TYPE_ENC;
+ p_cb->local_r_key |= SMP_SEC_KEY_TYPE_ENC;
+
+ /* In LE SC mode LK is derived from LTK only if both sides request it */
+ if (!(p_cb->local_i_key & SMP_SEC_KEY_TYPE_LK) ||
+ !(p_cb->local_r_key & SMP_SEC_KEY_TYPE_LK)) {
+ p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK;
+ p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK;
+ }
+
+ /* In LE SC mode only IRK, IAI, CSRK are exchanged with the peer.
+ ** Set local_r_key on master to expect only these keys.
+ */
+ if (p_cb->role == HCI_ROLE_MASTER) {
+ p_cb->local_r_key &= (SMP_SEC_KEY_TYPE_ID | SMP_SEC_KEY_TYPE_CSRK);
+ }
+ } else {
+ /* in legacy mode derivation of BR/EDR LK is not supported */
+ p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK;
+ p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK;
+ }
+ SMP_TRACE_DEBUG("%s rcvs upgrades: i_keys=0x%x r_keys=0x%x "
+ "(i-initiator r-responder)\n",
+ __func__, p_cb->local_i_key, p_cb->local_r_key);
+
+ if (/*((p_cb->peer_auth_req & SMP_AUTH_BOND) ||
+ (p_cb->loc_auth_req & SMP_AUTH_BOND)) &&*/
+ (p_cb->local_i_key || p_cb->local_r_key)) {
+ smp_sm_event(p_cb, SMP_BOND_REQ_EVT, NULL);
+ } else {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ }
+ } else if (enc_enable == 0) {
+ /* if failed for encryption after pairing, send callback */
+ if (p_cb->flags & SMP_PAIR_FLAG_ENC_AFTER_PAIR) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ }
+ /* if enc failed for old security information */
+ /* if master device, clean up and abck to idle; slave device do nothing */
+ else if (p_cb->role == HCI_ROLE_MASTER) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ }
+ }
+}
+
+/*******************************************************************************
+** Function smp_key_pick_key
+** Description Pick a key distribution function based on the key mask.
+*******************************************************************************/
+void smp_key_pick_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 key_to_dist = (p_cb->role == HCI_ROLE_SLAVE) ? p_cb->local_r_key : p_cb->local_i_key;
+ UINT8 i = 0;
+
+ SMP_TRACE_DEBUG("%s key_to_dist=0x%x\n", __func__, key_to_dist);
+ while (i < SMP_KEY_DIST_TYPE_MAX) {
+ SMP_TRACE_DEBUG("key to send = %02x, i = %d\n", key_to_dist, i);
+
+ if (key_to_dist & (1 << i) && smp_distribute_act[i] != NULL) {
+ SMP_TRACE_DEBUG("smp_distribute_act[%d]\n", i);
+ (* smp_distribute_act[i])(p_cb, p_data);
+ break;
+ }
+ i ++;
+ }
+}
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+** Function smp_key_distribution
+** Description start key distribution if required.
+*******************************************************************************/
+void smp_key_distribution(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 reason = SMP_SUCCESS;
+ SMP_TRACE_DEBUG("\n%s role=%d (0-master) r_keys=0x%x i_keys=0x%x\n",
+ __func__, p_cb->role, p_cb->local_r_key, p_cb->local_i_key);
+
+ if (p_cb->role == HCI_ROLE_SLAVE ||
+ (!p_cb->local_r_key && p_cb->role == HCI_ROLE_MASTER)) {
+ smp_key_pick_key(p_cb, p_data);
+ }
+
+ if (!p_cb->local_i_key && !p_cb->local_r_key) {
+ /* state check to prevent re-entrant */
+ if (smp_get_state() == SMP_STATE_BOND_PENDING) {
+ if (p_cb->derive_lk) {
+ smp_derive_link_key_from_long_term_key(p_cb, NULL);
+ p_cb->derive_lk = FALSE;
+ }
+
+ if (p_cb->total_tx_unacked == 0) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ } else {
+ p_cb->wait_for_authorization_complete = TRUE;
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+** Function smp_decide_association_model
+** Description This function is called to select assoc model to be used for
+** STK generation and to start STK generation process.
+**
+*******************************************************************************/
+void smp_decide_association_model(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 failure = SMP_UNKNOWN_IO_CAP;
+ UINT8 int_evt = 0;
+ tSMP_KEY key;
+ tSMP_INT_DATA *p = NULL;
+
+ SMP_TRACE_DEBUG("%s Association Model = %d\n", __func__, p_cb->selected_association_model);
+
+ switch (p_cb->selected_association_model) {
+ case SMP_MODEL_ENCRYPTION_ONLY: /* TK = 0, go calculate Confirm */
+ p_cb->sec_level = SMP_SEC_UNAUTHENTICATE;
+ SMP_TRACE_EVENT ("p_cb->sec_level =%d (SMP_SEC_UNAUTHENTICATE) \n", p_cb->sec_level );
+
+ key.key_type = SMP_KEY_TYPE_TK;
+ key.p_data = p_cb->tk;
+ p = (tSMP_INT_DATA *)&key;
+
+ memset(p_cb->tk, 0, BT_OCTET16_LEN);
+ /* TK, ready */
+ int_evt = SMP_KEY_READY_EVT;
+ break;
+
+ case SMP_MODEL_PASSKEY:
+ p_cb->sec_level = SMP_SEC_AUTHENTICATED;
+ SMP_TRACE_EVENT ("p_cb->sec_level =%d (SMP_SEC_AUTHENTICATED) \n", p_cb->sec_level );
+
+ p_cb->cb_evt = SMP_PASSKEY_REQ_EVT;
+ int_evt = SMP_TK_REQ_EVT;
+ break;
+
+ case SMP_MODEL_OOB:
+ SMP_TRACE_ERROR ("Association Model = SMP_MODEL_OOB\n");
+ p_cb->sec_level = SMP_SEC_AUTHENTICATED;
+ SMP_TRACE_EVENT ("p_cb->sec_level =%d (SMP_SEC_AUTHENTICATED) \n", p_cb->sec_level );
+
+ p_cb->cb_evt = SMP_OOB_REQ_EVT;
+ int_evt = SMP_TK_REQ_EVT;
+ break;
+
+ case SMP_MODEL_KEY_NOTIF:
+ p_cb->sec_level = SMP_SEC_AUTHENTICATED;
+ SMP_TRACE_DEBUG("Need to generate Passkey\n");
+
+ /* generate passkey and notify application */
+ smp_generate_passkey(p_cb, NULL);
+ break;
+
+ case SMP_MODEL_SEC_CONN_JUSTWORKS:
+ case SMP_MODEL_SEC_CONN_NUM_COMP:
+ case SMP_MODEL_SEC_CONN_PASSKEY_ENT:
+ case SMP_MODEL_SEC_CONN_PASSKEY_DISP:
+ case SMP_MODEL_SEC_CONN_OOB:
+ int_evt = SMP_PUBL_KEY_EXCH_REQ_EVT;
+ break;
+
+ case SMP_MODEL_OUT_OF_RANGE:
+ SMP_TRACE_ERROR("Association Model = SMP_MODEL_OUT_OF_RANGE (failed)\n");
+ p = (tSMP_INT_DATA *)&failure;
+ int_evt = SMP_AUTH_CMPL_EVT;
+ break;
+
+ default:
+ SMP_TRACE_ERROR("Association Model = %d (SOMETHING IS WRONG WITH THE CODE)\n",
+ p_cb->selected_association_model);
+ p = (tSMP_INT_DATA *)&failure;
+ int_evt = SMP_AUTH_CMPL_EVT;
+ }
+
+ SMP_TRACE_EVENT ("sec_level=%d \n", p_cb->sec_level );
+ if (int_evt) {
+ smp_sm_event(p_cb, int_evt, p);
+ }
+}
+
+/*******************************************************************************
+** Function smp_process_io_response
+** Description process IO response for a slave device.
+*******************************************************************************/
+void smp_process_io_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ uint8_t reason = SMP_PAIR_AUTH_FAIL;
+ SMP_TRACE_DEBUG("%s\n", __func__);
+ if (p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD) {
+ /* pairing started by local (slave) Security Request */
+ smp_set_state(SMP_STATE_SEC_REQ_PENDING);
+ smp_send_cmd(SMP_OPCODE_SEC_REQ, p_cb);
+ } else { /* plan to send pairing respond */
+ /* pairing started by peer (master) Pairing Request */
+ p_cb->selected_association_model = smp_select_association_model(p_cb);
+
+ if (p_cb->secure_connections_only_mode_required &&
+ (!(p_cb->le_secure_connections_mode_is_used) ||
+ (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS))) {
+ SMP_TRACE_ERROR ("Slave requires secure connection only mode \
+ but it can't be provided -> Slave fails pairing\n");
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+ uint16_t auth = smp_get_auth_mode(p_cb->selected_association_model);
+ if(p_cb->peer_auth_req & p_cb->loc_auth_req & SMP_AUTH_GEN_BOND) {
+ auth |= SMP_AUTH_GEN_BOND;
+ }
+ p_cb->auth_mode = auth;
+ if (p_cb->accept_specified_sec_auth) {
+ if ((auth & p_cb->origin_loc_auth_req) != p_cb->origin_loc_auth_req ) {
+ SMP_TRACE_ERROR("pairing failed - slave requires auth is 0x%x but peer auth is 0x%x local auth is 0x%x",
+ p_cb->origin_loc_auth_req, p_cb->peer_auth_req, p_cb->loc_auth_req);
+ if (BTM_IsAclConnectionUp(p_cb->pairing_bda, BT_TRANSPORT_LE)) {
+ btm_remove_acl (p_cb->pairing_bda, BT_TRANSPORT_LE);
+ }
+ reason = SMP_PAIR_AUTH_FAIL;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+ }
+
+ if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_OOB && p_cb->loc_oob_flag == SMP_OOB_PRESENT) {
+ if (smp_request_oob_data(p_cb)) {
+ return;
+ }
+ }
+ smp_send_pair_rsp(p_cb, NULL);
+ }
+}
+#endif ///BLE_INCLUDED == TRUE
+
+/*******************************************************************************
+** Function smp_br_process_slave_keys_response
+** Description process application keys response for a slave device
+** (BR/EDR transport).
+*******************************************************************************/
+void smp_br_process_slave_keys_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ smp_br_send_pair_response(p_cb, NULL);
+}
+
+/*******************************************************************************
+** Function smp_br_send_pair_response
+** Description actions related to sending pairing response over BR/EDR transport.
+*******************************************************************************/
+void smp_br_send_pair_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG("%s\n", __func__);
+
+ p_cb->local_i_key &= p_cb->peer_i_key;
+ p_cb->local_r_key &= p_cb->peer_r_key;
+
+ smp_send_cmd (SMP_OPCODE_PAIRING_RSP, p_cb);
+}
+
+/*******************************************************************************
+** Function smp_pairing_cmpl
+** Description This function is called to send the pairing complete callback
+** and remove the connection if needed.
+*******************************************************************************/
+void smp_pairing_cmpl(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ if (p_cb->total_tx_unacked == 0) {
+ /* process the pairing complete */
+ smp_proc_pairing_cmpl(p_cb);
+ }
+}
+
+/*******************************************************************************
+** Function smp_pair_terminate
+** Description This function is called to send the pairing complete callback
+** and remove the connection if needed.
+*******************************************************************************/
+void smp_pair_terminate(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG("%s\n", __func__);
+ p_cb->status = SMP_CONN_TOUT;
+ smp_proc_pairing_cmpl(p_cb);
+}
+
+/*******************************************************************************
+** Function smp_idle_terminate
+** Description This function calledin idle state to determine to send authentication
+** complete or not.
+*******************************************************************************/
+void smp_idle_terminate(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ if (p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD) {
+ SMP_TRACE_DEBUG("Pairing terminated at IDLE state.\n");
+ p_cb->status = SMP_FAIL;
+ smp_proc_pairing_cmpl(p_cb);
+ }
+}
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+** Function smp_fast_conn_param
+** Description apply default connection parameter for pairing process
+*******************************************************************************/
+void smp_fast_conn_param(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ if(p_cb->role == BTM_ROLE_MASTER) {
+#if (BT_MULTI_CONNECTION_ENBALE == FALSE)
+ L2CA_EnableUpdateBleConnParams(p_cb->pairing_bda, FALSE);
+#endif
+ } else {
+#if (SMP_SLAVE_CON_PARAMS_UPD_ENABLE == TRUE)
+ tBTM_SEC_DEV_REC *p_rec = btm_find_dev (p_cb->pairing_bda);
+ if(p_rec && p_rec->ble.skip_update_conn_param) {
+ //do nothing
+ return;
+ }
+ /* Disable L2CAP connection parameter updates while bonding since
+ some peripherals are not able to revert to fast connection parameters
+ during the start of service discovery. Connection paramter updates
+ get enabled again once service discovery completes. */
+ #if (BT_MULTI_CONNECTION_ENBALE == FALSE)
+ L2CA_EnableUpdateBleConnParams(p_cb->pairing_bda, FALSE);
+ #endif
+#endif
+ }
+}
+
+/*******************************************************************************
+** Function smp_both_have_public_keys
+** Description The function is called when both local and peer public keys are
+** saved.
+** Actions:
+** - invokes DHKey computation;
+** - on slave side invokes sending local public key to the peer.
+** - invokes SC phase 1 process.
+*******************************************************************************/
+void smp_both_have_public_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG("%s\n", __func__);
+
+ /* invokes DHKey computation */
+ smp_compute_dhkey(p_cb);
+
+ /* on slave side invokes sending local public key to the peer */
+ if (p_cb->role == HCI_ROLE_SLAVE) {
+ smp_send_pair_public_key(p_cb, NULL);
+ }
+
+ smp_sm_event(p_cb, SMP_SC_DHKEY_CMPLT_EVT, NULL);
+}
+
+/*******************************************************************************
+** Function smp_start_secure_connection_phase1
+** Description The function starts Secure Connection phase1 i.e. invokes initialization of Secure Connection
+** phase 1 parameters and starts building/sending to the peer
+** messages appropriate for the role and association model.
+*******************************************************************************/
+void smp_start_secure_connection_phase1(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG("%s\n", __func__);
+
+ if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS) {
+ p_cb->sec_level = SMP_SEC_UNAUTHENTICATE;
+ SMP_TRACE_EVENT ("p_cb->sec_level =%d (SMP_SEC_UNAUTHENTICATE)\n ", p_cb->sec_level );
+ } else {
+ p_cb->sec_level = SMP_SEC_AUTHENTICATED;
+ SMP_TRACE_EVENT ("p_cb->sec_level =%d (SMP_SEC_AUTHENTICATED)\n ", p_cb->sec_level );
+ }
+
+ switch (p_cb->selected_association_model) {
+ case SMP_MODEL_SEC_CONN_JUSTWORKS:
+ case SMP_MODEL_SEC_CONN_NUM_COMP:
+ memset(p_cb->local_random, 0, BT_OCTET16_LEN);
+ smp_start_nonce_generation(p_cb);
+ break;
+ case SMP_MODEL_SEC_CONN_PASSKEY_ENT:
+ /* user has to provide passkey */
+ p_cb->cb_evt = SMP_PASSKEY_REQ_EVT;
+ smp_sm_event(p_cb, SMP_TK_REQ_EVT, NULL);
+ break;
+ case SMP_MODEL_SEC_CONN_PASSKEY_DISP:
+ /* passkey has to be provided to user */
+ SMP_TRACE_DEBUG("Need to generate SC Passkey\n");
+ smp_generate_passkey(p_cb, NULL);
+ break;
+ case SMP_MODEL_SEC_CONN_OOB:
+ /* use the available OOB information */
+ smp_process_secure_connection_oob_data(p_cb, NULL);
+ break;
+ default:
+ SMP_TRACE_ERROR ("Association Model = %d is not used in LE SC\n",
+ p_cb->selected_association_model);
+ break;
+ }
+}
+
+/*******************************************************************************
+** Function smp_process_local_nonce
+** Description The function processes new local nonce.
+**
+** Note It is supposed to be called in SC phase1.
+*******************************************************************************/
+void smp_process_local_nonce(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG("%s\n", __func__);
+
+ switch (p_cb->selected_association_model) {
+ case SMP_MODEL_SEC_CONN_JUSTWORKS:
+ case SMP_MODEL_SEC_CONN_NUM_COMP:
+ if (p_cb->role == HCI_ROLE_SLAVE) {
+ /* slave calculates and sends local commitment */
+ smp_calculate_local_commitment(p_cb);
+ smp_send_commitment(p_cb, NULL);
+ /* slave has to wait for peer nonce */
+ smp_set_state(SMP_STATE_WAIT_NONCE);
+ } else { /* i.e. master */
+ if (p_cb->flags & SMP_PAIR_FLAG_HAVE_PEER_COMM) {
+ /* slave commitment is already received, send local nonce, wait for remote nonce*/
+ SMP_TRACE_DEBUG("master in assoc mode = %d \
+ already rcvd slave commitment - race condition\n",
+ p_cb->selected_association_model);
+ p_cb->flags &= ~SMP_PAIR_FLAG_HAVE_PEER_COMM;
+ smp_send_rand(p_cb, NULL);
+ smp_set_state(SMP_STATE_WAIT_NONCE);
+ }
+ }
+ break;
+ case SMP_MODEL_SEC_CONN_PASSKEY_ENT:
+ case SMP_MODEL_SEC_CONN_PASSKEY_DISP:
+ smp_calculate_local_commitment(p_cb);
+
+ if (p_cb->role == HCI_ROLE_MASTER) {
+ smp_send_commitment(p_cb, NULL);
+ } else { /* slave */
+ if (p_cb->flags & SMP_PAIR_FLAG_HAVE_PEER_COMM) {
+ /* master commitment is already received */
+ smp_send_commitment(p_cb, NULL);
+ smp_set_state(SMP_STATE_WAIT_NONCE);
+ }
+ }
+ break;
+ case SMP_MODEL_SEC_CONN_OOB:
+ if (p_cb->role == HCI_ROLE_MASTER) {
+ smp_send_rand(p_cb, NULL);
+ }
+
+ smp_set_state(SMP_STATE_WAIT_NONCE);
+ break;
+ default:
+ SMP_TRACE_ERROR ("Association Model = %d is not used in LE SC\n",
+ p_cb->selected_association_model);
+ break;
+ }
+}
+
+/*******************************************************************************
+** Function smp_process_peer_nonce
+** Description The function processes newly received and saved in CB peer nonce.
+** The actions depend on the selected association model and the role.
+**
+** Note It is supposed to be called in SC phase1.
+*******************************************************************************/
+void smp_process_peer_nonce(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 reason;
+
+ SMP_TRACE_DEBUG("%s start \n", __func__);
+
+ switch (p_cb->selected_association_model) {
+ case SMP_MODEL_SEC_CONN_JUSTWORKS:
+ case SMP_MODEL_SEC_CONN_NUM_COMP:
+ /* in these models only master receives commitment */
+ if (p_cb->role == HCI_ROLE_MASTER) {
+ if (!smp_check_commitment(p_cb)) {
+ reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ break;
+ }
+ } else {
+ /* slave sends local nonce */
+ smp_send_rand(p_cb, NULL);
+ }
+
+ if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS) {
+ /* go directly to phase 2 */
+ smp_sm_event(p_cb, SMP_SC_PHASE1_CMPLT_EVT, NULL);
+ } else { /* numeric comparison */
+ smp_set_state(SMP_STATE_WAIT_NONCE);
+ smp_sm_event(p_cb, SMP_SC_CALC_NC_EVT, NULL);
+ }
+ break;
+ case SMP_MODEL_SEC_CONN_PASSKEY_ENT:
+ case SMP_MODEL_SEC_CONN_PASSKEY_DISP:
+ if (!smp_check_commitment(p_cb)) {
+ reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ break;
+ }
+
+ if (p_cb->role == HCI_ROLE_SLAVE) {
+ smp_send_rand(p_cb, NULL);
+ }
+
+ if (++p_cb->round < 20) {
+ smp_set_state(SMP_STATE_SEC_CONN_PHS1_START);
+ p_cb->flags &= ~SMP_PAIR_FLAG_HAVE_PEER_COMM;
+ smp_start_nonce_generation(p_cb);
+ break;
+ }
+
+ smp_sm_event(p_cb, SMP_SC_PHASE1_CMPLT_EVT, NULL);
+ break;
+ case SMP_MODEL_SEC_CONN_OOB:
+ if (p_cb->role == HCI_ROLE_SLAVE) {
+ smp_send_rand(p_cb, NULL);
+ }
+
+ smp_sm_event(p_cb, SMP_SC_PHASE1_CMPLT_EVT, NULL);
+ break;
+ default:
+ SMP_TRACE_ERROR ("Association Model = %d is not used in LE SC\n",
+ p_cb->selected_association_model);
+ break;
+ }
+
+ SMP_TRACE_DEBUG("%s end\n ", __FUNCTION__);
+}
+#endif ///BLE_INCLUDED == TRUE
+
+/*******************************************************************************
+** Function smp_match_dhkey_checks
+** Description checks if the calculated peer DHKey Check value is the same as
+** received from the peer DHKey check value.
+*******************************************************************************/
+void smp_match_dhkey_checks(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 reason = SMP_DHKEY_CHK_FAIL;
+
+ SMP_TRACE_DEBUG("%s\n", __func__);
+
+ if (memcmp(p_data->key.p_data, p_cb->remote_dhkey_check, BT_OCTET16_LEN)) {
+ SMP_TRACE_WARNING ("dhkey checks do no match\n");
+ p_cb->failure = reason;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ SMP_TRACE_EVENT ("dhkey checks match\n");
+
+ /* compare the max encryption key size, and save the smaller one for the link */
+ if (p_cb->peer_enc_size < p_cb->loc_enc_size) {
+ p_cb->loc_enc_size = p_cb->peer_enc_size;
+ }
+
+ if (p_cb->role == HCI_ROLE_SLAVE) {
+ smp_sm_event(p_cb, SMP_PAIR_DHKEY_CHCK_EVT, NULL);
+ } else {
+ /* master device always use received i/r key as keys to distribute */
+ p_cb->local_i_key = p_cb->peer_i_key;
+ p_cb->local_r_key = p_cb->peer_r_key;
+ smp_sm_event(p_cb, SMP_ENC_REQ_EVT, NULL);
+ }
+}
+
+/*******************************************************************************
+** Function smp_move_to_secure_connections_phase2
+** Description Signal State Machine to start SC phase 2 initialization (to
+** compute local DHKey Check value).
+**
+** Note SM is supposed to be in the state SMP_STATE_SEC_CONN_PHS2_START.
+*******************************************************************************/
+void smp_move_to_secure_connections_phase2(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG("%s\n", __func__);
+ smp_sm_event(p_cb, SMP_SC_PHASE1_CMPLT_EVT, NULL);
+}
+
+/*******************************************************************************
+** Function smp_phase_2_dhkey_checks_are_present
+** Description generates event if dhkey check from the peer is already received.
+**
+** Note It is supposed to be used on slave to prevent race condition.
+** It is supposed to be called after slave dhkey check is calculated.
+*******************************************************************************/
+void smp_phase_2_dhkey_checks_are_present(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG("%s\n", __func__);
+
+ if (p_cb->flags & SMP_PAIR_FLAG_HAVE_PEER_DHK_CHK) {
+ smp_sm_event(p_cb, SMP_SC_2_DHCK_CHKS_PRES_EVT, NULL);
+ }
+}
+
+/*******************************************************************************
+** Function smp_wait_for_both_public_keys
+** Description generates SMP_BOTH_PUBL_KEYS_RCVD_EVT event when both local and master
+** public keys are available.
+**
+** Note on the slave it is used to prevent race condition.
+**
+*******************************************************************************/
+void smp_wait_for_both_public_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG("%s\n", __func__);
+
+ if ((p_cb->flags & SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY) &&
+ (p_cb->flags & SMP_PAIR_FLAG_HAVE_LOCAL_PUBL_KEY)) {
+ if ((p_cb->role == HCI_ROLE_SLAVE) &&
+ ((p_cb->req_oob_type == SMP_OOB_LOCAL) || (p_cb->req_oob_type == SMP_OOB_BOTH))) {
+ smp_set_state(SMP_STATE_PUBLIC_KEY_EXCH);
+ }
+ smp_sm_event(p_cb, SMP_BOTH_PUBL_KEYS_RCVD_EVT, NULL);
+ }
+}
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+** Function smp_start_passkey_verification
+** Description Starts SC passkey entry verification.
+*******************************************************************************/
+void smp_start_passkey_verification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 *p = NULL;
+
+ SMP_TRACE_DEBUG("%s\n", __func__);
+ p = p_cb->local_random;
+ UINT32_TO_STREAM(p, p_data->passkey);
+
+ p = p_cb->peer_random;
+ UINT32_TO_STREAM(p, p_data->passkey);
+
+ p_cb->round = 0;
+ smp_start_nonce_generation(p_cb);
+}
+
+/*******************************************************************************
+** Function smp_process_secure_connection_oob_data
+** Description Processes local/peer SC OOB data received from somewhere.
+*******************************************************************************/
+void smp_process_secure_connection_oob_data(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG("%s\n", __func__);
+
+ tSMP_SC_OOB_DATA *p_sc_oob_data = &p_cb->sc_oob_data;
+ if (p_sc_oob_data->loc_oob_data.present) {
+ memcpy(p_cb->local_random, p_sc_oob_data->loc_oob_data.randomizer,
+ sizeof(p_cb->local_random));
+ } else {
+ SMP_TRACE_EVENT ("local OOB randomizer is absent\n");
+ memset(p_cb->local_random, 0, sizeof (p_cb->local_random));
+ }
+
+ if (!p_sc_oob_data->peer_oob_data.present) {
+ SMP_TRACE_EVENT ("peer OOB data is absent\n");
+ memset(p_cb->peer_random, 0, sizeof (p_cb->peer_random));
+ } else {
+ memcpy(p_cb->peer_random, p_sc_oob_data->peer_oob_data.randomizer,
+ sizeof(p_cb->peer_random));
+ memcpy(p_cb->remote_commitment, p_sc_oob_data->peer_oob_data.commitment,
+ sizeof(p_cb->remote_commitment));
+
+ UINT8 reason = SMP_CONFIRM_VALUE_ERR;
+ /* check commitment */
+ if (!smp_check_commitment(p_cb)) {
+ p_cb->failure = reason;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ if (p_cb->peer_oob_flag != SMP_OOB_PRESENT) {
+ /* the peer doesn't have local randomiser */
+ SMP_TRACE_EVENT ("peer didn't receive local OOB data, set local randomizer to 0\n");
+ memset(p_cb->local_random, 0, sizeof (p_cb->local_random));
+ }
+ }
+
+ print128(p_cb->local_random, (const UINT8 *)"local OOB randomizer");
+ print128(p_cb->peer_random, (const UINT8 *)"peer OOB randomizer");
+ smp_start_nonce_generation(p_cb);
+}
+
+/*******************************************************************************
+** Function smp_set_local_oob_keys
+** Description Saves calculated private/public keys in sc_oob_data.loc_oob_data,
+** starts nonce generation
+** (to be saved in sc_oob_data.loc_oob_data.randomizer).
+*******************************************************************************/
+void smp_set_local_oob_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG("%s\n", __func__);
+
+ memcpy(p_cb->sc_oob_data.loc_oob_data.private_key_used, p_cb->private_key,
+ BT_OCTET32_LEN);
+ p_cb->sc_oob_data.loc_oob_data.publ_key_used = p_cb->loc_publ_key;
+ smp_start_nonce_generation(p_cb);
+}
+
+/*******************************************************************************
+** Function smp_set_local_oob_random_commitment
+** Description Saves calculated randomizer and commitment in sc_oob_data.loc_oob_data,
+** passes sc_oob_data.loc_oob_data up for safekeeping.
+*******************************************************************************/
+void smp_set_local_oob_random_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG("%s\n", __func__);
+ memcpy(p_cb->sc_oob_data.loc_oob_data.randomizer, p_cb->rand,
+ BT_OCTET16_LEN);
+
+ smp_calculate_f4(p_cb->sc_oob_data.loc_oob_data.publ_key_used.x,
+ p_cb->sc_oob_data.loc_oob_data.publ_key_used.x,
+ p_cb->sc_oob_data.loc_oob_data.randomizer, 0,
+ p_cb->sc_oob_data.loc_oob_data.commitment);
+
+ p_cb->sc_oob_data.loc_oob_data.present = true;
+#if SMP_DEBUG == TRUE
+ UINT8 *p_print = NULL;
+ SMP_TRACE_DEBUG("local SC OOB data set:\n");
+ p_print = (UINT8 *) &p_cb->sc_oob_data.loc_oob_data.addr_sent_to;
+ smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"addr_sent_to",
+ sizeof(tBLE_BD_ADDR));
+ p_print = (UINT8 *) &p_cb->sc_oob_data.loc_oob_data.private_key_used;
+ smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"private_key_used",
+ BT_OCTET32_LEN);
+ p_print = (UINT8 *) &p_cb->sc_oob_data.loc_oob_data.publ_key_used.x;
+ smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"publ_key_used.x",
+ BT_OCTET32_LEN);
+ p_print = (UINT8 *) &p_cb->sc_oob_data.loc_oob_data.publ_key_used.y;
+ smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"publ_key_used.y",
+ BT_OCTET32_LEN);
+ p_print = (UINT8 *) &p_cb->sc_oob_data.loc_oob_data.randomizer;
+ smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"randomizer",
+ BT_OCTET16_LEN);
+ p_print = (UINT8 *) &p_cb->sc_oob_data.loc_oob_data.commitment;
+ smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *) "commitment",
+ BT_OCTET16_LEN);
+ SMP_TRACE_DEBUG("");
+#endif
+
+ /* pass created OOB data up */
+ p_cb->cb_evt = SMP_SC_LOC_OOB_DATA_UP_EVT;
+ smp_send_app_cback(p_cb, NULL);
+
+ // Store the data for later use when we are paired with
+ smp_save_local_oob_data(p_cb);
+
+ smp_cb_cleanup(p_cb);
+}
+
+/*******************************************************************************
+**
+** Function smp_link_encrypted
+**
+** Description This function is called when link is encrypted and notified to
+** slave device. Proceed to to send LTK, DIV and ER to master if
+** bonding the devices.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_link_encrypted(BD_ADDR bda, UINT8 encr_enable)
+{
+ tSMP_CB *p_cb = &smp_cb;
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda);
+ SMP_TRACE_DEBUG("%s encr_enable=%d\n", __func__, encr_enable);
+
+ if (memcmp(&smp_cb.pairing_bda[0], bda, BD_ADDR_LEN) == 0) {
+ /* encryption completed with STK, remmeber the key size now, could be overwite
+ * when key exchange happens */
+ if (p_cb->loc_enc_size != 0 && encr_enable) {
+ /* update the link encryption key size if a SMP pairing just performed */
+ btm_ble_update_sec_key_size(bda, p_cb->loc_enc_size);
+ }
+
+ smp_sm_event(&smp_cb, SMP_ENCRYPTED_EVT, &encr_enable);
+ } else if (p_dev_rec && !p_dev_rec->role_master && !p_dev_rec->enc_init_by_we ){
+ /*
+ if enc_init_by_we is false, it means that client initiates encryption before slave calls esp_ble_set_encryption()
+ we need initiate pairing_bda and p_cb->role then encryption, for example iPhones
+ */
+ memcpy(&smp_cb.pairing_bda[0], bda, BD_ADDR_LEN);
+ p_cb->state = SMP_STATE_ENCRYPTION_PENDING;
+ p_cb->role = HCI_ROLE_SLAVE;
+ p_dev_rec->enc_init_by_we = FALSE;
+ smp_sm_event(&smp_cb, SMP_ENCRYPTED_EVT, &encr_enable);
+ } else if (p_dev_rec && p_dev_rec->role_master && p_dev_rec->enc_init_by_we){
+ memcpy(&smp_cb.pairing_bda[0], bda, BD_ADDR_LEN);
+ p_cb->state = SMP_STATE_ENCRYPTION_PENDING;
+ p_cb->role = HCI_ROLE_MASTER;
+ p_dev_rec->enc_init_by_we = FALSE;
+ smp_sm_event(&smp_cb, SMP_ENCRYPTED_EVT, &encr_enable);
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_proc_ltk_request
+**
+** Description This function is called when LTK request is received from
+** controller.
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN smp_proc_ltk_request(BD_ADDR bda)
+{
+ SMP_TRACE_DEBUG("%s state = %d\n", __func__, smp_cb.state);
+ BOOLEAN match = FALSE;
+
+ if (!memcmp(bda, smp_cb.pairing_bda, BD_ADDR_LEN)) {
+ match = TRUE;
+ } else {
+ BD_ADDR dummy_bda = {0};
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(bda);
+ if (p_dev_rec != NULL &&
+ 0 == memcmp(p_dev_rec->ble.pseudo_addr, smp_cb.pairing_bda, BD_ADDR_LEN) &&
+ 0 != memcmp(p_dev_rec->ble.pseudo_addr, dummy_bda, BD_ADDR_LEN)) {
+ match = TRUE;
+ }
+ }
+
+ if (match && smp_cb.state == SMP_STATE_ENCRYPTION_PENDING) {
+ smp_sm_event(&smp_cb, SMP_ENC_REQ_EVT, NULL);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function smp_process_secure_connection_long_term_key
+**
+** Description This function is called to process SC LTK.
+** SC LTK is calculated and used instead of STK.
+** Here SC LTK is saved in BLE DB.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_process_secure_connection_long_term_key(void)
+{
+ tSMP_CB *p_cb = &smp_cb;
+
+ SMP_TRACE_DEBUG("%s\n", __func__);
+ smp_save_secure_connections_long_term_key(p_cb);
+
+ smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ENC, FALSE);
+ smp_key_distribution(p_cb, NULL);
+}
+
+/*******************************************************************************
+**
+** Function smp_set_derive_link_key
+**
+** Description This function is called to set flag that indicates that
+** BR/EDR LK has to be derived from LTK after all keys are
+** distributed.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_set_derive_link_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG ("%s\n", __func__);
+ p_cb->derive_lk = TRUE;
+ smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_LK, FALSE);
+ smp_key_distribution(p_cb, NULL);
+}
+
+/*******************************************************************************
+**
+** Function smp_derive_link_key_from_long_term_key
+**
+** Description This function is called to derive BR/EDR LK from LTK.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_derive_link_key_from_long_term_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+ SMP_TRACE_DEBUG("%s\n", __func__);
+ if (!smp_calculate_link_key_from_long_term_key(p_cb)) {
+ SMP_TRACE_ERROR("%s failed\n", __FUNCTION__);
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ return;
+ }
+}
+#endif ///BLE_INCLUDED == TRUE
+
+#if (CLASSIC_BT_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function smp_br_process_link_key
+**
+** Description This function is called to process BR/EDR LK:
+** - to derive SMP LTK from BR/EDR LK;
+*8 - to save SMP LTK.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_br_process_link_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+ SMP_TRACE_DEBUG("%s\n", __func__);
+ if (!smp_calculate_long_term_key_from_link_key(p_cb)) {
+ SMP_TRACE_ERROR ("%s failed\n", __FUNCTION__);
+ smp_sm_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &status);
+ return;
+ }
+
+ SMP_TRACE_DEBUG("%s: LTK derivation from LK successfully completed\n", __FUNCTION__);
+ smp_save_secure_connections_long_term_key(p_cb);
+ smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ENC, FALSE);
+ smp_br_select_next_key(p_cb, NULL);
+}
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+
+/*******************************************************************************
+** Function smp_key_distribution_by_transport
+** Description depending on the transport used at the moment calls either
+** smp_key_distribution(...) or smp_br_key_distribution(...).
+*******************************************************************************/
+void smp_key_distribution_by_transport(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG("%s\n", __func__);
+ if (p_cb->smp_over_br) {
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ smp_br_select_next_key(p_cb, NULL);
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+ } else {
+#if (BLE_INCLUDED == TRUE)
+ smp_key_distribution(p_cb, NULL);
+#endif ///BLE_INCLUDED == TRUE
+ }
+}
+
+/*******************************************************************************
+** Function smp_br_pairing_complete
+** Description This function is called to send the pairing complete callback
+** and remove the connection if needed.
+*******************************************************************************/
+void smp_br_pairing_complete(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG("%s\n", __func__);
+
+ if (p_cb->total_tx_unacked == 0) {
+ /* process the pairing complete */
+ smp_proc_pairing_cmpl(p_cb);
+ }
+}
+
+#endif
diff --git a/lib/bt/host/bluedroid/stack/smp/smp_api.c b/lib/bt/host/bluedroid/stack/smp/smp_api.c
new file mode 100644
index 00000000..78e295f4
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/smp/smp_api.c
@@ -0,0 +1,615 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2008-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the implementation of the SMP interface used by
+ * applications that can run over an SMP.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "common/bt_target.h"
+//#include "bt_utils.h"
+#if SMP_INCLUDED == TRUE
+#include "smp_int.h"
+#include "stack/smp_api.h"
+#include "stack/l2cdefs.h"
+#include "l2c_int.h"
+#include "btm_int.h"
+#include "stack/hcimsgs.h"
+
+#include "stack/btu.h"
+#include "p_256_ecc_pp.h"
+#include "osi/allocator.h"
+
+/*******************************************************************************
+**
+** Function SMP_Init
+**
+** Description This function initializes the SMP unit.
+**
+** Returns void
+**
+*******************************************************************************/
+void SMP_Init(void)
+{
+#if SMP_DYNAMIC_MEMORY
+ smp_cb_ptr = (tSMP_CB *)osi_malloc(sizeof(tSMP_CB));
+ curve_ptr = (elliptic_curve_t *)osi_malloc(sizeof(elliptic_curve_t));
+ curve_p256_ptr = (elliptic_curve_t *)osi_malloc(sizeof(elliptic_curve_t));
+#endif
+ memset(&smp_cb, 0, sizeof(tSMP_CB));
+ memset(&curve, 0, sizeof(elliptic_curve_t));
+ memset(&curve_p256, 0, sizeof(elliptic_curve_t));
+
+#if defined(SMP_INITIAL_TRACE_LEVEL)
+ smp_cb.trace_level = SMP_INITIAL_TRACE_LEVEL;
+#else
+ smp_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
+#endif
+ SMP_TRACE_EVENT ("%s", __FUNCTION__);
+
+ smp_l2cap_if_init();
+ /* initialization of P-256 parameters */
+ p_256_init_curve(KEY_LENGTH_DWORDS_P256);
+}
+
+void SMP_Free(void)
+{
+ memset(&smp_cb, 0, sizeof(tSMP_CB));
+#if SMP_DYNAMIC_MEMORY
+ FREE_AND_RESET(smp_cb_ptr);
+ FREE_AND_RESET(curve_ptr);
+ FREE_AND_RESET(curve_p256_ptr);
+#endif /* #if SMP_DYNAMIC_MEMORY */
+}
+
+
+/*******************************************************************************
+**
+** Function SMP_SetTraceLevel
+**
+** Description This function sets the trace level for SMP. If called with
+** a value of 0xFF, it simply returns the current trace level.
+**
+** Input Parameters:
+** level: The level to set the GATT tracing to:
+** 0xff-returns the current setting.
+** 0-turns off tracing.
+** >= 1-Errors.
+** >= 2-Warnings.
+** >= 3-APIs.
+** >= 4-Events.
+** >= 5-Debug.
+**
+** Returns The new or current trace level
+**
+*******************************************************************************/
+extern UINT8 SMP_SetTraceLevel (UINT8 new_level)
+{
+ if (new_level != 0xFF) {
+ smp_cb.trace_level = new_level;
+ }
+
+ return (smp_cb.trace_level);
+}
+
+
+/*******************************************************************************
+**
+** Function SMP_Register
+**
+** Description This function register for the SMP services callback.
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN SMP_Register (tSMP_CALLBACK *p_cback)
+{
+ SMP_TRACE_EVENT ("SMP_Register state=%d", smp_cb.state);
+
+ if (smp_cb.p_callback != NULL) {
+ SMP_TRACE_WARNING ("SMP_Register: duplicate registration, overwrite it");
+ }
+ smp_cb.p_callback = p_cback;
+
+ return (TRUE);
+
+}
+
+/*******************************************************************************
+**
+** Function SMP_Pair
+**
+** Description This function call to perform a SMP pairing with peer device.
+** Device support one SMP pairing at one time.
+**
+** Parameters bd_addr - peer device bd address.
+**
+** Returns None
+**
+*******************************************************************************/
+tSMP_STATUS SMP_Pair (BD_ADDR bd_addr)
+{
+ tSMP_CB *p_cb = &smp_cb;
+ UINT8 status = SMP_PAIR_INTERNAL_ERR;
+
+ SMP_TRACE_EVENT ("%s state=%d br_state=%d flag=0x%x \n",
+ __FUNCTION__, p_cb->state, p_cb->br_state, p_cb->flags);
+ if (p_cb->state != SMP_STATE_IDLE || p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD ||
+ p_cb->smp_over_br) {
+ /* pending security on going, reject this one */
+ return SMP_BUSY;
+ } else {
+ p_cb->flags = SMP_PAIR_FLAGS_WE_STARTED_DD;
+
+ memcpy (p_cb->pairing_bda, bd_addr, BD_ADDR_LEN);
+
+ if (!L2CA_ConnectFixedChnl (L2CAP_SMP_CID, bd_addr, BLE_ADDR_UNKNOWN_TYPE, FALSE)) {
+ SMP_TRACE_ERROR("%s: L2C connect fixed channel failed.\n", __FUNCTION__);
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ return status;
+ }
+
+ return SMP_STARTED;
+ }
+}
+
+/*******************************************************************************
+**
+** Function SMP_BR_PairWith
+**
+** Description This function is called to start a SMP pairing over BR/EDR.
+** Device support one SMP pairing at one time.
+**
+** Parameters bd_addr - peer device bd address.
+**
+** Returns SMP_STARTED if pairing started, otherwise reason for failure.
+**
+*******************************************************************************/
+#if (CLASSIC_BT_INCLUDED == TRUE)
+tSMP_STATUS SMP_BR_PairWith (BD_ADDR bd_addr)
+{
+ tSMP_CB *p_cb = &smp_cb;
+ UINT8 status = SMP_PAIR_INTERNAL_ERR;
+
+ SMP_TRACE_EVENT ("%s state=%d br_state=%d flag=0x%x ",
+ __func__, p_cb->state, p_cb->br_state, p_cb->flags);
+
+ if (p_cb->state != SMP_STATE_IDLE ||
+ p_cb->smp_over_br ||
+ p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD) {
+ /* pending security on going, reject this one */
+ return SMP_BUSY;
+ }
+
+ p_cb->role = HCI_ROLE_MASTER;
+ p_cb->flags = SMP_PAIR_FLAGS_WE_STARTED_DD;
+ p_cb->smp_over_br = TRUE;
+
+ memcpy (p_cb->pairing_bda, bd_addr, BD_ADDR_LEN);
+
+ if (!L2CA_ConnectFixedChnl (L2CAP_SMP_BR_CID, bd_addr, BLE_ADDR_UNKNOWN_TYPE, FALSE)) {
+ SMP_TRACE_ERROR("%s: L2C connect fixed channel failed.", __FUNCTION__);
+ smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &status);
+ return status;
+ }
+
+ return SMP_STARTED;
+}
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function SMP_PairCancel
+**
+** Description This function call to cancel a SMP pairing with peer device.
+**
+** Parameters bd_addr - peer device bd address.
+**
+** Returns TRUE - Pairining is cancelled
+**
+*******************************************************************************/
+BOOLEAN SMP_PairCancel (BD_ADDR bd_addr)
+{
+ tSMP_CB *p_cb = &smp_cb;
+ UINT8 err_code = SMP_PAIR_FAIL_UNKNOWN;
+ BOOLEAN status = FALSE;
+
+ BTM_TRACE_EVENT ("SMP_CancelPair state=%d flag=0x%x ", p_cb->state, p_cb->flags);
+ if ( (p_cb->state != SMP_STATE_IDLE) &&
+ (!memcmp (p_cb->pairing_bda, bd_addr, BD_ADDR_LEN)) ) {
+ p_cb->is_pair_cancel = TRUE;
+ SMP_TRACE_DEBUG("Cancel Pairing: set fail reason Unknown");
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &err_code);
+ status = TRUE;
+ }
+
+ return status;
+}
+/*******************************************************************************
+**
+** Function SMP_SecurityGrant
+**
+** Description This function is called to grant security process.
+**
+** Parameters bd_addr - peer device bd address.
+** res - result of the operation SMP_SUCCESS if success.
+** Otherwise, SMP_REPEATED_ATTEMPTS is too many attempts.
+**
+** Returns None
+**
+*******************************************************************************/
+void SMP_SecurityGrant(BD_ADDR bd_addr, UINT8 res)
+{
+ SMP_TRACE_EVENT ("SMP_SecurityGrant ");
+
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ if (smp_cb.smp_over_br) {
+ if (smp_cb.br_state != SMP_BR_STATE_WAIT_APP_RSP ||
+ smp_cb.cb_evt != SMP_SEC_REQUEST_EVT ||
+ memcmp (smp_cb.pairing_bda, bd_addr, BD_ADDR_LEN)) {
+ return;
+ }
+
+ /* clear the SMP_SEC_REQUEST_EVT event after get grant */
+ /* avoid generating duplicate pair request */
+ smp_cb.cb_evt = 0;
+ smp_br_state_machine_event(&smp_cb, SMP_BR_API_SEC_GRANT_EVT, &res);
+ return;
+ }
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+
+ if (smp_cb.state != SMP_STATE_WAIT_APP_RSP ||
+ smp_cb.cb_evt != SMP_SEC_REQUEST_EVT ||
+ memcmp (smp_cb.pairing_bda, bd_addr, BD_ADDR_LEN)) {
+ return;
+ }
+ /* clear the SMP_SEC_REQUEST_EVT event after get grant */
+ /* avoid generate duplicate pair request */
+ smp_cb.cb_evt = 0;
+ smp_sm_event(&smp_cb, SMP_API_SEC_GRANT_EVT, &res);
+}
+
+/*******************************************************************************
+**
+** Function SMP_PasskeyReply
+**
+** Description This function is called after Security Manager submitted
+** passkey request to the application.
+**
+** Parameters: bd_addr - Address of the device for which passkey was requested
+** res - result of the operation SMP_SUCCESS if success
+** passkey - numeric value in the range of
+** BTM_MIN_PASSKEY_VAL(0) - BTM_MAX_PASSKEY_VAL(999999(0xF423F)).
+**
+*******************************************************************************/
+void SMP_PasskeyReply (BD_ADDR bd_addr, UINT8 res, UINT32 passkey)
+{
+ tSMP_CB *p_cb = & smp_cb;
+ UINT8 failure = SMP_PASSKEY_ENTRY_FAIL;
+
+ SMP_TRACE_EVENT ("SMP_PasskeyReply: Key: %d Result:%d",
+ passkey, res);
+
+ /* If timeout already expired or has been canceled, ignore the reply */
+ if (p_cb->cb_evt != SMP_PASSKEY_REQ_EVT) {
+ SMP_TRACE_WARNING ("SMP_PasskeyReply() - Wrong State: %d", p_cb->state);
+ return;
+ }
+
+ if (memcmp (bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) != 0) {
+ SMP_TRACE_ERROR ("SMP_PasskeyReply() - Wrong BD Addr");
+ return;
+ }
+
+ if (btm_find_dev (bd_addr) == NULL) {
+ SMP_TRACE_ERROR ("SMP_PasskeyReply() - no dev CB");
+ return;
+ }
+
+ if (passkey > BTM_MAX_PASSKEY_VAL || res != SMP_SUCCESS) {
+ SMP_TRACE_WARNING ("SMP_PasskeyReply() - Wrong key len: %d or passkey entry fail", passkey);
+ /* send pairing failure */
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+
+ } else if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_PASSKEY_ENT) {
+ smp_sm_event(&smp_cb, SMP_SC_KEY_READY_EVT, &passkey);
+ } else {
+ smp_convert_string_to_tk(p_cb->tk, passkey);
+ }
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function SMP_SetStaticPasskey
+**
+** Description This function is called to set static passkey
+**
+**
+** Parameters: add - set static passkey when add is TRUE
+** clear static passkey when add is FALSE
+** passkey - static passkey
+**
+**
+*******************************************************************************/
+void SMP_SetStaticPasskey (BOOLEAN add, UINT32 passkey)
+{
+ SMP_TRACE_DEBUG("static passkey %6d", passkey);
+ tSMP_CB *p_cb = & smp_cb;
+ if(add) {
+ p_cb->static_passkey = passkey;
+ p_cb->use_static_passkey = true;
+ } else {
+ p_cb->static_passkey = 0;
+ p_cb->use_static_passkey = false;
+ }
+}
+
+/*******************************************************************************
+**
+** Function SMP_ConfirmReply
+**
+** Description This function is called after Security Manager submitted
+** numeric comparison request to the application.
+**
+** Parameters: bd_addr - Address of the device with which numeric
+** comparison was requested
+** res - comparison result SMP_SUCCESS if success
+**
+*******************************************************************************/
+void SMP_ConfirmReply (BD_ADDR bd_addr, UINT8 res)
+{
+ tSMP_CB *p_cb = & smp_cb;
+ UINT8 failure = SMP_NUMERIC_COMPAR_FAIL;
+
+ SMP_TRACE_EVENT ("%s: Result:%d", __FUNCTION__, res);
+
+ /* If timeout already expired or has been canceled, ignore the reply */
+ if (p_cb->cb_evt != SMP_NC_REQ_EVT) {
+ SMP_TRACE_WARNING ("%s() - Wrong State: %d", __FUNCTION__, p_cb->state);
+ return;
+ }
+
+ if (memcmp (bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) != 0) {
+ SMP_TRACE_ERROR ("%s() - Wrong BD Addr", __FUNCTION__);
+ return;
+ }
+
+ if (btm_find_dev (bd_addr) == NULL) {
+ SMP_TRACE_ERROR ("%s() - no dev CB", __FUNCTION__);
+ return;
+ }
+
+ if (res != SMP_SUCCESS) {
+ SMP_TRACE_WARNING ("%s() - Numeric Comparison fails", __FUNCTION__);
+ /* send pairing failure */
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+ } else {
+ smp_sm_event(p_cb, SMP_SC_NC_OK_EVT, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function SMP_OobDataReply
+**
+** Description This function is called to provide the OOB data for
+** SMP in response to SMP_OOB_REQ_EVT
+**
+** Parameters: bd_addr - Address of the peer device
+** res - result of the operation SMP_SUCCESS if success
+** p_data - simple pairing Randomizer C.
+**
+*******************************************************************************/
+void SMP_OobDataReply(BD_ADDR bd_addr, tSMP_STATUS res, UINT8 len, UINT8 *p_data)
+{
+ tSMP_CB *p_cb = & smp_cb;
+ UINT8 failure = SMP_OOB_FAIL;
+ tSMP_KEY key;
+
+ SMP_TRACE_EVENT ("%s State: %d res:%d", __FUNCTION__, smp_cb.state, res);
+
+ /* If timeout already expired or has been canceled, ignore the reply */
+ if (p_cb->state != SMP_STATE_WAIT_APP_RSP || p_cb->cb_evt != SMP_OOB_REQ_EVT) {
+ return;
+ }
+
+ if (res != SMP_SUCCESS || len == 0 || !p_data) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+ } else {
+ if (len > BT_OCTET16_LEN) {
+ len = BT_OCTET16_LEN;
+ }
+
+ memcpy(p_cb->tk, p_data, len);
+
+ key.key_type = SMP_KEY_TYPE_TK;
+ key.p_data = p_cb->tk;
+
+ smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &key);
+ }
+}
+
+/*******************************************************************************
+**
+** Function SMP_SecureConnectionOobDataReply
+**
+** Description This function is called to provide the SC OOB data for
+** SMP in response to SMP_SC_OOB_REQ_EVT
+**
+** Parameters: p_data - pointer to the data
+**
+*******************************************************************************/
+void SMP_SecureConnectionOobDataReply(UINT8 *p_data)
+{
+ tSMP_CB *p_cb = &smp_cb;
+
+ UINT8 failure = SMP_OOB_FAIL;
+ tSMP_SC_OOB_DATA *p_oob = (tSMP_SC_OOB_DATA *) p_data;
+ if (!p_oob) {
+ SMP_TRACE_ERROR("%s received no data", __FUNCTION__);
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+ return;
+ }
+
+ /* Set local oob data when req_oob_type = SMP_OOB_BOTH */
+ memcpy(&p_oob->loc_oob_data, smp_get_local_oob_data(), sizeof(tSMP_LOC_OOB_DATA));
+
+ SMP_TRACE_EVENT ("%s req_oob_type: %d, loc_oob_data.present: %d, "
+ "peer_oob_data.present: %d",
+ __FUNCTION__, p_cb->req_oob_type, p_oob->loc_oob_data.present,
+ p_oob->peer_oob_data.present);
+
+ if (p_cb->state != SMP_STATE_WAIT_APP_RSP || p_cb->cb_evt != SMP_SC_OOB_REQ_EVT) {
+ return;
+ }
+
+ BOOLEAN data_missing = FALSE;
+ switch (p_cb->req_oob_type) {
+ case SMP_OOB_PEER:
+ if (!p_oob->peer_oob_data.present) {
+ data_missing = TRUE;
+ }
+ break;
+ case SMP_OOB_LOCAL:
+ if (!p_oob->loc_oob_data.present) {
+ data_missing = TRUE;
+ }
+ break;
+ case SMP_OOB_BOTH:
+ if (!p_oob->loc_oob_data.present || !p_oob->peer_oob_data.present) {
+ data_missing = TRUE;
+ }
+ break;
+ default:
+ SMP_TRACE_EVENT ("Unexpected OOB data type requested. Fail OOB");
+ data_missing = TRUE;
+ break;
+ }
+
+ if (data_missing) {
+ SMP_TRACE_ERROR("%s data missing", __func__);
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+ return;
+ }
+
+ p_cb->sc_oob_data = *p_oob;
+
+ smp_sm_event(&smp_cb, SMP_SC_OOB_DATA_EVT, p_data);
+}
+
+/*******************************************************************************
+**
+** Function SMP_Encrypt
+**
+** Description This function is called to encrypt the data with the specified
+** key
+**
+** Parameters: key - Pointer to key key[0] conatins the MSB
+** key_len - key length
+** plain_text - Pointer to data to be encrypted
+** plain_text[0] conatins the MSB
+** pt_len - plain text length
+** p_out - output of the encrypted texts
+**
+** Returns Boolean - request is successful
+*******************************************************************************/
+BOOLEAN SMP_Encrypt (UINT8 *key, UINT8 key_len,
+ UINT8 *plain_text, UINT8 pt_len,
+ tSMP_ENC *p_out)
+
+{
+ BOOLEAN status = FALSE;
+ status = smp_encrypt_data(key, key_len, plain_text, pt_len, p_out);
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function SMP_KeypressNotification
+**
+** Description This function is called to notify Security Manager about Keypress Notification.
+**
+** Parameters: bd_addr Address of the device to send keypress notification to
+** value Keypress notification parameter value
+**
+*******************************************************************************/
+void SMP_KeypressNotification (BD_ADDR bd_addr, UINT8 value)
+{
+ tSMP_CB *p_cb = &smp_cb;
+
+ SMP_TRACE_EVENT ("%s: Value: %d", __FUNCTION__, value);
+
+ if (memcmp (bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) != 0) {
+ SMP_TRACE_ERROR ("%s() - Wrong BD Addr", __FUNCTION__);
+ return;
+ }
+
+ if (btm_find_dev (bd_addr) == NULL) {
+ SMP_TRACE_ERROR ("%s() - no dev CB", __FUNCTION__);
+ return;
+ }
+
+ /* Keypress Notification is used by a device with KeyboardOnly IO capabilities */
+ /* during the passkey entry protocol */
+ if (p_cb->local_io_capability != SMP_IO_CAP_IN) {
+ SMP_TRACE_ERROR ("%s() - wrong local IO capabilities %d",
+ __FUNCTION__, p_cb->local_io_capability);
+ return;
+ }
+
+ if (p_cb->selected_association_model != SMP_MODEL_SEC_CONN_PASSKEY_ENT) {
+ SMP_TRACE_ERROR ("%s() - wrong protocol %d", __FUNCTION__,
+ p_cb->selected_association_model);
+ return;
+ }
+
+ smp_sm_event(p_cb, SMP_KEYPRESS_NOTIFICATION_EVENT, &value);
+}
+
+/*******************************************************************************
+**
+** Function SMP_CreateLocalSecureConnectionsOobData
+**
+** Description This function is called to start creation of local SC OOB
+** data set (tSMP_LOC_OOB_DATA).
+**
+** Returns Boolean - TRUE: creation of local SC OOB data set started.
+*******************************************************************************/
+BOOLEAN SMP_CreateLocalSecureConnectionsOobData (void)
+{
+ tSMP_CB *p_cb = &smp_cb;
+
+ SMP_TRACE_EVENT ("%s state: %u, br_state: %u", __FUNCTION__, p_cb->state, p_cb->br_state);
+
+ if ((p_cb->state != SMP_STATE_IDLE) || (p_cb->smp_over_br)) {
+ SMP_TRACE_WARNING ("%s creation of local OOB data set "\
+ "starts only in IDLE state", __FUNCTION__);
+ return FALSE;
+ }
+
+ smp_sm_event(p_cb, SMP_CR_LOC_SC_OOB_DATA_EVT, NULL);
+
+ return TRUE;
+}
+
+#endif /* SMP_INCLUDED */
diff --git a/lib/bt/host/bluedroid/stack/smp/smp_br_main.c b/lib/bt/host/bluedroid/stack/smp/smp_br_main.c
new file mode 100644
index 00000000..5ef7a7c6
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/smp/smp_br_main.c
@@ -0,0 +1,369 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014-2015 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "common/bt_target.h"
+
+#include <string.h>
+#include "smp_int.h"
+
+#if ( CLASSIC_BT_INCLUDED== TRUE && SMP_INCLUDED == TRUE)
+
+const char *const smp_br_state_name [SMP_BR_STATE_MAX + 1] = {
+ "SMP_BR_STATE_IDLE",
+ "SMP_BR_STATE_WAIT_APP_RSP",
+ "SMP_BR_STATE_PAIR_REQ_RSP",
+ "SMP_BR_STATE_BOND_PENDING",
+ "SMP_BR_STATE_OUT_OF_RANGE"
+};
+
+const char *const smp_br_event_name [SMP_BR_MAX_EVT] = {
+ "BR_PAIRING_REQ_EVT",
+ "BR_PAIRING_RSP_EVT",
+ "BR_CONFIRM_EVT",
+ "BR_RAND_EVT",
+ "BR_PAIRING_FAILED_EVT",
+ "BR_ENCRPTION_INFO_EVT",
+ "BR_MASTER_ID_EVT",
+ "BR_ID_INFO_EVT",
+ "BR_ID_ADDR_EVT",
+ "BR_SIGN_INFO_EVT",
+ "BR_SECURITY_REQ_EVT",
+ "BR_PAIR_PUBLIC_KEY_EVT",
+ "BR_PAIR_DHKEY_CHCK_EVT",
+ "BR_PAIR_KEYPR_NOTIF_EVT",
+ "BR_KEY_READY_EVT",
+ "BR_ENCRYPTED_EVT",
+ "BR_L2CAP_CONN_EVT",
+ "BR_L2CAP_DISCONN_EVT",
+ "BR_KEYS_RSP_EVT",
+ "BR_API_SEC_GRANT_EVT",
+ "BR_TK_REQ_EVT",
+ "BR_AUTH_CMPL_EVT",
+ "BR_ENC_REQ_EVT",
+ "BR_BOND_REQ_EVT",
+ "BR_DISCARD_SEC_REQ_EVT",
+ "BR_OUT_OF_RANGE_EVT"
+};
+
+const char *smp_get_br_event_name(tSMP_BR_EVENT event);
+const char *smp_get_br_state_name(tSMP_BR_STATE state);
+
+#define SMP_BR_SM_IGNORE 0
+#define SMP_BR_NUM_ACTIONS 2
+#define SMP_BR_SME_NEXT_STATE 2
+#define SMP_BR_SM_NUM_COLS 3
+typedef const UINT8 (*tSMP_BR_SM_TBL)[SMP_BR_SM_NUM_COLS];
+
+enum {
+ SMP_SEND_PAIR_REQ,
+ SMP_BR_SEND_PAIR_RSP,
+ SMP_SEND_PAIR_FAIL,
+ SMP_SEND_ID_INFO,
+ SMP_BR_PROC_PAIR_CMD,
+ SMP_PROC_PAIR_FAIL,
+ SMP_PROC_ID_INFO,
+ SMP_PROC_ID_ADDR,
+ SMP_PROC_SRK_INFO,
+ SMP_BR_PROC_SEC_GRANT,
+ SMP_BR_PROC_SL_KEYS_RSP,
+ SMP_BR_KEY_DISTRIBUTION,
+ SMP_BR_PAIRING_COMPLETE,
+ SMP_SEND_APP_CBACK,
+ SMP_BR_CHECK_AUTH_REQ,
+ SMP_PAIR_TERMINATE,
+ SMP_IDLE_TERMINATE,
+ SMP_BR_SM_NO_ACTION
+};
+
+static const tSMP_ACT smp_br_sm_action[] = {
+ smp_send_pair_req,
+ smp_br_send_pair_response,
+ smp_send_pair_fail,
+ smp_send_id_info,
+ smp_br_process_pairing_command,
+ smp_proc_pair_fail,
+ smp_proc_id_info,
+ smp_proc_id_addr,
+ smp_proc_srk_info,
+ smp_br_process_security_grant,
+ smp_br_process_slave_keys_response,
+ smp_br_select_next_key,
+ smp_br_pairing_complete,
+ smp_send_app_cback,
+ smp_br_check_authorization_request,
+ smp_pair_terminate,
+ smp_idle_terminate
+};
+
+static const UINT8 smp_br_all_table[][SMP_BR_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* BR_PAIRING_FAILED */ {SMP_PROC_PAIR_FAIL, SMP_BR_PAIRING_COMPLETE, SMP_BR_STATE_IDLE},
+ /* BR_AUTH_CMPL */ {SMP_SEND_PAIR_FAIL, SMP_BR_PAIRING_COMPLETE, SMP_BR_STATE_IDLE},
+ /* BR_L2CAP_DISCONN */ {SMP_PAIR_TERMINATE, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_IDLE}
+};
+
+/************ SMP Master FSM State/Event Indirection Table **************/
+static const UINT8 smp_br_master_entry_map[][SMP_BR_STATE_MAX] = {
+ /* br_state name: Idle WaitApp Pair Bond
+ Rsp ReqRsp Pend */
+ /* BR_PAIRING_REQ */ { 0, 0, 0, 0 },
+ /* BR_PAIRING_RSP */ { 0, 0, 1, 0 },
+ /* BR_CONFIRM */ { 0, 0, 0, 0 },
+ /* BR_RAND */ { 0, 0, 0, 0 },
+ /* BR_PAIRING_FAILED */ { 0, 0x81, 0x81, 0 },
+ /* BR_ENCRPTION_INFO */ { 0, 0, 0, 0 },
+ /* BR_MASTER_ID */ { 0, 0, 0, 0 },
+ /* BR_ID_INFO */ { 0, 0, 0, 1 },
+ /* BR_ID_ADDR */ { 0, 0, 0, 2 },
+ /* BR_SIGN_INFO */ { 0, 0, 0, 3 },
+ /* BR_SECURITY_REQ */ { 0, 0, 0, 0 },
+ /* BR_PAIR_PUBLIC_KEY_EVT */ { 0, 0, 0, 0 },
+ /* BR_PAIR_DHKEY_CHCK_EVT */ { 0, 0, 0, 0 },
+ /* BR_PAIR_KEYPR_NOTIF_EVT */ { 0, 0, 0, 0 },
+ /* BR_KEY_READY */ { 0, 0, 0, 0 },
+ /* BR_ENCRYPTED */ { 0, 0, 0, 0 },
+ /* BR_L2CAP_CONN */ { 1, 0, 0, 0 },
+ /* BR_L2CAP_DISCONN */ { 2, 0x83, 0x83, 0x83 },
+ /* BR_KEYS_RSP */ { 0, 1, 0, 0 },
+ /* BR_API_SEC_GRANT */ { 0, 0, 0, 0 },
+ /* BR_TK_REQ */ { 0, 0, 0, 0 },
+ /* BR_AUTH_CMPL */ { 0, 0x82, 0x82, 0x82 },
+ /* BR_ENC_REQ */ { 0, 0, 0, 0 },
+ /* BR_BOND_REQ */ { 0, 0, 2, 0 },
+ /* BR_DISCARD_SEC_REQ */ { 0, 0, 0, 0 }
+};
+
+static const UINT8 smp_br_master_idle_table[][SMP_BR_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* BR_L2CAP_CONN */ {SMP_SEND_APP_CBACK, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_WAIT_APP_RSP},
+ /* BR_L2CAP_DISCONN */ {SMP_IDLE_TERMINATE, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_IDLE}
+};
+
+static const UINT8 smp_br_master_wait_appln_response_table[][SMP_BR_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* BR_KEYS_RSP */{SMP_SEND_PAIR_REQ, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_PAIR_REQ_RSP}
+};
+
+static const UINT8 smp_br_master_pair_request_response_table [][SMP_BR_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* BR_PAIRING_RSP */ {SMP_BR_PROC_PAIR_CMD, SMP_BR_CHECK_AUTH_REQ, SMP_BR_STATE_PAIR_REQ_RSP},
+ /* BR_BOND_REQ */ {SMP_BR_SM_NO_ACTION, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING}
+};
+
+static const UINT8 smp_br_master_bond_pending_table[][SMP_BR_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* BR_ID_INFO */{SMP_PROC_ID_INFO, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING},
+ /* BR_ID_ADDR */{SMP_PROC_ID_ADDR, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING},
+ /* BR_SIGN_INFO */{SMP_PROC_SRK_INFO, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING}
+};
+
+static const UINT8 smp_br_slave_entry_map[][SMP_BR_STATE_MAX] = {
+ /* br_state name: Idle WaitApp Pair Bond
+ Rsp ReqRsp Pend */
+ /* BR_PAIRING_REQ */ { 1, 0, 0, 0 },
+ /* BR_PAIRING_RSP */ { 0, 0, 0, 0 },
+ /* BR_CONFIRM */ { 0, 0, 0, 0 },
+ /* BR_RAND */ { 0, 0, 0, 0 },
+ /* BR_PAIRING_FAILED */ { 0, 0x81, 0x81, 0x81 },
+ /* BR_ENCRPTION_INFO */ { 0, 0, 0, 0 },
+ /* BR_MASTER_ID */ { 0, 0, 0, 0 },
+ /* BR_ID_INFO */ { 0, 0, 0, 1 },
+ /* BR_ID_ADDR */ { 0, 0, 0, 2 },
+ /* BR_SIGN_INFO */ { 0, 0, 0, 3 },
+ /* BR_SECURITY_REQ */ { 0, 0, 0, 0 },
+ /* BR_PAIR_PUBLIC_KEY_EVT */ { 0, 0, 0, 0 },
+ /* BR_PAIR_DHKEY_CHCK_EVT */ { 0, 0, 0, 0 },
+ /* BR_PAIR_KEYPR_NOTIF_EVT */ { 0, 0, 0, 0 },
+ /* BR_KEY_READY */ { 0, 0, 0, 0 },
+ /* BR_ENCRYPTED */ { 0, 0, 0, 0 },
+ /* BR_L2CAP_CONN */ { 0, 0, 0, 0 },
+ /* BR_L2CAP_DISCONN */ { 0, 0x83, 0x83, 0x83 },
+ /* BR_KEYS_RSP */ { 0, 2, 0, 0 },
+ /* BR_API_SEC_GRANT */ { 0, 1, 0, 0 },
+ /* BR_TK_REQ */ { 0, 0, 0, 0 },
+ /* BR_AUTH_CMPL */ { 0, 0x82, 0x82, 0x82 },
+ /* BR_ENC_REQ */ { 0, 0, 0, 0 },
+ /* BR_BOND_REQ */ { 0, 3, 0, 0 },
+ /* BR_DISCARD_SEC_REQ */ { 0, 0, 0, 0 }
+};
+
+static const UINT8 smp_br_slave_idle_table[][SMP_BR_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* BR_PAIRING_REQ */ {SMP_BR_PROC_PAIR_CMD, SMP_SEND_APP_CBACK, SMP_BR_STATE_WAIT_APP_RSP}
+};
+
+static const UINT8 smp_br_slave_wait_appln_response_table [][SMP_BR_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* BR_API_SEC_GRANT */ {SMP_BR_PROC_SEC_GRANT, SMP_SEND_APP_CBACK, SMP_BR_STATE_WAIT_APP_RSP},
+ /* BR_KEYS_RSP */{SMP_BR_PROC_SL_KEYS_RSP, SMP_BR_CHECK_AUTH_REQ, SMP_BR_STATE_WAIT_APP_RSP},
+ /* BR_BOND_REQ */ {SMP_BR_KEY_DISTRIBUTION, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING}
+};
+
+static const UINT8 smp_br_slave_bond_pending_table[][SMP_BR_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* BR_ID_INFO */ {SMP_PROC_ID_INFO, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING},
+ /* BR_ID_ADDR */ {SMP_PROC_ID_ADDR, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING},
+ /* BR_SIGN_INFO */ {SMP_PROC_SRK_INFO, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING}
+};
+
+static const tSMP_BR_SM_TBL smp_br_state_table[][2] = {
+ /* SMP_BR_STATE_IDLE */
+ {smp_br_master_idle_table, smp_br_slave_idle_table},
+
+ /* SMP_BR_STATE_WAIT_APP_RSP */
+ {smp_br_master_wait_appln_response_table, smp_br_slave_wait_appln_response_table},
+
+ /* SMP_BR_STATE_PAIR_REQ_RSP */
+ {smp_br_master_pair_request_response_table, NULL},
+
+ /* SMP_BR_STATE_BOND_PENDING */
+ {smp_br_master_bond_pending_table, smp_br_slave_bond_pending_table},
+};
+
+typedef const UINT8 (*tSMP_BR_ENTRY_TBL)[SMP_BR_STATE_MAX];
+
+static const tSMP_BR_ENTRY_TBL smp_br_entry_table[] = {
+ smp_br_master_entry_map,
+ smp_br_slave_entry_map
+};
+
+#define SMP_BR_ALL_TABLE_MASK 0x80
+
+/*******************************************************************************
+** Function smp_set_br_state
+** Returns None
+*******************************************************************************/
+void smp_set_br_state(tSMP_BR_STATE br_state)
+{
+ if (br_state < SMP_BR_STATE_MAX) {
+ SMP_TRACE_DEBUG( "BR_State change: %s(%d) ==> %s(%d)",
+ smp_get_br_state_name(smp_cb.br_state), smp_cb.br_state,
+ smp_get_br_state_name(br_state), br_state );
+ smp_cb.br_state = br_state;
+ } else {
+ SMP_TRACE_DEBUG("%s invalid br_state =%d", __FUNCTION__, br_state );
+ }
+}
+
+/*******************************************************************************
+** Function smp_get_br_state
+** Returns The smp_br state
+*******************************************************************************/
+tSMP_BR_STATE smp_get_br_state(void)
+{
+ return smp_cb.br_state;
+}
+
+/*******************************************************************************
+** Function smp_get_br_state_name
+** Returns The smp_br state name.
+*******************************************************************************/
+const char *smp_get_br_state_name(tSMP_BR_STATE br_state)
+{
+ const char *p_str = smp_br_state_name[SMP_BR_STATE_MAX];
+
+ if (br_state < SMP_BR_STATE_MAX) {
+ p_str = smp_br_state_name[br_state];
+ }
+
+ return p_str;
+}
+/*******************************************************************************
+** Function smp_get_br_event_name
+** Returns The smp_br event name.
+*******************************************************************************/
+const char *smp_get_br_event_name(tSMP_BR_EVENT event)
+{
+ const char *p_str = smp_br_event_name[SMP_BR_MAX_EVT - 1];
+
+ if (event < SMP_BR_MAX_EVT) {
+ p_str = smp_br_event_name[event - 1];
+ }
+ return p_str;
+}
+
+/*******************************************************************************
+**
+** Function smp_br_state_machine_event
+**
+** Description Handle events to the state machine. It looks up the entry
+** in the smp_br_entry_table array.
+** If it is a valid entry, it gets the state table.Set the next state,
+** if not NULL state. Execute the action function according to the
+** state table. If the state returned by action function is not NULL
+** state, adjust the new state to the returned state.
+**
+** Returns void.
+**
+*******************************************************************************/
+void smp_br_state_machine_event(tSMP_CB *p_cb, tSMP_BR_EVENT event, void *p_data)
+{
+ tSMP_BR_STATE curr_state = p_cb->br_state;
+ tSMP_BR_SM_TBL state_table;
+ UINT8 action, entry;
+ tSMP_BR_ENTRY_TBL entry_table = smp_br_entry_table[p_cb->role];
+
+ SMP_TRACE_EVENT("main %s", __func__);
+ if (curr_state >= SMP_BR_STATE_MAX) {
+ SMP_TRACE_DEBUG( "Invalid br_state: %d", curr_state) ;
+ return;
+ }
+
+ SMP_TRACE_DEBUG( "SMP Role: %s State: [%s (%d)], Event: [%s (%d)]",
+ (p_cb->role == HCI_ROLE_SLAVE) ? "Slave" : "Master",
+ smp_get_br_state_name( p_cb->br_state),
+ p_cb->br_state, smp_get_br_event_name(event), event) ;
+
+ /* look up the state table for the current state */
+ /* lookup entry / w event & curr_state */
+ /* If entry is ignore, return.
+ * Otherwise, get state table (according to curr_state or all_state) */
+ if ((event <= SMP_BR_MAX_EVT) && ( (entry = entry_table[event - 1][curr_state])
+ != SMP_BR_SM_IGNORE )) {
+ if (entry & SMP_BR_ALL_TABLE_MASK) {
+ entry &= ~SMP_BR_ALL_TABLE_MASK;
+ state_table = smp_br_all_table;
+ } else {
+ state_table = smp_br_state_table[curr_state][p_cb->role];
+ }
+ } else {
+ SMP_TRACE_DEBUG( "Ignore event [%s (%d)] in state [%s (%d)]",
+ smp_get_br_event_name(event), event,
+ smp_get_br_state_name(curr_state), curr_state);
+ return;
+ }
+
+ /* Get possible next state from state table. */
+
+ smp_set_br_state(state_table[entry - 1][SMP_BR_SME_NEXT_STATE]);
+
+ /* If action is not ignore, clear param, exec action and get next state.
+ * The action function may set the Param for cback.
+ * Depending on param, call cback or free buffer. */
+ /* execute action functions */
+ for (UINT8 i = 0; i < SMP_BR_NUM_ACTIONS; i++) {
+ if ((action = state_table[entry - 1][i]) != SMP_BR_SM_NO_ACTION) {
+ (*smp_br_sm_action[action])(p_cb, (tSMP_INT_DATA *)p_data);
+ } else {
+ break;
+ }
+ }
+ SMP_TRACE_DEBUG( "result state = %s", smp_get_br_state_name( p_cb->br_state ) ) ;
+}
+
+#endif
diff --git a/lib/bt/host/bluedroid/stack/smp/smp_cmac.c b/lib/bt/host/bluedroid/stack/smp/smp_cmac.c
new file mode 100644
index 00000000..e47c56b7
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/smp/smp_cmac.c
@@ -0,0 +1,369 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2008-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the implementation of the AES128 CMAC algorithm.
+ *
+ ******************************************************************************/
+
+#include "common/bt_target.h"
+#include "osi/allocator.h"
+
+#if SMP_INCLUDED == TRUE
+// #include <stdio.h>
+#include <string.h>
+
+#include "stack/btm_ble_api.h"
+#include "smp_int.h"
+#include "stack/hcimsgs.h"
+
+typedef struct {
+ UINT8 *text;
+ UINT16 len;
+ UINT16 round;
+} tCMAC_CB;
+
+tCMAC_CB cmac_cb;
+
+/* Rb for AES-128 as block cipher, LSB as [0] */
+const BT_OCTET16 const_Rb = {
+ 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+void print128(BT_OCTET16 x, const UINT8 *key_name)
+{
+#if SMP_DEBUG == TRUE && SMP_DEBUG_VERBOSE == TRUE
+ UINT8 *p = (UINT8 *)x;
+ UINT8 i;
+
+ SMP_TRACE_WARNING("%s(MSB ~ LSB) = ", key_name);
+
+ for (i = 0; i < 4; i ++) {
+ SMP_TRACE_WARNING("%02x %02x %02x %02x",
+ p[BT_OCTET16_LEN - i * 4 - 1], p[BT_OCTET16_LEN - i * 4 - 2],
+ p[BT_OCTET16_LEN - i * 4 - 3], p[BT_OCTET16_LEN - i * 4 - 4]);
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function padding
+**
+** Description utility function to padding the given text to be a 128 bits
+** data. The parameter dest is input and output parameter, it
+** must point to a BT_OCTET16_LEN memory space; where include
+** length bytes valid data.
+**
+** Returns void
+**
+*******************************************************************************/
+static void padding ( BT_OCTET16 dest, UINT8 length )
+{
+ UINT8 i, *p = dest;
+ /* original last block */
+ for ( i = length ; i < BT_OCTET16_LEN; i++ ) {
+ p[BT_OCTET16_LEN - i - 1] = ( i == length ) ? 0x80 : 0;
+ }
+}
+/*******************************************************************************
+**
+** Function leftshift_onebit
+**
+** Description utility function to left shift one bit for a 128 bits value.
+**
+** Returns void
+**
+*******************************************************************************/
+static void leftshift_onebit(UINT8 *input, UINT8 *output)
+{
+ UINT8 i, overflow = 0 , next_overflow = 0;
+ SMP_TRACE_EVENT ("leftshift_onebit ");
+ /* input[0] is LSB */
+ for ( i = 0; i < BT_OCTET16_LEN ; i ++ ) {
+ next_overflow = (input[i] & 0x80) ? 1 : 0;
+ output[i] = (input[i] << 1) | overflow;
+ overflow = next_overflow;
+ }
+ return;
+}
+/*******************************************************************************
+**
+** Function cmac_aes_cleanup
+**
+** Description clean up function for AES_CMAC algorithm.
+**
+** Returns void
+**
+*******************************************************************************/
+static void cmac_aes_cleanup(void)
+{
+ if (cmac_cb.text != NULL) {
+ osi_free(cmac_cb.text);
+ }
+ memset(&cmac_cb, 0, sizeof(tCMAC_CB));
+}
+
+/*******************************************************************************
+**
+** Function cmac_aes_k_calculate
+**
+** Description This function is the calculation of block cipher using AES-128.
+**
+** Returns void
+**
+*******************************************************************************/
+static BOOLEAN cmac_aes_k_calculate(BT_OCTET16 key, UINT8 *p_signature, UINT16 tlen)
+{
+ tSMP_ENC output;
+ UINT16 i = 1, err = 0;
+ UINT8 x[16] = {0};
+ UINT8 *p_mac;
+
+ SMP_TRACE_EVENT ("cmac_aes_k_calculate ");
+
+ while (i <= cmac_cb.round) {
+ smp_xor_128(&cmac_cb.text[(cmac_cb.round - i)*BT_OCTET16_LEN], x); /* Mi' := Mi (+) X */
+
+ if (!SMP_Encrypt(key, BT_OCTET16_LEN, &cmac_cb.text[(cmac_cb.round - i)*BT_OCTET16_LEN], BT_OCTET16_LEN, &output)) {
+ err = 1;
+ break;
+ }
+
+ memcpy(x, output.param_buf, BT_OCTET16_LEN);
+ i ++;
+ }
+
+ if (!err) {
+ p_mac = output.param_buf + (BT_OCTET16_LEN - tlen);
+ memcpy(p_signature, p_mac, tlen);
+
+ SMP_TRACE_DEBUG("tlen = %d p_mac = %p", tlen, p_mac);
+ SMP_TRACE_DEBUG("p_mac[0] = 0x%02x p_mac[1] = 0x%02x p_mac[2] = 0x%02x p_mac[3] = 0x%02x",
+ *p_mac, *(p_mac + 1), *(p_mac + 2), *(p_mac + 3));
+ SMP_TRACE_DEBUG("p_mac[4] = 0x%02x p_mac[5] = 0x%02x p_mac[6] = 0x%02x p_mac[7] = 0x%02x",
+ *(p_mac + 4), *(p_mac + 5), *(p_mac + 6), *(p_mac + 7));
+
+ return TRUE;
+
+ } else {
+ return FALSE;
+ }
+}
+/*******************************************************************************
+**
+** Function cmac_prepare_last_block
+**
+** Description This function proceeed to prepare the last block of message
+** Mn depending on the size of the message.
+**
+** Returns void
+**
+*******************************************************************************/
+static void cmac_prepare_last_block (BT_OCTET16 k1, BT_OCTET16 k2)
+{
+// UINT8 x[16] = {0};
+ BOOLEAN flag;
+
+ SMP_TRACE_EVENT ("cmac_prepare_last_block ");
+ /* last block is a complete block set flag to 1 */
+ flag = ((cmac_cb.len % BT_OCTET16_LEN) == 0 && cmac_cb.len != 0) ? TRUE : FALSE;
+
+ SMP_TRACE_DEBUG("flag = %d round = %d", flag, cmac_cb.round);
+
+ if ( flag ) {
+ /* last block is complete block */
+ smp_xor_128(&cmac_cb.text[0], k1);
+ } else { /* padding then xor with k2 */
+ padding(&cmac_cb.text[0], (UINT8)(cmac_cb.len % 16));
+
+ smp_xor_128(&cmac_cb.text[0], k2);
+ }
+}
+/*******************************************************************************
+**
+** Function cmac_subkey_cont
+**
+** Description This is the callback function when CIPHk(0[128]) is completed.
+**
+** Returns void
+**
+*******************************************************************************/
+static void cmac_subkey_cont(tSMP_ENC *p)
+{
+ UINT8 k1[BT_OCTET16_LEN], k2[BT_OCTET16_LEN];
+ UINT8 *pp = p->param_buf;
+ SMP_TRACE_EVENT ("cmac_subkey_cont ");
+ print128(pp, (const UINT8 *)"K1 before shift");
+
+ /* If MSB(L) = 0, then K1 = L << 1 */
+ if ( (pp[BT_OCTET16_LEN - 1] & 0x80) != 0 ) {
+ /* Else K1 = ( L << 1 ) (+) Rb */
+ leftshift_onebit(pp, k1);
+ smp_xor_128(k1, const_Rb);
+ } else {
+ leftshift_onebit(pp, k1);
+ }
+
+ if ( (k1[BT_OCTET16_LEN - 1] & 0x80) != 0 ) {
+ /* K2 = (K1 << 1) (+) Rb */
+ leftshift_onebit(k1, k2);
+ smp_xor_128(k2, const_Rb);
+ } else {
+ /* If MSB(K1) = 0, then K2 = K1 << 1 */
+ leftshift_onebit(k1, k2);
+ }
+
+ print128(k1, (const UINT8 *)"K1");
+ print128(k2, (const UINT8 *)"K2");
+
+ cmac_prepare_last_block (k1, k2);
+}
+/*******************************************************************************
+**
+** Function cmac_generate_subkey
+**
+** Description This is the function to generate the two subkeys.
+**
+** Parameters key - CMAC key, expect SRK when used by SMP.
+**
+** Returns void
+**
+*******************************************************************************/
+static BOOLEAN cmac_generate_subkey(BT_OCTET16 key)
+{
+ BT_OCTET16 z = {0};
+ BOOLEAN ret = TRUE;
+ tSMP_ENC output;
+ SMP_TRACE_EVENT (" cmac_generate_subkey");
+
+ if (SMP_Encrypt(key, BT_OCTET16_LEN, z, BT_OCTET16_LEN, &output)) {
+ cmac_subkey_cont(&output);;
+ } else {
+ ret = FALSE;
+ }
+
+ return ret;
+}
+/*******************************************************************************
+**
+** Function aes_cipher_msg_auth_code
+**
+** Description This is the AES-CMAC Generation Function with tlen implemented.
+**
+** Parameters key - CMAC key in little endian order, expect SRK when used by SMP.
+** input - text to be signed in little endian byte order.
+** length - length of the input in byte.
+** tlen - lenth of mac desired
+** p_signature - data pointer to where signed data to be stored, tlen long.
+**
+** Returns FALSE if out of resources, TRUE in other cases.
+**
+*******************************************************************************/
+BOOLEAN aes_cipher_msg_auth_code(BT_OCTET16 key, UINT8 *input, UINT16 length,
+ UINT16 tlen, UINT8 *p_signature)
+{
+ UINT16 len, diff;
+ UINT16 n = (length + BT_OCTET16_LEN - 1) / BT_OCTET16_LEN; /* n is number of rounds */
+ BOOLEAN ret = FALSE;
+
+ SMP_TRACE_EVENT ("%s", __func__);
+
+ if (n == 0) {
+ n = 1;
+ }
+ len = n * BT_OCTET16_LEN;
+
+ SMP_TRACE_DEBUG("AES128_CMAC started, allocate buffer size = %d", len);
+ /* allocate a memory space of multiple of 16 bytes to hold text */
+ if ((cmac_cb.text = (UINT8 *)osi_malloc(len)) != NULL) {
+ cmac_cb.round = n;
+
+ memset(cmac_cb.text, 0, len);
+ diff = len - length;
+
+ if (input != NULL && length > 0) {
+ memcpy(&cmac_cb.text[diff] , input, (int)length);
+ cmac_cb.len = length;
+ } else {
+ cmac_cb.len = 0;
+ }
+
+ /* prepare calculation for subkey s and last block of data */
+ if (cmac_generate_subkey(key)) {
+ /* start calculation */
+ ret = cmac_aes_k_calculate(key, p_signature, tlen);
+ }
+ /* clean up */
+ cmac_aes_cleanup();
+ } else {
+ ret = FALSE;
+ SMP_TRACE_ERROR("No resources");
+ }
+
+ return ret;
+}
+
+#if 0 /* testing code, sample data from spec */
+void test_cmac_cback(UINT8 *p_mac, UINT16 tlen)
+{
+ SMP_TRACE_EVENT ("test_cmac_cback ");
+ SMP_TRACE_ERROR("test_cmac_cback");
+}
+
+void test_cmac(void)
+{
+ SMP_TRACE_EVENT ("test_cmac ");
+ UINT8 M[64] = {
+ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+ 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+ 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+ 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
+ };
+
+ UINT8 key[16] = {
+ 0x3c, 0x4f, 0xcf, 0x09, 0x88, 0x15, 0xf7, 0xab,
+ 0xa6, 0xd2, 0xae, 0x28, 0x16, 0x15, 0x7e, 0x2b
+ };
+ UINT8 i = 0, tmp;
+ UINT16 len;
+
+ len = 64;
+
+ for (i = 0; i < len / 2; i ++) {
+ tmp = M[i];
+ M[i] = M[len - 1 - i];
+ M[len - 1 - i] = tmp;
+ }
+
+
+ memset(&cmac_cb, 0, sizeof(tCMAC_CB));
+
+ SMP_TRACE_WARNING("\n Example 1: len = %d\n", len);
+
+ aes_cipher_msg_auth_code(key, M, len, 128, test_cmac_cback, 0);
+
+}
+#endif
+#endif
diff --git a/lib/bt/host/bluedroid/stack/smp/smp_keys.c b/lib/bt/host/bluedroid/stack/smp/smp_keys.c
new file mode 100644
index 00000000..aec6f709
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/smp/smp_keys.c
@@ -0,0 +1,2293 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains security manager protocol utility functions
+ *
+ ******************************************************************************/
+#include "common/bt_target.h"
+
+#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
+#if SMP_DEBUG == TRUE
+#include <stdio.h>
+#endif
+#include <string.h>
+//#include "bt_utils.h"
+#include "stack/btm_ble_api.h"
+#include "smp_int.h"
+#include "btm_int.h"
+#include "btm_ble_int.h"
+#include "stack/hcimsgs.h"
+#include "aes.h"
+#include "p_256_ecc_pp.h"
+#include "device/controller.h"
+
+#ifndef SMP_MAX_ENC_REPEAT
+#define SMP_MAX_ENC_REPEAT 3
+#endif
+
+static void smp_rand_back(tBTM_RAND_ENC *p);
+static void smp_generate_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+static void smp_generate_ltk_cont(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+static void smp_generate_y(tSMP_CB *p_cb, tSMP_INT_DATA *p);
+static void smp_generate_rand_vector (tSMP_CB *p_cb, tSMP_INT_DATA *p);
+static void smp_process_stk(tSMP_CB *p_cb, tSMP_ENC *p);
+static void smp_calculate_comfirm_cont(tSMP_CB *p_cb, tSMP_ENC *p);
+static void smp_process_confirm(tSMP_CB *p_cb, tSMP_ENC *p);
+static void smp_process_compare(tSMP_CB *p_cb, tSMP_ENC *p);
+static void smp_process_ediv(tSMP_CB *p_cb, tSMP_ENC *p);
+static BOOLEAN smp_calculate_legacy_short_term_key(tSMP_CB *p_cb, tSMP_ENC *output);
+static void smp_continue_private_key_creation(tSMP_CB *p_cb, tBTM_RAND_ENC *p);
+static void smp_process_private_key(tSMP_CB *p_cb);
+static void smp_finish_nonce_generation(tSMP_CB *p_cb);
+static void smp_process_new_nonce(tSMP_CB *p_cb);
+
+static const tSMP_ACT smp_encrypt_action[] = {
+ smp_generate_compare, /* SMP_GEN_COMPARE */
+ smp_generate_confirm, /* SMP_GEN_CONFIRM*/
+ smp_generate_stk, /* SMP_GEN_STK*/
+ smp_generate_ltk_cont, /* SMP_GEN_LTK */
+ smp_generate_ltk, /* SMP_GEN_DIV_LTK */
+ smp_generate_rand_vector, /* SMP_GEN_RAND_V */
+ smp_generate_y, /* SMP_GEN_EDIV */
+ smp_generate_passkey, /* SMP_GEN_TK */
+ smp_generate_srand_mrand_confirm, /* SMP_GEN_SRAND_MRAND */
+ smp_generate_rand_cont /* SMP_GEN_SRAND_MRAND_CONT */
+};
+
+/* If there is data saved here, then use its info instead
+ * This needs to be cleared on a successful pairing using the oob data
+ */
+static tSMP_LOC_OOB_DATA saved_local_oob_data = {};
+
+void smp_save_local_oob_data(tSMP_CB *p_cb)
+{
+ memcpy(&saved_local_oob_data, &p_cb->sc_oob_data.loc_oob_data, sizeof(tSMP_LOC_OOB_DATA));
+}
+
+void smp_clear_local_oob_data(void)
+{
+ memset(&saved_local_oob_data, 0, sizeof(tSMP_LOC_OOB_DATA));
+}
+
+static BOOLEAN oob_data_is_empty(tSMP_LOC_OOB_DATA *data)
+{
+ tSMP_LOC_OOB_DATA empty_data = {0};
+ return (memcmp(data, &empty_data, sizeof(tSMP_LOC_OOB_DATA)) == 0);
+}
+
+tSMP_LOC_OOB_DATA *smp_get_local_oob_data(void)
+{
+ return &saved_local_oob_data;
+}
+
+void smp_debug_print_nbyte_little_endian(UINT8 *p, const UINT8 *key_name, UINT8 len)
+{
+#if SMP_DEBUG == TRUE
+ int ind, x;
+ int col_count = 32;
+ int row_count;
+ UINT8 p_buf[512];
+
+ SMP_TRACE_WARNING("%s(LSB ~ MSB):\n", key_name);
+ memset(p_buf, 0, sizeof(p_buf));
+ row_count = len % col_count ? len / col_count + 1 : len / col_count;
+
+ ind = 0;
+ for (int row = 0; row < row_count; row++) {
+ for (int column = 0, x = 0; (ind < len) && (column < col_count); column++, ind++) {
+ x += sprintf((char *)&p_buf[x], "%02x ", p[ind]);
+ }
+ SMP_TRACE_WARNING(" [%03d]: %s", row * col_count, p_buf);
+ }
+#endif
+}
+
+#if 0 //Unused
+void smp_debug_print_nbyte_big_endian (UINT8 *p, const UINT8 *key_name, UINT8 len)
+{
+#if SMP_DEBUG == TRUE
+ UINT8 p_buf[512];
+
+ SMP_TRACE_WARNING("%s(MSB ~ LSB):", key_name);
+ memset(p_buf, 0, sizeof(p_buf));
+ nrows = len % ncols ? len / ncols + 1 : len / ncols;
+
+ int ind = 0;
+ int ncols = 32; /* num entries in one line */
+ int nrows; /* num lines */
+ int x;
+
+ for (int row = 0; row < nrows; row++) {
+ for (int col = 0, x = 0; (ind < len) && (col < ncols); col++, ind++) {
+ x += sprintf ((char *)&p_buf[len - x - 1], "%02x ", p[ind]);
+ }
+ SMP_TRACE_WARNING("[%03d]: %s", row * ncols, p_buf);
+ }
+#endif
+}
+#endif
+
+/*******************************************************************************
+**
+** Function smp_encrypt_data
+**
+** Description This function is called to encrypt data.
+** It uses AES-128 encryption algorithm.
+** Plain_text is encrypted using key, the result is at p_out.
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN smp_encrypt_data (UINT8 *key, UINT8 key_len,
+ UINT8 *plain_text, UINT8 pt_len,
+ tSMP_ENC *p_out)
+{
+ aes_context ctx;
+ UINT8 *p_start = NULL;
+ UINT8 *p = NULL;
+ UINT8 *p_rev_data = NULL; /* input data in big endilan format */
+ UINT8 *p_rev_key = NULL; /* input key in big endilan format */
+ UINT8 *p_rev_output = NULL; /* encrypted output in big endilan format */
+
+ SMP_TRACE_DEBUG ("%s\n", __func__);
+ if ( (p_out == NULL ) || (key_len != SMP_ENCRYT_KEY_SIZE) ) {
+ SMP_TRACE_ERROR ("%s failed\n", __func__);
+ return FALSE;
+ }
+
+ if ((p_start = (UINT8 *)osi_malloc((SMP_ENCRYT_DATA_SIZE * 4))) == NULL) {
+ SMP_TRACE_ERROR ("%s failed unable to allocate buffer\n", __func__);
+ return FALSE;
+ }
+
+ if (pt_len > SMP_ENCRYT_DATA_SIZE) {
+ pt_len = SMP_ENCRYT_DATA_SIZE;
+ }
+
+ memset(p_start, 0, SMP_ENCRYT_DATA_SIZE * 4);
+ p = p_start;
+ ARRAY_TO_STREAM (p, plain_text, pt_len); /* byte 0 to byte 15 */
+ p_rev_data = p = p_start + SMP_ENCRYT_DATA_SIZE; /* start at byte 16 */
+ REVERSE_ARRAY_TO_STREAM (p, p_start, SMP_ENCRYT_DATA_SIZE); /* byte 16 to byte 31 */
+ p_rev_key = p; /* start at byte 32 */
+ REVERSE_ARRAY_TO_STREAM (p, key, SMP_ENCRYT_KEY_SIZE); /* byte 32 to byte 47 */
+
+#if SMP_DEBUG == TRUE && SMP_DEBUG_VERBOSE == TRUE
+ smp_debug_print_nbyte_little_endian(key, (const UINT8 *)"Key", SMP_ENCRYT_KEY_SIZE);
+ smp_debug_print_nbyte_little_endian(p_start, (const UINT8 *)"Plain text", SMP_ENCRYT_DATA_SIZE);
+#endif
+ p_rev_output = p;
+ aes_set_key(p_rev_key, SMP_ENCRYT_KEY_SIZE, &ctx);
+ bluedroid_aes_encrypt(p_rev_data, p, &ctx); /* outputs in byte 48 to byte 63 */
+
+ p = p_out->param_buf;
+ REVERSE_ARRAY_TO_STREAM (p, p_rev_output, SMP_ENCRYT_DATA_SIZE);
+#if SMP_DEBUG == TRUE && SMP_DEBUG_VERBOSE == TRUE
+ smp_debug_print_nbyte_little_endian(p_out->param_buf, (const UINT8 *)"Encrypted text", SMP_ENCRYT_KEY_SIZE);
+#endif
+
+ p_out->param_len = SMP_ENCRYT_KEY_SIZE;
+ p_out->status = HCI_SUCCESS;
+ p_out->opcode = HCI_BLE_ENCRYPT;
+
+ osi_free(p_start);
+
+ return TRUE;
+}
+
+void smp_use_static_passkey(void)
+{
+ tSMP_CB *p_cb = &smp_cb;
+ UINT8 *tt = p_cb->tk;
+ tSMP_KEY key;
+ UINT32 passkey = p_cb->static_passkey;
+ /* save the TK */
+ memset(p_cb->tk, 0, BT_OCTET16_LEN);
+ UINT32_TO_STREAM(tt, passkey);
+
+ key.key_type = SMP_KEY_TYPE_TK;
+ key.p_data = p_cb->tk;
+
+ if (p_cb->p_callback) {
+ (*p_cb->p_callback)(SMP_PASSKEY_NOTIF_EVT, p_cb->pairing_bda, (tSMP_EVT_DATA *)&passkey);
+ }
+
+ if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_PASSKEY_DISP) {
+ smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &passkey);
+ } else {
+ smp_sm_event(p_cb, SMP_KEY_READY_EVT, (tSMP_INT_DATA *)&key);
+ }
+}
+/*******************************************************************************
+**
+** Function smp_generate_passkey
+**
+** Description This function is called to generate passkey.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_generate_passkey(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UNUSED(p_data);
+
+ if(p_cb->use_static_passkey) {
+ SMP_TRACE_DEBUG ("%s use static passkey %6d", __func__, p_cb->static_passkey);
+ smp_use_static_passkey();
+ return;
+ }
+ SMP_TRACE_DEBUG ("%s generate rand passkey", __func__);
+ p_cb->rand_enc_proc_state = SMP_GEN_TK;
+
+ /* generate MRand or SRand */
+ if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) {
+ smp_rand_back(NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_proc_passkey
+**
+** Description This function is called to process a passkey.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_proc_passkey(tSMP_CB *p_cb , tBTM_RAND_ENC *p)
+{
+ UINT8 *tt = p_cb->tk;
+ tSMP_KEY key;
+ UINT32 passkey; /* 19655 test number; */
+ UINT8 *pp = p->param_buf;
+
+ SMP_TRACE_DEBUG ("%s", __func__);
+ STREAM_TO_UINT32(passkey, pp);
+ passkey &= ~SMP_PASSKEY_MASK;
+
+ /* truncate by maximum value */
+ while (passkey > BTM_MAX_PASSKEY_VAL) {
+ passkey >>= 1;
+ }
+
+ /* save the TK */
+ memset(p_cb->tk, 0, BT_OCTET16_LEN);
+ UINT32_TO_STREAM(tt, passkey);
+
+ key.key_type = SMP_KEY_TYPE_TK;
+ key.p_data = p_cb->tk;
+
+ if (p_cb->p_callback) {
+ (*p_cb->p_callback)(SMP_PASSKEY_NOTIF_EVT, p_cb->pairing_bda, (tSMP_EVT_DATA *)&passkey);
+ }
+
+ if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_PASSKEY_DISP) {
+ smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &passkey);
+ } else {
+ smp_sm_event(p_cb, SMP_KEY_READY_EVT, (tSMP_INT_DATA *)&key);
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_generate_stk
+**
+** Description This function is called to generate STK calculated by running
+** AES with the TK value as key and a concatenation of the random
+** values.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_generate_stk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UNUSED(p_data);
+
+ tSMP_ENC output;
+ tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+ SMP_TRACE_DEBUG ("%s\n", __func__);
+
+ if (p_cb->le_secure_connections_mode_is_used) {
+ SMP_TRACE_WARNING ("FOR LE SC LTK IS USED INSTEAD OF STK");
+ output.param_len = SMP_ENCRYT_KEY_SIZE;
+ output.status = HCI_SUCCESS;
+ output.opcode = HCI_BLE_ENCRYPT;
+ memcpy(output.param_buf, p_cb->ltk, SMP_ENCRYT_DATA_SIZE);
+ } else if (!smp_calculate_legacy_short_term_key(p_cb, &output)) {
+ SMP_TRACE_ERROR("%s failed", __func__);
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ return;
+ }
+
+ smp_process_stk(p_cb, &output);
+}
+
+/*******************************************************************************
+**
+** Function smp_generate_srand_mrand_confirm
+**
+** Description This function is called to start the second pairing phase by
+** start generating random number.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_generate_srand_mrand_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UNUSED(p_data);
+
+ SMP_TRACE_DEBUG ("%s\n", __func__);
+ p_cb->rand_enc_proc_state = SMP_GEN_SRAND_MRAND;
+ /* generate MRand or SRand */
+ if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) {
+ smp_rand_back(NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_generate_rand_cont
+**
+** Description This function is called to generate another 64 bits random for
+** MRand or Srand.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_generate_rand_cont(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UNUSED(p_data);
+
+ SMP_TRACE_DEBUG ("%s\n", __func__);
+ p_cb->rand_enc_proc_state = SMP_GEN_SRAND_MRAND_CONT;
+ /* generate 64 MSB of MRand or SRand */
+ if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) {
+ smp_rand_back(NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_generate_ltk
+**
+** Description This function is called:
+** - in legacy pairing - to calculate LTK, starting with DIV
+** generation;
+** - in LE Secure Connections pairing over LE transport - to process LTK
+** already generated to encrypt LE link;
+** - in LE Secure Connections pairing over BR/EDR transport - to start
+** BR/EDR Link Key processing.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_generate_ltk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UNUSED(p_data);
+
+ BOOLEAN div_status;
+ SMP_TRACE_DEBUG ("%s\n", __FUNCTION__);
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ if (smp_get_br_state() == SMP_BR_STATE_BOND_PENDING) {
+ smp_br_process_link_key(p_cb, NULL);
+ return;
+ }
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+ if (p_cb->le_secure_connections_mode_is_used) {
+ smp_process_secure_connection_long_term_key();
+ return;
+ }
+
+ div_status = btm_get_local_div(p_cb->pairing_bda, &p_cb->div);
+
+ if (div_status) {
+ smp_generate_ltk_cont(p_cb, NULL);
+ } else {
+ SMP_TRACE_DEBUG ("Generate DIV for LTK\n");
+ p_cb->rand_enc_proc_state = SMP_GEN_DIV_LTK;
+ /* generate MRand or SRand */
+ if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) {
+ smp_rand_back(NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_compute_csrk
+**
+** Description This function is called to calculate CSRK
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_compute_csrk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UNUSED(p_data);
+
+ BT_OCTET16 er;
+ UINT8 buffer[4]; /* for (r || DIV) r=1*/
+ UINT16 r = 1;
+ UINT8 *p = buffer;
+ tSMP_ENC output;
+ tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+ SMP_TRACE_DEBUG ("smp_compute_csrk div=%x\n", p_cb->div);
+ BTM_GetDeviceEncRoot(er);
+ /* CSRK = d1(ER, DIV, 1) */
+ UINT16_TO_STREAM(p, p_cb->div);
+ UINT16_TO_STREAM(p, r);
+
+ if (!SMP_Encrypt(er, BT_OCTET16_LEN, buffer, 4, &output)) {
+ SMP_TRACE_ERROR("smp_generate_csrk failed\n");
+ if (p_cb->smp_over_br) {
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &status);
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+ } else {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ }
+ } else {
+ memcpy((void *)p_cb->csrk, output.param_buf, BT_OCTET16_LEN);
+ smp_send_csrk_info(p_cb, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_generate_csrk
+**
+** Description This function is called to calculate CSRK, starting with DIV
+** generation.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_generate_csrk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UNUSED(p_data);
+
+ BOOLEAN div_status;
+
+ SMP_TRACE_DEBUG ("smp_generate_csrk");
+
+ div_status = btm_get_local_div(p_cb->pairing_bda, &p_cb->div);
+ if (div_status) {
+ smp_compute_csrk(p_cb, NULL);
+ } else {
+ SMP_TRACE_DEBUG ("Generate DIV for CSRK");
+ p_cb->rand_enc_proc_state = SMP_GEN_DIV_CSRK;
+ if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) {
+ smp_rand_back(NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+** Function smp_concatenate_peer
+** add pairing command sent from local device into p1.
+*******************************************************************************/
+void smp_concatenate_local( tSMP_CB *p_cb, UINT8 **p_data, UINT8 op_code)
+{
+ UINT8 *p = *p_data;
+
+ SMP_TRACE_DEBUG ("%s\n", __func__);
+ UINT8_TO_STREAM(p, op_code);
+ UINT8_TO_STREAM(p, p_cb->local_io_capability);
+ UINT8_TO_STREAM(p, p_cb->loc_oob_flag);
+ UINT8_TO_STREAM(p, p_cb->loc_auth_req);
+ UINT8_TO_STREAM(p, p_cb->loc_enc_size);
+ UINT8_TO_STREAM(p, p_cb->local_i_key);
+ UINT8_TO_STREAM(p, p_cb->local_r_key);
+
+ *p_data = p;
+}
+
+/*******************************************************************************
+** Function smp_concatenate_peer
+** add pairing command received from peer device into p1.
+*******************************************************************************/
+void smp_concatenate_peer( tSMP_CB *p_cb, UINT8 **p_data, UINT8 op_code)
+{
+ UINT8 *p = *p_data;
+
+ SMP_TRACE_DEBUG ("smp_concatenate_peer \n");
+ UINT8_TO_STREAM(p, op_code);
+ UINT8_TO_STREAM(p, p_cb->peer_io_caps);
+ UINT8_TO_STREAM(p, p_cb->peer_oob_flag);
+ UINT8_TO_STREAM(p, p_cb->peer_auth_req);
+ UINT8_TO_STREAM(p, p_cb->peer_enc_size);
+ UINT8_TO_STREAM(p, p_cb->peer_i_key);
+ UINT8_TO_STREAM(p, p_cb->peer_r_key);
+
+ *p_data = p;
+}
+
+/*******************************************************************************
+**
+** Function smp_gen_p1_4_confirm
+**
+** Description Generate Confirm/Compare Step1:
+** p1 = pres || preq || rat' || iat'
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_gen_p1_4_confirm( tSMP_CB *p_cb, BT_OCTET16 p1)
+{
+ UINT8 *p = (UINT8 *)p1;
+ tBLE_ADDR_TYPE addr_type = 0;
+ BD_ADDR remote_bda;
+
+ SMP_TRACE_DEBUG ("smp_gen_p1_4_confirm\n");
+
+ if (!BTM_ReadRemoteConnectionAddr(p_cb->pairing_bda, remote_bda, &addr_type)) {
+ SMP_TRACE_ERROR("can not generate confirm for unknown device\n");
+ return;
+ }
+
+ BTM_ReadConnectionAddr( p_cb->pairing_bda, p_cb->local_bda, &p_cb->addr_type);
+
+ if (p_cb->role == HCI_ROLE_MASTER) {
+ /* LSB : rat': initiator's(local) address type */
+ UINT8_TO_STREAM(p, p_cb->addr_type);
+ /* LSB : iat': responder's address type */
+ UINT8_TO_STREAM(p, addr_type);
+ /* concatinate preq */
+ smp_concatenate_local(p_cb, &p, SMP_OPCODE_PAIRING_REQ);
+ /* concatinate pres */
+ smp_concatenate_peer(p_cb, &p, SMP_OPCODE_PAIRING_RSP);
+ } else {
+ /* LSB : iat': initiator's address type */
+ UINT8_TO_STREAM(p, addr_type);
+ /* LSB : rat': responder's(local) address type */
+ UINT8_TO_STREAM(p, p_cb->addr_type);
+ /* concatinate preq */
+ smp_concatenate_peer(p_cb, &p, SMP_OPCODE_PAIRING_REQ);
+ /* concatinate pres */
+ smp_concatenate_local(p_cb, &p, SMP_OPCODE_PAIRING_RSP);
+ }
+#if SMP_DEBUG == TRUE
+ SMP_TRACE_DEBUG("p1 = pres || preq || rat' || iat'\n");
+ smp_debug_print_nbyte_little_endian ((UINT8 *)p1, (const UINT8 *)"P1", 16);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function smp_gen_p2_4_confirm
+**
+** Description Generate Confirm/Compare Step2:
+** p2 = padding || ia || ra
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_gen_p2_4_confirm( tSMP_CB *p_cb, BT_OCTET16 p2)
+{
+ UINT8 *p = (UINT8 *)p2;
+ BD_ADDR remote_bda;
+ tBLE_ADDR_TYPE addr_type = 0;
+ SMP_TRACE_DEBUG ("smp_gen_p2_4_confirm\n");
+ if (!BTM_ReadRemoteConnectionAddr(p_cb->pairing_bda, remote_bda, &addr_type)) {
+ SMP_TRACE_ERROR("can not generate confirm p2 for unknown device\n");
+ return;
+ }
+
+ SMP_TRACE_DEBUG ("smp_gen_p2_4_confirm\n");
+
+ memset(p, 0, sizeof(BT_OCTET16));
+
+ if (p_cb->role == HCI_ROLE_MASTER) {
+ /* LSB ra */
+ BDADDR_TO_STREAM(p, remote_bda);
+ /* ia */
+ BDADDR_TO_STREAM(p, p_cb->local_bda);
+ } else {
+ /* LSB ra */
+ BDADDR_TO_STREAM(p, p_cb->local_bda);
+ /* ia */
+ BDADDR_TO_STREAM(p, remote_bda);
+ }
+#if SMP_DEBUG == TRUE
+ SMP_TRACE_DEBUG("p2 = padding || ia || ra");
+ smp_debug_print_nbyte_little_endian(p2, (const UINT8 *)"p2", 16);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function smp_calculate_comfirm
+**
+** Description This function is called to calculate Confirm value.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_calculate_comfirm (tSMP_CB *p_cb, BT_OCTET16 rand, BD_ADDR bda)
+{
+ UNUSED(bda);
+
+ BT_OCTET16 p1;
+ tSMP_ENC output;
+ tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+ SMP_TRACE_DEBUG ("smp_calculate_comfirm \n");
+ /* generate p1 = pres || preq || rat' || iat' */
+ smp_gen_p1_4_confirm(p_cb, p1);
+
+ /* p1 = rand XOR p1 */
+ smp_xor_128(p1, rand);
+
+ smp_debug_print_nbyte_little_endian ((UINT8 *)p1, (const UINT8 *)"P1' = r XOR p1", 16);
+
+ /* calculate e(k, r XOR p1), where k = TK */
+ if (!SMP_Encrypt(p_cb->tk, BT_OCTET16_LEN, p1, BT_OCTET16_LEN, &output)) {
+ SMP_TRACE_ERROR("smp_generate_csrk failed");
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ } else {
+ smp_calculate_comfirm_cont(p_cb, &output);
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_calculate_comfirm_cont
+**
+** Description This function is called when SConfirm/MConfirm is generated
+** proceed to send the Confirm request/response to peer device.
+**
+** Returns void
+**
+*******************************************************************************/
+static void smp_calculate_comfirm_cont(tSMP_CB *p_cb, tSMP_ENC *p)
+{
+ BT_OCTET16 p2;
+ tSMP_ENC output;
+ tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+ SMP_TRACE_DEBUG ("smp_calculate_comfirm_cont \n");
+#if SMP_DEBUG == TRUE
+ SMP_TRACE_DEBUG("Confirm step 1 p1' = e(k, r XOR p1) Generated\n");
+ smp_debug_print_nbyte_little_endian (p->param_buf, (const UINT8 *)"C1", 16);
+#endif
+
+ smp_gen_p2_4_confirm(p_cb, p2);
+
+ /* calculate p2 = (p1' XOR p2) */
+ smp_xor_128(p2, p->param_buf);
+ smp_debug_print_nbyte_little_endian ((UINT8 *)p2, (const UINT8 *)"p2' = C1 xor p2", 16);
+
+ /* calculate: Confirm = E(k, p1' XOR p2) */
+ if (!SMP_Encrypt(p_cb->tk, BT_OCTET16_LEN, p2, BT_OCTET16_LEN, &output)) {
+ SMP_TRACE_ERROR("smp_calculate_comfirm_cont failed\n");
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ } else {
+ SMP_TRACE_DEBUG("p_cb->rand_enc_proc_state=%d\n", p_cb->rand_enc_proc_state);
+ switch (p_cb->rand_enc_proc_state) {
+ case SMP_GEN_CONFIRM:
+ smp_process_confirm(p_cb, &output);
+ break;
+
+ case SMP_GEN_COMPARE:
+ smp_process_compare(p_cb, &output);
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_generate_confirm
+**
+** Description This function is called when a 48 bits random number is generated
+** as SRand or MRand, continue to calculate Sconfirm or MConfirm.
+**
+** Returns void
+**
+*******************************************************************************/
+static void smp_generate_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UNUSED(p_data);
+
+ SMP_TRACE_DEBUG ("%s\n", __func__);
+ p_cb->rand_enc_proc_state = SMP_GEN_CONFIRM;
+ smp_debug_print_nbyte_little_endian ((UINT8 *)p_cb->rand, (const UINT8 *)"local rand", 16);
+ smp_calculate_comfirm(p_cb, p_cb->rand, p_cb->pairing_bda);
+}
+
+/*******************************************************************************
+**
+** Function smp_generate_compare
+**
+** Description This function is called to generate SConfirm for Slave device,
+** or MSlave for Master device. This function can be also used for
+** generating Compare number for confirm value check.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_generate_compare (tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UNUSED(p_data);
+
+ SMP_TRACE_DEBUG ("smp_generate_compare \n");
+ p_cb->rand_enc_proc_state = SMP_GEN_COMPARE;
+ smp_debug_print_nbyte_little_endian ((UINT8 *)p_cb->rrand, (const UINT8 *)"peer rand", 16);
+ smp_calculate_comfirm(p_cb, p_cb->rrand, p_cb->local_bda);
+}
+
+/*******************************************************************************
+**
+** Function smp_process_confirm
+**
+** Description This function is called when SConfirm/MConfirm is generated
+** proceed to send the Confirm request/response to peer device.
+**
+** Returns void
+**
+*******************************************************************************/
+static void smp_process_confirm(tSMP_CB *p_cb, tSMP_ENC *p)
+{
+ tSMP_KEY key;
+
+ SMP_TRACE_DEBUG ("%s\n", __FUNCTION__);
+ memcpy(p_cb->confirm, p->param_buf, BT_OCTET16_LEN);
+
+#if (SMP_DEBUG == TRUE)
+ SMP_TRACE_DEBUG("Confirm Generated");
+ smp_debug_print_nbyte_little_endian ((UINT8 *)p_cb->confirm, (const UINT8 *)"Confirm", 16);
+#endif
+
+ key.key_type = SMP_KEY_TYPE_CFM;
+ key.p_data = p->param_buf;
+
+ smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key);
+
+}
+
+/*******************************************************************************
+**
+** Function smp_process_compare
+**
+** Description This function is called when Compare is generated using the
+** RRand and local BDA, TK information.
+**
+** Returns void
+**
+*******************************************************************************/
+static void smp_process_compare(tSMP_CB *p_cb, tSMP_ENC *p)
+{
+ tSMP_KEY key;
+
+ SMP_TRACE_DEBUG ("smp_process_compare \n");
+#if (SMP_DEBUG == TRUE)
+ SMP_TRACE_DEBUG("Compare Generated\n");
+ smp_debug_print_nbyte_little_endian (p->param_buf, (const UINT8 *)"Compare", 16);
+#endif
+ key.key_type = SMP_KEY_TYPE_CMP;
+ key.p_data = p->param_buf;
+ //smp_set_state(SMP_STATE_CONFIRM);
+ smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key);
+}
+
+/*******************************************************************************
+**
+** Function smp_process_stk
+**
+** Description This function is called when STK is generated
+** proceed to send the encrypt the link using STK.
+**
+** Returns void
+**
+*******************************************************************************/
+static void smp_process_stk(tSMP_CB *p_cb, tSMP_ENC *p)
+{
+ tSMP_KEY key;
+
+ SMP_TRACE_DEBUG ("smp_process_stk ");
+#if (SMP_DEBUG == TRUE)
+ SMP_TRACE_ERROR("STK Generated");
+#endif
+ smp_mask_enc_key(p_cb->loc_enc_size, p->param_buf);
+
+ key.key_type = SMP_KEY_TYPE_STK;
+ key.p_data = p->param_buf;
+
+ smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key);
+}
+
+/*******************************************************************************
+**
+** Function smp_generate_ltk_cont
+**
+** Description This function is to calculate LTK = d1(ER, DIV, 0)= e(ER, DIV)
+**
+** Returns void
+**
+*******************************************************************************/
+static void smp_generate_ltk_cont(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UNUSED(p_data);
+
+ BT_OCTET16 er;
+ tSMP_ENC output;
+ tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+ SMP_TRACE_DEBUG ("%s\n", __func__);
+ BTM_GetDeviceEncRoot(er);
+
+ /* LTK = d1(ER, DIV, 0)= e(ER, DIV)*/
+ if (!SMP_Encrypt(er, BT_OCTET16_LEN, (UINT8 *)&p_cb->div,
+ sizeof(UINT16), &output)) {
+ SMP_TRACE_ERROR("%s failed\n", __func__);
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ } else {
+ /* mask the LTK */
+ smp_mask_enc_key(p_cb->loc_enc_size, output.param_buf);
+ memcpy((void *)p_cb->ltk, output.param_buf, BT_OCTET16_LEN);
+ smp_generate_rand_vector(p_cb, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_generate_y
+**
+** Description This function is to proceed generate Y = E(DHK, Rand)
+**
+** Returns void
+**
+*******************************************************************************/
+static void smp_generate_y(tSMP_CB *p_cb, tSMP_INT_DATA *p)
+{
+ UNUSED(p);
+
+ BT_OCTET16 dhk;
+ tSMP_ENC output;
+ tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+
+ SMP_TRACE_DEBUG ("smp_generate_y \n");
+ BTM_GetDeviceDHK(dhk);
+
+ if (!SMP_Encrypt(dhk, BT_OCTET16_LEN, p_cb->enc_rand,
+ BT_OCTET8_LEN, &output)) {
+ SMP_TRACE_ERROR("smp_generate_y failed");
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ } else {
+ smp_process_ediv(p_cb, &output);
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_generate_rand_vector
+**
+** Description This function is called when LTK is generated, send state machine
+** event to SMP.
+**
+** Returns void
+**
+*******************************************************************************/
+static void smp_generate_rand_vector (tSMP_CB *p_cb, tSMP_INT_DATA *p)
+{
+ UNUSED(p);
+
+ /* generate EDIV and rand now */
+ /* generate random vector */
+ SMP_TRACE_DEBUG ("smp_generate_rand_vector\n");
+ p_cb->rand_enc_proc_state = SMP_GEN_RAND_V;
+ if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) {
+ smp_rand_back(NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_process_ediv
+**
+** Description This function is to calculate EDIV = Y xor DIV
+**
+** Returns void
+**
+*******************************************************************************/
+static void smp_process_ediv(tSMP_CB *p_cb, tSMP_ENC *p)
+{
+ tSMP_KEY key;
+ UINT8 *pp = p->param_buf;
+ UINT16 y;
+
+ SMP_TRACE_DEBUG ("smp_process_ediv ");
+ STREAM_TO_UINT16(y, pp);
+
+ /* EDIV = Y xor DIV */
+ p_cb->ediv = p_cb->div ^ y;
+ /* send LTK ready */
+ SMP_TRACE_DEBUG("LTK ready");
+ key.key_type = SMP_KEY_TYPE_LTK;
+ key.p_data = p->param_buf;
+
+ smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key);
+}
+
+/*******************************************************************************
+**
+** Function smp_calculate_legacy_short_term_key
+**
+** Description The function calculates legacy STK.
+**
+** Returns FALSE if out of resources, TRUE in other cases.
+**
+*******************************************************************************/
+BOOLEAN smp_calculate_legacy_short_term_key(tSMP_CB *p_cb, tSMP_ENC *output)
+{
+ BT_OCTET16 ptext;
+ UINT8 *p = ptext;
+
+ SMP_TRACE_DEBUG ("%s\n", __func__);
+ memset(p, 0, BT_OCTET16_LEN);
+ if (p_cb->role == HCI_ROLE_MASTER) {
+ memcpy(p, p_cb->rand, BT_OCTET8_LEN);
+ memcpy(&p[BT_OCTET8_LEN], p_cb->rrand, BT_OCTET8_LEN);
+ } else {
+ memcpy(p, p_cb->rrand, BT_OCTET8_LEN);
+ memcpy(&p[BT_OCTET8_LEN], p_cb->rand, BT_OCTET8_LEN);
+ }
+
+ BOOLEAN encrypted;
+ /* generate STK = Etk(rand|rrand)*/
+ encrypted = SMP_Encrypt( p_cb->tk, BT_OCTET16_LEN, ptext, BT_OCTET16_LEN, output);
+ if (!encrypted) {
+ SMP_TRACE_ERROR("%s failed\n", __func__);
+ }
+ return encrypted;
+}
+
+/*******************************************************************************
+**
+** Function smp_create_private_key
+**
+** Description This function is called to create private key used to
+** calculate public key and DHKey.
+** The function starts private key creation requesting controller
+** to generate [0-7] octets of private key.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_create_private_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_OOB) {
+ SMP_TRACE_EVENT("OOB Association Model");
+ if (!oob_data_is_empty(&saved_local_oob_data)) {
+ SMP_TRACE_EVENT("Found OOB data, loading keys");
+ memcpy(&p_cb->sc_oob_data.loc_oob_data, &saved_local_oob_data, sizeof(tSMP_LOC_OOB_DATA));
+ smp_process_private_key(p_cb);
+ return;
+ }
+ SMP_TRACE_EVENT("OOB Association Model with no saved data");
+ }
+
+ p_cb->rand_enc_proc_state = SMP_GENERATE_PRIVATE_KEY_0_7;
+ if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) {
+ smp_rand_back(NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_use_oob_private_key
+**
+** Description This function is called
+** - to save the secret key used to calculate the public key used
+** in calculations of commitment sent OOB to a peer
+** - to use this secret key to recalculate the public key and
+** start the process of sending this public key to the peer
+** if secret/public keys have to be reused.
+** If the keys aren't supposed to be reused, continue from the
+** point from which request for OOB data was issued.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_use_oob_private_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG ("%s req_oob_type: %d, role: %d\n",
+ __func__, p_cb->req_oob_type, p_cb->role);
+
+ switch (p_cb->req_oob_type) {
+ case SMP_OOB_BOTH:
+ case SMP_OOB_LOCAL:
+ SMP_TRACE_DEBUG("%s restore secret key\n", __func__);
+ // copy private key in smp_process_private_key
+ smp_process_private_key(p_cb);
+ break;
+ default:
+ SMP_TRACE_DEBUG("%s create secret key anew\n", __func__);
+ smp_set_state(SMP_STATE_PAIR_REQ_RSP);
+ smp_decide_association_model(p_cb, NULL);
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_continue_private_key_creation
+**
+** Description This function is used to continue private key creation.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_continue_private_key_creation (tSMP_CB *p_cb, tBTM_RAND_ENC *p)
+{
+ UINT8 state = p_cb->rand_enc_proc_state & ~0x80;
+ SMP_TRACE_DEBUG ("%s state=0x%x\n", __func__, state);
+
+ switch (state) {
+ case SMP_GENERATE_PRIVATE_KEY_0_7:
+ memcpy((void *)p_cb->private_key, p->param_buf, p->param_len);
+ p_cb->rand_enc_proc_state = SMP_GENERATE_PRIVATE_KEY_8_15;
+ if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) {
+ smp_rand_back(NULL);
+ }
+ break;
+
+ case SMP_GENERATE_PRIVATE_KEY_8_15:
+ memcpy((void *)&p_cb->private_key[8], p->param_buf, p->param_len);
+ p_cb->rand_enc_proc_state = SMP_GENERATE_PRIVATE_KEY_16_23;
+ if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) {
+ smp_rand_back(NULL);
+ }
+ break;
+
+ case SMP_GENERATE_PRIVATE_KEY_16_23:
+ memcpy((void *)&p_cb->private_key[16], p->param_buf, p->param_len);
+ p_cb->rand_enc_proc_state = SMP_GENERATE_PRIVATE_KEY_24_31;
+ if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) {
+ smp_rand_back(NULL);
+ }
+ break;
+
+ case SMP_GENERATE_PRIVATE_KEY_24_31:
+ memcpy((void *)&p_cb->private_key[24], p->param_buf, p->param_len);
+ smp_process_private_key (p_cb);
+ break;
+
+ default:
+ break;
+ }
+
+ return;
+}
+
+/*******************************************************************************
+**
+** Function smp_process_private_key
+**
+** Description This function processes private key.
+** It calculates public key and notifies SM that private key /
+** public key pair is created.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_process_private_key(tSMP_CB *p_cb)
+{
+ Point public_key;
+ BT_OCTET32 private_key;
+ tSMP_LOC_OOB_DATA *p_loc_oob = &p_cb->sc_oob_data.loc_oob_data;
+
+ SMP_TRACE_DEBUG ("%s", __FUNCTION__);
+
+ /* if local oob data present, then restore oob private and public key */
+ if (p_loc_oob->present) {
+ memcpy(p_cb->private_key, p_loc_oob->private_key_used, BT_OCTET32_LEN);
+ memcpy(p_cb->loc_publ_key.x, p_loc_oob->publ_key_used.x, BT_OCTET32_LEN);
+ memcpy(p_cb->loc_publ_key.y, p_loc_oob->publ_key_used.y, BT_OCTET32_LEN);
+ memcpy(p_cb->local_random, p_loc_oob->randomizer, BT_OCTET16_LEN);
+ } else {
+ memcpy(private_key, p_cb->private_key, BT_OCTET32_LEN);
+ ECC_PointMult(&public_key, &(curve_p256.G), (DWORD *) private_key, KEY_LENGTH_DWORDS_P256);
+ memcpy(p_cb->loc_publ_key.x, public_key.x, BT_OCTET32_LEN);
+ memcpy(p_cb->loc_publ_key.y, public_key.y, BT_OCTET32_LEN);
+ }
+
+ smp_debug_print_nbyte_little_endian (p_cb->private_key, (const UINT8 *)"private",
+ BT_OCTET32_LEN);
+ smp_debug_print_nbyte_little_endian (p_cb->loc_publ_key.x, (const UINT8 *)"local public(x)",
+ BT_OCTET32_LEN);
+ smp_debug_print_nbyte_little_endian (p_cb->loc_publ_key.y, (const UINT8 *)"local public(y)",
+ BT_OCTET32_LEN);
+ p_cb->flags |= SMP_PAIR_FLAG_HAVE_LOCAL_PUBL_KEY;
+ smp_sm_event(p_cb, SMP_LOC_PUBL_KEY_CRTD_EVT, NULL);
+}
+
+/*******************************************************************************
+**
+** Function smp_compute_dhkey
+**
+** Description The function:
+** - calculates a new public key using as input local private
+** key and peer public key;
+** - saves the new public key x-coordinate as DHKey.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_compute_dhkey (tSMP_CB *p_cb)
+{
+ Point peer_publ_key, new_publ_key;
+ BT_OCTET32 private_key;
+
+ SMP_TRACE_DEBUG ("%s\n", __FUNCTION__);
+
+ memcpy(private_key, p_cb->private_key, BT_OCTET32_LEN);
+ memcpy(peer_publ_key.x, p_cb->peer_publ_key.x, BT_OCTET32_LEN);
+ memcpy(peer_publ_key.y, p_cb->peer_publ_key.y, BT_OCTET32_LEN);
+
+ ECC_PointMult(&new_publ_key, &peer_publ_key, (DWORD *) private_key, KEY_LENGTH_DWORDS_P256);
+
+ memcpy(p_cb->dhkey, new_publ_key.x, BT_OCTET32_LEN);
+
+ smp_debug_print_nbyte_little_endian (p_cb->dhkey, (const UINT8 *)"Old DHKey",
+ BT_OCTET32_LEN);
+
+ smp_debug_print_nbyte_little_endian (p_cb->private_key, (const UINT8 *)"private",
+ BT_OCTET32_LEN);
+ smp_debug_print_nbyte_little_endian (p_cb->peer_publ_key.x, (const UINT8 *)"rem public(x)",
+ BT_OCTET32_LEN);
+ smp_debug_print_nbyte_little_endian (p_cb->peer_publ_key.y, (const UINT8 *)"rem public(y)",
+ BT_OCTET32_LEN);
+ smp_debug_print_nbyte_little_endian (p_cb->dhkey, (const UINT8 *)"Reverted DHKey",
+ BT_OCTET32_LEN);
+}
+
+/*******************************************************************************
+**
+** Function smp_calculate_local_commitment
+**
+** Description The function calculates and saves local commmitment in CB.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_calculate_local_commitment(tSMP_CB *p_cb)
+{
+ UINT8 random_input;
+
+ SMP_TRACE_DEBUG("%s\n", __FUNCTION__);
+
+ switch (p_cb->selected_association_model) {
+ case SMP_MODEL_SEC_CONN_JUSTWORKS:
+ case SMP_MODEL_SEC_CONN_NUM_COMP:
+ if (p_cb->role == HCI_ROLE_MASTER) {
+ SMP_TRACE_WARNING ("local commitment calc on master is not expected \
+ for Just Works/Numeric Comparison models\n");
+ }
+ smp_calculate_f4(p_cb->loc_publ_key.x, p_cb->peer_publ_key.x, p_cb->rand, 0,
+ p_cb->commitment);
+ break;
+ case SMP_MODEL_SEC_CONN_PASSKEY_ENT:
+ case SMP_MODEL_SEC_CONN_PASSKEY_DISP:
+ random_input = smp_calculate_random_input(p_cb->local_random, p_cb->round);
+ smp_calculate_f4(p_cb->loc_publ_key.x, p_cb->peer_publ_key.x, p_cb->rand,
+ random_input, p_cb->commitment);
+ break;
+ case SMP_MODEL_SEC_CONN_OOB:
+ SMP_TRACE_WARNING ("local commitment calc is expected for OOB model BEFORE pairing\n");
+ smp_calculate_f4(p_cb->loc_publ_key.x, p_cb->loc_publ_key.x, p_cb->local_random, 0,
+ p_cb->commitment);
+ break;
+ default:
+ SMP_TRACE_ERROR("Association Model = %d is not used in LE SC\n",
+ p_cb->selected_association_model);
+ return;
+ }
+
+ SMP_TRACE_EVENT ("local commitment calculation is completed");
+}
+
+/*******************************************************************************
+**
+** Function smp_calculate_peer_commitment
+**
+** Description The function calculates and saves peer commmitment at the
+** provided output buffer.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_calculate_peer_commitment(tSMP_CB *p_cb, BT_OCTET16 output_buf)
+{
+ UINT8 ri;
+
+ SMP_TRACE_DEBUG ("%s", __FUNCTION__);
+
+ switch (p_cb->selected_association_model) {
+ case SMP_MODEL_SEC_CONN_JUSTWORKS:
+ case SMP_MODEL_SEC_CONN_NUM_COMP:
+ if (p_cb->role == HCI_ROLE_SLAVE) {
+ SMP_TRACE_WARNING ("peer commitment calc on slave is not expected \
+ for Just Works/Numeric Comparison models\n");
+ }
+ smp_calculate_f4(p_cb->peer_publ_key.x, p_cb->loc_publ_key.x, p_cb->rrand, 0,
+ output_buf);
+ break;
+ case SMP_MODEL_SEC_CONN_PASSKEY_ENT:
+ case SMP_MODEL_SEC_CONN_PASSKEY_DISP:
+ ri = smp_calculate_random_input(p_cb->peer_random, p_cb->round);
+ smp_calculate_f4(p_cb->peer_publ_key.x, p_cb->loc_publ_key.x, p_cb->rrand, ri,
+ output_buf);
+ break;
+ case SMP_MODEL_SEC_CONN_OOB:
+ smp_calculate_f4(p_cb->peer_publ_key.x, p_cb->peer_publ_key.x, p_cb->peer_random, 0,
+ output_buf);
+ break;
+ default:
+ SMP_TRACE_ERROR("Association Model = %d is not used in LE SC\n",
+ p_cb->selected_association_model);
+ return;
+ }
+
+ SMP_TRACE_EVENT ("peer commitment calculation is completed\n");
+}
+
+/*******************************************************************************
+**
+** Function smp_calculate_f4
+**
+** Description The function calculates
+** C = f4(U, V, X, Z) = AES-CMAC (U||V||Z)
+** X
+** where
+** input: U is 256 bit,
+** V is 256 bit,
+** X is 128 bit,
+** Z is 8 bit,
+** output: C is 128 bit.
+**
+** Returns void
+**
+** Note The LSB is the first octet, the MSB is the last octet of
+** the AES-CMAC input/output stream.
+**
+*******************************************************************************/
+void smp_calculate_f4(UINT8 *u, UINT8 *v, UINT8 *x, UINT8 z, UINT8 *c)
+{
+ UINT8 msg_len = BT_OCTET32_LEN /* U size */ + BT_OCTET32_LEN /* V size */ + 1 /* Z size */;
+ UINT8 msg[BT_OCTET32_LEN + BT_OCTET32_LEN + 1];
+ UINT8 key[BT_OCTET16_LEN];
+ UINT8 cmac[BT_OCTET16_LEN];
+ UINT8 *p = NULL;
+#if SMP_DEBUG == TRUE
+ UINT8 *p_prnt = NULL;
+#endif
+
+ SMP_TRACE_DEBUG ("%s", __FUNCTION__);
+
+#if SMP_DEBUG == TRUE
+ p_prnt = u;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"U", BT_OCTET32_LEN);
+ p_prnt = v;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"V", BT_OCTET32_LEN);
+ p_prnt = x;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"X", BT_OCTET16_LEN);
+ p_prnt = &z;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"Z", 1);
+#endif
+
+ p = msg;
+ UINT8_TO_STREAM(p, z);
+ ARRAY_TO_STREAM(p, v, BT_OCTET32_LEN);
+ ARRAY_TO_STREAM(p, u, BT_OCTET32_LEN);
+#if SMP_DEBUG == TRUE
+ p_prnt = msg;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"M", msg_len);
+#endif
+
+ p = key;
+ ARRAY_TO_STREAM(p, x, BT_OCTET16_LEN);
+#if SMP_DEBUG == TRUE
+ p_prnt = key;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"K", BT_OCTET16_LEN);
+#endif
+
+ aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac);
+#if SMP_DEBUG == TRUE
+ p_prnt = cmac;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"AES_CMAC", BT_OCTET16_LEN);
+#endif
+
+ p = c;
+ ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
+}
+
+/*******************************************************************************
+**
+** Function smp_calculate_numeric_comparison_display_number
+**
+** Description The function calculates and saves number to display in numeric
+** comparison association mode.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_calculate_numeric_comparison_display_number(tSMP_CB *p_cb,
+ tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG ("%s", __func__);
+
+ if (p_cb->role == HCI_ROLE_MASTER) {
+ p_cb->number_to_display =
+ smp_calculate_g2(p_cb->loc_publ_key.x, p_cb->peer_publ_key.x, p_cb->rand,
+ p_cb->rrand);
+ } else {
+ p_cb->number_to_display =
+ smp_calculate_g2(p_cb->peer_publ_key.x, p_cb->loc_publ_key.x, p_cb->rrand,
+ p_cb->rand);
+ }
+
+ if (p_cb->number_to_display >= (BTM_MAX_PASSKEY_VAL + 1)) {
+ UINT8 reason;
+ reason = p_cb->failure = SMP_PAIR_FAIL_UNKNOWN;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ SMP_TRACE_EVENT("Number to display in numeric comparison = %d", p_cb->number_to_display);
+ p_cb->cb_evt = SMP_NC_REQ_EVT;
+ smp_sm_event(p_cb, SMP_SC_DSPL_NC_EVT, &p_cb->number_to_display);
+ return;
+}
+
+/*******************************************************************************
+**
+** Function smp_calculate_g2
+**
+** Description The function calculates
+** g2(U, V, X, Y) = AES-CMAC (U||V||Y) mod 2**32 mod 10**6
+** X
+** and
+** Vres = g2(U, V, X, Y) mod 10**6
+** where
+** input: U is 256 bit,
+** V is 256 bit,
+** X is 128 bit,
+** Y is 128 bit,
+**
+** Returns Vres.
+** Expected value has to be in the range [0 - 999999] i.e. [0 - 0xF423F].
+** Vres = 1000000 means that the calculation fails.
+**
+** Note The LSB is the first octet, the MSB is the last octet of
+** the AES-CMAC input/output stream.
+**
+*******************************************************************************/
+UINT32 smp_calculate_g2(UINT8 *u, UINT8 *v, UINT8 *x, UINT8 *y)
+{
+ UINT8 msg_len = BT_OCTET32_LEN /* U size */ + BT_OCTET32_LEN /* V size */
+ + BT_OCTET16_LEN /* Y size */;
+ UINT8 msg[BT_OCTET32_LEN + BT_OCTET32_LEN + BT_OCTET16_LEN];
+ UINT8 key[BT_OCTET16_LEN];
+ UINT8 cmac[BT_OCTET16_LEN];
+ UINT8 *p = NULL;
+ UINT32 vres;
+#if SMP_DEBUG == TRUE
+ UINT8 *p_prnt = NULL;
+#endif
+
+ SMP_TRACE_DEBUG ("%s\n", __FUNCTION__);
+
+ p = msg;
+ ARRAY_TO_STREAM(p, y, BT_OCTET16_LEN);
+ ARRAY_TO_STREAM(p, v, BT_OCTET32_LEN);
+ ARRAY_TO_STREAM(p, u, BT_OCTET32_LEN);
+#if SMP_DEBUG == TRUE
+ p_prnt = u;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"U", BT_OCTET32_LEN);
+ p_prnt = v;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"V", BT_OCTET32_LEN);
+ p_prnt = x;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"X", BT_OCTET16_LEN);
+ p_prnt = y;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"Y", BT_OCTET16_LEN);
+#endif
+
+ p = key;
+ ARRAY_TO_STREAM(p, x, BT_OCTET16_LEN);
+#if SMP_DEBUG == TRUE
+ p_prnt = key;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"K", BT_OCTET16_LEN);
+#endif
+
+ if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac)) {
+ SMP_TRACE_ERROR("%s failed", __FUNCTION__);
+ return (BTM_MAX_PASSKEY_VAL + 1);
+ }
+
+#if SMP_DEBUG == TRUE
+ p_prnt = cmac;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"AES-CMAC", BT_OCTET16_LEN);
+#endif
+
+ /* vres = cmac mod 2**32 mod 10**6 */
+ p = &cmac[0];
+ STREAM_TO_UINT32(vres, p);
+#if SMP_DEBUG == TRUE
+ p_prnt = (UINT8 *) &vres;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"cmac mod 2**32", 4);
+#endif
+
+ while (vres > BTM_MAX_PASSKEY_VAL) {
+ vres -= (BTM_MAX_PASSKEY_VAL + 1);
+ }
+#if SMP_DEBUG == TRUE
+ p_prnt = (UINT8 *) &vres;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"cmac mod 2**32 mod 10**6", 4);
+#endif
+
+ SMP_TRACE_ERROR("Value for numeric comparison = %d", vres);
+ return vres;
+}
+
+/*******************************************************************************
+**
+** Function smp_calculate_f5
+**
+** Description The function provides two AES-CMAC that are supposed to be used as
+** - MacKey (MacKey is used in pairing DHKey check calculation);
+** - LTK (LTK is used to ecrypt the link after completion of Phase 2
+** and on reconnection, to derive BR/EDR LK).
+** The function inputs are W, N1, N2, A1, A2.
+** F5 rules:
+** - the value used as key in MacKey/LTK (T) is calculated
+** (function smp_calculate_f5_key(...));
+** The formula is:
+** T = AES-CMAC (W)
+** salt
+** where salt is internal parameter of smp_calculate_f5_key(...).
+** - MacKey and LTK are calculated as AES-MAC values received with the
+** key T calculated in the previous step and the plaintext message
+** built from the external parameters N1, N2, A1, A2 and the internal
+** parameters counter, keyID, length.
+** The function smp_calculate_f5_mackey_or_long_term_key(...) is used in the
+** calculations.
+** The same formula is used in calculation of MacKey and LTK and the
+** same parameter values except the value of the internal parameter
+** counter:
+** - in MacKey calculations the value is 0;
+** - in LTK calculations the value is 1.
+** MacKey = AES-CMAC (Counter=0||keyID||N1||N2||A1||A2||Length=256)
+** T
+** LTK = AES-CMAC (Counter=1||keyID||N1||N2||A1||A2||Length=256)
+** T
+** The parameters are
+** input:
+** W is 256 bits,
+** N1 is 128 bits,
+** N2 is 128 bits,
+** A1 is 56 bit,
+** A2 is 56 bit.
+** internal:
+** Counter is 8 bits, its value is 0 for MacKey,
+** 1 for LTK;
+** KeyId is 32 bits, its value is
+** 0x62746c65 (MSB~LSB);
+** Length is 16 bits, its value is 0x0100
+** (MSB~LSB).
+** output:
+** MacKey is 128 bits;
+** LTK is 128 bits
+**
+** Returns FALSE if out of resources, TRUE in other cases.
+**
+** Note The LSB is the first octet, the MSB is the last octet of
+** the AES-CMAC input/output stream.
+**
+*******************************************************************************/
+BOOLEAN smp_calculate_f5(UINT8 *w, UINT8 *n1, UINT8 *n2, UINT8 *a1, UINT8 *a2,
+ UINT8 *mac_key, UINT8 *ltk)
+{
+ BT_OCTET16 t; /* AES-CMAC output in smp_calculate_f5_key(...), key in */
+ /* smp_calculate_f5_mackey_or_long_term_key(...) */
+#if SMP_DEBUG == TRUE
+ UINT8 *p_prnt = NULL;
+#endif
+ /* internal parameters: */
+
+ /*
+ counter is 0 for MacKey,
+ is 1 for LTK
+ */
+ UINT8 counter_mac_key[1] = {0};
+ UINT8 counter_ltk[1] = {1};
+ /*
+ keyID 62746c65
+ */
+ UINT8 key_id[4] = {0x65, 0x6c, 0x74, 0x62};
+ /*
+ length 0100
+ */
+ UINT8 length[2] = {0x00, 0x01};
+
+ SMP_TRACE_DEBUG ("%s", __FUNCTION__);
+#if SMP_DEBUG == TRUE
+ p_prnt = w;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"W", BT_OCTET32_LEN);
+ p_prnt = n1;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"N1", BT_OCTET16_LEN);
+ p_prnt = n2;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"N2", BT_OCTET16_LEN);
+ p_prnt = a1;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"A1", 7);
+ p_prnt = a2;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *) "A2", 7);
+#endif
+
+ if (!smp_calculate_f5_key(w, t)) {
+ SMP_TRACE_ERROR("%s failed to calc T", __FUNCTION__);
+ return FALSE;
+ }
+#if SMP_DEBUG == TRUE
+ p_prnt = t;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"T", BT_OCTET16_LEN);
+#endif
+
+ if (!smp_calculate_f5_mackey_or_long_term_key(t, counter_mac_key, key_id, n1, n2, a1, a2,
+ length, mac_key)) {
+ SMP_TRACE_ERROR("%s failed to calc MacKey", __FUNCTION__);
+ return FALSE;
+ }
+#if SMP_DEBUG == TRUE
+ p_prnt = mac_key;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"MacKey", BT_OCTET16_LEN);
+#endif
+
+ if (!smp_calculate_f5_mackey_or_long_term_key(t, counter_ltk, key_id, n1, n2, a1, a2,
+ length, ltk)) {
+ SMP_TRACE_ERROR("%s failed to calc LTK", __FUNCTION__);
+ return FALSE;
+ }
+#if SMP_DEBUG == TRUE
+ p_prnt = ltk;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"LTK", BT_OCTET16_LEN);
+#endif
+
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function smp_calculate_f5_mackey_or_long_term_key
+**
+** Description The function calculates the value of MacKey or LTK by the rules
+** defined for f5 function.
+** At the moment exactly the same formula is used to calculate
+** LTK and MacKey.
+** The difference is the value of input parameter Counter:
+** - in MacKey calculations the value is 0;
+** - in LTK calculations the value is 1.
+** The formula:
+** mac = AES-CMAC (Counter||keyID||N1||N2||A1||A2||Length)
+** T
+** where
+** input: T is 256 bits;
+** Counter is 8 bits, its value is 0 for MacKey,
+** 1 for LTK;
+** keyID is 32 bits, its value is 0x62746c65;
+** N1 is 128 bits;
+** N2 is 128 bits;
+** A1 is 56 bits;
+** A2 is 56 bits;
+** Length is 16 bits, its value is 0x0100
+** output: LTK is 128 bit.
+**
+** Returns FALSE if out of resources, TRUE in other cases.
+**
+** Note The LSB is the first octet, the MSB is the last octet of
+** the AES-CMAC input/output stream.
+**
+*******************************************************************************/
+BOOLEAN smp_calculate_f5_mackey_or_long_term_key(UINT8 *t, UINT8 *counter,
+ UINT8 *key_id, UINT8 *n1, UINT8 *n2, UINT8 *a1, UINT8 *a2,
+ UINT8 *length, UINT8 *mac)
+{
+ UINT8 *p = NULL;
+ UINT8 cmac[BT_OCTET16_LEN];
+ UINT8 key[BT_OCTET16_LEN];
+ UINT8 msg_len = 1 /* Counter size */ + 4 /* keyID size */ +
+ BT_OCTET16_LEN /* N1 size */ + BT_OCTET16_LEN /* N2 size */ +
+ 7 /* A1 size*/ + 7 /* A2 size*/ + 2 /* Length size */;
+ UINT8 msg[1 + 4 + BT_OCTET16_LEN + BT_OCTET16_LEN + 7 + 7 + 2];
+ BOOLEAN ret = TRUE;
+#if SMP_DEBUG == TRUE
+ UINT8 *p_prnt = NULL;
+#endif
+
+ SMP_TRACE_DEBUG ("%s", __FUNCTION__);
+#if SMP_DEBUG == TRUE
+ p_prnt = t;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"T", BT_OCTET16_LEN);
+ p_prnt = counter;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"Counter", 1);
+ p_prnt = key_id;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"KeyID", 4);
+ p_prnt = n1;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"N1", BT_OCTET16_LEN);
+ p_prnt = n2;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"N2", BT_OCTET16_LEN);
+ p_prnt = a1;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"A1", 7);
+ p_prnt = a2;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"A2", 7);
+ p_prnt = length;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"Length", 2);
+#endif
+
+ p = key;
+ ARRAY_TO_STREAM(p, t, BT_OCTET16_LEN);
+#if SMP_DEBUG == TRUE
+ p_prnt = key;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"K", BT_OCTET16_LEN);
+#endif
+ p = msg;
+ ARRAY_TO_STREAM(p, length, 2);
+ ARRAY_TO_STREAM(p, a2, 7);
+ ARRAY_TO_STREAM(p, a1, 7);
+ ARRAY_TO_STREAM(p, n2, BT_OCTET16_LEN);
+ ARRAY_TO_STREAM(p, n1, BT_OCTET16_LEN);
+ ARRAY_TO_STREAM(p, key_id, 4);
+ ARRAY_TO_STREAM(p, counter, 1);
+#if SMP_DEBUG == TRUE
+ p_prnt = msg;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"M", msg_len);
+#endif
+
+ if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac)) {
+ SMP_TRACE_ERROR("%s failed", __FUNCTION__);
+ ret = FALSE;
+ }
+
+#if SMP_DEBUG == TRUE
+ p_prnt = cmac;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"AES-CMAC", BT_OCTET16_LEN);
+#endif
+
+ p = mac;
+ ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
+ return ret;
+}
+
+/*******************************************************************************
+**
+** Function smp_calculate_f5_key
+**
+** Description The function calculates key T used in calculation of
+** MacKey and LTK (f5 output is defined as MacKey || LTK).
+** T = AES-CMAC (W)
+** salt
+** where
+** Internal: salt is 128 bit.
+** input: W is 256 bit.
+** Output: T is 128 bit.
+**
+** Returns FALSE if out of resources, TRUE in other cases.
+**
+** Note The LSB is the first octet, the MSB is the last octet of
+** the AES-CMAC input/output stream.
+**
+*******************************************************************************/
+BOOLEAN smp_calculate_f5_key(UINT8 *w, UINT8 *t)
+{
+ UINT8 *p = NULL;
+ /* Please see 2.2.7 LE Secure Connections Key Generation Function f5 */
+ /*
+ salt: 6C88 8391 AAF5 A538 6037 0BDB 5A60 83BE
+ */
+ BT_OCTET16 salt = {
+ 0xBE, 0x83, 0x60, 0x5A, 0xDB, 0x0B, 0x37, 0x60,
+ 0x38, 0xA5, 0xF5, 0xAA, 0x91, 0x83, 0x88, 0x6C
+ };
+#if SMP_DEBUG == TRUE
+ UINT8 *p_prnt = NULL;
+#endif
+
+ SMP_TRACE_DEBUG ("%s", __FUNCTION__);
+#if SMP_DEBUG == TRUE
+ p_prnt = salt;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"salt", BT_OCTET16_LEN);
+ p_prnt = w;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"W", BT_OCTET32_LEN);
+#endif
+
+ BT_OCTET16 key;
+ BT_OCTET32 msg;
+
+ p = key;
+ ARRAY_TO_STREAM(p, salt, BT_OCTET16_LEN);
+ p = msg;
+ ARRAY_TO_STREAM(p, w, BT_OCTET32_LEN);
+#if SMP_DEBUG == TRUE
+ p_prnt = key;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"K", BT_OCTET16_LEN);
+ p_prnt = msg;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"M", BT_OCTET32_LEN);
+#endif
+
+ BT_OCTET16 cmac;
+ BOOLEAN ret = TRUE;
+ if (!aes_cipher_msg_auth_code(key, msg, BT_OCTET32_LEN, BT_OCTET16_LEN, cmac)) {
+ SMP_TRACE_ERROR("%s failed", __FUNCTION__);
+ ret = FALSE;
+ }
+
+#if SMP_DEBUG == TRUE
+ p_prnt = cmac;
+ smp_debug_print_nbyte_little_endian (p_prnt, (const UINT8 *)"AES-CMAC", BT_OCTET16_LEN);
+#endif
+
+ p = t;
+ ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
+ return ret;
+}
+
+/*******************************************************************************
+**
+** Function smp_calculate_local_dhkey_check
+**
+** Description The function calculates and saves local device DHKey check
+** value in CB.
+** Before doing this it calls smp_calculate_f5_mackey_and_long_term_key(...).
+** to calculate MacKey and LTK.
+** MacKey is used in dhkey calculation.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_calculate_local_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 iocap[3], a[7], b[7];
+
+ SMP_TRACE_DEBUG ("%s", __FUNCTION__);
+
+ smp_calculate_f5_mackey_and_long_term_key(p_cb);
+
+ smp_collect_local_io_capabilities(iocap, p_cb);
+
+ smp_collect_local_ble_address(a, p_cb);
+ smp_collect_peer_ble_address(b, p_cb);
+ smp_calculate_f6(p_cb->mac_key, p_cb->rand, p_cb->rrand, p_cb->peer_random, iocap, a, b,
+ p_cb->dhkey_check);
+
+ SMP_TRACE_EVENT ("local DHKey check calculation is completed");
+}
+
+/*******************************************************************************
+**
+** Function smp_calculate_peer_dhkey_check
+**
+** Description The function calculates peer device DHKey check value.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_calculate_peer_dhkey_check(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 iocap[3], a[7], b[7];
+ BT_OCTET16 param_buf;
+ BOOLEAN ret;
+ tSMP_KEY key;
+ tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+ SMP_TRACE_DEBUG ("%s", __FUNCTION__);
+
+ smp_collect_peer_io_capabilities(iocap, p_cb);
+
+ smp_collect_local_ble_address(a, p_cb);
+ smp_collect_peer_ble_address(b, p_cb);
+ ret = smp_calculate_f6(p_cb->mac_key, p_cb->rrand, p_cb->rand, p_cb->local_random, iocap,
+ b, a, param_buf);
+
+ if (ret) {
+ SMP_TRACE_EVENT ("peer DHKey check calculation is completed");
+#if (SMP_DEBUG == TRUE)
+ smp_debug_print_nbyte_little_endian (param_buf, (const UINT8 *)"peer DHKey check",
+ BT_OCTET16_LEN);
+#endif
+ key.key_type = SMP_KEY_TYPE_PEER_DHK_CHCK;
+ key.p_data = param_buf;
+ smp_sm_event(p_cb, SMP_SC_KEY_READY_EVT, &key);
+ } else {
+ SMP_TRACE_EVENT ("peer DHKey check calculation failed");
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_calculate_f6
+**
+** Description The function calculates
+** C = f6(W, N1, N2, R, IOcap, A1, A2) = AES-CMAC (N1||N2||R||IOcap||A1||A2)
+** W
+** where
+** input: W is 128 bit,
+** N1 is 128 bit,
+** N2 is 128 bit,
+** R is 128 bit,
+** IOcap is 24 bit,
+** A1 is 56 bit,
+** A2 is 56 bit,
+** output: C is 128 bit.
+**
+** Returns FALSE if out of resources, TRUE in other cases.
+**
+** Note The LSB is the first octet, the MSB is the last octet of
+** the AES-CMAC input/output stream.
+**
+*******************************************************************************/
+BOOLEAN smp_calculate_f6(UINT8 *w, UINT8 *n1, UINT8 *n2, UINT8 *r, UINT8 *iocap, UINT8 *a1,
+ UINT8 *a2, UINT8 *c)
+{
+ UINT8 *p = NULL;
+ UINT8 msg_len = BT_OCTET16_LEN /* N1 size */ + BT_OCTET16_LEN /* N2 size */ +
+ BT_OCTET16_LEN /* R size */ + 3 /* IOcap size */ + 7 /* A1 size*/
+ + 7 /* A2 size*/;
+ UINT8 msg[BT_OCTET16_LEN + BT_OCTET16_LEN + BT_OCTET16_LEN + 3 + 7 + 7];
+#if SMP_DEBUG == TRUE
+ UINT8 *p_print = NULL;
+#endif
+
+ SMP_TRACE_DEBUG ("%s", __FUNCTION__);
+#if SMP_DEBUG == TRUE
+ p_print = w;
+ smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"W", BT_OCTET16_LEN);
+ p_print = n1;
+ smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"N1", BT_OCTET16_LEN);
+ p_print = n2;
+ smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"N2", BT_OCTET16_LEN);
+ p_print = r;
+ smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"R", BT_OCTET16_LEN);
+ p_print = iocap;
+ smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"IOcap", 3);
+ p_print = a1;
+ smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"A1", 7);
+ p_print = a2;
+ smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"A2", 7);
+#endif
+
+ UINT8 cmac[BT_OCTET16_LEN];
+ UINT8 key[BT_OCTET16_LEN];
+
+ p = key;
+ ARRAY_TO_STREAM(p, w, BT_OCTET16_LEN);
+#if SMP_DEBUG == TRUE
+ p_print = key;
+ smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"K", BT_OCTET16_LEN);
+#endif
+
+ p = msg;
+ ARRAY_TO_STREAM(p, a2, 7);
+ ARRAY_TO_STREAM(p, a1, 7);
+ ARRAY_TO_STREAM(p, iocap, 3);
+ ARRAY_TO_STREAM(p, r, BT_OCTET16_LEN);
+ ARRAY_TO_STREAM(p, n2, BT_OCTET16_LEN);
+ ARRAY_TO_STREAM(p, n1, BT_OCTET16_LEN);
+#if SMP_DEBUG == TRUE
+ p_print = msg;
+ smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"M", msg_len);
+#endif
+
+ BOOLEAN ret = TRUE;
+ if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac)) {
+ SMP_TRACE_ERROR("%s failed", __FUNCTION__);
+ ret = FALSE;
+ }
+
+#if SMP_DEBUG == TRUE
+ p_print = cmac;
+ smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"AES-CMAC", BT_OCTET16_LEN);
+#endif
+
+ p = c;
+ ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
+ return ret;
+}
+
+/*******************************************************************************
+**
+** Function smp_calculate_link_key_from_long_term_key
+**
+** Description The function calculates and saves BR/EDR link key derived from
+** LE SC LTK.
+**
+** Returns FALSE if out of resources, TRUE in other cases.
+**
+*******************************************************************************/
+BOOLEAN smp_calculate_link_key_from_long_term_key(tSMP_CB *p_cb)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ BD_ADDR bda_for_lk;
+ tBLE_ADDR_TYPE conn_addr_type;
+
+ SMP_TRACE_DEBUG ("%s", __func__);
+
+ if (p_cb->id_addr_rcvd && p_cb->id_addr_type == BLE_ADDR_PUBLIC) {
+ SMP_TRACE_DEBUG ("Use rcvd identity address as BD_ADDR of LK rcvd identity address");
+ memcpy(bda_for_lk, p_cb->id_addr, BD_ADDR_LEN);
+ } else if ((BTM_ReadRemoteConnectionAddr(p_cb->pairing_bda, bda_for_lk, &conn_addr_type)) &&
+ conn_addr_type == BLE_ADDR_PUBLIC) {
+ SMP_TRACE_DEBUG ("Use rcvd connection address as BD_ADDR of LK");
+ } else {
+ SMP_TRACE_WARNING ("Don't have peer public address to associate with LK");
+ return FALSE;
+ }
+
+ if ((p_dev_rec = btm_find_dev (p_cb->pairing_bda)) == NULL) {
+ SMP_TRACE_ERROR("%s failed to find Security Record", __func__);
+ return FALSE;
+ }
+
+ BT_OCTET16 intermediate_link_key;
+ BOOLEAN ret = TRUE;
+
+ ret = smp_calculate_h6(p_cb->ltk, (UINT8 *)"1pmt" /* reversed "tmp1" */, intermediate_link_key);
+ if (!ret) {
+ SMP_TRACE_ERROR("%s failed to derive intermediate_link_key", __func__);
+ return ret;
+ }
+
+ BT_OCTET16 link_key;
+ ret = smp_calculate_h6(intermediate_link_key, (UINT8 *) "rbel" /* reversed "lebr" */, link_key);
+ if (!ret) {
+ SMP_TRACE_ERROR("%s failed", __func__);
+ } else {
+ UINT8 link_key_type;
+ if (btm_cb.security_mode == BTM_SEC_MODE_SC) {
+ /* Secure Connections Only Mode */
+ link_key_type = BTM_LKEY_TYPE_AUTH_COMB_P_256;
+ } else if (controller_get_interface()->supports_secure_connections()) {
+ /* both transports are SC capable */
+ if (p_cb->sec_level == SMP_SEC_AUTHENTICATED) {
+ link_key_type = BTM_LKEY_TYPE_AUTH_COMB_P_256;
+ } else {
+ link_key_type = BTM_LKEY_TYPE_UNAUTH_COMB_P_256;
+ }
+ } else if (btm_cb.security_mode == BTM_SEC_MODE_SP) {
+ /* BR/EDR transport is SSP capable */
+ if (p_cb->sec_level == SMP_SEC_AUTHENTICATED) {
+ link_key_type = BTM_LKEY_TYPE_AUTH_COMB;
+ } else {
+ link_key_type = BTM_LKEY_TYPE_UNAUTH_COMB;
+ }
+ } else {
+ SMP_TRACE_ERROR ("%s failed to update link_key. Sec Mode = %d, sm4 = 0x%02x",
+ __func__, btm_cb.security_mode, p_dev_rec->sm4);
+ return FALSE;
+ }
+
+ link_key_type += BTM_LTK_DERIVED_LKEY_OFFSET;
+
+ UINT8 *p;
+ BT_OCTET16 notif_link_key;
+ p = notif_link_key;
+ ARRAY16_TO_STREAM(p, link_key);
+
+ btm_sec_link_key_notification (bda_for_lk, notif_link_key, link_key_type);
+
+ SMP_TRACE_EVENT ("%s is completed", __func__);
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+**
+** Function smp_calculate_long_term_key_from_link_key
+**
+** Description The function calculates and saves SC LTK derived from BR/EDR
+** link key.
+**
+** Returns FALSE if out of resources, TRUE in other cases.
+**
+*******************************************************************************/
+BOOLEAN smp_calculate_long_term_key_from_link_key(tSMP_CB *p_cb)
+{
+ BOOLEAN ret = TRUE;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ UINT8 rev_link_key[16];
+
+ SMP_TRACE_DEBUG ("%s", __FUNCTION__);
+
+ if ((p_dev_rec = btm_find_dev (p_cb->pairing_bda)) == NULL) {
+ SMP_TRACE_ERROR("%s failed to find Security Record", __FUNCTION__);
+ return FALSE;
+ }
+
+ UINT8 br_link_key_type;
+ if ((br_link_key_type = BTM_SecGetDeviceLinkKeyType (p_cb->pairing_bda))
+ == BTM_LKEY_TYPE_IGNORE) {
+ SMP_TRACE_ERROR("%s failed to retrieve BR link type", __FUNCTION__);
+ return FALSE;
+ }
+
+ if ((br_link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256) &&
+ (br_link_key_type != BTM_LKEY_TYPE_UNAUTH_COMB_P_256)) {
+ SMP_TRACE_ERROR("%s LE SC LTK can't be derived from LK %d",
+ __FUNCTION__, br_link_key_type);
+ return FALSE;
+ }
+
+ UINT8 *p1;
+ UINT8 *p2;
+ p1 = rev_link_key;
+ p2 = p_dev_rec->link_key;
+ REVERSE_ARRAY_TO_STREAM(p1, p2, 16);
+
+ BT_OCTET16 intermediate_long_term_key;
+ /* "tmp2" obtained from the spec */
+ ret = smp_calculate_h6(rev_link_key, (UINT8 *) "2pmt" /* reversed "tmp2" */,
+ intermediate_long_term_key);
+
+ if (!ret) {
+ SMP_TRACE_ERROR("%s failed to derive intermediate_long_term_key", __FUNCTION__);
+ return ret;
+ }
+
+ /* "brle" obtained from the spec */
+ ret = smp_calculate_h6(intermediate_long_term_key, (UINT8 *) "elrb" /* reversed "brle" */,
+ p_cb->ltk);
+
+ if (!ret) {
+ SMP_TRACE_ERROR("%s failed", __FUNCTION__);
+ } else {
+ p_cb->sec_level = (br_link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256)
+ ? SMP_SEC_AUTHENTICATED : SMP_SEC_UNAUTHENTICATE;
+ SMP_TRACE_EVENT ("%s is completed", __FUNCTION__);
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+**
+** Function smp_calculate_h6
+**
+** Description The function calculates
+** C = h6(W, KeyID) = AES-CMAC (KeyID)
+** W
+** where
+** input: W is 128 bit,
+** KeyId is 32 bit,
+** output: C is 128 bit.
+**
+** Returns FALSE if out of resources, TRUE in other cases.
+**
+** Note The LSB is the first octet, the MSB is the last octet of
+** the AES-CMAC input/output stream.
+**
+*******************************************************************************/
+BOOLEAN smp_calculate_h6(UINT8 *w, UINT8 *keyid, UINT8 *c)
+{
+#if SMP_DEBUG == TRUE
+ UINT8 *p_print = NULL;
+#endif
+
+ SMP_TRACE_DEBUG ("%s", __FUNCTION__);
+#if SMP_DEBUG == TRUE
+ p_print = w;
+ smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"W", BT_OCTET16_LEN);
+ p_print = keyid;
+ smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"keyID", 4);
+#endif
+
+ UINT8 *p = NULL;
+ UINT8 key[BT_OCTET16_LEN];
+
+ p = key;
+ ARRAY_TO_STREAM(p, w, BT_OCTET16_LEN);
+
+#if SMP_DEBUG == TRUE
+ p_print = key;
+ smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"K", BT_OCTET16_LEN);
+#endif
+
+ UINT8 msg_len = 4 /* KeyID size */;
+ UINT8 msg[4];
+
+ p = msg;
+ ARRAY_TO_STREAM(p, keyid, 4);
+
+#if SMP_DEBUG == TRUE
+ p_print = msg;
+ smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *) "M", msg_len);
+#endif
+
+ BOOLEAN ret = TRUE;
+ UINT8 cmac[BT_OCTET16_LEN];
+ if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac)) {
+ SMP_TRACE_ERROR("%s failed", __FUNCTION__);
+ ret = FALSE;
+ }
+
+#if SMP_DEBUG == TRUE
+ p_print = cmac;
+ smp_debug_print_nbyte_little_endian (p_print, (const UINT8 *)"AES-CMAC", BT_OCTET16_LEN);
+#endif
+
+ p = c;
+ ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
+ return ret;
+}
+
+/*******************************************************************************
+**
+** Function smp_start_nonce_generation
+**
+** Description This function starts nonce generation.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_start_nonce_generation(tSMP_CB *p_cb)
+{
+ SMP_TRACE_DEBUG("%s", __FUNCTION__);
+ p_cb->rand_enc_proc_state = SMP_GEN_NONCE_0_7;
+ if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) {
+ smp_rand_back(NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_finish_nonce_generation
+**
+** Description This function finishes nonce generation.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_finish_nonce_generation(tSMP_CB *p_cb)
+{
+ SMP_TRACE_DEBUG("%s", __FUNCTION__);
+ p_cb->rand_enc_proc_state = SMP_GEN_NONCE_8_15;
+ if (!btsnd_hcic_ble_rand((void *)smp_rand_back)) {
+ smp_rand_back(NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_process_new_nonce
+**
+** Description This function notifies SM that it has new nonce.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_process_new_nonce(tSMP_CB *p_cb)
+{
+ SMP_TRACE_DEBUG ("%s round %d", __FUNCTION__, p_cb->round);
+ smp_sm_event(p_cb, SMP_HAVE_LOC_NONCE_EVT, NULL);
+}
+
+/*******************************************************************************
+**
+** Function smp_rand_back
+**
+** Description This function is to process the rand command finished,
+** process the random/encrypted number for further action.
+**
+** Returns void
+**
+*******************************************************************************/
+static void smp_rand_back(tBTM_RAND_ENC *p)
+{
+ tSMP_CB *p_cb = &smp_cb;
+ UINT8 *pp = p->param_buf;
+ UINT8 failure = SMP_PAIR_FAIL_UNKNOWN;
+ UINT8 state = p_cb->rand_enc_proc_state & ~0x80;
+
+ SMP_TRACE_DEBUG ("%s state=0x%x", __FUNCTION__, state);
+ if (p && p->status == HCI_SUCCESS) {
+ switch (state) {
+ case SMP_GEN_SRAND_MRAND:
+ memcpy((void *)p_cb->rand, p->param_buf, p->param_len);
+ smp_generate_rand_cont(p_cb, NULL);
+ break;
+
+ case SMP_GEN_SRAND_MRAND_CONT:
+ memcpy((void *)&p_cb->rand[8], p->param_buf, p->param_len);
+ smp_generate_confirm(p_cb, NULL);
+ break;
+
+ case SMP_GEN_DIV_LTK:
+ STREAM_TO_UINT16(p_cb->div, pp);
+ smp_generate_ltk_cont(p_cb, NULL);
+ break;
+
+ case SMP_GEN_DIV_CSRK:
+ STREAM_TO_UINT16(p_cb->div, pp);
+ smp_compute_csrk(p_cb, NULL);
+ break;
+
+ case SMP_GEN_TK:
+ smp_proc_passkey(p_cb, p);
+ break;
+
+ case SMP_GEN_RAND_V:
+ memcpy(p_cb->enc_rand, p->param_buf, BT_OCTET8_LEN);
+ smp_generate_y(p_cb, NULL);
+ break;
+
+ case SMP_GENERATE_PRIVATE_KEY_0_7:
+ case SMP_GENERATE_PRIVATE_KEY_8_15:
+ case SMP_GENERATE_PRIVATE_KEY_16_23:
+ case SMP_GENERATE_PRIVATE_KEY_24_31:
+ smp_continue_private_key_creation(p_cb, p);
+ break;
+
+ case SMP_GEN_NONCE_0_7:
+ memcpy((void *)p_cb->rand, p->param_buf, p->param_len);
+ smp_finish_nonce_generation(p_cb);
+ break;
+
+ case SMP_GEN_NONCE_8_15:
+ memcpy((void *)&p_cb->rand[8], p->param_buf, p->param_len);
+ smp_process_new_nonce(p_cb);
+ break;
+ }
+
+ return;
+ }
+
+ SMP_TRACE_ERROR("%s key generation failed: (%d)", __FUNCTION__, p_cb->rand_enc_proc_state);
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+}
+
+#endif
diff --git a/lib/bt/host/bluedroid/stack/smp/smp_l2c.c b/lib/bt/host/bluedroid/stack/smp/smp_l2c.c
new file mode 100644
index 00000000..a6f06705
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/smp/smp_l2c.c
@@ -0,0 +1,344 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains functions for the SMP L2Cap interface
+ *
+ ******************************************************************************/
+
+#include "common/bt_target.h"
+#include "osi/allocator.h"
+
+#if SMP_INCLUDED == TRUE
+
+#include <string.h>
+#include "stack/btm_ble_api.h"
+#include "stack/l2c_api.h"
+
+#include "smp_int.h"
+
+
+static void smp_tx_complete_callback(UINT16 cid, UINT16 num_pkt);
+#if (BLE_INCLUDED == TRUE)
+
+static void smp_connect_callback(UINT16 channel, BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason,
+ tBT_TRANSPORT transport);
+static void smp_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf);
+#endif ///BLE_INCLUDED == TRUE
+#if (CLASSIC_BT_INCLUDED == TRUE)
+static void smp_br_connect_callback(UINT16 channel, BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason,
+ tBT_TRANSPORT transport);
+static void smp_br_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf);
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function smp_l2cap_if_init
+**
+** Description This function is called during the SMP task startup
+** to register interface functions with L2CAP.
+**
+*******************************************************************************/
+void smp_l2cap_if_init (void)
+{
+ tL2CAP_FIXED_CHNL_REG fixed_reg;
+ SMP_TRACE_EVENT ("SMDBG l2c %s", __func__);
+ fixed_reg.fixed_chnl_opts.mode = L2CAP_FCR_BASIC_MODE;
+ fixed_reg.fixed_chnl_opts.max_transmit = 0;
+ fixed_reg.fixed_chnl_opts.rtrans_tout = 0;
+ fixed_reg.fixed_chnl_opts.mon_tout = 0;
+ fixed_reg.fixed_chnl_opts.mps = 0;
+ fixed_reg.fixed_chnl_opts.tx_win_sz = 0;
+
+ fixed_reg.pL2CA_FixedTxComplete_Cb = smp_tx_complete_callback;
+
+ fixed_reg.pL2CA_FixedCong_Cb = NULL; /* do not handle congestion on this channel */
+ fixed_reg.default_idle_tout = 0; /* set 0 seconds timeout, 0xffff default idle timeout.
+ This timeout is used to wait for the end of the pairing
+ and then make a disconnect request, setting a larger value
+ will cause the disconnect event to go back up for a long time.
+ Set to 0 will be disconnected directly, and it will come up
+ pairing failure, so it will not cause adverse effects. */
+#if (BLE_INCLUDED == TRUE)
+ fixed_reg.pL2CA_FixedConn_Cb = smp_connect_callback;
+ fixed_reg.pL2CA_FixedData_Cb = smp_data_received;
+ L2CA_RegisterFixedChannel (L2CAP_SMP_CID, &fixed_reg);
+#endif ///BLE_INCLUDED == TRUE
+
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ fixed_reg.pL2CA_FixedConn_Cb = smp_br_connect_callback;
+ fixed_reg.pL2CA_FixedData_Cb = smp_br_data_received;
+
+ L2CA_RegisterFixedChannel (L2CAP_SMP_BR_CID, &fixed_reg);
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+}
+
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function smp_connect_callback
+**
+** Description This callback function is called by L2CAP to indicate that
+** SMP channel is
+** connected (conn = TRUE)/disconnected (conn = FALSE).
+**
+*******************************************************************************/
+static void smp_connect_callback (UINT16 channel, BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason,
+ tBT_TRANSPORT transport)
+{
+ tSMP_CB *p_cb = &smp_cb;
+ tSMP_INT_DATA int_data;
+ BD_ADDR dummy_bda = {0};
+
+ SMP_TRACE_EVENT ("SMDBG l2c %s\n", __FUNCTION__);
+
+ if (transport == BT_TRANSPORT_BR_EDR || memcmp(bd_addr, dummy_bda, BD_ADDR_LEN) == 0) {
+ return;
+ }
+ if(!connected) {
+ //free timer
+ btu_free_timer(&p_cb->rsp_timer_ent);
+ }
+ if (memcmp(bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) == 0) {
+ SMP_TRACE_EVENT ("%s() for pairing BDA: %08x%04x Event: %s\n",
+ __FUNCTION__,
+ (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3],
+ (bd_addr[4] << 8) + bd_addr[5],
+ (connected) ? "connected" : "disconnected");
+
+ if (connected) {
+ if (!p_cb->connect_initialized) {
+ p_cb->connect_initialized = TRUE;
+ /* initiating connection established */
+ p_cb->role = L2CA_GetBleConnRole(bd_addr);
+
+ /* initialize local i/r key to be default keys */
+ p_cb->local_r_key = p_cb->local_i_key = SMP_SEC_DEFAULT_KEY;
+ p_cb->loc_auth_req = p_cb->peer_auth_req = SMP_DEFAULT_AUTH_REQ;
+ p_cb->cb_evt = SMP_IO_CAP_REQ_EVT;
+ smp_sm_event(p_cb, SMP_L2CAP_CONN_EVT, NULL);
+ }
+ } else {
+ int_data.reason = reason;
+ /* Disconnected while doing security */
+ smp_sm_event(p_cb, SMP_L2CAP_DISCONN_EVT, &int_data);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_data_received
+**
+** Description This function is called when data is received from L2CAP on
+** SMP channel.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void smp_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf)
+{
+ tSMP_CB *p_cb = &smp_cb;
+ UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ UINT8 cmd ;
+ SMP_TRACE_EVENT ("\nSMDBG l2c %s\n", __FUNCTION__);
+
+ STREAM_TO_UINT8(cmd, p);
+
+ /* sanity check */
+ if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) {
+ SMP_TRACE_WARNING( "Ignore received command with RESERVED code 0x%02x\n", cmd);
+ osi_free (p_buf);
+ return;
+ }
+
+ /* reject the pairing request if there is an on-going SMP pairing */
+ if (SMP_OPCODE_PAIRING_REQ == cmd || SMP_OPCODE_SEC_REQ == cmd) {
+ if ((p_cb->state == SMP_STATE_IDLE) && (p_cb->br_state == SMP_BR_STATE_IDLE) &&
+ !(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)) {
+ p_cb->role = L2CA_GetBleConnRole(bd_addr);
+ memcpy(&p_cb->pairing_bda[0], bd_addr, BD_ADDR_LEN);
+ } else if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN)) {
+ osi_free (p_buf);
+ smp_reject_unexpected_pairing_command(bd_addr);
+ return;
+ }
+ /* else, out of state pairing request/security request received, passed into SM */
+ }
+
+ if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN) == 0) {
+ btu_stop_timer (&p_cb->rsp_timer_ent);
+ btu_start_timer (&p_cb->rsp_timer_ent, BTU_TTYPE_SMP_PAIRING_CMD,
+ SMP_WAIT_FOR_RSP_TOUT);
+
+ if (cmd == SMP_OPCODE_CONFIRM) {
+ SMP_TRACE_DEBUG ("in %s cmd = 0x%02x, peer_auth_req = 0x%02x,"
+ "loc_auth_req = 0x%02x\n",
+ __FUNCTION__, cmd, p_cb->peer_auth_req, p_cb->loc_auth_req);
+
+ if ((p_cb->peer_auth_req & SMP_SC_SUPPORT_BIT) &&
+ (p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT)) {
+ cmd = SMP_OPCODE_PAIR_COMMITM;
+ }
+ }
+
+ p_cb->rcvd_cmd_code = cmd;
+ p_cb->rcvd_cmd_len = (UINT8) p_buf->len;
+ smp_sm_event(p_cb, cmd, p);
+ }
+
+ osi_free (p_buf);
+}
+#endif ///BLE_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function smp_tx_complete_callback
+**
+** Description SMP channel tx complete callback
+**
+*******************************************************************************/
+static void smp_tx_complete_callback (UINT16 cid, UINT16 num_pkt)
+{
+ tSMP_CB *p_cb = &smp_cb;
+
+ if (p_cb->total_tx_unacked >= num_pkt) {
+ p_cb->total_tx_unacked -= num_pkt;
+ } else {
+ SMP_TRACE_ERROR("Unexpected %s: num_pkt = %d", __func__, num_pkt);
+ }
+
+ UINT8 reason = SMP_SUCCESS;
+ if (p_cb->total_tx_unacked == 0 && p_cb->wait_for_authorization_complete) {
+ if (cid == L2CAP_SMP_CID) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ } else {
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason);
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_br_connect_callback
+**
+** Description This callback function is called by L2CAP to indicate that
+** SMP BR channel is
+** connected (conn = TRUE)/disconnected (conn = FALSE).
+**
+*******************************************************************************/
+#if (CLASSIC_BT_INCLUDED == TRUE)
+static void smp_br_connect_callback(UINT16 channel, BD_ADDR bd_addr, BOOLEAN connected,
+ UINT16 reason, tBT_TRANSPORT transport)
+{
+ tSMP_CB *p_cb = &smp_cb;
+ tSMP_INT_DATA int_data;
+
+ SMP_TRACE_EVENT ("%s", __func__);
+
+ if (transport != BT_TRANSPORT_BR_EDR) {
+ SMP_TRACE_EVENT ("%s is called on unexpected transport %d\n",
+ __func__, transport);
+ return;
+ }
+
+ if (!(memcmp(bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) == 0)) {
+ return;
+ }
+
+ SMP_TRACE_EVENT ("%s for pairing BDA: %08x%04x Event: %s\n",
+ __func__,
+ (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3],
+ (bd_addr[4] << 8) + bd_addr[5],
+ (connected) ? "connected" : "disconnected");
+
+ if (connected) {
+ if (!p_cb->connect_initialized) {
+ p_cb->connect_initialized = TRUE;
+ /* initialize local i/r key to be default keys */
+ p_cb->local_r_key = p_cb->local_i_key = SMP_BR_SEC_DEFAULT_KEY;
+ p_cb->loc_auth_req = p_cb->peer_auth_req = 0;
+ p_cb->cb_evt = SMP_BR_KEYS_REQ_EVT;
+ smp_br_state_machine_event(p_cb, SMP_BR_L2CAP_CONN_EVT, NULL);
+ }
+ } else {
+ int_data.reason = reason;
+ /* Disconnected while doing security */
+ smp_br_state_machine_event(p_cb, SMP_BR_L2CAP_DISCONN_EVT, &int_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_br_data_received
+**
+** Description This function is called when data is received from L2CAP on
+** SMP BR channel.
+**
+** Returns void
+**
+*******************************************************************************/
+static void smp_br_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf)
+{
+ tSMP_CB *p_cb = &smp_cb;
+ UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ UINT8 cmd ;
+ SMP_TRACE_EVENT ("SMDBG l2c %s\n", __func__);
+
+ STREAM_TO_UINT8(cmd, p);
+
+ /* sanity check */
+ if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) {
+ SMP_TRACE_WARNING( "Ignore received command with RESERVED code 0x%02x", cmd);
+ osi_free(p_buf);
+ return;
+ }
+
+ /* reject the pairing request if there is an on-going SMP pairing */
+ if (SMP_OPCODE_PAIRING_REQ == cmd) {
+ if ((p_cb->state == SMP_STATE_IDLE) && (p_cb->br_state == SMP_BR_STATE_IDLE)) {
+ p_cb->role = HCI_ROLE_SLAVE;
+ p_cb->smp_over_br = TRUE;
+ memcpy(&p_cb->pairing_bda[0], bd_addr, BD_ADDR_LEN);
+ } else if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN)) {
+ osi_free (p_buf);
+ smp_reject_unexpected_pairing_command(bd_addr);
+ return;
+ }
+ /* else, out of state pairing request received, passed into State Machine */
+ }
+
+ if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN) == 0) {
+ btu_stop_timer (&p_cb->rsp_timer_ent);
+ btu_start_timer (&p_cb->rsp_timer_ent, BTU_TTYPE_SMP_PAIRING_CMD,
+ SMP_WAIT_FOR_RSP_TOUT);
+
+ p_cb->rcvd_cmd_code = cmd;
+ p_cb->rcvd_cmd_len = (UINT8) p_buf->len;
+ smp_br_state_machine_event(p_cb, cmd, p);
+ }
+
+ osi_free (p_buf);
+}
+#endif /* CLASSIC_BT_INCLUDED == TRUE */
+
+#endif /* SMP_INCLUDED == TRUE */
diff --git a/lib/bt/host/bluedroid/stack/smp/smp_main.c b/lib/bt/host/bluedroid/stack/smp/smp_main.c
new file mode 100644
index 00000000..512aca0a
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/smp/smp_main.c
@@ -0,0 +1,810 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "common/bt_target.h"
+
+#if SMP_INCLUDED == TRUE
+
+#include <string.h>
+#include "smp_int.h"
+
+const char *const smp_state_name [] = {
+ "SMP_STATE_IDLE",
+ "SMP_STATE_WAIT_APP_RSP",
+ "SMP_STATE_SEC_REQ_PENDING",
+ "SMP_STATE_PAIR_REQ_RSP",
+ "SMP_STATE_WAIT_CONFIRM",
+ "SMP_STATE_CONFIRM",
+ "SMP_STATE_RAND",
+ "SMP_STATE_PUBLIC_KEY_EXCH",
+ "SMP_STATE_SEC_CONN_PHS1_START",
+ "SMP_STATE_WAIT_COMMITMENT",
+ "SMP_STATE_WAIT_NONCE",
+ "SMP_STATE_SEC_CONN_PHS2_START",
+ "SMP_STATE_WAIT_DHK_CHECK",
+ "SMP_STATE_DHK_CHECK",
+ "SMP_STATE_ENCRYPTION_PENDING",
+ "SMP_STATE_BOND_PENDING",
+ "SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA",
+ "SMP_STATE_MAX"
+};
+
+const char *const smp_event_name [] = {
+ "PAIRING_REQ_EVT",
+ "PAIRING_RSP_EVT",
+ "CONFIRM_EVT",
+ "RAND_EVT",
+ "PAIRING_FAILED_EVT",
+ "ENC_INFO_EVT",
+ "MASTER_ID_EVT",
+ "ID_INFO_EVT",
+ "ID_ADDR_EVT",
+ "SIGN_INFO_EVT",
+ "SECURITY_REQ_EVT",
+ "PAIR_PUBLIC_KEY_EVT",
+ "PAIR_DHKEY_CHECK_EVT",
+ "PAIR_KEYPRESS_NOTIFICATION_EVT",
+ "PAIR_COMMITMENT_EVT",
+ "KEY_READY_EVT",
+ "ENCRYPTED_EVT",
+ "L2CAP_CONN_EVT",
+ "L2CAP_DISCONN_EVT",
+ "API_IO_RSP_EVT",
+ "API_SEC_GRANT_EVT",
+ "TK_REQ_EVT",
+ "AUTH_CMPL_EVT",
+ "ENC_REQ_EVT",
+ "BOND_REQ_EVT",
+ "DISCARD_SEC_REQ_EVT",
+ "PUBLIC_KEY_EXCHANGE_REQ_EVT",
+ "LOCAL_PUBLIC_KEY_CRTD_EVT",
+ "BOTH_PUBLIC_KEYS_RCVD_EVT",
+ "SEC_CONN_DHKEY_COMPLETE_EVT",
+ "HAVE_LOCAL_NONCE_EVT",
+ "SEC_CONN_PHASE1_CMPLT_EVT",
+ "SEC_CONN_CALC_NC_EVT",
+ "SEC_CONN_DISPLAY_NC_EVT",
+ "SEC_CONN_OK_EVT",
+ "SEC_CONN_2_DHCK_CHECKS_PRESENT_EVT",
+ "SEC_CONN_KEY_READY_EVT",
+ "KEYPRESS_NOTIFICATION_EVT",
+ "SEC_CONN_OOB_DATA_EVT",
+ "CREATE_LOCAL_SEC_CONN_OOB_DATA_EVT",
+ "OUT_OF_RANGE_EVT"
+};
+
+const char *smp_get_event_name(tSMP_EVENT event);
+const char *smp_get_state_name(tSMP_STATE state);
+
+#define SMP_SM_IGNORE 0
+#define SMP_NUM_ACTIONS 2
+#define SMP_SME_NEXT_STATE 2
+#define SMP_SM_NUM_COLS 3
+
+typedef const UINT8(*tSMP_SM_TBL)[SMP_SM_NUM_COLS];
+
+enum {
+ SMP_PROC_SEC_REQ,
+ SMP_SEND_PAIR_REQ,
+ SMP_SEND_PAIR_RSP,
+ SMP_SEND_CONFIRM,
+ SMP_SEND_PAIR_FAIL,
+ SMP_SEND_RAND,
+ SMP_SEND_ENC_INFO,
+ SMP_SEND_ID_INFO,
+ SMP_SEND_LTK_REPLY,
+ SMP_PROC_PAIR_CMD,
+ SMP_PROC_PAIR_FAIL,
+ SMP_PROC_CONFIRM,
+ SMP_PROC_RAND,
+ SMP_PROC_ENC_INFO,
+ SMP_PROC_MASTER_ID,
+ SMP_PROC_ID_INFO,
+ SMP_PROC_ID_ADDR,
+ SMP_PROC_SRK_INFO,
+ SMP_PROC_SEC_GRANT,
+ SMP_PROC_SL_KEY,
+ SMP_PROC_COMPARE,
+ SMP_PROC_IO_RSP,
+ SMP_GENERATE_COMPARE,
+ SMP_GENERATE_CONFIRM,
+ SMP_GENERATE_STK,
+ SMP_KEY_DISTRIBUTE,
+ SMP_START_ENC,
+ SMP_PAIRING_CMPL,
+ SMP_DECIDE_ASSO_MODEL,
+ SMP_SEND_APP_CBACK,
+ SMP_CHECK_AUTH_REQ,
+ SMP_PAIR_TERMINATE,
+ SMP_ENC_CMPL,
+ SMP_PROC_DISCARD,
+ SMP_CREATE_PRIVATE_KEY,
+ SMP_USE_OOB_PRIVATE_KEY,
+ SMP_SEND_PAIR_PUBLIC_KEY,
+ SMP_PROCESS_PAIR_PUBLIC_KEY,
+ SMP_HAVE_BOTH_PUBLIC_KEYS,
+ SMP_START_SEC_CONN_PHASE1,
+ SMP_PROCESS_LOCAL_NONCE,
+ SMP_SEND_COMMITMENT,
+ SMP_PROCESS_PAIRING_COMMITMENT,
+ SMP_PROCESS_PEER_NONCE,
+ SMP_CALCULATE_LOCAL_DHKEY_CHECK,
+ SMP_SEND_DHKEY_CHECK,
+ SMP_PROCESS_DHKEY_CHECK,
+ SMP_CALCULATE_PEER_DHKEY_CHECK,
+ SMP_MATCH_DHKEY_CHECKS,
+ SMP_CALCULATE_NUMERIC_COMPARISON_DISPLAY_NUMBER,
+ SMP_MOVE_TO_SEC_CONN_PHASE2,
+ SMP_PH2_DHKEY_CHECKS_ARE_PRESENT,
+ SMP_WAIT_FOR_BOTH_PUBLIC_KEYS,
+ SMP_START_PASSKEY_VERIFICATION,
+ SMP_SEND_KEYPRESS_NOTIFICATION,
+ SMP_PROCESS_KEYPRESS_NOTIFICATION,
+ SMP_PROCESS_SECURE_CONNECTION_OOB_DATA,
+ SMP_SET_LOCAL_OOB_KEYS,
+ SMP_SET_LOCAL_OOB_RAND_COMMITMENT,
+ SMP_IDLE_TERMINATE,
+ SMP_FAST_CONN_PARAM,
+ SMP_SM_NO_ACTION
+};
+
+#if (BLE_INCLUDED == TRUE)
+static const tSMP_ACT smp_sm_action[SMP_SM_NO_ACTION] = {
+ smp_proc_sec_req,
+ smp_send_pair_req,
+ smp_send_pair_rsp,
+ smp_send_confirm,
+ smp_send_pair_fail,
+ smp_send_rand,
+ smp_send_enc_info,
+ smp_send_id_info,
+ smp_send_ltk_reply,
+ smp_proc_pair_cmd,
+ smp_proc_pair_fail,
+ smp_proc_confirm,
+ smp_proc_rand,
+ smp_proc_enc_info,
+ smp_proc_master_id,
+ smp_proc_id_info,
+ smp_proc_id_addr,
+ smp_proc_srk_info,
+ smp_proc_sec_grant,
+ smp_proc_sl_key,
+ smp_proc_compare,
+ smp_process_io_response,
+ smp_generate_compare,
+ smp_generate_srand_mrand_confirm,
+ smp_generate_stk,
+ smp_key_distribution,
+ smp_start_enc,
+ smp_pairing_cmpl,
+ smp_decide_association_model,
+ smp_send_app_cback,
+ smp_check_auth_req,
+ smp_pair_terminate,
+ smp_enc_cmpl,
+ smp_proc_discard,
+ smp_create_private_key,
+ smp_use_oob_private_key,
+ smp_send_pair_public_key,
+ smp_process_pairing_public_key,
+ smp_both_have_public_keys,
+ smp_start_secure_connection_phase1,
+ smp_process_local_nonce,
+ smp_send_commitment,
+ smp_process_pairing_commitment,
+ smp_process_peer_nonce,
+ smp_calculate_local_dhkey_check,
+ smp_send_dhkey_check,
+ smp_process_dhkey_check,
+ smp_calculate_peer_dhkey_check,
+ smp_match_dhkey_checks,
+ smp_calculate_numeric_comparison_display_number,
+ smp_move_to_secure_connections_phase2,
+ smp_phase_2_dhkey_checks_are_present,
+ smp_wait_for_both_public_keys,
+ smp_start_passkey_verification,
+ smp_send_keypress_notification,
+ smp_process_keypress_notification,
+ smp_process_secure_connection_oob_data,
+ smp_set_local_oob_keys,
+ smp_set_local_oob_random_commitment,
+ smp_idle_terminate,
+ smp_fast_conn_param
+};
+#else
+static const tSMP_ACT smp_sm_action[SMP_SM_NO_ACTION] = {NULL};
+#endif ///BLE_INCLUDED == TRUE
+
+/************ SMP Master FSM State/Event Indirection Table **************/
+static const UINT8 smp_master_entry_map[][SMP_STATE_MAX] = {
+ /* state name: Idle WaitApp SecReq Pair Wait Confirm Rand PublKey SCPhs1 Wait Wait SCPhs2 Wait DHKChk Enc Bond CrLocSc
+ Rsp Pend ReqRsp Cfm Exch Strt Cmtm Nonce Strt DHKChk Pend Pend OobData */
+ /* PAIR_REQ */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* PAIR_RSP */{ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* CONFIRM */{ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* RAND */{ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 },
+ /* PAIR_FAIL */{ 0, 0x81, 0, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0, 0x81, 0 },
+ /* ENC_INFO */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 },
+ /* MASTER_ID */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0 },
+ /* ID_INFO */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0 },
+ /* ID_ADDR */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0 },
+ /* SIGN_INFO */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0 },
+ /* SEC_REQ */{ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* PAIR_PUBLIC_KEY */{ 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* PAIR_DHKEY_CHCK */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
+ /* PAIR_KEYPR_NOTIF */{ 0, 8, 0, 0, 0, 0, 0, 0, 5, 2, 0, 0, 0, 0, 0, 0, 0 },
+ /* PAIR_COMMITM */{ 0, 0, 0, 0, 0, 0, 0, 0, 6, 1, 0, 0, 0, 0, 0, 0, 0 },
+ /* KEY_READY */{ 0, 3, 0, 3, 1, 0, 2, 0, 4, 0, 0, 0, 0, 0, 1, 6, 0 },
+ /* ENC_CMPL */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0 },
+ /* L2C_CONN */{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* L2C_DISC */{ 3, 0x83, 0, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0 },
+ /* IO_RSP */{ 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* SEC_GRANT */{ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* TK_REQ */{ 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* AUTH_CMPL */{ 4, 0x82, 0, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0 },
+ /* ENC_REQ */{ 0, 4, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0 },
+ /* BOND_REQ */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 },
+ /* DISCARD_SEC_REQ */{ 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 },
+ /* PUBL_KEY_EXCH_REQ */{ 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* LOC_PUBL_KEY_CRTD */{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
+ /* BOTH_PUBL_KEYS_RCVD */{ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* SC_DHKEY_CMPLT */{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* HAVE_LOC_NONCE */{ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2 },
+ /* SC_PHASE1_CMPLT */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 },
+ /* SC_CALC_NC */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0 },
+ /* SC_DSPL_NC */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0 },
+ /* SC_NC_OK */{ 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* SC_2_DHCK_CHKS_PRES */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* SC_KEY_READY */{ 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 },
+ /* KEYPR_NOTIF */{ 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* SC_OOB_DATA */{ 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* CR_LOC_SC_OOB_DATA */{ 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+};
+
+static const UINT8 smp_all_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* PAIR_FAIL */ {SMP_PROC_PAIR_FAIL, SMP_PAIRING_CMPL, SMP_STATE_IDLE},
+ /* AUTH_CMPL */ {SMP_SEND_PAIR_FAIL, SMP_PAIRING_CMPL, SMP_STATE_IDLE},
+ /* L2C_DISC */ {SMP_PAIR_TERMINATE, SMP_SM_NO_ACTION, SMP_STATE_IDLE}
+};
+
+static const UINT8 smp_master_idle_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* L2C_CONN */ {SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+ /* SEC_REQ */ {SMP_PROC_SEC_REQ, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP},
+ /* L2C_DISC */ {SMP_IDLE_TERMINATE, SMP_SM_NO_ACTION, SMP_STATE_IDLE},
+ /* AUTH_CMPL */ {SMP_PAIRING_CMPL, SMP_SM_NO_ACTION, SMP_STATE_IDLE}
+ /* CR_LOC_SC_OOB_DATA */ , {SMP_CREATE_PRIVATE_KEY, SMP_SM_NO_ACTION, SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA}
+
+};
+
+static const UINT8 smp_master_wait_for_app_response_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* SEC_GRANT */ {SMP_PROC_SEC_GRANT, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP},
+ /* IO_RSP */ {SMP_SEND_PAIR_REQ, SMP_FAST_CONN_PARAM, SMP_STATE_PAIR_REQ_RSP},
+
+ /* TK ready */
+ /* KEY_READY */ {SMP_GENERATE_CONFIRM, SMP_SM_NO_ACTION, SMP_STATE_WAIT_CONFIRM},
+
+ /* start enc mode setup */
+ /* ENC_REQ */ { SMP_START_ENC, SMP_FAST_CONN_PARAM, SMP_STATE_ENCRYPTION_PENDING},
+ /* DISCARD_SEC_REQ */ { SMP_PROC_DISCARD, SMP_SM_NO_ACTION, SMP_STATE_IDLE}
+ /* user confirms NC 'OK', i.e. phase 1 is completed */
+ /* SC_NC_OK */, { SMP_MOVE_TO_SEC_CONN_PHASE2, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS2_START},
+ /* user-provided passkey is rcvd */
+ /* SC_KEY_READY */ { SMP_START_PASSKEY_VERIFICATION, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START},
+ /* PAIR_KEYPR_NOTIF */ { SMP_PROCESS_KEYPRESS_NOTIFICATION, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP},
+ /* KEYPR_NOTIF */ { SMP_SEND_KEYPRESS_NOTIFICATION, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+ /* SC_OOB_DATA */ { SMP_USE_OOB_PRIVATE_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH}
+};
+
+static const UINT8 smp_master_pair_request_response_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* PAIR_RSP */ { SMP_PROC_PAIR_CMD, SMP_SM_NO_ACTION, SMP_STATE_PAIR_REQ_RSP},
+ /* TK_REQ */ { SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+
+ /* TK ready */
+ /* KEY_READY */{ SMP_GENERATE_CONFIRM, SMP_SM_NO_ACTION, SMP_STATE_WAIT_CONFIRM}
+ /* PUBL_KEY_EXCH_REQ */, { SMP_CREATE_PRIVATE_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH}
+};
+
+static const UINT8 smp_master_wait_for_confirm_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* KEY_READY*/ {SMP_SEND_CONFIRM, SMP_SM_NO_ACTION, SMP_STATE_CONFIRM}/* CONFIRM ready */
+};
+
+static const UINT8 smp_master_confirm_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* CONFIRM */ { SMP_PROC_CONFIRM, SMP_SEND_RAND, SMP_STATE_RAND}
+};
+
+static const UINT8 smp_master_rand_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* RAND */ { SMP_PROC_RAND, SMP_GENERATE_COMPARE, SMP_STATE_RAND},
+ /* KEY_READY*/ { SMP_PROC_COMPARE, SMP_SM_NO_ACTION, SMP_STATE_RAND}, /* Compare ready */
+ /* ENC_REQ */ { SMP_GENERATE_STK, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING}
+};
+
+static const UINT8 smp_master_public_key_exchange_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* LOC_PUBL_KEY_CRTD */{ SMP_SEND_PAIR_PUBLIC_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH},
+ /* PAIR_PUBLIC_KEY */{ SMP_PROCESS_PAIR_PUBLIC_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH},
+ /* BOTH_PUBL_KEYS_RCVD */{ SMP_HAVE_BOTH_PUBLIC_KEYS, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START},
+};
+
+static const UINT8 smp_master_sec_conn_phs1_start_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* SC_DHKEY_CMPLT */{ SMP_START_SEC_CONN_PHASE1, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START},
+ /* HAVE_LOC_NONCE */{ SMP_PROCESS_LOCAL_NONCE, SMP_SM_NO_ACTION, SMP_STATE_WAIT_COMMITMENT},
+ /* TK_REQ */{ SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+ /* SMP_MODEL_SEC_CONN_PASSKEY_DISP model, passkey is sent up to display,*/
+ /* It's time to start commitment calculation */
+ /* KEY_READY */{ SMP_START_PASSKEY_VERIFICATION, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START},
+ /* PAIR_KEYPR_NOTIF */{ SMP_PROCESS_KEYPRESS_NOTIFICATION, SMP_SEND_APP_CBACK, SMP_STATE_SEC_CONN_PHS1_START},
+ /* PAIR_COMMITM */{ SMP_PROCESS_PAIRING_COMMITMENT, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START},
+};
+
+static const UINT8 smp_master_wait_commitment_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* PAIR_COMMITM */{ SMP_PROCESS_PAIRING_COMMITMENT, SMP_SEND_RAND, SMP_STATE_WAIT_NONCE},
+ /* PAIR_KEYPR_NOTIF */{ SMP_PROCESS_KEYPRESS_NOTIFICATION, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_COMMITMENT},
+};
+
+static const UINT8 smp_master_wait_nonce_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* peer nonce is received */
+ /* RAND */{SMP_PROC_RAND, SMP_PROCESS_PEER_NONCE, SMP_STATE_SEC_CONN_PHS2_START},
+ /* NC model, time to calculate number for NC */
+ /* SC_CALC_NC */{SMP_CALCULATE_NUMERIC_COMPARISON_DISPLAY_NUMBER, SMP_SM_NO_ACTION, SMP_STATE_WAIT_NONCE},
+ /* NC model, time to display calculated number for NC to the user */
+ /* SC_DSPL_NC */{SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+};
+
+static const UINT8 smp_master_sec_conn_phs2_start_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* SC_PHASE1_CMPLT */{SMP_CALCULATE_LOCAL_DHKEY_CHECK, SMP_SEND_DHKEY_CHECK, SMP_STATE_WAIT_DHK_CHECK},
+};
+
+static const UINT8 smp_master_wait_dhk_check_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* PAIR_DHKEY_CHCK */{SMP_PROCESS_DHKEY_CHECK, SMP_CALCULATE_PEER_DHKEY_CHECK, SMP_STATE_DHK_CHECK},
+};
+
+static const UINT8 smp_master_dhk_check_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* locally calculated peer dhkey check is ready -> compare it withs DHKey Check actually received from peer */
+ /* SC_KEY_READY */{SMP_MATCH_DHKEY_CHECKS, SMP_SM_NO_ACTION, SMP_STATE_DHK_CHECK},
+ /* locally calculated peer dhkey check is ready -> calculate STK, go to sending */
+ /* HCI LE Start Encryption command */
+ /* ENC_REQ */{SMP_GENERATE_STK, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING},
+};
+
+static const UINT8 smp_master_enc_pending_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* STK ready */
+ /* KEY_READY */ { SMP_START_ENC, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING},
+ /* ENCRYPTED */ { SMP_CHECK_AUTH_REQ, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING},
+ /* BOND_REQ */ { SMP_KEY_DISTRIBUTE, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}
+};
+static const UINT8 smp_master_bond_pending_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* ENC_INFO */ { SMP_PROC_ENC_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+ /* ID_INFO */ { SMP_PROC_ID_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+ /* SIGN_INFO*/ { SMP_PROC_SRK_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+ /* MASTER_ID*/ { SMP_PROC_MASTER_ID, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+ /* ID_ADDR */ { SMP_PROC_ID_ADDR, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+ /* KEY_READY */{SMP_SEND_ENC_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING} /* LTK ready */
+};
+
+static const UINT8 smp_master_create_local_sec_conn_oob_data[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* LOC_PUBL_KEY_CRTD */ {SMP_SET_LOCAL_OOB_KEYS, SMP_SM_NO_ACTION, SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA},
+ /* HAVE_LOC_NONCE */ {SMP_SET_LOCAL_OOB_RAND_COMMITMENT, SMP_SM_NO_ACTION, SMP_STATE_IDLE}
+};
+
+
+/************ SMP Slave FSM State/Event Indirection Table **************/
+static const UINT8 smp_slave_entry_map[][SMP_STATE_MAX] = {
+ /* state name: Idle WaitApp SecReq Pair Wait Confirm Rand PublKey SCPhs1 Wait Wait SCPhs2 Wait DHKChk Enc Bond CrLocSc
+ Rsp Pend ReqRsp Cfm Exch Strt Cmtm Nonce Strt DHKChk Pend Pend OobData */
+ /* PAIR_REQ */{ 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* PAIR_RSP */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* CONFIRM */{ 0, 4, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* RAND */{ 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 },
+ /* PAIR_FAIL */{ 0, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0, 0 },
+ /* ENC_INFO */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0 },
+ /* MASTER_ID */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0 },
+ /* ID_INFO */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0 },
+ /* ID_ADDR */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 },
+ /* SIGN_INFO */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0 },
+ /* SEC_REQ */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* PAIR_PUBLIC_KEY */{ 0, 0, 0, 5, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* PAIR_DHKEY_CHCK */{ 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 0, 0, 0 },
+ /* PAIR_KEYPR_NOTIF */{ 0, 9, 0, 0, 0, 0, 0, 0, 5, 2, 0, 0, 0, 0, 0, 0, 0 },
+ /* PAIR_COMMITM */{ 0, 8, 0, 0, 0, 0, 0, 0, 6, 1, 0, 0, 0, 0, 0, 0, 0 },
+ /* KEY_READY */{ 0, 3, 0, 3, 2, 2, 1, 0, 4, 0, 0, 0, 0, 0, 2, 1, 0 },
+ /* ENC_CMPL */{ 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 },
+ /* L2C_CONN */{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* L2C_DISC */{ 0, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0 },
+ /* IO_RSP */{ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* SEC_GRANT */{ 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* TK_REQ */{ 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* AUTH_CMPL */{ 0, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0 },
+ /* ENC_REQ */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
+ /* BOND_REQ */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0 },
+ /* DISCARD_SEC_REQ */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* PUBL_KEY_EXCH_REQ */{ 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* LOC_PUBL_KEY_CRTD */{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
+ /* BOTH_PUBL_KEYS_RCVD */{ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* SC_DHKEY_CMPLT */{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* HAVE_LOC_NONCE */{ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2 },
+ /* SC_PHASE1_CMPLT */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 },
+ /* SC_CALC_NC */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0 },
+ /* SC_DSPL_NC */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0 },
+ /* SC_NC_OK */{ 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* SC_2_DHCK_CHKS_PRES */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0 },
+ /* SC_KEY_READY */{ 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 },
+ /* KEYPR_NOTIF */{ 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* SC_OOB_DATA */{ 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* CR_LOC_SC_OOB_DATA */{ 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+};
+
+static const UINT8 smp_slave_idle_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* L2C_CONN */ {SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+ /* PAIR_REQ */ {SMP_PROC_PAIR_CMD, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP}
+ /* CR_LOC_SC_OOB_DATA */ , {SMP_CREATE_PRIVATE_KEY, SMP_SM_NO_ACTION, SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA}
+};
+
+static const UINT8 smp_slave_wait_for_app_response_table [][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* IO_RSP */ {SMP_PROC_IO_RSP, SMP_FAST_CONN_PARAM, SMP_STATE_PAIR_REQ_RSP},
+ /* SEC_GRANT */ {SMP_PROC_SEC_GRANT, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP},
+
+ /* TK ready */
+ /* KEY_READY */ {SMP_PROC_SL_KEY, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+ /* CONFIRM */ {SMP_PROC_CONFIRM, SMP_SM_NO_ACTION, SMP_STATE_CONFIRM}
+ /* DHKey Check from master is received before phase 1 is completed - race */
+ /* PAIR_DHKEY_CHCK */, {SMP_PROCESS_DHKEY_CHECK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+ /* user confirms NC 'OK', i.e. phase 1 is completed */
+ /* SC_NC_OK */ {SMP_MOVE_TO_SEC_CONN_PHASE2, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS2_START},
+ /* user-provided passkey is rcvd */
+ /* SC_KEY_READY */ {SMP_START_PASSKEY_VERIFICATION, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START},
+ /* PAIR_COMMITM */ {SMP_PROCESS_PAIRING_COMMITMENT, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+ /* PAIR_KEYPR_NOTIF */ {SMP_PROCESS_KEYPRESS_NOTIFICATION, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP},
+ /* KEYPR_NOTIF */ {SMP_SEND_KEYPRESS_NOTIFICATION, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+ /* SC_OOB_DATA */ {SMP_SEND_PAIR_RSP, SMP_SM_NO_ACTION, SMP_STATE_PAIR_REQ_RSP},
+};
+
+static const UINT8 smp_slave_sec_request_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* PAIR_REQ */{SMP_PROC_PAIR_CMD, SMP_SM_NO_ACTION, SMP_STATE_PAIR_REQ_RSP},
+ /* ENCRYPTED*/{SMP_ENC_CMPL, SMP_SM_NO_ACTION, SMP_STATE_PAIR_REQ_RSP},
+};
+
+static const UINT8 smp_slave_pair_request_response_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* CONFIRM */ {SMP_PROC_CONFIRM, SMP_SM_NO_ACTION, SMP_STATE_CONFIRM},
+ /* TK_REQ */ {SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+ /* TK/Confirm ready */
+ /* KEY_READY */{SMP_PROC_SL_KEY, SMP_SM_NO_ACTION, SMP_STATE_PAIR_REQ_RSP}
+ /* PUBL_KEY_EXCH_REQ */, { SMP_CREATE_PRIVATE_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH},
+ /* PAIR_PUBLIC_KEY */ { SMP_PROCESS_PAIR_PUBLIC_KEY, SMP_SM_NO_ACTION, SMP_STATE_PAIR_REQ_RSP},
+};
+
+static const UINT8 smp_slave_wait_confirm_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* CONFIRM */ {SMP_PROC_CONFIRM, SMP_SEND_CONFIRM, SMP_STATE_CONFIRM},
+ /* KEY_READY*/ {SMP_PROC_SL_KEY, SMP_SM_NO_ACTION, SMP_STATE_WAIT_CONFIRM}
+};
+
+static const UINT8 smp_slave_confirm_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* RAND */ {SMP_PROC_RAND, SMP_GENERATE_COMPARE, SMP_STATE_RAND},
+
+ /* TK/Confirm ready */
+ /* KEY_READY*/ {SMP_PROC_SL_KEY, SMP_SM_NO_ACTION, SMP_STATE_CONFIRM}
+};
+
+static const UINT8 smp_slave_rand_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* KEY_READY */ {SMP_PROC_COMPARE, SMP_SM_NO_ACTION, SMP_STATE_RAND}, /* compare match */
+ /* RAND */ {SMP_SEND_RAND, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING}
+};
+
+static const UINT8 smp_slave_public_key_exch_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* LOC_PUBL_KEY_CRTD */{ SMP_WAIT_FOR_BOTH_PUBLIC_KEYS, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH},
+ /* PAIR_PUBLIC_KEY */{ SMP_PROCESS_PAIR_PUBLIC_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH},
+ /* BOTH_PUBL_KEYS_RCVD */{ SMP_HAVE_BOTH_PUBLIC_KEYS, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START},
+};
+
+static const UINT8 smp_slave_sec_conn_phs1_start_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* SC_DHKEY_CMPLT */{ SMP_START_SEC_CONN_PHASE1, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START},
+ /* HAVE_LOC_NONCE */{ SMP_PROCESS_LOCAL_NONCE, SMP_SM_NO_ACTION, SMP_STATE_WAIT_COMMITMENT},
+ /* TK_REQ */{ SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+ /* SMP_MODEL_SEC_CONN_PASSKEY_DISP model, passkey is sent up to display, it's time to start */
+ /* commitment calculation */
+ /* KEY_READY */{ SMP_START_PASSKEY_VERIFICATION, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START},
+ /* PAIR_KEYPR_NOTIF */{ SMP_PROCESS_KEYPRESS_NOTIFICATION, SMP_SEND_APP_CBACK, SMP_STATE_SEC_CONN_PHS1_START},
+ /*COMMIT*/{SMP_PROCESS_PAIRING_COMMITMENT, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS1_START},
+};
+
+static const UINT8 smp_slave_wait_commitment_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* PAIR_COMMITM */{SMP_PROCESS_PAIRING_COMMITMENT, SMP_SEND_COMMITMENT, SMP_STATE_WAIT_NONCE},
+ /* PAIR_KEYPR_NOTIF */{SMP_PROCESS_KEYPRESS_NOTIFICATION, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_COMMITMENT},
+};
+
+static const UINT8 smp_slave_wait_nonce_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* peer nonce is received */
+ /* RAND */{SMP_PROC_RAND, SMP_PROCESS_PEER_NONCE, SMP_STATE_SEC_CONN_PHS2_START},
+ /* NC model, time to calculate number for NC */
+ /* SC_CALC_NC */{SMP_CALCULATE_NUMERIC_COMPARISON_DISPLAY_NUMBER, SMP_SM_NO_ACTION, SMP_STATE_WAIT_NONCE},
+ /* NC model, time to display calculated number for NC to the user */
+ /* SC_DSPL_NC */{SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+};
+
+static const UINT8 smp_slave_sec_conn_phs2_start_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* SC_PHASE1_CMPLT */{SMP_CALCULATE_LOCAL_DHKEY_CHECK, SMP_PH2_DHKEY_CHECKS_ARE_PRESENT, SMP_STATE_WAIT_DHK_CHECK},
+ /* DHKey Check from master is received before slave DHKey calculation is completed - race */
+ /* PAIR_DHKEY_CHCK */{SMP_PROCESS_DHKEY_CHECK, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS2_START},
+};
+
+static const UINT8 smp_slave_wait_dhk_check_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* PAIR_DHKEY_CHCK */{SMP_PROCESS_DHKEY_CHECK, SMP_CALCULATE_PEER_DHKEY_CHECK, SMP_STATE_DHK_CHECK},
+ /* DHKey Check from master was received before slave came to this state */
+ /* SC_2_DHCK_CHKS_PRES */{SMP_CALCULATE_PEER_DHKEY_CHECK, SMP_SM_NO_ACTION, SMP_STATE_DHK_CHECK},
+};
+
+static const UINT8 smp_slave_dhk_check_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+
+ /* locally calculated peer dhkey check is ready -> compare it withs DHKey Check */
+ /* actually received from peer */
+ /* SC_KEY_READY */{SMP_MATCH_DHKEY_CHECKS, SMP_SM_NO_ACTION, SMP_STATE_DHK_CHECK},
+
+ /* dhkey checks match -> send local dhkey check to master, go to wait for HCI LE */
+ /* Long Term Key Request Event */
+ /* PAIR_DHKEY_CHCK */{SMP_SEND_DHKEY_CHECK, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING},
+};
+
+static const UINT8 smp_slave_enc_pending_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* ENC_REQ */ {SMP_GENERATE_STK, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING},
+
+ /* STK ready */
+ /* KEY_READY */ {SMP_SEND_LTK_REPLY, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING},
+ /* ENCRYPTED */ {SMP_CHECK_AUTH_REQ, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING},
+ /* BOND_REQ */ {SMP_KEY_DISTRIBUTE, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}
+};
+static const UINT8 smp_slave_bond_pending_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+
+ /* LTK ready */
+ /* KEY_READY */{ SMP_SEND_ENC_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+
+ /* rev SRK */
+ /* SIGN_INFO */{ SMP_PROC_SRK_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+ /* ENC_INFO */ { SMP_PROC_ENC_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+ /* ID_INFO */ { SMP_PROC_ID_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+ /* MASTER_ID*/ { SMP_PROC_MASTER_ID, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+ /* ID_ADDR */ { SMP_PROC_ID_ADDR, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}
+
+};
+
+static const UINT8 smp_slave_create_local_sec_conn_oob_data[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* LOC_PUBL_KEY_CRTD */ {SMP_SET_LOCAL_OOB_KEYS, SMP_SM_NO_ACTION, SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA},
+ /* HAVE_LOC_NONCE */ {SMP_SET_LOCAL_OOB_RAND_COMMITMENT, SMP_SM_NO_ACTION, SMP_STATE_IDLE}
+};
+
+static const tSMP_SM_TBL smp_state_table[][2] = {
+ /* SMP_STATE_IDLE */
+ {smp_master_idle_table, smp_slave_idle_table},
+
+ /* SMP_STATE_WAIT_APP_RSP */
+ {smp_master_wait_for_app_response_table, smp_slave_wait_for_app_response_table},
+
+ /* SMP_STATE_SEC_REQ_PENDING */
+ {NULL, smp_slave_sec_request_table},
+
+ /* SMP_STATE_PAIR_REQ_RSP */
+ {smp_master_pair_request_response_table, smp_slave_pair_request_response_table},
+
+ /* SMP_STATE_WAIT_CONFIRM */
+ {smp_master_wait_for_confirm_table, smp_slave_wait_confirm_table},
+
+ /* SMP_STATE_CONFIRM */
+ {smp_master_confirm_table, smp_slave_confirm_table},
+
+ /* SMP_STATE_RAND */
+ {smp_master_rand_table, smp_slave_rand_table},
+
+ /* SMP_STATE_PUBLIC_KEY_EXCH */
+ {smp_master_public_key_exchange_table, smp_slave_public_key_exch_table},
+
+ /* SMP_STATE_SEC_CONN_PHS1_START */
+ {smp_master_sec_conn_phs1_start_table, smp_slave_sec_conn_phs1_start_table},
+
+ /* SMP_STATE_WAIT_COMMITMENT */
+ {smp_master_wait_commitment_table, smp_slave_wait_commitment_table},
+
+ /* SMP_STATE_WAIT_NONCE */
+ {smp_master_wait_nonce_table, smp_slave_wait_nonce_table},
+
+ /* SMP_STATE_SEC_CONN_PHS2_START */
+ {smp_master_sec_conn_phs2_start_table, smp_slave_sec_conn_phs2_start_table},
+
+ /* SMP_STATE_WAIT_DHK_CHECK */
+ {smp_master_wait_dhk_check_table, smp_slave_wait_dhk_check_table},
+
+ /* SMP_STATE_DHK_CHECK */
+ {smp_master_dhk_check_table, smp_slave_dhk_check_table},
+
+ /* SMP_STATE_ENCRYPTION_PENDING */
+ {smp_master_enc_pending_table, smp_slave_enc_pending_table},
+
+ /* SMP_STATE_BOND_PENDING */
+ {smp_master_bond_pending_table, smp_slave_bond_pending_table},
+
+ /* SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA */
+ {smp_master_create_local_sec_conn_oob_data, smp_slave_create_local_sec_conn_oob_data}
+};
+
+typedef const UINT8 (*tSMP_ENTRY_TBL)[SMP_STATE_MAX];
+static const tSMP_ENTRY_TBL smp_entry_table[] = {
+ smp_master_entry_map,
+ smp_slave_entry_map
+};
+
+#if SMP_DYNAMIC_MEMORY == FALSE
+tSMP_CB smp_cb;
+#else
+tSMP_CB *smp_cb_ptr;
+#endif
+#define SMP_ALL_TBL_MASK 0x80
+
+/*******************************************************************************
+** Function smp_set_state
+** Returns None
+*******************************************************************************/
+void smp_set_state(tSMP_STATE state)
+{
+ if (state < SMP_STATE_MAX) {
+ SMP_TRACE_DEBUG( "State change: %s(%d) ==> %s(%d)",
+ smp_get_state_name(smp_cb.state), smp_cb.state,
+ smp_get_state_name(state), state );
+ smp_cb.state = state;
+ } else {
+ SMP_TRACE_DEBUG("smp_set_state invalid state =%d", state );
+ }
+}
+
+/*******************************************************************************
+** Function smp_get_state
+** Returns The smp state
+*******************************************************************************/
+tSMP_STATE smp_get_state(void)
+{
+ return smp_cb.state;
+}
+
+/*******************************************************************************
+**
+** Function smp_sm_event
+**
+** Description Handle events to the state machine. It looks up the entry
+** in the smp_entry_table array.
+** If it is a valid entry, it gets the state table.Set the next state,
+** if not NULL state.Execute the action function according to the
+** state table. If the state returned by action function is not NULL
+** state, adjust the new state to the returned state.If (api_evt != MAX),
+** call callback function.
+**
+** Returns void.
+**
+*******************************************************************************/
+void smp_sm_event(tSMP_CB *p_cb, tSMP_EVENT event, void *p_data)
+{
+ UINT8 curr_state = p_cb->state;
+ tSMP_SM_TBL state_table;
+ UINT8 action, entry, i;
+ tSMP_ENTRY_TBL entry_table = smp_entry_table[p_cb->role];
+
+ SMP_TRACE_EVENT("main smp_sm_event\n");
+ if (curr_state >= SMP_STATE_MAX) {
+ SMP_TRACE_DEBUG( "Invalid state: %d\n", curr_state) ;
+ return;
+ }
+
+ SMP_TRACE_DEBUG( "SMP Role: %s State: [%s (%d)], Event: [%s (%d)]", \
+ (p_cb->role == 0x01) ? "Slave" : "Master\n", smp_get_state_name( p_cb->state),
+ p_cb->state, smp_get_event_name(event), event) ;
+
+ /* look up the state table for the current state */
+ /* lookup entry /w event & curr_state */
+ /* If entry is ignore, return.
+ * Otherwise, get state table (according to curr_state or all_state) */
+ if ((event <= SMP_MAX_EVT) && ( (entry = entry_table[event - 1][curr_state]) != SMP_SM_IGNORE )) {
+ if (entry & SMP_ALL_TBL_MASK) {
+ entry &= ~SMP_ALL_TBL_MASK;
+ state_table = smp_all_table;
+ } else {
+ state_table = smp_state_table[curr_state][p_cb->role ? 1 : 0];
+ }
+ } else {
+ SMP_TRACE_DEBUG( "Ignore event [%s (%d)] in state [%s (%d)]\n",
+ smp_get_event_name(event), event, smp_get_state_name(curr_state),
+ curr_state);
+ return;
+ }
+
+ /* Get possible next state from state table. */
+
+ smp_set_state(state_table[entry - 1][SMP_SME_NEXT_STATE]);
+
+ /* If action is not ignore, clear param, exec action and get next state.
+ * The action function may set the Param for cback.
+ * Depending on param, call cback or free buffer. */
+ /* execute action */
+ /* execute action functions */
+ for (i = 0; i < SMP_NUM_ACTIONS; i++) {
+ if ((action = state_table[entry - 1][i]) != SMP_SM_NO_ACTION && smp_sm_action[action] != NULL) {
+ (*smp_sm_action[action])(p_cb, (tSMP_INT_DATA *)p_data);
+ } else {
+ break;
+ }
+ }
+ SMP_TRACE_DEBUG( "result state = %s\n", smp_get_state_name( p_cb->state ) ) ;
+}
+
+/*******************************************************************************
+** Function smp_get_state_name
+** Returns The smp state name.
+*******************************************************************************/
+const char *smp_get_state_name(tSMP_STATE state)
+{
+ const char *p_str = smp_state_name[SMP_STATE_MAX];
+
+ if (state < SMP_STATE_MAX) {
+ p_str = smp_state_name[state];
+ }
+ return p_str;
+}
+
+/*******************************************************************************
+** Function smp_get_event_name
+** Returns The smp event name.
+*******************************************************************************/
+const char *smp_get_event_name(tSMP_EVENT event)
+{
+ const char *p_str = smp_event_name[SMP_MAX_EVT];
+
+ if (event <= SMP_MAX_EVT) {
+ p_str = smp_event_name[event - 1];
+ }
+ return p_str;
+}
+
+#endif
diff --git a/lib/bt/host/bluedroid/stack/smp/smp_utils.c b/lib/bt/host/bluedroid/stack/smp/smp_utils.c
new file mode 100644
index 00000000..2e9fac77
--- /dev/null
+++ b/lib/bt/host/bluedroid/stack/smp/smp_utils.c
@@ -0,0 +1,1645 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains functions for the SMP L2CAP utility functions
+ *
+ ******************************************************************************/
+#include "common/bt_target.h"
+
+#if SMP_INCLUDED == TRUE
+
+#include "stack/bt_types.h"
+//#include "bt_utils.h"
+#include <string.h>
+//#include <ctype.h>
+#include "stack/hcidefs.h"
+#include "stack/btm_ble_api.h"
+#include "stack/l2c_api.h"
+#include "l2c_int.h"
+#include "smp_int.h"
+#include "device/controller.h"
+#include "btm_int.h"
+#include "common/bte_appl.h"
+
+#define SMP_PAIRING_REQ_SIZE 7
+#define SMP_CONFIRM_CMD_SIZE (BT_OCTET16_LEN + 1)
+#define SMP_RAND_CMD_SIZE (BT_OCTET16_LEN + 1)
+#define SMP_INIT_CMD_SIZE (BT_OCTET16_LEN + 1)
+#define SMP_ENC_INFO_SIZE (BT_OCTET16_LEN + 1)
+#define SMP_MASTER_ID_SIZE (BT_OCTET8_LEN + 2 + 1)
+#define SMP_ID_INFO_SIZE (BT_OCTET16_LEN + 1)
+#define SMP_ID_ADDR_SIZE (BD_ADDR_LEN + 1 + 1)
+#define SMP_SIGN_INFO_SIZE (BT_OCTET16_LEN + 1)
+#define SMP_PAIR_FAIL_SIZE 2
+#define SMP_SECURITY_REQUEST_SIZE 2
+#define SMP_PAIR_PUBL_KEY_SIZE (1 /* opcode */ + (2*BT_OCTET32_LEN))
+#define SMP_PAIR_COMMITM_SIZE (1 /* opcode */ + BT_OCTET16_LEN /*Commitment*/)
+#define SMP_PAIR_DHKEY_CHECK_SIZE (1 /* opcode */ + BT_OCTET16_LEN /*DHKey Check*/)
+#define SMP_PAIR_KEYPR_NOTIF_SIZE (1 /* opcode */ + 1 /*Notif Type*/)
+
+/* SMP command sizes per spec */
+static const UINT8 smp_cmd_size_per_spec[] = {
+ 0,
+ SMP_PAIRING_REQ_SIZE, /* 0x01: pairing request */
+ SMP_PAIRING_REQ_SIZE, /* 0x02: pairing response */
+ SMP_CONFIRM_CMD_SIZE, /* 0x03: pairing confirm */
+ SMP_RAND_CMD_SIZE, /* 0x04: pairing random */
+ SMP_PAIR_FAIL_SIZE, /* 0x05: pairing failed */
+ SMP_ENC_INFO_SIZE, /* 0x06: encryption information */
+ SMP_MASTER_ID_SIZE, /* 0x07: master identification */
+ SMP_ID_INFO_SIZE, /* 0x08: identity information */
+ SMP_ID_ADDR_SIZE, /* 0x09: identity address information */
+ SMP_SIGN_INFO_SIZE, /* 0x0A: signing information */
+ SMP_SECURITY_REQUEST_SIZE, /* 0x0B: security request */
+ SMP_PAIR_PUBL_KEY_SIZE, /* 0x0C: pairing public key */
+ SMP_PAIR_DHKEY_CHECK_SIZE, /* 0x0D: pairing dhkey check */
+ SMP_PAIR_KEYPR_NOTIF_SIZE, /* 0x0E: pairing keypress notification */
+ SMP_PAIR_COMMITM_SIZE /* 0x0F: pairing commitment */
+};
+
+static BOOLEAN smp_parameter_unconditionally_valid(tSMP_CB *p_cb);
+static BOOLEAN smp_parameter_unconditionally_invalid(tSMP_CB *p_cb);
+
+/* type for SMP command length validation functions */
+typedef BOOLEAN (*tSMP_CMD_LEN_VALID)(tSMP_CB *p_cb);
+
+static BOOLEAN smp_command_has_valid_fixed_length(tSMP_CB *p_cb);
+
+static const tSMP_CMD_LEN_VALID smp_cmd_len_is_valid[] = {
+ smp_parameter_unconditionally_invalid,
+ smp_command_has_valid_fixed_length, /* 0x01: pairing request */
+ smp_command_has_valid_fixed_length, /* 0x02: pairing response */
+ smp_command_has_valid_fixed_length, /* 0x03: pairing confirm */
+ smp_command_has_valid_fixed_length, /* 0x04: pairing random */
+ smp_command_has_valid_fixed_length, /* 0x05: pairing failed */
+ smp_command_has_valid_fixed_length, /* 0x06: encryption information */
+ smp_command_has_valid_fixed_length, /* 0x07: master identification */
+ smp_command_has_valid_fixed_length, /* 0x08: identity information */
+ smp_command_has_valid_fixed_length, /* 0x09: identity address information */
+ smp_command_has_valid_fixed_length, /* 0x0A: signing information */
+ smp_command_has_valid_fixed_length, /* 0x0B: security request */
+ smp_command_has_valid_fixed_length, /* 0x0C: pairing public key */
+ smp_command_has_valid_fixed_length, /* 0x0D: pairing dhkey check */
+ smp_command_has_valid_fixed_length, /* 0x0E: pairing keypress notification */
+ smp_command_has_valid_fixed_length /* 0x0F: pairing commitment */
+};
+
+/* type for SMP command parameter ranges validation functions */
+typedef BOOLEAN (*tSMP_CMD_PARAM_RANGES_VALID)(tSMP_CB *p_cb);
+
+static BOOLEAN smp_pairing_request_response_parameters_are_valid(tSMP_CB *p_cb);
+static BOOLEAN smp_pairing_keypress_notification_is_valid(tSMP_CB *p_cb);
+
+static const tSMP_CMD_PARAM_RANGES_VALID smp_cmd_param_ranges_are_valid[] = {
+ smp_parameter_unconditionally_invalid,
+ smp_pairing_request_response_parameters_are_valid, /* 0x01: pairing request */
+ smp_pairing_request_response_parameters_are_valid, /* 0x02: pairing response */
+ smp_parameter_unconditionally_valid, /* 0x03: pairing confirm */
+ smp_parameter_unconditionally_valid, /* 0x04: pairing random */
+ smp_parameter_unconditionally_valid, /* 0x05: pairing failed */
+ smp_parameter_unconditionally_valid, /* 0x06: encryption information */
+ smp_parameter_unconditionally_valid, /* 0x07: master identification */
+ smp_parameter_unconditionally_valid, /* 0x08: identity information */
+ smp_parameter_unconditionally_valid, /* 0x09: identity address information */
+ smp_parameter_unconditionally_valid, /* 0x0A: signing information */
+ smp_parameter_unconditionally_valid, /* 0x0B: security request */
+ smp_parameter_unconditionally_valid, /* 0x0C: pairing public key */
+ smp_parameter_unconditionally_valid, /* 0x0D: pairing dhkey check */
+ smp_pairing_keypress_notification_is_valid, /* 0x0E: pairing keypress notification */
+ smp_parameter_unconditionally_valid /* 0x0F: pairing commitment */
+};
+
+/* type for action functions */
+typedef BT_HDR *(*tSMP_CMD_ACT)(UINT8 cmd_code, tSMP_CB *p_cb);
+
+static BT_HDR *smp_build_pairing_cmd(UINT8 cmd_code, tSMP_CB *p_cb);
+static BT_HDR *smp_build_confirm_cmd(UINT8 cmd_code, tSMP_CB *p_cb);
+static BT_HDR *smp_build_rand_cmd(UINT8 cmd_code, tSMP_CB *p_cb);
+static BT_HDR *smp_build_pairing_fail(UINT8 cmd_code, tSMP_CB *p_cb);
+static BT_HDR *smp_build_identity_info_cmd(UINT8 cmd_code, tSMP_CB *p_cb);
+static BT_HDR *smp_build_encrypt_info_cmd(UINT8 cmd_code, tSMP_CB *p_cb);
+static BT_HDR *smp_build_security_request(UINT8 cmd_code, tSMP_CB *p_cb);
+static BT_HDR *smp_build_signing_info_cmd(UINT8 cmd_code, tSMP_CB *p_cb);
+static BT_HDR *smp_build_master_id_cmd(UINT8 cmd_code, tSMP_CB *p_cb);
+static BT_HDR *smp_build_id_addr_cmd(UINT8 cmd_code, tSMP_CB *p_cb);
+static BT_HDR *smp_build_pair_public_key_cmd(UINT8 cmd_code, tSMP_CB *p_cb);
+static BT_HDR *smp_build_pairing_commitment_cmd(UINT8 cmd_code, tSMP_CB *p_cb);
+static BT_HDR *smp_build_pair_dhkey_check_cmd(UINT8 cmd_code, tSMP_CB *p_cb);
+static BT_HDR *smp_build_pairing_keypress_notification_cmd(UINT8 cmd_code, tSMP_CB *p_cb);
+
+static const tSMP_CMD_ACT smp_cmd_build_act[] = {
+ NULL,
+ smp_build_pairing_cmd, /* 0x01: pairing request */
+ smp_build_pairing_cmd, /* 0x02: pairing response */
+ smp_build_confirm_cmd, /* 0x03: pairing confirm */
+ smp_build_rand_cmd, /* 0x04: pairing random */
+ smp_build_pairing_fail, /* 0x05: pairing failure */
+ smp_build_encrypt_info_cmd, /* 0x06: encryption information */
+ smp_build_master_id_cmd, /* 0x07: master identification */
+ smp_build_identity_info_cmd, /* 0x08: identity information */
+ smp_build_id_addr_cmd, /* 0x09: identity address information */
+ smp_build_signing_info_cmd, /* 0x0A: signing information */
+ smp_build_security_request, /* 0x0B: security request */
+ smp_build_pair_public_key_cmd, /* 0x0C: pairing public key */
+ smp_build_pair_dhkey_check_cmd, /* 0x0D: pairing DHKey check */
+ smp_build_pairing_keypress_notification_cmd, /* 0x0E: pairing keypress notification */
+ smp_build_pairing_commitment_cmd /* 0x0F: pairing commitment */
+};
+
+static const UINT8 smp_association_table[2][SMP_IO_CAP_MAX][SMP_IO_CAP_MAX] = {
+ /* display only */ /* Display Yes/No */ /* keyboard only */
+ /* No Input/Output */ /* keyboard display */
+
+ /* initiator */
+ /* model = tbl[peer_io_caps][loc_io_caps] */
+ /* Display Only */
+ { {
+ SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY,
+ SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY
+ },
+
+ /* Display Yes/No */
+ {
+ SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY,
+ SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY
+ },
+
+ /* Keyboard only */
+ {
+ SMP_MODEL_KEY_NOTIF, SMP_MODEL_KEY_NOTIF, SMP_MODEL_PASSKEY,
+ SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF
+ },
+
+ /* No Input No Output */
+ {
+ SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY,
+ SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY
+ },
+
+ /* keyboard display */
+ {
+ SMP_MODEL_KEY_NOTIF, SMP_MODEL_KEY_NOTIF, SMP_MODEL_PASSKEY,
+ SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF
+ }
+ },
+
+ /* responder */
+ /* model = tbl[loc_io_caps][peer_io_caps] */
+ /* Display Only */
+ { {
+ SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF,
+ SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF
+ },
+
+ /* Display Yes/No */
+ {
+ SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF,
+ SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF
+ },
+
+ /* keyboard only */
+ {
+ SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY,
+ SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY
+ },
+
+ /* No Input No Output */
+ {
+ SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY,
+ SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY
+ },
+
+ /* keyboard display */
+ {
+ SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_KEY_NOTIF,
+ SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY
+ }
+ }
+};
+
+static const UINT8 smp_association_table_sc[2][SMP_IO_CAP_MAX][SMP_IO_CAP_MAX] = {
+ /* display only */ /* Display Yes/No */ /* keyboard only */
+ /* No InputOutput */ /* keyboard display */
+
+ /* initiator */
+ /* model = tbl[peer_io_caps][loc_io_caps] */
+
+ /* Display Only */
+ { {
+ SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_PASSKEY_ENT,
+ SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_PASSKEY_ENT
+ },
+
+ /* Display Yes/No */
+ {
+ SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_NUM_COMP, SMP_MODEL_SEC_CONN_PASSKEY_ENT,
+ SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_NUM_COMP
+ },
+
+ /* keyboard only */
+ {
+ SMP_MODEL_SEC_CONN_PASSKEY_DISP, SMP_MODEL_SEC_CONN_PASSKEY_DISP, SMP_MODEL_SEC_CONN_PASSKEY_ENT,
+ SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_PASSKEY_DISP
+ },
+
+ /* No Input No Output */
+ {
+ SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS,
+ SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS
+ },
+
+ /* keyboard display */
+ {
+ SMP_MODEL_SEC_CONN_PASSKEY_DISP, SMP_MODEL_SEC_CONN_NUM_COMP, SMP_MODEL_SEC_CONN_PASSKEY_ENT,
+ SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_NUM_COMP
+ }
+ },
+
+ /* responder */
+ /* model = tbl[loc_io_caps][peer_io_caps] */
+
+ /* Display Only */
+ { {
+ SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_PASSKEY_DISP,
+ SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_PASSKEY_DISP
+ },
+
+ /* Display Yes/No */
+ {
+ SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_NUM_COMP, SMP_MODEL_SEC_CONN_PASSKEY_DISP,
+ SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_NUM_COMP
+ },
+
+ /* keyboard only */
+ {
+ SMP_MODEL_SEC_CONN_PASSKEY_ENT, SMP_MODEL_SEC_CONN_PASSKEY_ENT, SMP_MODEL_SEC_CONN_PASSKEY_ENT,
+ SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_PASSKEY_ENT
+ },
+
+ /* No Input No Output */
+ {
+ SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS,
+ SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS
+ },
+
+ /* keyboard display */
+ {
+ SMP_MODEL_SEC_CONN_PASSKEY_ENT, SMP_MODEL_SEC_CONN_NUM_COMP, SMP_MODEL_SEC_CONN_PASSKEY_DISP,
+ SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_NUM_COMP
+ }
+ }
+};
+
+static tSMP_ASSO_MODEL smp_select_legacy_association_model(tSMP_CB *p_cb);
+static tSMP_ASSO_MODEL smp_select_association_model_secure_connections(tSMP_CB *p_cb);
+
+/*******************************************************************************
+**
+** Function smp_send_msg_to_L2CAP
+**
+** Description Send message to L2CAP.
+**
+*******************************************************************************/
+BOOLEAN smp_send_msg_to_L2CAP(BD_ADDR rem_bda, BT_HDR *p_toL2CAP)
+{
+ UINT16 l2cap_ret;
+ UINT16 fixed_cid = L2CAP_SMP_CID;
+
+ if (smp_cb.smp_over_br) {
+ fixed_cid = L2CAP_SMP_BR_CID;
+ }
+
+ SMP_TRACE_EVENT("%s", __FUNCTION__);
+ smp_cb.total_tx_unacked += 1;
+
+ if ((l2cap_ret = L2CA_SendFixedChnlData (fixed_cid, rem_bda, p_toL2CAP)) == L2CAP_DW_FAILED) {
+ smp_cb.total_tx_unacked -= 1;
+ SMP_TRACE_ERROR("SMP failed to pass msg:0x%0x to L2CAP",
+ *((UINT8 *)(p_toL2CAP + 1) + p_toL2CAP->offset));
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_send_cmd
+**
+** Description send a SMP command on L2CAP channel.
+**
+*******************************************************************************/
+BOOLEAN smp_send_cmd(UINT8 cmd_code, tSMP_CB *p_cb)
+{
+ BT_HDR *p_buf;
+ BOOLEAN sent = FALSE;
+ UINT8 failure = SMP_PAIR_INTERNAL_ERR;
+ SMP_TRACE_EVENT("smp_send_cmd on l2cap cmd_code=0x%x\n", cmd_code);
+ if ( cmd_code <= (SMP_OPCODE_MAX + 1 /* for SMP_OPCODE_PAIR_COMMITM */) &&
+ smp_cmd_build_act[cmd_code] != NULL) {
+ p_buf = (*smp_cmd_build_act[cmd_code])(cmd_code, p_cb);
+
+ if (p_buf != NULL &&
+ smp_send_msg_to_L2CAP(p_cb->pairing_bda, p_buf)) {
+ sent = TRUE;
+
+ btu_stop_timer (&p_cb->rsp_timer_ent);
+ btu_start_timer (&p_cb->rsp_timer_ent, BTU_TTYPE_SMP_PAIRING_CMD,
+ SMP_WAIT_FOR_RSP_TOUT);
+ }
+ }
+
+ if (!sent) {
+ if (p_cb->smp_over_br) {
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &failure);
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+ } else {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+ }
+ }
+ return sent;
+}
+
+/*******************************************************************************
+**
+** Function smp_rsp_timeout
+**
+** Description Called when SMP wait for SMP command response timer expires
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_rsp_timeout(TIMER_LIST_ENT *p_tle)
+{
+ tSMP_CB *p_cb = &smp_cb;
+ UINT8 failure = SMP_RSP_TIMEOUT;
+ UNUSED(p_tle);
+
+ SMP_TRACE_EVENT("%s state:%d br_state:%d", __FUNCTION__, p_cb->state, p_cb->br_state);
+
+ if (p_cb->smp_over_br) {
+#if (CLASSIC_BT_INCLUDED == TRUE)
+ smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &failure);
+#endif ///CLASSIC_BT_INCLUDED == TRUE
+ } else {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_build_pairing_req_cmd
+**
+** Description Build pairing request command.
+**
+*******************************************************************************/
+BT_HDR *smp_build_pairing_cmd(UINT8 cmd_code, tSMP_CB *p_cb)
+{
+ BT_HDR *p_buf = NULL ;
+ UINT8 *p;
+
+ SMP_TRACE_EVENT("smp_build_pairing_cmd");
+ if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + SMP_PAIRING_REQ_SIZE + L2CAP_MIN_OFFSET)) != NULL) {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, cmd_code);
+ UINT8_TO_STREAM (p, p_cb->local_io_capability);
+ UINT8_TO_STREAM (p, p_cb->loc_oob_flag);
+ UINT8_TO_STREAM (p, p_cb->loc_auth_req);
+ UINT8_TO_STREAM (p, p_cb->loc_enc_size);
+ UINT8_TO_STREAM (p, p_cb->local_i_key);
+ UINT8_TO_STREAM (p, p_cb->local_r_key);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ /* 1B ERR_RSP op code + 1B cmd_op_code + 2B handle + 1B status */
+ p_buf->len = SMP_PAIRING_REQ_SIZE;
+ }
+
+ return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function smp_build_confirm_cmd
+**
+** Description Build confirm request command.
+**
+*******************************************************************************/
+static BT_HDR *smp_build_confirm_cmd(UINT8 cmd_code, tSMP_CB *p_cb)
+{
+ BT_HDR *p_buf = NULL ;
+ UINT8 *p;
+ UNUSED(cmd_code);
+
+ SMP_TRACE_EVENT("smp_build_confirm_cmd\n");
+ if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + SMP_CONFIRM_CMD_SIZE + L2CAP_MIN_OFFSET)) != NULL) {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, SMP_OPCODE_CONFIRM);
+ ARRAY_TO_STREAM (p, p_cb->confirm, BT_OCTET16_LEN);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_CONFIRM_CMD_SIZE;
+ }
+
+ return p_buf;
+}
+/*******************************************************************************
+**
+** Function smp_build_rand_cmd
+**
+** Description Build Random command.
+**
+*******************************************************************************/
+static BT_HDR *smp_build_rand_cmd(UINT8 cmd_code, tSMP_CB *p_cb)
+{
+ BT_HDR *p_buf = NULL ;
+ UINT8 *p;
+ UNUSED(cmd_code);
+
+ SMP_TRACE_EVENT("%s\n", __func__);
+ if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + SMP_RAND_CMD_SIZE + L2CAP_MIN_OFFSET))
+ != NULL) {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, SMP_OPCODE_RAND);
+ ARRAY_TO_STREAM (p, p_cb->rand, BT_OCTET16_LEN);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_RAND_CMD_SIZE;
+ }
+
+ return p_buf;
+}
+/*******************************************************************************
+**
+** Function smp_build_encrypt_info_cmd
+**
+** Description Build security information command.
+**
+*******************************************************************************/
+static BT_HDR *smp_build_encrypt_info_cmd(UINT8 cmd_code, tSMP_CB *p_cb)
+{
+ BT_HDR *p_buf = NULL ;
+ UINT8 *p;
+ UNUSED(cmd_code);
+
+ SMP_TRACE_EVENT("smp_build_encrypt_info_cmd\n");
+ if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + SMP_ENC_INFO_SIZE + L2CAP_MIN_OFFSET)) != NULL) {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, SMP_OPCODE_ENCRYPT_INFO);
+ ARRAY_TO_STREAM (p, p_cb->ltk, BT_OCTET16_LEN);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_ENC_INFO_SIZE;
+ }
+
+ return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function smp_build_master_id_cmd
+**
+** Description Build security information command.
+**
+*******************************************************************************/
+static BT_HDR *smp_build_master_id_cmd(UINT8 cmd_code, tSMP_CB *p_cb)
+{
+ BT_HDR *p_buf = NULL ;
+ UINT8 *p;
+ UNUSED(cmd_code);
+
+ SMP_TRACE_EVENT("%s\n", __func__);
+
+ if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + SMP_MASTER_ID_SIZE + L2CAP_MIN_OFFSET)) != NULL) {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, SMP_OPCODE_MASTER_ID);
+ UINT16_TO_STREAM (p, p_cb->ediv);
+ ARRAY_TO_STREAM (p, p_cb->enc_rand, BT_OCTET8_LEN);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_MASTER_ID_SIZE;
+ }
+
+ return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function smp_build_identity_info_cmd
+**
+** Description Build identity information command.
+**
+*******************************************************************************/
+static BT_HDR *smp_build_identity_info_cmd(UINT8 cmd_code, tSMP_CB *p_cb)
+{
+ BT_HDR *p_buf = NULL ;
+#if (BLE_INCLUDED == TRUE)
+ UINT8 *p;
+ BT_OCTET16 irk;
+ UNUSED(cmd_code);
+ UNUSED(p_cb);
+
+ SMP_TRACE_EVENT("smp_build_identity_info_cmd\n");
+ if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + SMP_ID_INFO_SIZE + L2CAP_MIN_OFFSET)) != NULL) {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ BTM_GetDeviceIDRoot(irk);
+
+ UINT8_TO_STREAM (p, SMP_OPCODE_IDENTITY_INFO);
+ ARRAY_TO_STREAM (p, irk, BT_OCTET16_LEN);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_ID_INFO_SIZE;
+ }
+
+#endif ///BLE_INCLUDED == TRUE
+ return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function smp_build_id_addr_cmd
+**
+** Description Build identity address information command.
+**
+*******************************************************************************/
+static BT_HDR *smp_build_id_addr_cmd(UINT8 cmd_code, tSMP_CB *p_cb)
+{
+ BT_HDR *p_buf = NULL;
+ UINT8 *p;
+
+ UNUSED(cmd_code);
+ UNUSED(p_cb);
+ SMP_TRACE_EVENT("smp_build_id_addr_cmd\n");
+ if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + SMP_ID_ADDR_SIZE + L2CAP_MIN_OFFSET)) != NULL) {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, SMP_OPCODE_ID_ADDR);
+ /* Identity Address Information is used in the Transport Specific Key Distribution phase to distribute
+ its public device address or static random address. if slave using static random address is encrypted,
+ it should distribute its static random address */
+#if (BLE_INCLUDED == TRUE)
+ if(btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type == BLE_ADDR_RANDOM && memcmp(btm_cb.ble_ctr_cb.addr_mgnt_cb.static_rand_addr, btm_cb.ble_ctr_cb.addr_mgnt_cb.private_addr,6) == 0) {
+ UINT8_TO_STREAM (p, 0x01);
+ BDADDR_TO_STREAM (p, btm_cb.ble_ctr_cb.addr_mgnt_cb.static_rand_addr);
+ } else
+#endif ///BLE_INCLUDED == TRUE
+ {
+ UINT8_TO_STREAM (p, 0);
+ BDADDR_TO_STREAM (p, controller_get_interface()->get_address()->address);
+ }
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_ID_ADDR_SIZE;
+ }
+
+ return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function smp_build_signing_info_cmd
+**
+** Description Build signing information command.
+**
+*******************************************************************************/
+static BT_HDR *smp_build_signing_info_cmd(UINT8 cmd_code, tSMP_CB *p_cb)
+{
+ BT_HDR *p_buf = NULL ;
+ UINT8 *p;
+ UNUSED(cmd_code);
+
+ SMP_TRACE_EVENT("smp_build_signing_info_cmd\n");
+ if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + SMP_SIGN_INFO_SIZE + L2CAP_MIN_OFFSET)) != NULL) {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, SMP_OPCODE_SIGN_INFO);
+ ARRAY_TO_STREAM (p, p_cb->csrk, BT_OCTET16_LEN);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_SIGN_INFO_SIZE;
+ }
+
+ return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function smp_build_pairing_fail
+**
+** Description Build Pairing Fail command.
+**
+*******************************************************************************/
+static BT_HDR *smp_build_pairing_fail(UINT8 cmd_code, tSMP_CB *p_cb)
+{
+ BT_HDR *p_buf = NULL ;
+ UINT8 *p;
+ UNUSED(cmd_code);
+
+ SMP_TRACE_EVENT("%s\n", __func__);
+ if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + SMP_PAIR_FAIL_SIZE + L2CAP_MIN_OFFSET)) != NULL) {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, SMP_OPCODE_PAIRING_FAILED);
+ UINT8_TO_STREAM (p, p_cb->failure);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_PAIR_FAIL_SIZE;
+ }
+
+ return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function smp_build_security_request
+**
+** Description Build security request command.
+**
+*******************************************************************************/
+static BT_HDR *smp_build_security_request(UINT8 cmd_code, tSMP_CB *p_cb)
+{
+ BT_HDR *p_buf = NULL ;
+ UINT8 *p;
+ UNUSED(cmd_code);
+
+ SMP_TRACE_EVENT("%s\n", __func__);
+ if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + 2 + L2CAP_MIN_OFFSET)) != NULL) {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, SMP_OPCODE_SEC_REQ);
+ UINT8_TO_STREAM (p, p_cb->loc_auth_req);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_SECURITY_REQUEST_SIZE;
+
+ SMP_TRACE_EVENT("opcode=%d auth_req=0x%x", SMP_OPCODE_SEC_REQ, p_cb->loc_auth_req );
+ }
+
+ return p_buf;
+
+}
+
+/*******************************************************************************
+**
+** Function smp_build_pair_public_key_cmd
+**
+** Description Build pairing public key command.
+**
+*******************************************************************************/
+static BT_HDR *smp_build_pair_public_key_cmd(UINT8 cmd_code, tSMP_CB *p_cb)
+{
+ BT_HDR *p_buf = NULL ;
+ UINT8 *p;
+ UINT8 publ_key[2 * BT_OCTET32_LEN];
+ UINT8 *p_publ_key = publ_key;
+ UNUSED(cmd_code);
+
+ SMP_TRACE_EVENT("%s\n", __FUNCTION__);
+
+ memcpy(p_publ_key, p_cb->loc_publ_key.x, BT_OCTET32_LEN);
+ memcpy(p_publ_key + BT_OCTET32_LEN, p_cb->loc_publ_key.y, BT_OCTET32_LEN);
+
+ if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) +
+ SMP_PAIR_PUBL_KEY_SIZE + L2CAP_MIN_OFFSET)) != NULL) {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, SMP_OPCODE_PAIR_PUBLIC_KEY);
+ ARRAY_TO_STREAM (p, p_publ_key, 2 * BT_OCTET32_LEN);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_PAIR_PUBL_KEY_SIZE;
+ }
+
+ return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function smp_build_pairing_commitment_cmd
+**
+** Description Build pairing commitment command.
+**
+*******************************************************************************/
+static BT_HDR *smp_build_pairing_commitment_cmd(UINT8 cmd_code, tSMP_CB *p_cb)
+{
+ BT_HDR *p_buf = NULL;
+ UINT8 *p;
+ UNUSED(cmd_code);
+
+ SMP_TRACE_EVENT("%s\n", __func__);
+ if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + SMP_PAIR_COMMITM_SIZE + L2CAP_MIN_OFFSET))
+ != NULL) {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, SMP_OPCODE_CONFIRM);
+ ARRAY_TO_STREAM (p, p_cb->commitment, BT_OCTET16_LEN);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_PAIR_COMMITM_SIZE;
+ }
+
+ return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function smp_build_pair_dhkey_check_cmd
+**
+** Description Build pairing DHKey check command.
+**
+*******************************************************************************/
+static BT_HDR *smp_build_pair_dhkey_check_cmd(UINT8 cmd_code, tSMP_CB *p_cb)
+{
+ BT_HDR *p_buf = NULL;
+ UINT8 *p;
+ UNUSED(cmd_code);
+
+ SMP_TRACE_EVENT("%s\n", __FUNCTION__);
+ if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) +
+ SMP_PAIR_DHKEY_CHECK_SIZE + L2CAP_MIN_OFFSET)) != NULL) {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, SMP_OPCODE_PAIR_DHKEY_CHECK);
+ ARRAY_TO_STREAM (p, p_cb->dhkey_check, BT_OCTET16_LEN);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_PAIR_DHKEY_CHECK_SIZE;
+ }
+
+ return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function smp_build_pairing_keypress_notification_cmd
+**
+** Description Build keypress notification command.
+**
+*******************************************************************************/
+static BT_HDR *smp_build_pairing_keypress_notification_cmd(UINT8 cmd_code, tSMP_CB *p_cb)
+{
+ BT_HDR *p_buf = NULL ;
+ UINT8 *p;
+ UNUSED(cmd_code);
+
+ SMP_TRACE_EVENT("%s\n", __FUNCTION__);
+ if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR)\
+ + SMP_PAIR_KEYPR_NOTIF_SIZE + L2CAP_MIN_OFFSET)) != NULL) {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, SMP_OPCODE_PAIR_KEYPR_NOTIF);
+ UINT8_TO_STREAM (p, p_cb->local_keypress_notification);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_PAIR_KEYPR_NOTIF_SIZE;
+ }
+
+ return p_buf;
+}
+
+/*******************************************************************************
+**
+** Function smp_convert_string_to_tk
+**
+** Description This function is called to convert a 6 to 16 digits numeric
+** character string into SMP TK.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_convert_string_to_tk(BT_OCTET16 tk, UINT32 passkey)
+{
+ UINT8 *p = tk;
+ tSMP_KEY key;
+ SMP_TRACE_EVENT("smp_convert_string_to_tk\n");
+ UINT32_TO_STREAM(p, passkey);
+
+ key.key_type = SMP_KEY_TYPE_TK;
+ key.p_data = tk;
+
+ smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &key);
+}
+
+/*******************************************************************************
+**
+** Function smp_mask_enc_key
+**
+** Description This function is called to mask off the encryption key based
+** on the maximum encryption key size.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_mask_enc_key(UINT8 loc_enc_size, UINT8 *p_data)
+{
+ SMP_TRACE_EVENT("smp_mask_enc_key\n");
+ if (loc_enc_size < BT_OCTET16_LEN) {
+ for (; loc_enc_size < BT_OCTET16_LEN; loc_enc_size ++) {
+ * (p_data + loc_enc_size) = 0;
+ }
+ }
+ return;
+}
+
+/*******************************************************************************
+**
+** Function smp_xor_128
+**
+** Description utility function to do an biteise exclusive-OR of two bit
+** strings of the length of BT_OCTET16_LEN.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_xor_128(BT_OCTET16 a, const BT_OCTET16 b)
+{
+ UINT8 i, *aa = a;
+ const UINT8 *bb = b;
+
+ SMP_TRACE_EVENT("smp_xor_128\n");
+ for (i = 0; i < BT_OCTET16_LEN; i++) {
+ aa[i] = aa[i] ^ bb[i];
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_cb_cleanup
+**
+** Description Clean up SMP control block
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_cb_cleanup(tSMP_CB *p_cb)
+{
+ tSMP_CALLBACK *p_callback = p_cb->p_callback;
+ UINT8 trace_level = p_cb->trace_level;
+ UINT32 static_passkey = p_cb->static_passkey;
+ BOOLEAN use_static_passkey = p_cb->use_static_passkey;
+ SMP_TRACE_EVENT("smp_cb_cleanup\n");
+
+ memset(p_cb, 0, sizeof(tSMP_CB));
+ p_cb->p_callback = p_callback;
+ p_cb->trace_level = trace_level;
+ if(use_static_passkey) {
+ p_cb->use_static_passkey = use_static_passkey;
+ p_cb->static_passkey = static_passkey;
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_remove_fixed_channel
+**
+** Description This function is called to remove the fixed channel
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_remove_fixed_channel(tSMP_CB *p_cb)
+{
+ SMP_TRACE_DEBUG("%s\n", __func__);
+
+ if (p_cb->smp_over_br) {
+ L2CA_RemoveFixedChnl (L2CAP_SMP_BR_CID, p_cb->pairing_bda);
+ } else {
+ L2CA_RemoveFixedChnl (L2CAP_SMP_CID, p_cb->pairing_bda);
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_reset_control_value
+**
+** Description This function is called to reset the control block value when
+** pairing procedure finished.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_reset_control_value(tSMP_CB *p_cb)
+{
+ SMP_TRACE_EVENT("smp_reset_control_value\n");
+ btu_stop_timer (&p_cb->rsp_timer_ent);
+ p_cb->flags = 0;
+ /* set the link idle timer to drop the link when pairing is done
+ usually service discovery will follow authentication complete, to avoid
+ racing condition for a link down/up, set link idle timer to be
+ SMP_LINK_TOUT_MIN to guarantee SMP key exchange */
+ L2CA_SetIdleTimeoutByBdAddr(p_cb->pairing_bda, SMP_LINK_TOUT_MIN, BT_TRANSPORT_LE);
+
+ /* We can tell L2CAP to remove the fixed channel (if it has one) */
+ smp_remove_fixed_channel(p_cb);
+ smp_cb_cleanup(p_cb);
+}
+
+/*******************************************************************************
+**
+** Function smp_proc_pairing_cmpl
+**
+** Description This function is called to process pairing complete
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_proc_pairing_cmpl(tSMP_CB *p_cb)
+{
+ tSMP_EVT_DATA evt_data = {0};
+ tSMP_CALLBACK *p_callback = p_cb->p_callback;
+ BD_ADDR pairing_bda;
+
+ SMP_TRACE_DEBUG ("smp_proc_pairing_cmpl \n");
+
+ evt_data.cmplt.reason = p_cb->status;
+ evt_data.cmplt.smp_over_br = p_cb->smp_over_br;
+ evt_data.cmplt.auth_mode = 0;
+#if (BLE_INCLUDED == TRUE)
+ tBTM_SEC_DEV_REC *p_rec = btm_find_dev (p_cb->pairing_bda);
+ if (p_cb->status == SMP_SUCCESS) {
+ evt_data.cmplt.sec_level = p_cb->sec_level;
+ if (p_cb->auth_mode) { // the first encryption
+ evt_data.cmplt.auth_mode = p_cb->auth_mode;
+ if (p_rec) {
+ p_rec->ble.auth_mode = p_cb->auth_mode;
+ }
+ } else if (p_rec) {
+ evt_data.cmplt.auth_mode = p_rec->ble.auth_mode;
+ }
+ }
+#else
+ if (p_cb->status == SMP_SUCCESS) {
+ evt_data.cmplt.sec_level = p_cb->sec_level;
+ evt_data.cmplt.auth_mode = p_cb->auth_mode;
+ }
+#endif
+
+ evt_data.cmplt.is_pair_cancel = FALSE;
+
+ if (p_cb->is_pair_cancel) {
+ evt_data.cmplt.is_pair_cancel = TRUE;
+ }
+
+
+ SMP_TRACE_DEBUG ("send SMP_COMPLT_EVT reason=0x%0x sec_level=0x%0x\n",
+ evt_data.cmplt.reason,
+ evt_data.cmplt.sec_level );
+
+ memcpy (pairing_bda, p_cb->pairing_bda, BD_ADDR_LEN);
+
+#if (BLE_INCLUDED == TRUE)
+#if (SMP_SLAVE_CON_PARAMS_UPD_ENABLE == TRUE)
+ if (p_cb->role == HCI_ROLE_SLAVE) {
+ if(p_rec && p_rec->ble.skip_update_conn_param) {
+ //clear flag
+ p_rec->ble.skip_update_conn_param = false;
+ } else {
+ #if (BT_MULTI_CONNECTION_ENBALE == FALSE)
+ L2CA_EnableUpdateBleConnParams(p_cb->pairing_bda, TRUE);
+ #endif
+ }
+ }
+
+#endif
+#endif ///BLE_INCLUDED == TRUE
+
+ smp_reset_control_value(p_cb);
+ // TODO: clear local oob data when start advertising
+ smp_clear_local_oob_data();
+
+ if (p_callback) {
+ (*p_callback) (SMP_COMPLT_EVT, pairing_bda, &evt_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_command_has_invalid_parameters
+**
+** Description Checks if the received SMP command has invalid parameters i.e.
+** if the command length is valid and the command parameters are
+** inside specified range.
+** It returns TRUE if the command has invalid parameters.
+**
+** Returns TRUE if the command has invalid parameters, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN smp_command_has_invalid_parameters(tSMP_CB *p_cb)
+{
+ UINT8 cmd_code = p_cb->rcvd_cmd_code;
+
+ SMP_TRACE_DEBUG("%s for cmd code 0x%02x\n", __func__, cmd_code);
+
+ if ((cmd_code > (SMP_OPCODE_MAX + 1 /* for SMP_OPCODE_PAIR_COMMITM */)) ||
+ (cmd_code < SMP_OPCODE_MIN)) {
+ SMP_TRACE_WARNING("Somehow received command with the RESERVED code 0x%02x\n", cmd_code);
+ return TRUE;
+ }
+
+ if (!(*smp_cmd_len_is_valid[cmd_code])(p_cb)) {
+ return TRUE;
+ }
+
+ if (!(*smp_cmd_param_ranges_are_valid[cmd_code])(p_cb)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function smp_command_has_valid_fixed_length
+**
+** Description Checks if the received command size is equal to the size
+** according to specs.
+**
+** Returns TRUE if the command size is as expected, FALSE otherwise.
+**
+** Note The command is expected to have fixed length.
+*******************************************************************************/
+BOOLEAN smp_command_has_valid_fixed_length(tSMP_CB *p_cb)
+{
+ UINT8 cmd_code = p_cb->rcvd_cmd_code;
+
+ SMP_TRACE_DEBUG("%s for cmd code 0x%02x\n", __func__, cmd_code);
+
+ if (p_cb->rcvd_cmd_len != smp_cmd_size_per_spec[cmd_code]) {
+ SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with invalid length\
+ 0x%02x (per spec the length is 0x%02x).\n",
+ cmd_code, p_cb->rcvd_cmd_len, smp_cmd_size_per_spec[cmd_code]);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function smp_pairing_request_response_parameters_are_valid
+**
+** Description Validates parameter ranges in the received SMP command
+** pairing request or pairing response.
+** The parameters to validate:
+** IO capability,
+** OOB data flag,
+** Bonding_flags in AuthReq
+** Maximum encryption key size.
+** Returns FALSE if at least one of these parameters is out of range.
+**
+*******************************************************************************/
+BOOLEAN smp_pairing_request_response_parameters_are_valid(tSMP_CB *p_cb)
+{
+ UINT8 io_caps = p_cb->peer_io_caps;
+ UINT8 oob_flag = p_cb->peer_oob_flag;
+ UINT8 bond_flag = p_cb->peer_auth_req & 0x03; //0x03 is gen bond with appropriate mask
+ UINT8 enc_size = p_cb->peer_enc_size;
+
+ SMP_TRACE_DEBUG("%s for cmd code 0x%02x\n", __func__, p_cb->rcvd_cmd_code);
+
+ if (io_caps >= BTM_IO_CAP_MAX) {
+ SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with IO Capabilty \
+ value (0x%02x) out of range).\n",
+ p_cb->rcvd_cmd_code, io_caps);
+ return FALSE;
+ }
+
+ if (!((oob_flag == SMP_OOB_NONE) || (oob_flag == SMP_OOB_PRESENT))) {
+ SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with OOB data flag value \
+ (0x%02x) out of range).\n",
+ p_cb->rcvd_cmd_code, oob_flag);
+ return FALSE;
+ }
+
+ if (!((bond_flag == SMP_AUTH_NO_BOND) || (bond_flag == SMP_AUTH_BOND))) {
+ SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with Bonding_Flags value (0x%02x)\
+ out of range).\n",
+ p_cb->rcvd_cmd_code, bond_flag);
+ return FALSE;
+ }
+
+ /* `bte_appl_cfg.ble_min_enc_key_size` will be `SMP_ENCR_KEY_SIZE_MIN` by
+ * default if not set explicitly */
+#if (BLE_INCLUDED == TRUE)
+ if (enc_size < bte_appl_cfg.ble_min_key_size) {
+ SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with Maximum Encryption \
+ Key value (0x%02x) less than minimum required key size).\n",
+ p_cb->rcvd_cmd_code, enc_size);
+ return FALSE;
+ }
+#else
+ if (enc_size < SMP_ENCR_KEY_SIZE_MIN) {
+ SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with Maximum Encryption \
+ Key value (0x%02x) less than minimum required key size).\n",
+ p_cb->rcvd_cmd_code, enc_size);
+ return FALSE;
+ }
+#endif
+
+ if (enc_size > SMP_ENCR_KEY_SIZE_MAX) {
+ SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with Maximum Encryption \
+ Key value (0x%02x) greater than supported by stack).\n",
+ p_cb->rcvd_cmd_code, enc_size);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function smp_pairing_keypress_notification_is_valid
+**
+** Description Validates Notification Type parameter range in the received SMP command
+** pairing keypress notification.
+** Returns FALSE if this parameter is out of range.
+**
+*******************************************************************************/
+BOOLEAN smp_pairing_keypress_notification_is_valid(tSMP_CB *p_cb)
+{
+ tBTM_SP_KEY_TYPE keypress_notification = p_cb->peer_keypress_notification;
+
+ SMP_TRACE_DEBUG("%s for cmd code 0x%02x\n", __func__, p_cb->rcvd_cmd_code);
+
+ if (keypress_notification >= BTM_SP_KEY_OUT_OF_RANGE) {
+ SMP_TRACE_WARNING("Rcvd from the peer cmd 0x%02x with Pairing Keypress \
+ Notification value (0x%02x) out of range).\n",
+ p_cb->rcvd_cmd_code, keypress_notification);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function smp_parameter_unconditionally_valid
+**
+** Description Always returns TRUE.
+**
+*******************************************************************************/
+BOOLEAN smp_parameter_unconditionally_valid(tSMP_CB *p_cb)
+{
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function smp_parameter_unconditionally_invalid
+**
+** Description Always returns FALSE.
+**
+*******************************************************************************/
+BOOLEAN smp_parameter_unconditionally_invalid(tSMP_CB *p_cb)
+{
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function smp_reject_unexpected_pairing_command
+**
+** Description send pairing failure to an unexpected pairing command during
+** an active pairing process.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_reject_unexpected_pairing_command(BD_ADDR bd_addr)
+{
+ BT_HDR *p_buf;
+ UINT8 *p;
+
+ SMP_TRACE_DEBUG ("%s\n", __FUNCTION__);
+
+ if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + \
+ SMP_PAIR_FAIL_SIZE + L2CAP_MIN_OFFSET)) != NULL) {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, SMP_OPCODE_PAIRING_FAILED);
+ UINT8_TO_STREAM (p, SMP_PAIR_NOT_SUPPORT);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_PAIR_FAIL_SIZE;
+
+ smp_send_msg_to_L2CAP(bd_addr, p_buf);
+ }
+}
+
+/*******************************************************************************
+** Function smp_select_association_model
+**
+** Description This function selects association model to use for STK
+** generation. Selection is based on both sides' io capability,
+** oob data flag and authentication request.
+**
+** Note If Secure Connections Only mode is required locally then we
+** come to this point only if both sides support Secure Connections
+** mode, i.e. if p_cb->secure_connections_only_mode_required = TRUE then we come
+** to this point only if
+** (p_cb->peer_auth_req & SMP_SC_SUPPORT_BIT) ==
+** (p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT) ==
+** SMP_SC_SUPPORT_BIT
+**
+*******************************************************************************/
+tSMP_ASSO_MODEL smp_select_association_model(tSMP_CB *p_cb)
+{
+ tSMP_ASSO_MODEL model = SMP_MODEL_OUT_OF_RANGE;
+ p_cb->le_secure_connections_mode_is_used = FALSE;
+
+ SMP_TRACE_EVENT("%s\n", __FUNCTION__);
+ SMP_TRACE_DEBUG("%s p_cb->peer_io_caps = %d p_cb->local_io_capability = %d\n",
+ __FUNCTION__, p_cb->peer_io_caps, p_cb->local_io_capability);
+ SMP_TRACE_DEBUG("%s p_cb->peer_oob_flag = %d p_cb->loc_oob_flag = %d\n",
+ __FUNCTION__, p_cb->peer_oob_flag, p_cb->loc_oob_flag);
+ SMP_TRACE_DEBUG("%s p_cb->peer_auth_req = 0x%02x p_cb->loc_auth_req = 0x%02x\n",
+ __FUNCTION__, p_cb->peer_auth_req, p_cb->loc_auth_req);
+ SMP_TRACE_DEBUG("%s p_cb->secure_connections_only_mode_required = %s\n",
+ __FUNCTION__, p_cb->secure_connections_only_mode_required ?
+ "TRUE" : "FALSE");
+
+ if ((p_cb->peer_auth_req & SMP_SC_SUPPORT_BIT) && (p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT)) {
+ p_cb->le_secure_connections_mode_is_used = TRUE;
+ }
+
+ SMP_TRACE_DEBUG("use_sc_process = %d\n", p_cb->le_secure_connections_mode_is_used);
+
+ if (p_cb->le_secure_connections_mode_is_used) {
+ model = smp_select_association_model_secure_connections(p_cb);
+ } else {
+ model = smp_select_legacy_association_model(p_cb);
+ }
+ return model;
+}
+
+/*******************************************************************************
+** Function smp_select_legacy_association_model
+**
+** Description This function is called to select association mode if at least
+** one side doesn't support secure connections.
+**
+*******************************************************************************/
+tSMP_ASSO_MODEL smp_select_legacy_association_model(tSMP_CB *p_cb)
+{
+ tSMP_ASSO_MODEL model = SMP_MODEL_OUT_OF_RANGE;
+
+ SMP_TRACE_DEBUG("%s\n", __func__);
+ /* if OOB data is present on both devices, then use OOB association model */
+ if (p_cb->peer_oob_flag == SMP_OOB_PRESENT && p_cb->loc_oob_flag == SMP_OOB_PRESENT) {
+ return SMP_MODEL_OOB;
+ }
+
+ /* else if neither device requires MITM, then use Just Works association model */
+ if (SMP_NO_MITM_REQUIRED (p_cb->peer_auth_req) && SMP_NO_MITM_REQUIRED(p_cb->loc_auth_req)) {
+ return SMP_MODEL_ENCRYPTION_ONLY;
+ }
+
+ /* otherwise use IO capability to select association model */
+ if (p_cb->peer_io_caps < SMP_IO_CAP_MAX && p_cb->local_io_capability < SMP_IO_CAP_MAX) {
+ if (p_cb->role == HCI_ROLE_MASTER) {
+ model = smp_association_table[p_cb->role][p_cb->peer_io_caps]
+ [p_cb->local_io_capability];
+ } else {
+ model = smp_association_table[p_cb->role][p_cb->local_io_capability]
+ [p_cb->peer_io_caps];
+ }
+ }
+
+ return model;
+}
+
+/*******************************************************************************
+** Function smp_select_association_model_secure_connections
+**
+** Description This function is called to select association mode if both
+** sides support secure connections.
+**
+*******************************************************************************/
+tSMP_ASSO_MODEL smp_select_association_model_secure_connections(tSMP_CB *p_cb)
+{
+ tSMP_ASSO_MODEL model = SMP_MODEL_OUT_OF_RANGE;
+
+ SMP_TRACE_DEBUG("%s\n", __func__);
+ /* if OOB data is present on at least one device, then use OOB association model */
+ if (p_cb->peer_oob_flag == SMP_OOB_PRESENT || p_cb->loc_oob_flag == SMP_OOB_PRESENT) {
+ return SMP_MODEL_SEC_CONN_OOB;
+ }
+
+ /* else if neither device requires MITM, then use Just Works association model */
+ if (SMP_NO_MITM_REQUIRED (p_cb->peer_auth_req) && SMP_NO_MITM_REQUIRED(p_cb->loc_auth_req)) {
+ return SMP_MODEL_SEC_CONN_JUSTWORKS;
+ }
+
+ /* otherwise use IO capability to select association model */
+ if (p_cb->peer_io_caps < SMP_IO_CAP_MAX && p_cb->local_io_capability < SMP_IO_CAP_MAX) {
+ if (p_cb->role == HCI_ROLE_MASTER) {
+ model = smp_association_table_sc[p_cb->role][p_cb->peer_io_caps]
+ [p_cb->local_io_capability];
+ } else {
+ model = smp_association_table_sc[p_cb->role][p_cb->local_io_capability]
+ [p_cb->peer_io_caps];
+ }
+ }
+
+ return model;
+}
+
+/*******************************************************************************
+** Function smp_reverse_array
+**
+** Description This function reverses array bytes
+**
+*******************************************************************************/
+void smp_reverse_array(UINT8 *arr, UINT8 len)
+{
+ UINT8 i = 0, tmp;
+
+ SMP_TRACE_DEBUG("smp_reverse_array\n");
+
+ for (i = 0; i < len / 2; i ++) {
+ tmp = arr[i];
+ arr[i] = arr[len - 1 - i];
+ arr[len - 1 - i] = tmp;
+ }
+}
+
+/*******************************************************************************
+** Function smp_calculate_random_input
+**
+** Description This function returns random input value to be used in commitment
+** calculation for SC passkey entry association mode
+** (if bit["round"] in "random" array == 1 then returns 0x81
+** else returns 0x80).
+**
+** Returns ri value
+**
+*******************************************************************************/
+UINT8 smp_calculate_random_input(UINT8 *random, UINT8 round)
+{
+ UINT8 i = round / 8;
+ UINT8 j = round % 8;
+ UINT8 ri;
+
+ SMP_TRACE_DEBUG("random: 0x%02x, round: %d, i: %d, j: %d\n", random[i], round, i, j);
+ ri = ((random[i] >> j) & 1) | 0x80;
+ SMP_TRACE_DEBUG("%s ri=0x%02x\n", __func__, ri);
+ return ri;
+}
+
+/*******************************************************************************
+** Function smp_collect_local_io_capabilities
+**
+** Description This function puts into IOcap array local device
+** IOCapability, OOB data, AuthReq.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_collect_local_io_capabilities(UINT8 *iocap, tSMP_CB *p_cb)
+{
+ SMP_TRACE_DEBUG("%s\n", __func__);
+
+ iocap[0] = p_cb->local_io_capability;
+ iocap[1] = p_cb->loc_oob_flag;
+ iocap[2] = p_cb->loc_auth_req;
+}
+
+/*******************************************************************************
+** Function smp_collect_peer_io_capabilities
+**
+** Description This function puts into IOcap array peer device
+** IOCapability, OOB data, AuthReq.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_collect_peer_io_capabilities(UINT8 *iocap, tSMP_CB *p_cb)
+{
+ SMP_TRACE_DEBUG("%s\n", __func__);
+
+ iocap[0] = p_cb->peer_io_caps;
+ iocap[1] = p_cb->peer_oob_flag;
+ iocap[2] = p_cb->peer_auth_req;
+}
+#if (BLE_INCLUDED == TRUE)
+/*******************************************************************************
+** Function smp_collect_local_ble_address
+**
+** Description This function puts into le_addr array local device le address:
+** le_addr[0-5] = local BD ADDR,
+** le_addr[6] = local le address type (PUBLIC/RANDOM).
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_collect_local_ble_address(UINT8 *le_addr, tSMP_CB *p_cb)
+{
+ tBLE_ADDR_TYPE addr_type = 0;
+ BD_ADDR bda;
+ UINT8 *p = le_addr;
+
+ SMP_TRACE_DEBUG("%s\n", __func__);
+
+ BTM_ReadConnectionAddr( p_cb->pairing_bda, bda, &addr_type);
+ BDADDR_TO_STREAM(p, bda);
+ UINT8_TO_STREAM(p, addr_type);
+}
+
+/*******************************************************************************
+** Function smp_collect_peer_ble_address
+**
+** Description This function puts into le_addr array peer device le address:
+** le_addr[0-5] = peer BD ADDR,
+** le_addr[6] = peer le address type (PUBLIC/RANDOM).
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_collect_peer_ble_address(UINT8 *le_addr, tSMP_CB *p_cb)
+{
+ tBLE_ADDR_TYPE addr_type = 0;
+ BD_ADDR bda;
+ UINT8 *p = le_addr;
+
+ SMP_TRACE_DEBUG("%s\n", __func__);
+
+ if (!BTM_ReadRemoteConnectionAddr(p_cb->pairing_bda, bda, &addr_type)) {
+ SMP_TRACE_ERROR("can not collect peer le addr information for unknown device\n");
+ return;
+ }
+
+ BDADDR_TO_STREAM(p, bda);
+ UINT8_TO_STREAM(p, addr_type);
+}
+
+/*******************************************************************************
+** Function smp_check_commitment
+**
+** Description This function compares peer commitment values:
+** - expected (i.e. calculated locally),
+** - received from the peer.
+**
+** Returns TRUE if the values are the same
+** FALSE otherwise
+**
+*******************************************************************************/
+BOOLEAN smp_check_commitment(tSMP_CB *p_cb)
+{
+ BT_OCTET16 expected;
+
+ SMP_TRACE_DEBUG("%s\n", __func__);
+
+ smp_calculate_peer_commitment(p_cb, expected);
+ print128(expected, (const UINT8 *)"calculated peer commitment");
+ print128(p_cb->remote_commitment, (const UINT8 *)"received peer commitment");
+
+ if (memcmp(p_cb->remote_commitment, expected, BT_OCTET16_LEN)) {
+ SMP_TRACE_WARNING("Commitment check fails\n");
+ return FALSE;
+ }
+
+ SMP_TRACE_DEBUG("Commitment check succeeds\n");
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function smp_save_secure_connections_long_term_key
+**
+** Description The function saves SC LTK as BLE key for future use as local
+** and/or peer key.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_save_secure_connections_long_term_key(tSMP_CB *p_cb)
+{
+ tBTM_LE_LENC_KEYS lle_key;
+ tBTM_LE_PENC_KEYS ple_key;
+
+ SMP_TRACE_DEBUG("%s-Save LTK as local LTK key\n", __func__);
+ memcpy(lle_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
+ lle_key.div = 0;
+ lle_key.key_size = p_cb->loc_enc_size;
+ lle_key.sec_level = p_cb->sec_level;
+ btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LENC, (tBTM_LE_KEY_VALUE *)&lle_key, TRUE);
+
+ SMP_TRACE_DEBUG("%s-Save LTK as peer LTK key\n", __func__);
+ ple_key.ediv = 0;
+ memset(ple_key.rand, 0, BT_OCTET8_LEN);
+ memcpy(ple_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
+ ple_key.sec_level = p_cb->sec_level;
+ ple_key.key_size = p_cb->loc_enc_size;
+ btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PENC, (tBTM_LE_KEY_VALUE *)&ple_key, TRUE);
+}
+
+/*******************************************************************************
+**
+** Function smp_calculate_f5_mackey_and_long_term_key
+**
+** Description The function calculates MacKey and LTK and saves them in CB.
+** To calculate MacKey and LTK it calls smp_calc_f5(...).
+** MacKey is used in dhkey calculation, LTK is used to encrypt
+** the link.
+**
+** Returns FALSE if out of resources, TRUE otherwise.
+**
+*******************************************************************************/
+BOOLEAN smp_calculate_f5_mackey_and_long_term_key(tSMP_CB *p_cb)
+{
+ UINT8 a[7];
+ UINT8 b[7];
+ UINT8 *p_na;
+ UINT8 *p_nb;
+
+ SMP_TRACE_DEBUG("%s\n", __func__);
+
+ if (p_cb->role == HCI_ROLE_MASTER) {
+ smp_collect_local_ble_address(a, p_cb);
+ smp_collect_peer_ble_address(b, p_cb);
+ p_na = p_cb->rand;
+ p_nb = p_cb->rrand;
+ } else {
+ smp_collect_local_ble_address(b, p_cb);
+ smp_collect_peer_ble_address(a, p_cb);
+ p_na = p_cb->rrand;
+ p_nb = p_cb->rand;
+ }
+
+ if (!smp_calculate_f5(p_cb->dhkey, p_na, p_nb, a, b, p_cb->mac_key, p_cb->ltk)) {
+ SMP_TRACE_ERROR("%s failed\n", __func__);
+ return FALSE;
+ }
+
+ SMP_TRACE_EVENT ("%s is completed\n", __func__);
+ return TRUE;
+}
+#endif ///BLE_INCLUDED == TRUE
+/*******************************************************************************
+**
+** Function smp_request_oob_data
+**
+** Description Requests application to provide OOB data.
+**
+** Returns TRUE - OOB data has to be provided by application
+** FALSE - otherwise (unexpected)
+**
+*******************************************************************************/
+BOOLEAN smp_request_oob_data(tSMP_CB *p_cb)
+{
+ tSMP_OOB_DATA_TYPE req_oob_type = SMP_OOB_INVALID_TYPE;
+
+ SMP_TRACE_DEBUG("%s\n", __func__);
+
+ if (p_cb->peer_oob_flag == SMP_OOB_PRESENT && p_cb->loc_oob_flag == SMP_OOB_PRESENT) {
+ /* both local and peer rcvd data OOB */
+ req_oob_type = SMP_OOB_BOTH;
+ } else if (p_cb->peer_oob_flag == SMP_OOB_PRESENT) {
+ /* peer rcvd OOB local data, local didn't receive OOB peer data */
+ req_oob_type = SMP_OOB_LOCAL;
+ } else if (p_cb->loc_oob_flag == SMP_OOB_PRESENT) {
+ req_oob_type = SMP_OOB_PEER;
+ }
+
+ SMP_TRACE_DEBUG("req_oob_type = %d\n", req_oob_type);
+
+ if (req_oob_type == SMP_OOB_INVALID_TYPE) {
+ return FALSE;
+ }
+
+ p_cb->req_oob_type = req_oob_type;
+ p_cb->cb_evt = SMP_SC_OOB_REQ_EVT;
+ smp_sm_event(p_cb, SMP_TK_REQ_EVT, &req_oob_type);
+
+ return TRUE;
+}
+
+
+#endif