summaryrefslogtreecommitdiffstats
path: root/stack/smp
diff options
context:
space:
mode:
Diffstat (limited to 'stack/smp')
-rw-r--r--stack/smp/aes.c926
-rw-r--r--stack/smp/aes.h162
-rw-r--r--stack/smp/smp_act.c950
-rw-r--r--stack/smp/smp_api.c337
-rw-r--r--stack/smp/smp_cmac.c388
-rw-r--r--stack/smp/smp_int.h315
-rw-r--r--stack/smp/smp_keys.c909
-rw-r--r--stack/smp/smp_l2c.c161
-rw-r--r--stack/smp/smp_main.c518
-rw-r--r--stack/smp/smp_utils.c675
10 files changed, 5341 insertions, 0 deletions
diff --git a/stack/smp/aes.c b/stack/smp/aes.c
new file mode 100644
index 0000000..1028d5b
--- /dev/null
+++ b/stack/smp/aes.c
@@ -0,0 +1,926 @@
+/*
+ ---------------------------------------------------------------------------
+ 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>
+
+/* 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 unsigned long 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 */
+
+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:
+ keylen = 16;
+ break;
+ case 24:
+ case 192:
+ keylen = 24;
+ break;
+ case 32:
+ case 256:
+ 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 */
+
+return_type 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(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 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(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 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 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 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 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/stack/smp/aes.h b/stack/smp/aes.h
new file mode 100644
index 0000000..dcfde93
--- /dev/null
+++ b/stack/smp/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 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 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 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 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 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 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/stack/smp/smp_act.c b/stack/smp/smp_act.c
new file mode 100644
index 0000000..ca24225
--- /dev/null
+++ b/stack/smp/smp_act.c
@@ -0,0 +1,950 @@
+/******************************************************************************
+ *
+ * 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 "bt_target.h"
+
+#if SMP_INCLUDED == TRUE
+
+ #include <string.h>
+ #include "btm_int.h"
+ #include "l2c_api.h"
+ #include "smp_int.h"
+
+
+const UINT8 smp_association_table[2][SMP_IO_CAP_MAX][SMP_IO_CAP_MAX] =
+{
+ /* initiator */
+ {{SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY, SMP_MODEL_PASSKEY, SMP_MODEL_ENC_ONLY, SMP_MODEL_PASSKEY}, /* Display Only */
+ {SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY, SMP_MODEL_PASSKEY, SMP_MODEL_ENC_ONLY, SMP_MODEL_PASSKEY}, /* SMP_CAP_IO = 1 */
+ {SMP_MODEL_KEY_NOTIF, SMP_MODEL_KEY_NOTIF, SMP_MODEL_PASSKEY, SMP_MODEL_ENC_ONLY, SMP_MODEL_KEY_NOTIF}, /* keyboard only */
+ {SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY},/* No Input No Output */
+ {SMP_MODEL_KEY_NOTIF, SMP_MODEL_KEY_NOTIF, SMP_MODEL_PASSKEY, SMP_MODEL_ENC_ONLY, SMP_MODEL_KEY_NOTIF}}, /* keyboard display */
+ /* responder */
+ {{SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY, SMP_MODEL_KEY_NOTIF, SMP_MODEL_ENC_ONLY, SMP_MODEL_KEY_NOTIF}, /* Display Only */
+ {SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY, SMP_MODEL_PASSKEY, SMP_MODEL_ENC_ONLY, SMP_MODEL_KEY_NOTIF}, /* SMP_CAP_IO = 1 */
+ {SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_ENC_ONLY, SMP_MODEL_PASSKEY}, /* keyboard only */
+ {SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY},/* No Input No Output */
+ {SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_KEY_NOTIF, SMP_MODEL_ENC_ONLY, SMP_MODEL_PASSKEY}} /* keyboard display */
+ /* display only */ /*SMP_CAP_IO = 1 */ /* keyboard only */ /* No InputOutput */ /* keyboard display */
+};
+
+const tSMP_ACT smp_distribute_act [] =
+{
+ smp_generate_ltk,
+ smp_send_id_info,
+ smp_generate_csrk
+};
+
+/*******************************************************************************
+** 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_DEBUG0 ("smp_update_key_mask ");
+ SMP_TRACE_DEBUG4("before update role=%d recv=%d loc_i_key = %02x, loc_r_key = %02x", p_cb->role, recv, p_cb->loc_i_key, p_cb->loc_r_key);
+ if (p_cb->role == HCI_ROLE_SLAVE)
+ {
+ if (recv)
+ p_cb->loc_i_key &= ~key_type;
+ else
+ p_cb->loc_r_key &= ~key_type;
+ }
+ else
+ {
+ if (recv)
+ p_cb->loc_r_key &= ~key_type;
+ else
+ p_cb->loc_i_key &= ~key_type;
+ }
+
+ SMP_TRACE_DEBUG2("updated loc_i_key = %02x, loc_r_key = %02x", p_cb->loc_i_key, p_cb->loc_r_key);
+}
+/*******************************************************************************
+** Function smp_io_cap_req
+** Description send SMP IO request
+*******************************************************************************/
+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_DEBUG1 ("smp_send_app_cback p_cb->cb_evt=%d", p_cb->cb_evt );
+ if (p_cb->p_callback && p_cb->cb_evt != 0)
+ {
+ if (p_cb->cb_evt == 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->loc_i_key ;
+ cb_data.io_req.resp_keys = p_cb->loc_r_key ;
+
+ SMP_TRACE_WARNING1( "io_cap = %d",cb_data.io_req.io_cap);
+ }
+ callback_rc = (*p_cb->p_callback)(p_cb->cb_evt, p_cb->pairing_bda, &cb_data);
+
+ SMP_TRACE_DEBUG2 ("callback_rc=%d p_cb->cb_evt=%d",callback_rc, p_cb->cb_evt );
+
+ if (callback_rc == SMP_SUCCESS && p_cb->cb_evt == SMP_IO_CAP_REQ_EVT)
+ {
+ p_cb->loc_auth_req = cb_data.io_req.auth_req;
+ p_cb->loc_io_caps = 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->loc_i_key = cb_data.io_req.init_keys;
+ p_cb->loc_r_key = cb_data.io_req.resp_keys;
+
+ SMP_TRACE_WARNING2( "new io_cap = %d p_cb->loc_enc_size = %d",p_cb->loc_io_caps, p_cb->loc_enc_size);
+
+ smp_sm_event(p_cb, SMP_IO_RSP_EVT, NULL);
+ }
+ }
+
+ 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_DEBUG0 ("smp_send_app_cback return");
+}
+/*******************************************************************************
+** 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_DEBUG2 ("smp_send_pair_fail status=%d failure=%d ",p_cb->status, p_cb->failure);
+
+ if (p_cb->status <= SMP_REPEATED_ATTEMPTS && p_cb->status != SMP_SUCCESS)
+ {
+ smp_send_cmd(SMP_OPCODE_PAIRING_FAILED, p_cb);
+ }
+}
+
+/*******************************************************************************
+** Function smp_send_pair_req
+** Description process pairing request to slave device
+*******************************************************************************/
+void smp_send_pair_req(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (p_cb->pairing_bda);
+ SMP_TRACE_DEBUG0 ("smp_send_pair_req ");
+
+ /* erase all keys when master sends pairing req*/
+ if (p_dev_rec)
+ btm_sec_clear_ble_keys(p_dev_rec);
+ /* 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 process pairing response to slave device
+*******************************************************************************/
+void smp_send_pair_rsp(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG0 ("smp_send_pair_rsp ");
+
+ p_cb->loc_i_key &= p_cb->peer_i_key;
+ p_cb->loc_r_key &= p_cb->peer_r_key;
+
+ if (smp_send_cmd (SMP_OPCODE_PAIRING_RSP, p_cb))
+ {
+ smp_decide_asso_model(p_cb, NULL);
+ }
+}
+
+/*******************************************************************************
+** Function smp_send_pair_request
+** Description process pairing request to slave device
+*******************************************************************************/
+void smp_send_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG0 ("smp_send_confirm ");
+ smp_send_cmd(SMP_OPCODE_CONFIRM, p_cb);
+}
+/*******************************************************************************
+** 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_DEBUG0 ("smp_send_init ");
+
+#if SMP_CONFORMANCE_TESTING == TRUE
+ if (p_cb->enable_test_rand_val)
+ {
+ SMP_TRACE_DEBUG0 ("Use rand value from script");
+ memcpy(p_cb->rand, p_cb->test_rand, BT_OCTET16_LEN);
+ }
+#endif
+
+ smp_send_cmd(SMP_OPCODE_INIT, p_cb);
+}
+/*******************************************************************************
+** Function smp_send_enc_info
+** Description send security information command.
+*******************************************************************************/
+void smp_send_enc_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ tBTM_LE_LENC_KEYS le_key;
+
+ SMP_TRACE_DEBUG1 ("smp_send_enc_info p_cb->loc_enc_size = %d", 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 */
+ le_key.div = p_cb->div;
+ le_key.key_size = p_cb->loc_enc_size;
+ le_key.sec_level = p_cb->sec_level;
+ btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LENC, (tBTM_LE_KEY_VALUE *)&le_key, TRUE);
+
+ SMP_TRACE_WARNING0( "smp_send_enc_info");
+
+ smp_key_distribution(p_cb, NULL);
+}
+/*******************************************************************************
+** 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_DEBUG0 ("smp_send_id_info ");
+ 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);
+
+ SMP_TRACE_WARNING0( "smp_send_id_info");
+
+ smp_key_distribution(p_cb, NULL);
+}
+/*******************************************************************************
+** 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_KEY_VALUE key;
+ SMP_TRACE_DEBUG0 ("smp_send_csrk_info ");
+ smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_CSRK, FALSE);
+
+ if (smp_send_cmd(SMP_OPCODE_SIGN_INFO, p_cb))
+ {
+ key.lcsrk_key.div = p_cb->div;
+ key.lcsrk_key.sec_level = p_cb->sec_level;
+ key.lcsrk_key.counter = 0; /* initialize the local counter */
+ btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LCSRK, &key, TRUE);
+ }
+
+ smp_key_distribution(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_DEBUG0 ("smp_send_ltk_reply ");
+ /* 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;
+
+
+ SMP_TRACE_DEBUG1 ("smp_proc_sec_req auth_req=0x%x",auth_req);
+
+ p_cb->cb_evt = 0;
+
+ btm_ble_link_sec_check(p_cb->pairing_bda, auth_req, &sec_req_act);
+
+ SMP_TRACE_DEBUG1 ("smp_proc_sec_req sec_req_act=0x%x",sec_req_act);
+
+ switch (sec_req_act)
+ {
+ case BTM_BLE_SEC_REQ_ACT_ENCRYPT:
+ SMP_TRACE_DEBUG0 ("smp_proc_sec_req BTM_BLE_SEC_REQ_ACT_ENCRYPT");
+ smp_sm_event(p_cb, SMP_ENC_REQ_EVT, NULL);
+ break;
+
+ case BTM_BLE_SEC_REQ_ACT_PAIR:
+ /* initialize local i/r key to be default keys */
+ SMP_TRACE_DEBUG0 ("smp_proc_sec_req BTM_BLE_SEC_REQ_ACT_PAIR");
+ p_cb->peer_auth_req = auth_req;
+ p_cb->loc_r_key = p_cb->loc_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;
+ }
+}
+/*******************************************************************************
+** 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_DEBUG0 ("smp_proc_sec_grant ");
+ 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_DEBUG0 ("smp_proc_pair_fail ");
+ p_cb->status = *(UINT8 *)p_data;
+}
+/*******************************************************************************
+** 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_DEBUG0 ("smp_proc_pair_cmd ");
+ /* 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_CONFORMANCE_TESTING == TRUE
+ if (p_cb->enable_test_pair_fail)
+ {
+ SMP_TRACE_DEBUG0 ("Forced pair fair");
+ if (p_cb->peer_enc_size < SMP_MIN_ENC_KEY_SIZE)
+ {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ }
+ else
+ {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &(p_cb->pair_fail_status));
+ }
+ return;
+ }
+#endif
+
+
+ if (p_cb->peer_enc_size < SMP_MIN_ENC_KEY_SIZE)
+ {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ }
+ else if (p_cb->role == HCI_ROLE_SLAVE)
+ {
+ if (!(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD))
+ {
+ p_cb->loc_i_key = p_cb->peer_i_key;
+ p_cb->loc_r_key = p_cb->peer_r_key;
+ }
+ else /* update local i/r key according to pairing request */
+ {
+ p_cb->loc_i_key &= p_cb->peer_i_key;
+ p_cb->loc_r_key &= p_cb->peer_r_key;
+ }
+
+ p_cb->cb_evt = SMP_SEC_REQUEST_EVT;
+ }
+}
+/*******************************************************************************
+** 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;
+
+ SMP_TRACE_DEBUG0 ("smp_proc_confirm ");
+ 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;
+}
+
+/*******************************************************************************
+** 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;
+ SMP_TRACE_DEBUG0 ("smp_proc_init ");
+ /* save the SRand for comparison */
+ STREAM_TO_ARRAY(p_cb->rrand, p, BT_OCTET16_LEN);
+
+}
+/*******************************************************************************
+** 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_DEBUG0 ("smp_proc_enc_info ");
+ STREAM_TO_ARRAY(p_cb->ltk, p, BT_OCTET16_LEN);
+
+ smp_key_distribution(p_cb, NULL);
+}
+/*******************************************************************************
+** 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_DEBUG0 (" smp_proc_master_id");
+ 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;
+ 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);
+}
+/*******************************************************************************
+** 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_DEBUG0 ("smp_proc_id_info ");
+ STREAM_TO_ARRAY (p_cb->tk, p, BT_OCTET16_LEN); /* reuse TK for IRK */
+ /* store the ID key from peer device */
+ btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PID, (tBTM_LE_KEY_VALUE *)&p_cb->tk, TRUE);
+
+ smp_key_distribution(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;
+ BD_ADDR mac_bda;
+
+ SMP_TRACE_DEBUG0 ("smp_proc_id_addr ");
+ smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ID, TRUE);
+
+ STREAM_TO_BDADDR(mac_bda, p);
+
+ /* TODO, update MAC address */
+
+ smp_key_distribution(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)
+{
+ tBTM_LE_PCSRK_KEYS le_key;
+
+ SMP_TRACE_DEBUG0 ("smp_proc_srk_info ");
+ 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 */
+ btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PCSRK, (tBTM_LE_KEY_VALUE *)&le_key, TRUE);
+
+ smp_key_distribution(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_DEBUG0 ("smp_proc_compare ");
+ 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->loc_i_key = p_cb->peer_i_key;
+ p_cb->loc_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);
+ }
+}
+/*******************************************************************************
+** 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_DEBUG0 ("smp_proc_sl_keysmp_proc_sl_key ");
+ if (key_type == SMP_KEY_TYPE_TK)
+ {
+ smp_generate_confirm(p_cb, NULL);
+ }
+ else if (key_type == SMP_KEY_TYPE_CFM)
+ {
+ smp_set_state(SMP_ST_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)
+{
+ BOOLEAN cmd;
+ UINT8 reason = SMP_ENC_FAIL;
+
+ SMP_TRACE_DEBUG0 ("smp_start_enc ");
+ 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)
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+
+}
+
+/*******************************************************************************
+** 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_DEBUG0 ("smp_proc_discard ");
+ smp_cb_cleanup(p_cb);
+}
+/*******************************************************************************
+** Function smp_proc_release_delay
+** Description process the release delay request
+*******************************************************************************/
+void smp_proc_release_delay(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG0 ("smp_proc_release_delay ");
+ btu_stop_timer (&p_cb->rsp_timer_ent);
+ btu_start_timer (&p_cb->rsp_timer_ent, BTU_TTYPE_SMP_PAIRING_CMD,
+ SMP_WAIT_FOR_REL_DELAY_TOUT);
+}
+
+/*******************************************************************************
+** Function smp_proc_release_delay_tout
+** Description processing the release delay timeout
+*******************************************************************************/
+void smp_proc_release_delay_tout(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG0 ("smp_proc_release_delay_tout ");
+ btu_stop_timer (&p_cb->rsp_timer_ent);
+ smp_proc_pairing_cmpl(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_DEBUG0 ("smp_enc_cmpl ");
+ 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_DEBUG3 ("smp_check_auth_req enc_enable=%d i_keys=0x%x r_keys=0x%x (i-initiator r-responder)",
+ enc_enable, p_cb->loc_i_key, p_cb->loc_r_key);
+ if (enc_enable == 1)
+ {
+ if (/*((p_cb->peer_auth_req & SMP_AUTH_BOND) ||
+ (p_cb->loc_auth_req & SMP_AUTH_BOND)) &&*/
+ (p_cb->loc_i_key || p_cb->loc_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->loc_r_key : p_cb->loc_i_key;
+ UINT8 i = 0;
+
+ SMP_TRACE_DEBUG1 ("smp_key_pick_key key_to_dist=0x%x", key_to_dist);
+ while (i < 3)
+ {
+ SMP_TRACE_DEBUG2("key to send = %02x, i = %d", key_to_dist, i);
+
+ if (key_to_dist & (1 << i))
+ {
+ SMP_TRACE_DEBUG1 ("smp_distribute_act[%d]", i);
+ (* smp_distribute_act[i])(p_cb, p_data);
+ break;
+ }
+ i ++;
+ }
+}
+/*******************************************************************************
+** 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_DEBUG3 ("smp_key_distribution role=%d (0-master) r_keys=0x%x i_keys=0x%x",
+ p_cb->role, p_cb->loc_r_key, p_cb->loc_i_key);
+
+ if (p_cb->role == HCI_ROLE_SLAVE||
+ (!p_cb->loc_r_key && p_cb->role == HCI_ROLE_MASTER))
+ {
+ smp_key_pick_key(p_cb, p_data);
+ }
+
+ if (!p_cb->loc_i_key && !p_cb->loc_r_key)
+ {
+ /* state check to prevent re-entrant */
+ if (smp_get_state() == SMP_ST_BOND_PENDING)
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ }
+}
+/*******************************************************************************
+** Function smp_decide_asso_model
+** Description This function is called to compare both sides' io capability
+** oob data flag and authentication request, and decide the
+** association model to use for the authentication.
+*******************************************************************************/
+void smp_decide_asso_model(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ UINT8 failure = SMP_UNKNOWN_IO_CAP;
+ tSMP_ASSO_MODEL model = SMP_MODEL_MAX;
+ UINT8 int_evt = 0;
+ tSMP_KEY key;
+ tSMP_INT_DATA *p;
+
+ SMP_TRACE_DEBUG3 ("smp_decide_asso_model p_cb->peer_io_caps = %d p_cb->loc_io_caps = %d \
+ p_cb->peer_auth_req = %02x",
+ p_cb->peer_io_caps, p_cb->loc_io_caps, p_cb->peer_auth_req);
+
+ /* OOB data present on both devices, use OOB association model */
+ if (p_cb->peer_oob_flag == SMP_OOB_PRESENT && p_cb->loc_oob_flag == SMP_OOB_PRESENT)
+ {
+ model = SMP_MODEL_OOB;
+ }
+ /* no MITM required, ignore IO cap, use encryption only */
+ else if (SMP_NO_MITM_REQUIRED (p_cb->peer_auth_req) &&
+ SMP_NO_MITM_REQUIRED(p_cb->loc_auth_req))
+ {
+ model = SMP_MODEL_ENC_ONLY;
+ }
+ else/* use IO capability to decide assiciation model */
+ {
+ if (p_cb->peer_io_caps < SMP_IO_CAP_MAX && p_cb->loc_io_caps < 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->loc_io_caps];
+ else
+ model = smp_association_table[p_cb->role][p_cb->loc_io_caps][p_cb->peer_io_caps];
+ }
+ }
+
+ SMP_TRACE_DEBUG1("Association Model = %d", model);
+
+ if (model == SMP_MODEL_OOB)
+ {
+ SMP_TRACE_ERROR0("Association Model = SMP_MODEL_OOB");
+ p_cb->sec_level = SMP_SEC_AUTHENTICATED;
+ SMP_TRACE_EVENT1 ("p_cb->sec_level =%d (SMP_SEC_AUTHENTICATED) ", p_cb->sec_level );
+ p_cb->cb_evt = SMP_OOB_REQ_EVT;
+
+ int_evt = SMP_TK_REQ_EVT;
+ }
+ else if (model == SMP_MODEL_PASSKEY)
+ {
+ p_cb->sec_level = SMP_SEC_AUTHENTICATED;
+ SMP_TRACE_EVENT1 ("p_cb->sec_level =%d (SMP_SEC_AUTHENTICATED) ", p_cb->sec_level );
+
+ p_cb->cb_evt = SMP_PASSKEY_REQ_EVT;
+ int_evt = SMP_TK_REQ_EVT;
+ }
+ else if (model == SMP_MODEL_KEY_NOTIF)
+ {
+ p_cb->sec_level = SMP_SEC_AUTHENTICATED;
+
+ SMP_TRACE_DEBUG0("Need to generate Passkey");
+ /* generate passkey and notify application */
+ smp_generate_passkey(p_cb, NULL);
+ }
+ else if (model == SMP_MODEL_ENC_ONLY) /* TK = 0, go calculate Confirm */
+ {
+ if (p_cb->role == HCI_ROLE_MASTER &&
+ ((p_cb->peer_auth_req & SMP_AUTH_YN_BIT) != 0) &&
+ ((p_cb->loc_auth_req & SMP_AUTH_YN_BIT) == 0))
+ {
+ SMP_TRACE_ERROR0("IO capability does not meet authentication requirement");
+ failure = SMP_PAIR_AUTH_FAIL;
+ p = (tSMP_INT_DATA *)&failure;
+ int_evt = SMP_AUTH_CMPL_EVT;
+ }
+ else
+ {
+ p_cb->sec_level = SMP_SEC_UNAUTHENTICATE;
+ SMP_TRACE_EVENT1 ("p_cb->sec_level =%d (SMP_SEC_UNAUTHENTICATE) ", 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;
+ }
+ }
+ else if (model == SMP_MODEL_MAX)
+ {
+ SMP_TRACE_ERROR0("Association Model = SMP_MODEL_MAX (failed)");
+ p = (tSMP_INT_DATA *)&failure;
+ int_evt = SMP_AUTH_CMPL_EVT;
+ }
+
+ SMP_TRACE_EVENT1 ("sec_level=%d ", p_cb->sec_level );
+ if (int_evt)
+ smp_sm_event(p_cb, int_evt, p);
+}
+
+/*******************************************************************************
+** Function smp_proc_io_rsp
+** Description process IO response for a slave device.
+*******************************************************************************/
+void smp_proc_io_rsp(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG0 ("smp_proc_io_rsp ");
+ if (p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)
+ {
+ smp_set_state(SMP_ST_SEC_REQ_PENDING);
+ smp_send_cmd(SMP_OPCODE_SEC_REQ, p_cb);
+ }
+ else /* respond to pairing request */
+ {
+ smp_send_pair_rsp(p_cb, NULL);
+ }
+}
+/*******************************************************************************
+** 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)
+{
+
+ SMP_TRACE_DEBUG0 ("smp_pairing_cmpl ");
+
+ if ((p_cb->status == SMP_SUCCESS) ||
+ (p_cb->status <= SMP_REPEATED_ATTEMPTS && p_cb->status != SMP_SUCCESS))
+ {
+ smp_sm_event(p_cb, SMP_RELEASE_DELAY_EVT, p_data);
+ }
+ else
+ {
+ /* this will transition to idle state right away */
+ smp_sm_event(p_cb, SMP_RELEASE_DELAY_TOUT_EVT, p_data);
+ }
+
+}
+/*******************************************************************************
+** 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_DEBUG0 ("smp_pair_terminate ");
+ p_cb->status = SMP_PAIR_FAIL_UNKNOWN;
+ 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_DEBUG0("Pairing terminated at IDLE state.");
+ p_cb->status = SMP_FAIL;
+ smp_proc_pairing_cmpl(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;
+
+ SMP_TRACE_DEBUG1 ("smp_link_encrypted encr_enable=%d",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);
+ }
+}
+/*******************************************************************************
+**
+** 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_DEBUG1 ("smp_proc_ltk_request state = %d", smp_cb.state);
+ if ( smp_cb.state == SMP_ST_ENC_PENDING &&
+ !memcmp(bda, smp_cb.pairing_bda, BD_ADDR_LEN))
+ {
+ smp_sm_event(&smp_cb, SMP_ENC_REQ_EVT, NULL);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+#endif
+
diff --git a/stack/smp/smp_api.c b/stack/smp/smp_api.c
new file mode 100644
index 0000000..cfde2d4
--- /dev/null
+++ b/stack/smp/smp_api.c
@@ -0,0 +1,337 @@
+/******************************************************************************
+ *
+ * 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 "bt_target.h"
+#if SMP_INCLUDED == TRUE
+ #include "smp_int.h"
+ #include "smp_api.h"
+ #include "l2cdefs.h"
+ #include "l2c_int.h"
+ #include "btm_int.h"
+ #include "hcimsgs.h"
+
+ #include "btu.h"
+
+
+/*******************************************************************************
+**
+** Function SMP_Init
+**
+** Description This function initializes the SMP unit.
+**
+** Returns void
+**
+*******************************************************************************/
+void SMP_Init(void)
+{
+
+ SMP_TRACE_EVENT0 ("SMP_Init");
+ memset(&smp_cb, 0, sizeof(tSMP_CB));
+
+#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_l2cap_if_init();
+}
+
+
+/*******************************************************************************
+**
+** 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
+**
+*******************************************************************************/
+SMP_API 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_EVENT1 ("SMP_Register state=%d", smp_cb.state);
+
+ if (smp_cb.p_callback != NULL)
+ {
+ SMP_TRACE_ERROR0 ("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;
+
+ BTM_TRACE_EVENT2 ("SMP_Pair state=%d flag=0x%x ", p_cb->state, p_cb->flags);
+ if (p_cb->state != SMP_ST_IDLE || p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)
+ {
+ /* 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))
+ {
+ SMP_TRACE_ERROR0("SMP_Pair: L2C connect fixed channel failed.");
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ return status;
+ }
+
+ return SMP_STARTED;
+ }
+}
+
+
+/*******************************************************************************
+**
+** 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_EVENT2 ("SMP_CancelPair state=%d flag=0x%x ", p_cb->state, p_cb->flags);
+ if ( (p_cb->state != SMP_ST_IDLE) &&
+ (!memcmp (p_cb->pairing_bda, bd_addr, BD_ADDR_LEN)) )
+ {
+ p_cb->is_pair_cancel = TRUE;
+ SMP_TRACE_DEBUG0("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_EVENT0 ("SMP_SecurityGrant ");
+ if (smp_cb.state != SMP_ST_WAIT_APP_RSP ||
+ smp_cb.cb_evt != SMP_SEC_REQUEST_EVT ||
+ memcmp (smp_cb.pairing_bda, bd_addr, BD_ADDR_LEN))
+ return;
+
+ 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;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ SMP_TRACE_EVENT2 ("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_WARNING1 ("SMP_PasskeyReply() - Wrong State: %d", p_cb->state);
+ return;
+ }
+
+ if (memcmp (bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) != 0)
+ {
+ SMP_TRACE_ERROR0 ("SMP_PasskeyReply() - Wrong BD Addr");
+ return;
+ }
+
+ if ((p_dev_rec = btm_find_dev (bd_addr)) == NULL)
+ {
+ SMP_TRACE_ERROR0 ("SMP_PasskeyReply() - no dev CB");
+ return;
+ }
+
+
+ if (passkey > BTM_MAX_PASSKEY_VAL || res != SMP_SUCCESS)
+ {
+ SMP_TRACE_WARNING1 ("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
+ {
+ smp_convert_string_to_tk(p_cb->tk, passkey);
+ }
+
+ return;
+}
+
+/*******************************************************************************
+**
+** 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_EVENT2 ("SMP_OobDataReply State: %d res:%d",
+ smp_cb.state, res);
+
+ /* If timeout already expired or has been canceled, ignore the reply */
+ if (p_cb->state != SMP_ST_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_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;
+}
+#endif /* SMP_INCLUDED */
+
+
diff --git a/stack/smp/smp_cmac.c b/stack/smp/smp_cmac.c
new file mode 100644
index 0000000..44e776e
--- /dev/null
+++ b/stack/smp/smp_cmac.c
@@ -0,0 +1,388 @@
+/******************************************************************************
+ *
+ * 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 "bt_target.h"
+
+#if SMP_INCLUDED == TRUE
+ #include <stdio.h>
+ #include <string.h>
+
+ #include "btm_ble_api.h"
+ #include "smp_int.h"
+ #include "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] */
+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
+ UINT8 *p = (UINT8 *)x;
+ UINT8 i;
+
+ SMP_TRACE_WARNING1("%s(MSB ~ LSB) = ", key_name);
+
+ for (i = 0; i < 4; i ++)
+ {
+ SMP_TRACE_WARNING4("%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_EVENT0 ("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)
+ {
+ GKI_freebuf(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;
+ UINT8 i = 1, err = 0;
+ UINT8 x[16] = {0};
+ UINT8 *p_mac;
+
+ SMP_TRACE_EVENT0 ("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_DEBUG2("tlen = %d p_mac = %d", tlen, p_mac);
+ SMP_TRACE_DEBUG4("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_DEBUG4("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_EVENT0 ("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_WARNING2("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_EVENT0 ("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_EVENT0 (" 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_CMAC
+**
+** 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 void
+**
+*******************************************************************************/
+BOOLEAN AES_CMAC ( 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_EVENT0 ("AES_CMAC ");
+
+ if (n == 0) n = 1;
+ len = n * BT_OCTET16_LEN;
+
+ SMP_TRACE_WARNING1("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 *)GKI_getbuf(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_ERROR0("No resources");
+ }
+
+ return ret;
+}
+
+ #if 0 /* testing code, sample data from spec */
+void test_cmac_cback(UINT8 *p_mac, UINT16 tlen)
+{
+ SMP_TRACE_EVENT0 ("test_cmac_cback ");
+ SMP_TRACE_ERROR0("test_cmac_cback");
+}
+
+void test_cmac(void)
+{
+ SMP_TRACE_EVENT0 ("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_WARNING1("\n Example 1: len = %d\n", len);
+
+ AES_CMAC(key, M, len, 128, test_cmac_cback, 0);
+
+}
+ #endif
+#endif
+
diff --git a/stack/smp/smp_int.h b/stack/smp/smp_int.h
new file mode 100644
index 0000000..9eb2f10
--- /dev/null
+++ b/stack/smp/smp_int.h
@@ -0,0 +1,315 @@
+/******************************************************************************
+ *
+ * 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
+
+#include "btu.h"
+#include "smp_api.h"
+
+#define SMP_MODEL_ENC_ONLY 0
+#define SMP_MODEL_PASSKEY 1
+#define SMP_MODEL_OOB 2
+#define SMP_MODEL_KEY_NOTIF 3
+#define SMP_MODEL_MAX 4
+typedef UINT8 tSMP_ASSO_MODEL;
+
+
+#ifndef SMP_MAX_CONN
+ #define SMP_MAX_CONN 2
+#endif
+
+#define SMP_WAIT_FOR_RSP_TOUT 30
+#define SMP_WAIT_FOR_REL_DELAY_TOUT 5
+/* SMP L2CAP command code */
+#define SMP_OPCODE_PAIRING_REQ 0x01
+#define SMP_OPCODE_PAIRING_RSP 0x02
+#define SMP_OPCODE_CONFIRM 0x03
+#define SMP_OPCODE_INIT 0x04
+#define SMP_OPCODE_PAIRING_FAILED 0x05
+#define SMP_OPCODE_ENCRYPT_INFO 0x06
+#define SMP_OPCODE_MASTER_ID 0x07
+#define SMP_OPCODE_IDENTITY_INFO 0x08
+#define SMP_OPCODE_ID_ADDR 0x09
+#define SMP_OPCODE_SIGN_INFO 0x0A
+#define SMP_OPCODE_SEC_REQ 0x0B
+#define SMP_OPCODE_MAX (SMP_OPCODE_SEC_REQ + 1)
+
+/* 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_INIT
+#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_SELF_DEF_EVT SMP_SECURITY_REQ_EVT
+#define SMP_KEY_READY_EVT (SMP_SELF_DEF_EVT + 1)
+#define SMP_ENCRYPTED_EVT (SMP_SELF_DEF_EVT + 2)
+#define SMP_L2CAP_CONN_EVT (SMP_SELF_DEF_EVT + 3)
+#define SMP_L2CAP_DISCONN_EVT (SMP_SELF_DEF_EVT + 4)
+#define SMP_IO_RSP_EVT (SMP_SELF_DEF_EVT + 5)
+#define SMP_API_SEC_GRANT_EVT (SMP_SELF_DEF_EVT + 6)
+#define SMP_TK_REQ_EVT (SMP_SELF_DEF_EVT + 7)
+#define SMP_AUTH_CMPL_EVT (SMP_SELF_DEF_EVT + 8)
+#define SMP_ENC_REQ_EVT (SMP_SELF_DEF_EVT + 9)
+#define SMP_BOND_REQ_EVT (SMP_SELF_DEF_EVT + 10)
+#define SMP_DISCARD_SEC_REQ_EVT (SMP_SELF_DEF_EVT + 11)
+#define SMP_RELEASE_DELAY_EVT (SMP_SELF_DEF_EVT + 12)
+#define SMP_RELEASE_DELAY_TOUT_EVT (SMP_SELF_DEF_EVT + 13)
+typedef UINT8 tSMP_EVENT;
+#define SMP_MAX_EVT SMP_RELEASE_DELAY_TOUT_EVT + 1
+
+/* auumption it's only using the low 8 bits, if bigger than that, need to expand it to be 16 bits */
+#define SMP_SEC_KEY_MASK 0x00ff
+
+/* SMP pairing state */
+enum
+{
+ SMP_ST_IDLE,
+ SMP_ST_WAIT_APP_RSP,
+ SMP_ST_SEC_REQ_PENDING,
+ SMP_ST_PAIR_REQ_RSP,
+ SMP_ST_WAIT_CONFIRM,
+ SMP_ST_CONFIRM,
+ SMP_ST_RAND,
+ SMP_ST_ENC_PENDING,
+ SMP_ST_BOND_PENDING,
+ SMP_ST_RELEASE_DELAY,
+ SMP_ST_MAX
+};
+typedef UINT8 tSMP_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
+};
+
+enum
+{
+ SMP_KEY_TYPE_TK,
+ SMP_KEY_TYPE_CFM,
+ SMP_KEY_TYPE_CMP,
+ 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;
+}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)
+
+/* 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
+
+/* 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;
+ UINT8 failure;
+ UINT8 status;
+ UINT8 role;
+ UINT8 flags;
+ UINT8 cb_evt;
+
+ tSMP_SEC_LEVEL sec_level;
+ BOOLEAN connect_initialized;
+ BT_OCTET16 confirm;
+ BT_OCTET16 rconfirm;
+ BT_OCTET16 rrand;
+ BT_OCTET16 rand;
+ tSMP_IO_CAP peer_io_caps;
+ tSMP_IO_CAP loc_io_caps;
+ tSMP_OOB_FLAG peer_oob_flag;
+ tSMP_OOB_FLAG loc_oob_flag;
+ tSMP_AUTH_REQ peer_auth_req;
+ tSMP_AUTH_REQ loc_auth_req;
+ UINT8 peer_enc_size;
+ UINT8 loc_enc_size;
+ UINT8 peer_i_key;
+ UINT8 peer_r_key;
+ UINT8 loc_i_key;
+ UINT8 loc_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;
+ BOOLEAN last_cmd;
+ BD_ADDR local_bda;
+ BOOLEAN is_pair_cancel;
+ BOOLEAN discard_sec_req;
+#if SMP_CONFORMANCE_TESTING == TRUE
+ BOOLEAN enable_test_confirm_val;
+ BT_OCTET16 test_confirm;
+ BOOLEAN enable_test_rand_val;
+ BT_OCTET16 test_rand;
+ BOOLEAN enable_test_pair_fail;
+ UINT8 pair_fail_status;
+ BOOLEAN remove_fixed_channel_disable;
+#endif
+
+}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
+ SMP_API extern tSMP_CB smp_cb;
+#else
+ SMP_API extern tSMP_CB *smp_cb_ptr;
+#define smp_cb (*smp_cb_ptr)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Functions provided by att_main.c */
+SMP_API extern void smp_init (void);
+
+#if SMP_CONFORMANCE_TESTING == TRUE
+/* Used only for conformance testing */
+SMP_API extern void smp_set_test_confirm_value (BOOLEAN enable, UINT8 *p_c_value);
+SMP_API extern void smp_set_test_rand_value (BOOLEAN enable, UINT8 *p_c_value);
+SMP_API extern void smp_set_test_pair_fail_status (BOOLEAN enable, UINT8 status);
+SMP_API extern void smp_remove_fixed_channel_disable (BOOLEAN disable);
+#endif
+/* 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_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_init(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_sec_request(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_init(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_proc_release_delay(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_proc_release_delay_tout(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_asso_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_proc_io_rsp(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);
+/* smp_l2c */
+extern void smp_l2cap_if_init (void);
+
+/* smp utility */
+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, BT_OCTET16 b);
+extern BOOLEAN smp_encrypt_data (UINT8 *key, UINT8 key_len,
+ UINT8 *plain_text, UINT8 pt_len,
+ tSMP_ENC *p_out);
+/* smp key */
+extern void smp_generate_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_genenrate_rand_cont(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+
+/* smp main util */
+extern void smp_set_state(tSMP_STATE state);
+extern tSMP_STATE smp_get_state(void);
+
+#endif /* SMP_INT_H */
+
diff --git a/stack/smp/smp_keys.c b/stack/smp/smp_keys.c
new file mode 100644
index 0000000..c61b548
--- /dev/null
+++ b/stack/smp/smp_keys.c
@@ -0,0 +1,909 @@
+/******************************************************************************
+ *
+ * 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 utility functions used
+ * by SMP.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if SMP_INCLUDED == TRUE
+ #if SMP_DEBUG == TRUE
+ #include <stdio.h>
+ #endif
+ #include <string.h>
+
+ #include "btm_ble_api.h"
+ #include "smp_int.h"
+ #include "btm_int.h"
+ #include "btm_ble_int.h"
+ #include "hcimsgs.h"
+ #include "aes.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_genenrate_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+static void smp_genenrate_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 const tSMP_ACT smp_encrypt_action[] =
+{
+ smp_generate_compare, /* SMP_GEN_COMPARE */
+ smp_genenrate_confirm, /* SMP_GEN_CONFIRM*/
+ smp_generate_stk, /* SMP_GEN_STK*/
+ smp_genenrate_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_confirm, /* SMP_GEN_SRAND_MRAND */
+ smp_genenrate_rand_cont /* SMP_GEN_SRAND_MRAND_CONT */
+};
+
+
+ #define SMP_PASSKEY_MASK 0xfff00000
+
+ #if SMP_DEBUG == TRUE
+static void smp_debug_print_nbyte_little_endian (UINT8 *p, const UINT8 *key_name, UINT8 len)
+{
+ int i, x = 0;
+ UINT8 p_buf[100];
+ memset(p_buf, 0, 100);
+
+ for (i = 0; i < len; i ++)
+ {
+ x += sprintf ((char *)&p_buf[x], "%02x ", p[i]);
+ }
+ SMP_TRACE_WARNING2("%s(LSB ~ MSB) = %s", key_name, p_buf);
+}
+ #else
+ #define smp_debug_print_nbyte_little_endian(p, key_name, len)
+ #endif
+
+/*******************************************************************************
+**
+** Function smp_encrypt_data
+**
+** Description This function is called to generate passkey.
+**
+** 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_DEBUG0 ("smp_encrypt_data");
+ if ( (p_out == NULL ) || (key_len != SMP_ENCRYT_KEY_SIZE) )
+ {
+ BTM_TRACE_ERROR0 ("smp_encrypt_data Failed");
+ return(FALSE);
+ }
+
+ if ((p_start = (UINT8 *)GKI_getbuf((SMP_ENCRYT_DATA_SIZE*4))) == NULL)
+ {
+ BTM_TRACE_ERROR0 ("smp_encrypt_data Failed unable to allocate buffer");
+ 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 */
+
+ 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);
+ p_rev_output = p;
+ aes_set_key(p_rev_key, SMP_ENCRYT_KEY_SIZE, &ctx);
+ 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);
+ smp_debug_print_nbyte_little_endian(p_out->param_buf, (const UINT8 *)"Encrypted text", SMP_ENCRYT_KEY_SIZE);
+
+ p_out->param_len = SMP_ENCRYT_KEY_SIZE;
+ p_out->status = HCI_SUCCESS;
+ p_out->opcode = HCI_BLE_ENCRYPT;
+
+ GKI_freebuf(p_start);
+
+ return(TRUE);
+}
+
+
+/*******************************************************************************
+**
+** 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)
+{
+ SMP_TRACE_DEBUG0 ("smp_generate_passkey");
+ p_cb->rand_enc_proc = 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_DEBUG0 ("smp_proc_passkey ");
+ STREAM_TO_UINT32(passkey, pp);
+ passkey &= ~SMP_PASSKEY_MASK;
+
+ /* truncate by maximum value */
+ while (passkey > BTM_MAX_PASSKEY_VAL)
+ passkey >>= 1;
+ SMP_TRACE_ERROR1("Passkey generated = %d", 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);
+ }
+
+ 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)
+{
+ BT_OCTET16 ptext;
+ UINT8 *p = ptext;
+ tSMP_ENC output;
+ tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+ SMP_TRACE_DEBUG0 ("smp_generate_stk ");
+
+ 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);
+ }
+
+ /* generate STK = Etk(rand|rrand)*/
+ if (!SMP_Encrypt( p_cb->tk, BT_OCTET16_LEN, ptext, BT_OCTET16_LEN, &output))
+ {
+ SMP_TRACE_ERROR0("smp_generate_stk failed");
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ }
+ else
+ {
+ smp_process_stk(p_cb, &output);
+ }
+
+}
+/*******************************************************************************
+**
+** Function smp_generate_confirm
+**
+** Description This function is called to start the second pairing phase by
+** start generating initializer random number.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_generate_confirm (tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG0 ("smp_generate_confirm");
+ p_cb->rand_enc_proc = SMP_GEN_SRAND_MRAND;
+ /* generate MRand or SRand */
+ if (!btsnd_hcic_ble_rand((void *)smp_rand_back))
+ smp_rand_back(NULL);
+}
+/*******************************************************************************
+**
+** Function smp_genenrate_rand_cont
+**
+** Description This function is called to generate another 64 bits random for
+** MRand or Srand.
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_genenrate_rand_cont(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG0 ("smp_genenrate_rand_cont ");
+ p_cb->rand_enc_proc = 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 to calculate LTK, starting with DIV
+** generation.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_generate_ltk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ BOOLEAN div_status;
+
+ SMP_TRACE_DEBUG0 ("smp_generate_ltk ");
+
+ div_status = btm_get_local_div(p_cb->pairing_bda, &p_cb->div);
+
+ if (div_status)
+ {
+ smp_genenrate_ltk_cont(p_cb, NULL);
+ }
+ else
+ {
+ SMP_TRACE_DEBUG0 ("Generate DIV for LTK");
+ p_cb->rand_enc_proc = 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)
+{
+ 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_DEBUG1 ("smp_compute_csrk div=%x", 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_ERROR0("smp_generate_csrk failed");
+ 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 LTK, starting with DIV
+** generation.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_generate_csrk(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ BOOLEAN div_status;
+
+ SMP_TRACE_DEBUG0 ("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_DEBUG0 ("Generate DIV for CSRK");
+ p_cb->rand_enc_proc = 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_DEBUG0 ("smp_concatenate_local ");
+ UINT8_TO_STREAM(p, op_code);
+ UINT8_TO_STREAM(p, p_cb->loc_io_caps);
+ 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->loc_i_key);
+ UINT8_TO_STREAM(p, p_cb->loc_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_DEBUG0 ("smp_concatenate_peer ");
+ 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;
+ tBTM_SEC_DEV_REC *p_dev_rec;
+
+ SMP_TRACE_DEBUG0 ("smp_gen_p1_4_confirm");
+ if ((p_dev_rec = btm_find_dev (p_cb->pairing_bda)) == NULL)
+ {
+ SMP_TRACE_ERROR0("can not generate confirm for unknown device");
+ return;
+ }
+
+ BTM_ReadConnectionAddr(p_cb->local_bda);
+
+ if (p_cb->role == HCI_ROLE_MASTER)
+ {
+ /* LSB : rat': initiator's(local) address type */
+ UINT8_TO_STREAM(p, 0);
+ /* LSB : iat': responder's address type */
+ UINT8_TO_STREAM(p, p_dev_rec->ble.ble_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, p_dev_rec->ble.ble_addr_type);
+ /* LSB : rat': responder's(local) address type */
+ UINT8_TO_STREAM(p, 0);
+ /* 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_DEBUG0("p1 = pres || preq || rat' || iat'");
+ 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;
+
+ SMP_TRACE_DEBUG0 ("smp_gen_p2_4_confirm");
+ memset(p, 0, sizeof(BT_OCTET16));
+
+ if (p_cb->role == HCI_ROLE_MASTER)
+ {
+ /* LSB ra */
+ BDADDR_TO_STREAM(p, p_cb->pairing_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, p_cb->pairing_bda);
+ }
+#if SMP_DEBUG == TRUE
+ SMP_TRACE_DEBUG0("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)
+{
+ BT_OCTET16 p1;
+ tSMP_ENC output;
+ tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+ SMP_TRACE_DEBUG0 ("smp_calculate_comfirm ");
+ /* 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_ERROR0("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_DEBUG0 ("smp_calculate_comfirm_cont ");
+#if SMP_DEBUG == TRUE
+ SMP_TRACE_DEBUG0("Confirm step 1 p1' = e(k, r XOR p1) Generated");
+ 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_ERROR0("smp_calculate_comfirm_cont failed");
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ }
+ else
+ {
+ switch (p_cb->rand_enc_proc)
+ {
+ case SMP_GEN_CONFIRM:
+ smp_process_confirm(p_cb, &output);
+ break;
+
+ case SMP_GEN_COMPARE:
+ smp_process_compare(p_cb, &output);
+ break;
+ }
+ }
+}
+/*******************************************************************************
+**
+** Function smp_genenrate_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_genenrate_confirm(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ SMP_TRACE_DEBUG0 ("smp_genenrate_confirm ");
+ p_cb->rand_enc_proc = 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)
+{
+ SMP_TRACE_DEBUG0 ("smp_generate_compare ");
+ p_cb->rand_enc_proc = 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_DEBUG0 ("smp_process_confirm ");
+#if SMP_CONFORMANCE_TESTING == TRUE
+ if (p_cb->enable_test_confirm_val)
+ {
+ BTM_TRACE_DEBUG0 ("Use confirm value from script");
+ memcpy(p_cb->confirm, p_cb->test_confirm, BT_OCTET16_LEN);
+ }
+ else
+ memcpy(p_cb->confirm, p->param_buf, BT_OCTET16_LEN);
+#else
+ memcpy(p_cb->confirm, p->param_buf, BT_OCTET16_LEN);
+#endif
+
+
+#if (SMP_DEBUG == TRUE)
+ SMP_TRACE_DEBUG0("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_DEBUG0 ("smp_process_compare ");
+#if (SMP_DEBUG == TRUE)
+ SMP_TRACE_DEBUG0("Compare Generated");
+ 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_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_DEBUG0 ("smp_process_stk ");
+#if (SMP_DEBUG == TRUE)
+ SMP_TRACE_ERROR0("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_genenrate_ltk_cont
+**
+** Description This function is to calculate LTK = d1(ER, DIV, 0)= e(ER, DIV)
+**
+** Returns void
+**
+*******************************************************************************/
+static void smp_genenrate_ltk_cont(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+ BT_OCTET16 er;
+ tSMP_ENC output;
+ tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+ SMP_TRACE_DEBUG0 ("smp_genenrate_ltk_cont ");
+ 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_ERROR0("smp_genenrate_ltk_cont failed");
+ 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)
+{
+ BT_OCTET16 dhk;
+ tSMP_ENC output;
+ tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+
+ SMP_TRACE_DEBUG0 ("smp_generate_y ");
+ BTM_GetDeviceDHK(dhk);
+
+ if (!SMP_Encrypt(dhk, BT_OCTET16_LEN, p_cb->enc_rand,
+ BT_OCTET8_LEN, &output))
+ {
+ SMP_TRACE_ERROR0("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)
+{
+ /* generate EDIV and rand now */
+ /* generate random vector */
+ SMP_TRACE_DEBUG0 ("smp_generate_rand_vector ");
+ p_cb->rand_enc_proc = SMP_GEN_RAND_V;
+ if (!btsnd_hcic_ble_rand((void *)smp_rand_back))
+ smp_rand_back(NULL);
+
+}
+/*******************************************************************************
+**
+** Function smp_genenrate_smp_process_edivltk_cont
+**
+** 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_DEBUG0 ("smp_process_ediv ");
+ STREAM_TO_UINT16(y, pp);
+
+ /* EDIV = Y xor DIV */
+ p_cb->ediv = p_cb->div ^ y;
+ /* send LTK ready */
+ SMP_TRACE_ERROR0("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_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 & ~0x80;
+
+ SMP_TRACE_DEBUG1 ("smp_rand_back state=0x%x", 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_genenrate_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_genenrate_confirm(p_cb, NULL);
+ break;
+
+ case SMP_GEN_DIV_LTK:
+ STREAM_TO_UINT16(p_cb->div, pp);
+ smp_genenrate_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;
+
+ }
+
+ return;
+ }
+
+ SMP_TRACE_ERROR1("smp_rand_back Key generation failed: (%d)", p_cb->rand_enc_proc);
+
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+
+}
+#endif
+
diff --git a/stack/smp/smp_l2c.c b/stack/smp/smp_l2c.c
new file mode 100644
index 0000000..648cd59
--- /dev/null
+++ b/stack/smp/smp_l2c.c
@@ -0,0 +1,161 @@
+/******************************************************************************
+ *
+ * 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 "bt_target.h"
+
+#if SMP_INCLUDED == TRUE
+
+#include <string.h>
+#include "btm_ble_api.h"
+#include "l2c_api.h"
+
+#include "smp_int.h"
+
+
+
+static void smp_connect_cback (BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason);
+static void smp_data_ind (BD_ADDR bd_addr, BT_HDR *p_buf);
+
+/*******************************************************************************
+**
+** 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_EVENT0 ("SMDBG l2c smp_l2cap_if_init");
+ 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_FixedConn_Cb = smp_connect_cback;
+ fixed_reg.pL2CA_FixedData_Cb = smp_data_ind;
+ fixed_reg.default_idle_tout = 60; /* set 60 seconds timeout, 0xffff default idle timeout */
+
+ /* Now, register with L2CAP */
+ L2CA_RegisterFixedChannel (L2CAP_SMP_CID, &fixed_reg);
+}
+
+/*******************************************************************************
+**
+** Function smp_connect_cback
+**
+** Description This callback function is called by L2CAP to indicate that
+** SMP channel is
+** connected (conn = TRUE)/disconnected (conn = FALSE).
+**
+*******************************************************************************/
+static void smp_connect_cback (BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason)
+{
+ tSMP_CB *p_cb = &smp_cb;
+ tSMP_INT_DATA int_data;
+
+ SMP_TRACE_EVENT0 ("SMDBG l2c smp_connect_cback ");
+
+ if (memcmp(bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) == 0)
+ {
+ SMP_TRACE_EVENT3 ("smp_connect_cback() for pairing BDA: %08x%04x Event: %s",
+ (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->loc_r_key = p_cb->loc_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);
+
+ BTM_ReadConnectionAddr(p_cb->local_bda);
+ }
+ }
+ else
+ {
+ int_data.reason = reason;
+ /* Disconnected while doing security */
+ smp_sm_event(p_cb, SMP_L2CAP_DISCONN_EVT, &int_data);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function smp_data_ind
+**
+** Description This function is called when data is received from L2CAP on
+** SMP channel.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void smp_data_ind (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_EVENT0 ("SMDBG l2c smp_data_ind");
+
+ SMP_TRACE_EVENT0 ("Got smp_data_ind");
+
+ STREAM_TO_UINT8(cmd, p);
+
+
+ /* 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_ST_IDLE)
+ {
+ 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))
+ {
+ p_cb->failure = SMP_PAIR_NOT_SUPPORT;
+ smp_send_cmd(SMP_OPCODE_PAIRING_FAILED, p_cb);
+ }
+ }
+
+ if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN) == 0)
+ {
+ btu_stop_timer (&p_cb->rsp_timer_ent);
+ smp_sm_event(p_cb, cmd, p);
+ }
+
+ GKI_freebuf (p_buf);
+}
+#endif
diff --git a/stack/smp/smp_main.c b/stack/smp/smp_main.c
new file mode 100644
index 0000000..a60f54b
--- /dev/null
+++ b/stack/smp/smp_main.c
@@ -0,0 +1,518 @@
+/******************************************************************************
+ *
+ * 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 "bt_target.h"
+
+#if SMP_INCLUDED == TRUE
+
+ #include <string.h>
+ #include "smp_int.h"
+
+
+const char * const smp_state_name [] =
+{
+ "SMP_ST_IDLE",
+ "SMP_ST_WAIT_APP_RSP",
+ "SMP_ST_SEC_REQ_PENDING",
+ "SMP_ST_PAIR_REQ_RSP",
+ "SMP_ST_WAIT_CONFIRM",
+ "SMP_ST_CONFIRM",
+ "SMP_ST_RAND",
+ "SMP_ST_ENC_PENDING",
+ "SMP_ST_BOND_PENDING",
+ "SMP_ST_RELEASE_DELAY",
+ "SMP_ST_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",
+ "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",
+ "RELEASE_DELAY_EVT",
+ "RELEASE_DELAY_TOUT_EVT",
+ "MAX_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_INIT,
+ SMP_SEND_SECU_INFO,
+ SMP_SEND_ID_INFO,
+ SMP_SEND_LTK_REPLY,
+ SMP_PROC_PAIR_CMD,
+ SMP_PROC_PAIR_FAIL,
+ SMP_PROC_CONFIRM,
+ SMP_PROC_INIT,
+ 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_PROC_REL_DELAY,
+ SMP_PROC_REL_DELAY_TOUT,
+ SMP_SM_NO_ACTION
+};
+
+static const tSMP_ACT smp_sm_action[] =
+{
+ smp_proc_sec_req,
+ smp_send_pair_req,
+ smp_send_pair_rsp,
+ smp_send_confirm,
+ smp_send_pair_fail,
+ smp_send_init,
+ 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_init,
+ 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_distribution,
+ 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_proc_release_delay,
+ smp_proc_release_delay_tout,
+};
+/************ SMP Master FSM State/Event Indirection Table **************/
+static const UINT8 smp_ma_entry_map[][SMP_ST_MAX] =
+{
+/* state name: Idle WaitApp SecReq Pair Wait Confirm Init Enc Bond Rel
+ Rsp Pend ReqRsp Cfm Pend Pend Delay */
+/* PAIR_REQ */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+/* PAIR_RSP */{ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 },
+/* CONFIRM */{ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
+/* INIT */{ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 },
+/* PAIR_FAIL */{ 0, 0x81, 0, 0x81, 0x81,0x81, 0x81,0, 0, 0 },
+/* ENC_INFO */{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 },
+/* MASTER_ID */{ 0, 0, 0, 0, 0, 0, 0, 0, 4, 0 },
+/* ID_INFO */{ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0 },
+/* ID_ADDR */{ 0, 0, 0, 0, 0, 0, 0, 0, 5, 0 },
+/* SIGN_INFO */{ 0, 0, 0, 0, 0, 0, 0, 0, 3, 0 },
+/* SEC_REQ */{ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+/* KEY_READY */{ 0, 3, 0, 3, 1, 0, 2, 1, 6, 0 },
+/* ENC_CMPL */{ 0, 0, 0, 0, 0, 0, 0, 2, 0, 0 },
+/* L2C_CONN */{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+/* L2C_DISC */{ 0, 0x83, 0, 0x83, 0x83,0x83, 0x83,0x83, 0x83, 2 },
+/* IO_RSP */{ 0, 2, 0, 0, 0, 0, 0, 0, 0, 0 },
+/* SEC_GRANT */{ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
+/* TK_REQ */{ 0, 0, 0, 2, 0, 0, 0, 0, 0, 0 },
+/* AUTH_CMPL */{ 0, 0x82, 0, 0x82, 0x82,0x82, 0x82,0x82, 0x82, 0 },
+/* ENC_REQ */{ 0, 4, 0, 0, 0, 0, 3, 0, 0, 0 },
+/* BOND_REQ */{ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 },
+/* DISCARD_SEC_REQ */{ 0, 5, 0, 0, 0, 0, 0, 3, 0, 0 },
+/* RELEASE_DELAY */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
+/* RELEASE_DELAY_TOUT */{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 },
+};
+
+static const UINT8 smp_all_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* PAIR_FAIL */ {SMP_PROC_PAIR_FAIL, SMP_PROC_REL_DELAY_TOUT, SMP_ST_IDLE},
+/* AUTH_CMPL */ {SMP_SEND_PAIR_FAIL, SMP_PAIRING_CMPL, SMP_ST_RELEASE_DELAY},
+/* L2C_DISC */ {SMP_PAIR_TERMINATE, SMP_SM_NO_ACTION, SMP_ST_IDLE}
+};
+
+static const UINT8 smp_ma_idle_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* L2C_CONN */ {SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_ST_WAIT_APP_RSP},
+/* SEC_REQ */ {SMP_PROC_SEC_REQ, SMP_SEND_APP_CBACK, SMP_ST_WAIT_APP_RSP}
+};
+
+static const UINT8 smp_ma_wait_app_rsp_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* SEC_GRANT */ { SMP_PROC_SEC_GRANT, SMP_SEND_APP_CBACK, SMP_ST_WAIT_APP_RSP},
+/* IO_RSP */ { SMP_SEND_PAIR_REQ, SMP_SM_NO_ACTION, SMP_ST_PAIR_REQ_RSP},
+/* KEY_READY */ { SMP_GENERATE_CONFIRM, SMP_SM_NO_ACTION, SMP_ST_WAIT_CONFIRM},/* TK ready */
+/* ENC_REQ */ { SMP_START_ENC, SMP_SM_NO_ACTION, SMP_ST_ENC_PENDING},/* start enc mode setup */
+/* DISCARD_SEC_REQ */ { SMP_PROC_DISCARD, SMP_SM_NO_ACTION, SMP_ST_IDLE}
+};
+
+static const UINT8 smp_ma_pair_req_rsp_table [][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* PAIR_RSP */ { SMP_PROC_PAIR_CMD, SMP_DECIDE_ASSO_MODEL, SMP_ST_PAIR_REQ_RSP},
+/* TK_REQ */ { SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_ST_WAIT_APP_RSP},
+/* KEY_READY */{ SMP_GENERATE_CONFIRM, SMP_SM_NO_ACTION, SMP_ST_WAIT_CONFIRM} /* TK ready */
+};
+
+static const UINT8 smp_ma_wait_confirm_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* KEY_READY*/ {SMP_SEND_CONFIRM, SMP_SM_NO_ACTION, SMP_ST_CONFIRM}/* CONFIRM ready */
+};
+
+static const UINT8 smp_ma_confirm_table [][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* CONFIRM */ { SMP_PROC_CONFIRM, SMP_SEND_INIT, SMP_ST_RAND}
+};
+
+static const UINT8 smp_ma_init_table [][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* INIT */ { SMP_PROC_INIT, SMP_GENERATE_COMPARE, SMP_ST_RAND},
+/* KEY_READY*/ { SMP_PROC_COMPARE, SMP_SM_NO_ACTION, SMP_ST_RAND}, /* Compare ready */
+/* ENC_REQ */ { SMP_GENERATE_STK, SMP_SM_NO_ACTION, SMP_ST_ENC_PENDING}
+};
+static const UINT8 smp_ma_enc_pending_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* KEY_READY */ { SMP_START_ENC, SMP_SM_NO_ACTION, SMP_ST_ENC_PENDING}, /* STK ready */
+/* ENCRYPTED */ { SMP_CHECK_AUTH_REQ, SMP_SM_NO_ACTION, SMP_ST_ENC_PENDING},
+/* BOND_REQ */ { SMP_KEY_DISTRIBUTE, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING}
+};
+static const UINT8 smp_ma_bond_pending_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* ENC_INFO */ { SMP_PROC_ENC_INFO, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING},
+/* ID_INFO */ { SMP_PROC_ID_INFO, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING},
+/* SIGN_INFO*/ { SMP_PROC_SRK_INFO, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING},
+/* MASTER_ID*/ { SMP_PROC_MASTER_ID, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING},
+/* ID_ADDR */ { SMP_PROC_ID_ADDR, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING},
+/* KEY_READY */ {SMP_SEND_SECU_INFO, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING} /* LTK ready */
+};
+
+static const UINT8 smp_ma_rel_delay_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* RELEASE_DELAY*/ {SMP_PROC_REL_DELAY, SMP_SM_NO_ACTION, SMP_ST_RELEASE_DELAY},
+/* RELEASE_DELAY_TOUT*/ {SMP_PROC_REL_DELAY_TOUT, SMP_SM_NO_ACTION, SMP_ST_IDLE}
+};
+
+
+/************ SMP Slave FSM State/Event Indirection Table **************/
+static const UINT8 smp_sl_entry_map[][SMP_ST_MAX] =
+{
+/* state name: Idle Wait SecReq Pair Wait Confirm Init Enc Bond Rel
+ AppRsp Pend ReqRsp Cfm Pend Pend Delay */
+/* PAIR_REQ */ { 2, 0, 1, 0, 0, 0, 0, 0, 0, 0 },
+/* PAIR_RSP */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+/* CONFIRM */ { 0, 4, 0, 1, 1, 0, 0, 0, 0, 0 },
+/* INIT */ { 0, 0, 0, 0, 0, 1, 2, 0, 0, 0 },
+/* PAIR_FAIL*/ { 0, 0x81, 0x81, 0x81, 0x81,0x81, 0x81,0x81, 0, 0 },
+/* ENC_INFO */ { 0, 0, 0, 0, 0, 0, 0, 0, 3, 0 },
+/* MASTER_ID*/ { 0, 0, 0, 0, 0, 0, 0, 0, 5, 0 },
+/* ID_INFO */ { 0, 0, 0, 0, 0, 0, 0, 0, 4, 0 },
+/* ID_ADDR */ { 0, 0, 0, 0, 0, 0, 0, 0, 6, 0 },
+/* SIGN_INFO*/ { 0, 0, 0, 0, 0, 0, 0, 0, 2, 0 },
+/* SEC_REQ */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+
+/* KEY_READY*/ { 0, 3, 0, 3, 2, 2, 1, 2, 1, 0 },
+/* ENC_CMPL */ { 0, 0, 2, 0, 0, 0, 0, 3, 0, 0 },
+/* L2C_CONN */ { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+/* L2C_DISC */ { 0, 0x83, 0x83, 0x83, 0x83,0x83, 0x83,0x83, 0x83, 2 },
+/* IO_RSP */ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
+/* SEC_GRANT*/ { 0, 2, 0, 0, 0, 0, 0, 0, 0, 0 },
+
+/* TK_REQ */ { 0, 0, 0, 2, 0, 0, 0, 0, 0, 0 },
+/* AUTH_CMPL*/ { 0, 0x82, 0x82, 0x82, 0x82,0x82, 0x82,0x82, 0x82, 0 },
+/* ENC_REQ */ { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
+/* BOND_REQ */ { 0, 0, 0, 0, 0, 0, 0, 4, 0, 0 },
+/* DISCARD_SEC_REQ */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+/* RELEASE_DELAY */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
+/* RELEASE_DELAY_TOUT */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 },
+};
+
+static const UINT8 smp_sl_idle_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* L2C_CONN */ {SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_ST_WAIT_APP_RSP},
+/* PAIR_REQ */ {SMP_PROC_PAIR_CMD, SMP_SEND_APP_CBACK, SMP_ST_WAIT_APP_RSP}
+};
+
+static const UINT8 smp_sl_wait_app_rsp_table [][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* IO_RSP */ {SMP_PROC_IO_RSP, SMP_SM_NO_ACTION, SMP_ST_PAIR_REQ_RSP},
+/* SEC_GRANT */ {SMP_PROC_SEC_GRANT, SMP_SEND_APP_CBACK, SMP_ST_WAIT_APP_RSP},
+/* KEY_READY */ {SMP_PROC_SL_KEY, SMP_SM_NO_ACTION, SMP_ST_WAIT_APP_RSP},/* TK ready */
+/* CONFIRM */ {SMP_PROC_CONFIRM, SMP_SM_NO_ACTION, SMP_ST_CONFIRM}
+};
+
+static const UINT8 smp_sl_sec_request_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* PAIR_REQ */{SMP_PROC_PAIR_CMD, SMP_SEND_PAIR_RSP, SMP_ST_PAIR_REQ_RSP},
+/* ENCRYPTED*/{SMP_ENC_CMPL, SMP_SM_NO_ACTION, SMP_ST_PAIR_REQ_RSP},
+};
+
+static const UINT8 smp_sl_pair_req_rsp_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* CONFIRM */ {SMP_PROC_CONFIRM, SMP_SM_NO_ACTION, SMP_ST_CONFIRM},
+/* TK_REQ */ {SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_ST_WAIT_APP_RSP},
+/* KEY_READY */{SMP_PROC_SL_KEY, SMP_SM_NO_ACTION, SMP_ST_PAIR_REQ_RSP} /* TK/Confirm ready */
+
+};
+
+static const UINT8 smp_sl_wait_confirm_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* CONFIRM */ {SMP_PROC_CONFIRM, SMP_SEND_CONFIRM, SMP_ST_CONFIRM},
+/* KEY_READY*/ {SMP_PROC_SL_KEY, SMP_SM_NO_ACTION, SMP_ST_WAIT_CONFIRM}
+};
+static const UINT8 smp_sl_confirm_table [][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* INIT_EVT */{ SMP_PROC_INIT, SMP_GENERATE_COMPARE, SMP_ST_RAND},
+/* KEY_READY*/ {SMP_PROC_SL_KEY, SMP_SM_NO_ACTION, SMP_ST_CONFIRM} /* TK/Confirm ready */
+};
+static const UINT8 smp_sl_init_table [][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* KEY_READY */ {SMP_PROC_COMPARE, SMP_SM_NO_ACTION, SMP_ST_RAND}, /* compare match */
+/* INIT_EVT */ {SMP_SEND_INIT, SMP_SM_NO_ACTION, SMP_ST_ENC_PENDING}
+};
+static const UINT8 smp_sl_enc_pending_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* ENC_REQ */ {SMP_GENERATE_STK, SMP_SM_NO_ACTION, SMP_ST_ENC_PENDING},
+/* KEY_READY */ {SMP_SEND_LTK_REPLY, SMP_SM_NO_ACTION, SMP_ST_ENC_PENDING},/* STK ready */
+/* ENCRYPTED */ {SMP_CHECK_AUTH_REQ, SMP_SM_NO_ACTION, SMP_ST_ENC_PENDING},
+/* BOND_REQ */ {SMP_KEY_DISTRIBUTE, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING}
+};
+static const UINT8 smp_sl_bond_pending_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* KEY_READY */ {SMP_SEND_SECU_INFO, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING}, /* LTK ready */
+/* SIGN_INFO */ {SMP_PROC_SRK_INFO, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING}, /* rev SRK */
+/* ENC_INFO */ { SMP_PROC_ENC_INFO, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING},
+/* ID_INFO */ { SMP_PROC_ID_INFO, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING},
+/* MASTER_ID*/ { SMP_PROC_MASTER_ID, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING},
+/* ID_ADDR */ { SMP_PROC_ID_ADDR, SMP_SM_NO_ACTION, SMP_ST_BOND_PENDING}
+
+};
+
+static const UINT8 smp_sl_rel_delay_table[][SMP_SM_NUM_COLS] = {
+/* Event Action Next State */
+/* RELEASE_DELAY*/ {SMP_PROC_REL_DELAY, SMP_SM_NO_ACTION, SMP_ST_RELEASE_DELAY},
+/* RELEASE_DELAY_TOUT*/ {SMP_PROC_REL_DELAY_TOUT, SMP_SM_NO_ACTION, SMP_ST_IDLE}
+};
+
+static const tSMP_SM_TBL smp_state_table[][2] = {
+ {smp_ma_idle_table, smp_sl_idle_table}, /* SMP_ST_IDLE*/
+ {smp_ma_wait_app_rsp_table, smp_sl_wait_app_rsp_table}, /* SMP_ST_WAIT_APP_RSP */
+ {NULL, smp_sl_sec_request_table}, /* SMP_ST_SEC_REQ_PENDING */
+ {smp_ma_pair_req_rsp_table, smp_sl_pair_req_rsp_table}, /* SMP_ST_PAIR_REQ_RSP */
+ {smp_ma_wait_confirm_table, smp_sl_wait_confirm_table}, /* SMP_ST_WAIT_CONFIRM */
+ {smp_ma_confirm_table, smp_sl_confirm_table}, /* SMP_ST_CONFIRM */
+ {smp_ma_init_table, smp_sl_init_table}, /* SMP_ST_RAND */
+ {smp_ma_enc_pending_table, smp_sl_enc_pending_table}, /* SMP_ST_ENC_PENDING */
+ {smp_ma_bond_pending_table, smp_sl_bond_pending_table}, /* SMP_ST_BOND_PENDING */
+ {smp_ma_rel_delay_table, smp_sl_rel_delay_table} /* SMP_ST_RELEASE_DELAY */
+};
+
+typedef const UINT8 (*tSMP_ENTRY_TBL)[SMP_ST_MAX];
+static const tSMP_ENTRY_TBL smp_entry_table[] ={
+ smp_ma_entry_map,
+ smp_sl_entry_map
+};
+
+#if SMP_DYNAMIC_MEMORY == FALSE
+tSMP_CB smp_cb;
+#endif
+#define SMP_ALL_TBL_MASK 0x80
+
+
+/*******************************************************************************
+** Function smp_set_state
+** Returns None
+*******************************************************************************/
+void smp_set_state(tSMP_STATE state)
+{
+ if (state < SMP_ST_MAX)
+ {
+ SMP_TRACE_DEBUG4( "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_DEBUG1("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_EVENT0("main smp_sm_event");
+ if (curr_state >= SMP_ST_MAX)
+ {
+ SMP_TRACE_DEBUG1( "Invalid state: %d", curr_state) ;
+ return;
+ }
+
+ SMP_TRACE_DEBUG5( "SMP Role: %s State: [%s (%d)], Event: [%s (%d)]",\
+ (p_cb->role == 0x01) ?"Slave" : "Master", 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 ( (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];
+ }
+ else
+ {
+ SMP_TRACE_DEBUG4( "Ignore event [%s (%d)] in state [%s (%d)]",
+ 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])(p_cb, (tSMP_INT_DATA *)p_data);
+ }
+ else
+ {
+ break;
+ }
+ }
+ SMP_TRACE_DEBUG1( "result state = %s", 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_ST_MAX];
+
+ if (state < SMP_ST_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 - 1];
+
+ if (event < SMP_MAX_EVT)
+ {
+ p_str = smp_event_name[event- 1];
+ }
+ return p_str;
+}
+#endif
+
diff --git a/stack/smp/smp_utils.c b/stack/smp/smp_utils.c
new file mode 100644
index 0000000..5622880
--- /dev/null
+++ b/stack/smp/smp_utils.c
@@ -0,0 +1,675 @@
+/******************************************************************************
+ *
+ * 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 "bt_target.h"
+
+#if SMP_INCLUDED == TRUE
+
+#include "bt_types.h"
+#include <string.h>
+#include <ctype.h>
+#include "hcidefs.h"
+#include "btm_ble_api.h"
+#include "l2c_api.h"
+#include "l2c_int.h"
+#include "smp_int.h"
+
+
+#define SMP_PAIRING_REQ_SIZE 7
+#define SMP_CONFIRM_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
+
+
+/* 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);
+
+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 initializer request */
+ smp_build_pairing_fail, /* 0x05: pairing failure */
+ smp_build_encrypt_info_cmd, /* 0x06: security information command */
+ smp_build_master_id_cmd, /* 0x07: master identity command */
+ smp_build_identity_info_cmd, /* 0x08: identity information command */
+ smp_build_id_addr_cmd, /* 0x09: signing information */
+ smp_build_signing_info_cmd, /* 0x0A: signing information */
+ smp_build_security_request /* 0x0B: security request */
+};
+/*******************************************************************************
+**
+** 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;
+
+ SMP_TRACE_EVENT0("smp_send_msg_to_L2CAP");
+
+ if ((l2cap_ret = L2CA_SendFixedChnlData (L2CAP_SMP_CID, rem_bda, p_toL2CAP)) == L2CAP_DW_FAILED)
+ {
+ SMP_TRACE_ERROR1("SMP failed to pass msg:0x%0x to L2CAP",
+ *((UINT8 *)(p_toL2CAP + 1) + p_toL2CAP->offset));
+ GKI_freebuf(p_toL2CAP);
+ 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_EVENT1("smp_send_cmd on l2cap cmd_code=0x%x", cmd_code);
+ if ( cmd_code < SMP_OPCODE_MAX &&
+ 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)
+ {
+ 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;
+
+ SMP_TRACE_EVENT1("smp_rsp_timeout state:%d", p_cb->state);
+
+ if (smp_get_state() == SMP_ST_RELEASE_DELAY)
+ {
+ smp_sm_event(p_cb, SMP_RELEASE_DELAY_TOUT_EVT, NULL);
+ }
+ 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_EVENT0("smp_build_pairing_cmd");
+ if ((p_buf = (BT_HDR *)GKI_getbuf(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->loc_io_caps);
+ 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->loc_i_key);
+ UINT8_TO_STREAM (p, p_cb->loc_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;
+ SMP_TRACE_EVENT0("smp_build_confirm_cmd");
+ if ((p_buf = (BT_HDR *)GKI_getbuf(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 Initializer command.
+**
+*******************************************************************************/
+static BT_HDR * smp_build_rand_cmd(UINT8 cmd_code, tSMP_CB *p_cb)
+{
+ BT_HDR *p_buf = NULL ;
+ UINT8 *p;
+ SMP_TRACE_EVENT0("smp_build_rand_cmd");
+ if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + SMP_INIT_CMD_SIZE + L2CAP_MIN_OFFSET)) != NULL)
+ {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM (p, SMP_OPCODE_INIT);
+ ARRAY_TO_STREAM (p, p_cb->rand, BT_OCTET16_LEN);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_INIT_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;
+ SMP_TRACE_EVENT0("smp_build_encrypt_info_cmd");
+ if ((p_buf = (BT_HDR *)GKI_getbuf(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;
+ SMP_TRACE_EVENT0("smp_build_master_id_cmd ");
+ if ((p_buf = (BT_HDR *)GKI_getbuf(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 ;
+ UINT8 *p;
+ BT_OCTET16 irk;
+ SMP_TRACE_EVENT0("smp_build_identity_info_cmd");
+ if ((p_buf = (BT_HDR *)GKI_getbuf(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;
+ }
+
+ 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;
+ BT_OCTET16 irk;
+ SMP_TRACE_EVENT0("smp_build_id_addr_cmd");
+ if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + SMP_ID_ADDR_SIZE + L2CAP_MIN_OFFSET)) != NULL)
+ {
+ p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ BTM_GetDeviceIDRoot(irk);
+
+ UINT8_TO_STREAM (p, SMP_OPCODE_ID_ADDR);
+ UINT8_TO_STREAM (p, 0); /* TODO: update with local address type */
+ BTM_ReadConnectionAddr(p_cb->local_bda);
+ BDADDR_TO_STREAM (p, p_cb->local_bda);
+
+ 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;
+ //BT_OCTET16 srk; remove
+ SMP_TRACE_EVENT0("smp_build_signing_info_cmd");
+ if ((p_buf = (BT_HDR *)GKI_getbuf(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;
+ SMP_TRACE_EVENT0("smp_build_pairing_fail");
+ if ((p_buf = (BT_HDR *)GKI_getbuf(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;
+ SMP_TRACE_EVENT0("smp_build_security_request");
+
+ if ((p_buf = (BT_HDR *)GKI_getbuf(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 = 2;
+
+ SMP_TRACE_EVENT2("opcode=%d auth_req=0x%x",SMP_OPCODE_SEC_REQ, p_cb->loc_auth_req );
+ }
+
+ 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_EVENT0("smp_convert_string_to_tk");
+ 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_EVENT0("smp_mask_enc_key");
+ 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, BT_OCTET16 b)
+{
+ UINT8 i, *aa = a, *bb = b;
+
+ SMP_TRACE_EVENT0("smp_xor_128");
+ 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;
+
+ SMP_TRACE_EVENT0("smp_cb_cleanup");
+ memset(p_cb, 0, sizeof(tSMP_CB));
+ p_cb->p_callback = p_callback;
+ p_cb->trace_level = trace_level;
+}
+/*******************************************************************************
+**
+** 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_EVENT0("smp_reset_control_value");
+ btu_stop_timer (&p_cb->rsp_timer_ent);
+#if SMP_CONFORMANCE_TESTING == TRUE
+
+ SMP_TRACE_EVENT1("smp_cb.remove_fixed_channel_disable=%d", smp_cb.remove_fixed_channel_disable);
+ if (!smp_cb.remove_fixed_channel_disable)
+ {
+ L2CA_RemoveFixedChnl (L2CAP_SMP_CID, p_cb->pairing_bda);
+ }
+ else
+ {
+ SMP_TRACE_EVENT0("disable the removal of the fixed channel");
+ }
+
+
+#else
+ /* We can tell L2CAP to remove the fixed channel (if it has one) */
+ L2CA_RemoveFixedChnl (L2CAP_SMP_CID, p_cb->pairing_bda);
+
+#endif
+ 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};
+
+ SMP_TRACE_DEBUG0 ("smp_proc_pairing_cmpl ");
+
+ evt_data.cmplt.reason = p_cb->status;
+
+ if (p_cb->status == SMP_SUCCESS)
+ evt_data.cmplt.sec_level = p_cb->sec_level;
+
+ evt_data.cmplt.is_pair_cancel = FALSE;
+
+ if (p_cb->is_pair_cancel)
+ evt_data.cmplt.is_pair_cancel = TRUE;
+
+
+ SMP_TRACE_DEBUG2 ("send SMP_COMPLT_EVT reason=0x%0x sec_level=0x%0x",
+ evt_data.cmplt.reason,
+ evt_data.cmplt.sec_level );
+ if (p_cb->p_callback)
+ (*p_cb->p_callback) (SMP_COMPLT_EVT, p_cb->pairing_bda, &evt_data);
+
+#if 0 /* TESTING CODE : as a master, reencrypt using LTK */
+ if (evt_data.cmplt.reason == 0 && p_cb->role == HCI_ROLE_MASTER)
+ {
+ btm_ble_start_encrypt(p_cb->pairing_bda, FALSE, NULL);
+ }
+#endif
+
+ smp_reset_control_value(p_cb);
+}
+
+#if SMP_CONFORMANCE_TESTING == TRUE
+/*******************************************************************************
+**
+** Function smp_set_test_confirm_value
+**
+** Description This function is called to set the test confirm value
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_set_test_confirm_value(BOOLEAN enable, UINT8 *p_c_val)
+{
+ SMP_TRACE_DEBUG1("smp_set_test_confirm_value enable=%d", enable);
+ smp_cb.enable_test_confirm_val = enable;
+ memcpy(smp_cb.test_confirm, p_c_val, BT_OCTET16_LEN);
+}
+
+
+/*******************************************************************************
+**
+** Function smp_set_test_confirm_value
+**
+** Description This function is called to set the test rand value
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_set_test_rand_value(BOOLEAN enable, UINT8 *p_c_val)
+{
+ SMP_TRACE_DEBUG1("smp_set_test_rand_value enable=%d", enable);
+ smp_cb.enable_test_rand_val = enable;
+ memcpy(smp_cb.test_rand, p_c_val, BT_OCTET16_LEN);
+}
+
+
+/*******************************************************************************
+**
+** Function smp_set_test_pair_fail_status
+**
+** Description This function is called to set the test fairing fair status
+**
+** Returns void
+**
+*******************************************************************************/
+void smp_set_test_pair_fail_status (BOOLEAN enable, UINT8 status)
+{
+ SMP_TRACE_DEBUG1("smp_set_test_confirm_value enable=%d", enable);
+ smp_cb.enable_test_pair_fail = enable;
+ smp_cb.pair_fail_status = status;
+}
+
+/*******************************************************************************
+**
+** Function smp_set_test_pair_fail_status
+**
+** Description This function is called to disable the removal of fixed channel
+** in smp_reset_control_value
+** Returns void
+**
+*******************************************************************************/
+void smp_remove_fixed_channel_disable (BOOLEAN disable)
+{
+ SMP_TRACE_DEBUG1("smp_remove_fixed_channel_disable disable =%d", disable);
+ smp_cb.remove_fixed_channel_disable = disable;
+}
+
+#endif
+
+
+#endif
+