diff options
author | Andre Eisenbach <andre@broadcom.com> | 2012-02-22 13:18:21 -0800 |
---|---|---|
committer | Matthew Xie <mattx@google.com> | 2012-07-14 11:19:11 -0700 |
commit | e448862a47c08eb23185aaed574b39264f5005fc (patch) | |
tree | 2bc6246e3091315e77224fd798ea2fe8074ef972 /stack/smp | |
parent | a2ca4b83ab8bbbfd8d5f6693e927ed4b82094624 (diff) | |
download | external_bluetooth_bluedroid-e448862a47c08eb23185aaed574b39264f5005fc.zip external_bluetooth_bluedroid-e448862a47c08eb23185aaed574b39264f5005fc.tar.gz external_bluetooth_bluedroid-e448862a47c08eb23185aaed574b39264f5005fc.tar.bz2 |
Initial Bluedroid stack commit
Diffstat (limited to 'stack/smp')
-rw-r--r-- | stack/smp/aes.c | 926 | ||||
-rw-r--r-- | stack/smp/aes.h | 162 | ||||
-rw-r--r-- | stack/smp/smp_act.c | 943 | ||||
-rw-r--r-- | stack/smp/smp_api.c | 324 | ||||
-rw-r--r-- | stack/smp/smp_cmac.c | 376 | ||||
-rw-r--r-- | stack/smp/smp_int.h | 301 | ||||
-rw-r--r-- | stack/smp/smp_keys.c | 896 | ||||
-rw-r--r-- | stack/smp/smp_l2c.c | 148 | ||||
-rw-r--r-- | stack/smp/smp_main.c | 511 | ||||
-rw-r--r-- | stack/smp/smp_utils.c | 665 |
10 files changed, 5252 insertions, 0 deletions
diff --git a/stack/smp/aes.c b/stack/smp/aes.c new file mode 100644 index 0000000..5b3fefa --- /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..af4bd2e --- /dev/null +++ b/stack/smp/smp_act.c @@ -0,0 +1,943 @@ +/***************************************************************************** +** +** Name: smp_act.c +** +** File: SMP Action Functions +** +** Copyright (c) 2003-2009, Broadcom Corp., All Rights Reserved. +** WIDCOMM Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ + +#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..e0c37e0 --- /dev/null +++ b/stack/smp/smp_api.c @@ -0,0 +1,324 @@ +/***************************************************************************** +** +** Name: smp_api.c +** +** Description: This file contains the implementation of the SMP +** interface used by applications that can run over an SMP. +** +** +** Copyright (c) 2008-2009, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +******************************************************************************/ +#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..d72c3b5 --- /dev/null +++ b/stack/smp/smp_cmac.c @@ -0,0 +1,376 @@ +/***************************************************************************** +** +** Name: smp_cmac.c +** +** Description: This file contains the implementation of the AES128 CMAC +** algorithm. +** +** +** Copyright (c) 2008-2009, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +******************************************************************************/ + +#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..4ca9563 --- /dev/null +++ b/stack/smp/smp_int.h @@ -0,0 +1,301 @@ +/****************************************************************************/ +/* */ +/* Name: smp_int.h */ +/* */ +/* Function this file contains internally used SMP definitions */ +/* */ +/* Copyright (c) 1999-2008, Broadcom Corp., All Rights Reserved. */ +/* WIDCOMM Bluetooth Core. Proprietary and confidential. */ +/* */ +/*****************************************************************************/ +#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..a7c8496 --- /dev/null +++ b/stack/smp/smp_keys.c @@ -0,0 +1,896 @@ +/***************************************************************************** +** +** Name: smp_keys.c +** +** Description: This file contains the implementation of the SMP +** utility functions used by SMP. +** +** +** Copyright (c) 2008-2010, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +******************************************************************************/ + +#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..0356612 --- /dev/null +++ b/stack/smp/smp_l2c.c @@ -0,0 +1,148 @@ +/***************************************************************************** +** * +** Name: smp_l2c.c * +** * +** Description: This file contains functions for the SMP L2Cap interface * +** * +** * +** Copyright (c) 1999-2009, Broadcom Corp., All Rights Reserved. * +** Broadcom Bluetooth Core. Proprietary and confidential. * +******************************************************************************/ + +#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..1b67011 --- /dev/null +++ b/stack/smp/smp_main.c @@ -0,0 +1,511 @@ +/***************************************************************************** +** +** Name: smp_main.c +** +** File: SMP State Machine and Control Block Access Functions +** +** Copyright (c) 2003-2009, Broadcom Corp., All Rights Reserved. +** WIDCOMM Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ + +#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..7e4700f --- /dev/null +++ b/stack/smp/smp_utils.c @@ -0,0 +1,665 @@ +/***************************************************************************** +** * +** Name: smp_utils.c * +** * +** Description: This file contains functions for the SMP L2Cap utility * +** functions * +** * +** Copyright (c) 1999-2009, Broadcom Corp., All Rights Reserved. * +** Broadcom Bluetooth Core. Proprietary and confidential. * +******************************************************************************/ +#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" + + #if (BT_TRACE_PROTOCOL == TRUE) + #include "trace_api.h" + #endif + + #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 + |