xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/host/src/ble_sm.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
1*042d53a7SEvalZero /*
2*042d53a7SEvalZero  * Licensed to the Apache Software Foundation (ASF) under one
3*042d53a7SEvalZero  * or more contributor license agreements.  See the NOTICE file
4*042d53a7SEvalZero  * distributed with this work for additional information
5*042d53a7SEvalZero  * regarding copyright ownership.  The ASF licenses this file
6*042d53a7SEvalZero  * to you under the Apache License, Version 2.0 (the
7*042d53a7SEvalZero  * "License"); you may not use this file except in compliance
8*042d53a7SEvalZero  * with the License.  You may obtain a copy of the License at
9*042d53a7SEvalZero  *
10*042d53a7SEvalZero  *  http://www.apache.org/licenses/LICENSE-2.0
11*042d53a7SEvalZero  *
12*042d53a7SEvalZero  * Unless required by applicable law or agreed to in writing,
13*042d53a7SEvalZero  * software distributed under the License is distributed on an
14*042d53a7SEvalZero  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15*042d53a7SEvalZero  * KIND, either express or implied.  See the License for the
16*042d53a7SEvalZero  * specific language governing permissions and limitations
17*042d53a7SEvalZero  * under the License.
18*042d53a7SEvalZero  */
19*042d53a7SEvalZero 
20*042d53a7SEvalZero /**
21*042d53a7SEvalZero  * L2CAP Security Manager (channel ID = 6).
22*042d53a7SEvalZero  *
23*042d53a7SEvalZero  * Design overview:
24*042d53a7SEvalZero  *
25*042d53a7SEvalZero  * L2CAP sm procedures are initiated by the application via function calls.
26*042d53a7SEvalZero  * Such functions return when either of the following happens:
27*042d53a7SEvalZero  *
28*042d53a7SEvalZero  * (1) The procedure completes (success or failure).
29*042d53a7SEvalZero  * (2) The procedure cannot proceed until a BLE peer responds.
30*042d53a7SEvalZero  *
31*042d53a7SEvalZero  * For (1), the result of the procedure if fully indicated by the function
32*042d53a7SEvalZero  * return code.
33*042d53a7SEvalZero  * For (2), the procedure result is indicated by an application-configured
34*042d53a7SEvalZero  * callback.  The callback is executed when the procedure completes.
35*042d53a7SEvalZero  *
36*042d53a7SEvalZero  * Notes on thread-safety:
37*042d53a7SEvalZero  * 1. The ble_hs mutex must never be locked when an application callback is
38*042d53a7SEvalZero  *    executed.  A callback is free to initiate additional host procedures.
39*042d53a7SEvalZero  * 2. Keep the host mutex locked whenever:
40*042d53a7SEvalZero  *      o A proc entry is read from or written to.
41*042d53a7SEvalZero  *      o The proc list is read or modified.
42*042d53a7SEvalZero  */
43*042d53a7SEvalZero 
44*042d53a7SEvalZero #include <string.h>
45*042d53a7SEvalZero #include <errno.h>
46*042d53a7SEvalZero #include "nimble/ble.h"
47*042d53a7SEvalZero #include "nimble/nimble_opt.h"
48*042d53a7SEvalZero #include "host/ble_sm.h"
49*042d53a7SEvalZero #include "ble_hs_priv.h"
50*042d53a7SEvalZero 
51*042d53a7SEvalZero #if NIMBLE_BLE_SM
52*042d53a7SEvalZero 
53*042d53a7SEvalZero /** Procedure timeout; 30 seconds. */
54*042d53a7SEvalZero #define BLE_SM_TIMEOUT_MS             (30000)
55*042d53a7SEvalZero 
56*042d53a7SEvalZero STAILQ_HEAD(ble_sm_proc_list, ble_sm_proc);
57*042d53a7SEvalZero 
58*042d53a7SEvalZero typedef void ble_sm_rx_fn(uint16_t conn_handle, struct os_mbuf **om,
59*042d53a7SEvalZero                           struct ble_sm_result *res);
60*042d53a7SEvalZero 
61*042d53a7SEvalZero static ble_sm_rx_fn ble_sm_rx_noop;
62*042d53a7SEvalZero static ble_sm_rx_fn ble_sm_pair_req_rx;
63*042d53a7SEvalZero static ble_sm_rx_fn ble_sm_pair_rsp_rx;
64*042d53a7SEvalZero static ble_sm_rx_fn ble_sm_confirm_rx;
65*042d53a7SEvalZero static ble_sm_rx_fn ble_sm_random_rx;
66*042d53a7SEvalZero static ble_sm_rx_fn ble_sm_fail_rx;
67*042d53a7SEvalZero static ble_sm_rx_fn ble_sm_enc_info_rx;
68*042d53a7SEvalZero static ble_sm_rx_fn ble_sm_master_id_rx;
69*042d53a7SEvalZero static ble_sm_rx_fn ble_sm_id_info_rx;
70*042d53a7SEvalZero static ble_sm_rx_fn ble_sm_id_addr_info_rx;
71*042d53a7SEvalZero static ble_sm_rx_fn ble_sm_sign_info_rx;
72*042d53a7SEvalZero static ble_sm_rx_fn ble_sm_sec_req_rx;
73*042d53a7SEvalZero 
74*042d53a7SEvalZero static ble_sm_rx_fn * const ble_sm_dispatch[] = {
75*042d53a7SEvalZero    [BLE_SM_OP_PAIR_REQ] = ble_sm_pair_req_rx,
76*042d53a7SEvalZero    [BLE_SM_OP_PAIR_RSP] = ble_sm_pair_rsp_rx,
77*042d53a7SEvalZero    [BLE_SM_OP_PAIR_CONFIRM] = ble_sm_confirm_rx,
78*042d53a7SEvalZero    [BLE_SM_OP_PAIR_RANDOM] = ble_sm_random_rx,
79*042d53a7SEvalZero    [BLE_SM_OP_PAIR_FAIL] = ble_sm_fail_rx,
80*042d53a7SEvalZero    [BLE_SM_OP_ENC_INFO] = ble_sm_enc_info_rx,
81*042d53a7SEvalZero    [BLE_SM_OP_MASTER_ID] = ble_sm_master_id_rx,
82*042d53a7SEvalZero    [BLE_SM_OP_IDENTITY_INFO] = ble_sm_id_info_rx,
83*042d53a7SEvalZero    [BLE_SM_OP_IDENTITY_ADDR_INFO] = ble_sm_id_addr_info_rx,
84*042d53a7SEvalZero    [BLE_SM_OP_SIGN_INFO] = ble_sm_sign_info_rx,
85*042d53a7SEvalZero    [BLE_SM_OP_SEC_REQ] = ble_sm_sec_req_rx,
86*042d53a7SEvalZero    [BLE_SM_OP_PAIR_KEYPRESS_NOTIFY] = ble_sm_rx_noop,
87*042d53a7SEvalZero #if MYNEWT_VAL(BLE_SM_SC)
88*042d53a7SEvalZero    [BLE_SM_OP_PAIR_PUBLIC_KEY] = ble_sm_sc_public_key_rx,
89*042d53a7SEvalZero    [BLE_SM_OP_PAIR_DHKEY_CHECK] = ble_sm_sc_dhkey_check_rx,
90*042d53a7SEvalZero #else
91*042d53a7SEvalZero    [BLE_SM_OP_PAIR_PUBLIC_KEY] = ble_sm_rx_noop,
92*042d53a7SEvalZero    [BLE_SM_OP_PAIR_DHKEY_CHECK] = ble_sm_rx_noop,
93*042d53a7SEvalZero #endif
94*042d53a7SEvalZero };
95*042d53a7SEvalZero 
96*042d53a7SEvalZero typedef void ble_sm_state_fn(struct ble_sm_proc *proc,
97*042d53a7SEvalZero                              struct ble_sm_result *res, void *arg);
98*042d53a7SEvalZero 
99*042d53a7SEvalZero static ble_sm_state_fn ble_sm_pair_exec;
100*042d53a7SEvalZero static ble_sm_state_fn ble_sm_confirm_exec;
101*042d53a7SEvalZero static ble_sm_state_fn ble_sm_random_exec;
102*042d53a7SEvalZero static ble_sm_state_fn ble_sm_ltk_start_exec;
103*042d53a7SEvalZero static ble_sm_state_fn ble_sm_ltk_restore_exec;
104*042d53a7SEvalZero static ble_sm_state_fn ble_sm_enc_start_exec;
105*042d53a7SEvalZero static ble_sm_state_fn ble_sm_enc_restore_exec;
106*042d53a7SEvalZero static ble_sm_state_fn ble_sm_key_exch_exec;
107*042d53a7SEvalZero static ble_sm_state_fn ble_sm_sec_req_exec;
108*042d53a7SEvalZero 
109*042d53a7SEvalZero static ble_sm_state_fn * const
110*042d53a7SEvalZero ble_sm_state_dispatch[BLE_SM_PROC_STATE_CNT] = {
111*042d53a7SEvalZero     [BLE_SM_PROC_STATE_PAIR]          = ble_sm_pair_exec,
112*042d53a7SEvalZero     [BLE_SM_PROC_STATE_CONFIRM]       = ble_sm_confirm_exec,
113*042d53a7SEvalZero     [BLE_SM_PROC_STATE_RANDOM]        = ble_sm_random_exec,
114*042d53a7SEvalZero     [BLE_SM_PROC_STATE_LTK_START]     = ble_sm_ltk_start_exec,
115*042d53a7SEvalZero     [BLE_SM_PROC_STATE_LTK_RESTORE]   = ble_sm_ltk_restore_exec,
116*042d53a7SEvalZero     [BLE_SM_PROC_STATE_ENC_START]     = ble_sm_enc_start_exec,
117*042d53a7SEvalZero     [BLE_SM_PROC_STATE_ENC_RESTORE]   = ble_sm_enc_restore_exec,
118*042d53a7SEvalZero     [BLE_SM_PROC_STATE_KEY_EXCH]      = ble_sm_key_exch_exec,
119*042d53a7SEvalZero     [BLE_SM_PROC_STATE_SEC_REQ]       = ble_sm_sec_req_exec,
120*042d53a7SEvalZero #if MYNEWT_VAL(BLE_SM_SC)
121*042d53a7SEvalZero     [BLE_SM_PROC_STATE_PUBLIC_KEY]    = ble_sm_sc_public_key_exec,
122*042d53a7SEvalZero     [BLE_SM_PROC_STATE_DHKEY_CHECK]   = ble_sm_sc_dhkey_check_exec,
123*042d53a7SEvalZero #else
124*042d53a7SEvalZero     [BLE_SM_PROC_STATE_PUBLIC_KEY]    = NULL,
125*042d53a7SEvalZero     [BLE_SM_PROC_STATE_DHKEY_CHECK]   = NULL,
126*042d53a7SEvalZero #endif
127*042d53a7SEvalZero };
128*042d53a7SEvalZero 
129*042d53a7SEvalZero static os_membuf_t ble_sm_proc_mem[
130*042d53a7SEvalZero     OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_SM_MAX_PROCS),
131*042d53a7SEvalZero                     sizeof (struct ble_sm_proc))
132*042d53a7SEvalZero ];
133*042d53a7SEvalZero 
134*042d53a7SEvalZero static struct os_mempool ble_sm_proc_pool;
135*042d53a7SEvalZero 
136*042d53a7SEvalZero /* Maintains the list of active security manager procedures. */
137*042d53a7SEvalZero static struct ble_sm_proc_list ble_sm_procs;
138*042d53a7SEvalZero 
139*042d53a7SEvalZero static void ble_sm_pair_cfg(struct ble_sm_proc *proc);
140*042d53a7SEvalZero 
141*042d53a7SEvalZero 
142*042d53a7SEvalZero /*****************************************************************************
143*042d53a7SEvalZero  * $debug                                                                    *
144*042d53a7SEvalZero  *****************************************************************************/
145*042d53a7SEvalZero 
146*042d53a7SEvalZero #if MYNEWT_VAL(BLE_HS_DEBUG)
147*042d53a7SEvalZero 
148*042d53a7SEvalZero static uint8_t ble_sm_dbg_next_pair_rand[16];
149*042d53a7SEvalZero static uint8_t ble_sm_dbg_next_pair_rand_set;
150*042d53a7SEvalZero static uint16_t ble_sm_dbg_next_ediv;
151*042d53a7SEvalZero static uint8_t ble_sm_dbg_next_ediv_set;
152*042d53a7SEvalZero static uint64_t ble_sm_dbg_next_master_id_rand;
153*042d53a7SEvalZero static uint8_t ble_sm_dbg_next_master_id_rand_set;
154*042d53a7SEvalZero static uint8_t ble_sm_dbg_next_ltk[16];
155*042d53a7SEvalZero static uint8_t ble_sm_dbg_next_ltk_set;
156*042d53a7SEvalZero static uint8_t ble_sm_dbg_next_csrk[16];
157*042d53a7SEvalZero static uint8_t ble_sm_dbg_next_csrk_set;
158*042d53a7SEvalZero 
159*042d53a7SEvalZero void
ble_sm_dbg_set_next_pair_rand(uint8_t * next_pair_rand)160*042d53a7SEvalZero ble_sm_dbg_set_next_pair_rand(uint8_t *next_pair_rand)
161*042d53a7SEvalZero {
162*042d53a7SEvalZero     memcpy(ble_sm_dbg_next_pair_rand, next_pair_rand,
163*042d53a7SEvalZero            sizeof ble_sm_dbg_next_pair_rand);
164*042d53a7SEvalZero     ble_sm_dbg_next_pair_rand_set = 1;
165*042d53a7SEvalZero }
166*042d53a7SEvalZero 
167*042d53a7SEvalZero void
ble_sm_dbg_set_next_ediv(uint16_t next_ediv)168*042d53a7SEvalZero ble_sm_dbg_set_next_ediv(uint16_t next_ediv)
169*042d53a7SEvalZero {
170*042d53a7SEvalZero     ble_sm_dbg_next_ediv = next_ediv;
171*042d53a7SEvalZero     ble_sm_dbg_next_ediv_set = 1;
172*042d53a7SEvalZero }
173*042d53a7SEvalZero 
174*042d53a7SEvalZero void
ble_sm_dbg_set_next_master_id_rand(uint64_t next_master_id_rand)175*042d53a7SEvalZero ble_sm_dbg_set_next_master_id_rand(uint64_t next_master_id_rand)
176*042d53a7SEvalZero {
177*042d53a7SEvalZero     ble_sm_dbg_next_master_id_rand = next_master_id_rand;
178*042d53a7SEvalZero     ble_sm_dbg_next_master_id_rand_set = 1;
179*042d53a7SEvalZero }
180*042d53a7SEvalZero 
181*042d53a7SEvalZero void
ble_sm_dbg_set_next_ltk(uint8_t * next_ltk)182*042d53a7SEvalZero ble_sm_dbg_set_next_ltk(uint8_t *next_ltk)
183*042d53a7SEvalZero {
184*042d53a7SEvalZero     memcpy(ble_sm_dbg_next_ltk, next_ltk,
185*042d53a7SEvalZero            sizeof ble_sm_dbg_next_ltk);
186*042d53a7SEvalZero     ble_sm_dbg_next_ltk_set = 1;
187*042d53a7SEvalZero }
188*042d53a7SEvalZero 
189*042d53a7SEvalZero void
ble_sm_dbg_set_next_csrk(uint8_t * next_csrk)190*042d53a7SEvalZero ble_sm_dbg_set_next_csrk(uint8_t *next_csrk)
191*042d53a7SEvalZero {
192*042d53a7SEvalZero     memcpy(ble_sm_dbg_next_csrk, next_csrk,
193*042d53a7SEvalZero            sizeof ble_sm_dbg_next_csrk);
194*042d53a7SEvalZero     ble_sm_dbg_next_csrk_set = 1;
195*042d53a7SEvalZero }
196*042d53a7SEvalZero 
197*042d53a7SEvalZero #endif
198*042d53a7SEvalZero 
199*042d53a7SEvalZero static void
ble_sm_dbg_assert_no_cycles(void)200*042d53a7SEvalZero ble_sm_dbg_assert_no_cycles(void)
201*042d53a7SEvalZero {
202*042d53a7SEvalZero #if MYNEWT_VAL(BLE_HS_DEBUG)
203*042d53a7SEvalZero     ble_sm_num_procs();
204*042d53a7SEvalZero #endif
205*042d53a7SEvalZero }
206*042d53a7SEvalZero 
207*042d53a7SEvalZero static void
ble_sm_dbg_assert_not_inserted(struct ble_sm_proc * proc)208*042d53a7SEvalZero ble_sm_dbg_assert_not_inserted(struct ble_sm_proc *proc)
209*042d53a7SEvalZero {
210*042d53a7SEvalZero #if MYNEWT_VAL(BLE_HS_DEBUG)
211*042d53a7SEvalZero     struct ble_sm_proc *cur;
212*042d53a7SEvalZero 
213*042d53a7SEvalZero     STAILQ_FOREACH(cur, &ble_sm_procs, next) {
214*042d53a7SEvalZero         BLE_HS_DBG_ASSERT(cur != proc);
215*042d53a7SEvalZero     }
216*042d53a7SEvalZero #endif
217*042d53a7SEvalZero }
218*042d53a7SEvalZero 
219*042d53a7SEvalZero /*****************************************************************************
220*042d53a7SEvalZero  * $misc                                                                     *
221*042d53a7SEvalZero  *****************************************************************************/
222*042d53a7SEvalZero 
223*042d53a7SEvalZero /**
224*042d53a7SEvalZero  * Calculates the number of active SM procedures.
225*042d53a7SEvalZero  */
226*042d53a7SEvalZero int
ble_sm_num_procs(void)227*042d53a7SEvalZero ble_sm_num_procs(void)
228*042d53a7SEvalZero {
229*042d53a7SEvalZero     struct ble_sm_proc *proc;
230*042d53a7SEvalZero     int cnt;
231*042d53a7SEvalZero 
232*042d53a7SEvalZero     cnt = 0;
233*042d53a7SEvalZero     STAILQ_FOREACH(proc, &ble_sm_procs, next) {
234*042d53a7SEvalZero         BLE_HS_DBG_ASSERT(cnt < MYNEWT_VAL(BLE_SM_MAX_PROCS));
235*042d53a7SEvalZero         cnt++;
236*042d53a7SEvalZero     }
237*042d53a7SEvalZero 
238*042d53a7SEvalZero     return cnt;
239*042d53a7SEvalZero }
240*042d53a7SEvalZero 
241*042d53a7SEvalZero int
ble_sm_gen_pair_rand(uint8_t * pair_rand)242*042d53a7SEvalZero ble_sm_gen_pair_rand(uint8_t *pair_rand)
243*042d53a7SEvalZero {
244*042d53a7SEvalZero     int rc;
245*042d53a7SEvalZero 
246*042d53a7SEvalZero #if MYNEWT_VAL(BLE_HS_DEBUG)
247*042d53a7SEvalZero     if (ble_sm_dbg_next_pair_rand_set) {
248*042d53a7SEvalZero         ble_sm_dbg_next_pair_rand_set = 0;
249*042d53a7SEvalZero         memcpy(pair_rand, ble_sm_dbg_next_pair_rand,
250*042d53a7SEvalZero                sizeof ble_sm_dbg_next_pair_rand);
251*042d53a7SEvalZero         return 0;
252*042d53a7SEvalZero     }
253*042d53a7SEvalZero #endif
254*042d53a7SEvalZero 
255*042d53a7SEvalZero     rc = ble_hs_hci_util_rand(pair_rand, 16);
256*042d53a7SEvalZero     if (rc != 0) {
257*042d53a7SEvalZero         return rc;
258*042d53a7SEvalZero     }
259*042d53a7SEvalZero 
260*042d53a7SEvalZero     return 0;
261*042d53a7SEvalZero }
262*042d53a7SEvalZero 
263*042d53a7SEvalZero static int
ble_sm_gen_ediv(struct ble_sm_master_id * master_id)264*042d53a7SEvalZero ble_sm_gen_ediv(struct ble_sm_master_id *master_id)
265*042d53a7SEvalZero {
266*042d53a7SEvalZero     int rc;
267*042d53a7SEvalZero 
268*042d53a7SEvalZero #if MYNEWT_VAL(BLE_HS_DEBUG)
269*042d53a7SEvalZero     if (ble_sm_dbg_next_ediv_set) {
270*042d53a7SEvalZero         ble_sm_dbg_next_ediv_set = 0;
271*042d53a7SEvalZero         master_id->ediv = ble_sm_dbg_next_ediv;
272*042d53a7SEvalZero         return 0;
273*042d53a7SEvalZero     }
274*042d53a7SEvalZero #endif
275*042d53a7SEvalZero 
276*042d53a7SEvalZero     rc = ble_hs_hci_util_rand(&master_id->ediv, sizeof master_id->ediv);
277*042d53a7SEvalZero     if (rc != 0) {
278*042d53a7SEvalZero         return rc;
279*042d53a7SEvalZero     }
280*042d53a7SEvalZero 
281*042d53a7SEvalZero     return 0;
282*042d53a7SEvalZero }
283*042d53a7SEvalZero 
284*042d53a7SEvalZero static int
ble_sm_gen_master_id_rand(struct ble_sm_master_id * master_id)285*042d53a7SEvalZero ble_sm_gen_master_id_rand(struct ble_sm_master_id *master_id)
286*042d53a7SEvalZero {
287*042d53a7SEvalZero     int rc;
288*042d53a7SEvalZero 
289*042d53a7SEvalZero #if MYNEWT_VAL(BLE_HS_DEBUG)
290*042d53a7SEvalZero     if (ble_sm_dbg_next_master_id_rand_set) {
291*042d53a7SEvalZero         ble_sm_dbg_next_master_id_rand_set = 0;
292*042d53a7SEvalZero         master_id->rand_val = ble_sm_dbg_next_master_id_rand;
293*042d53a7SEvalZero         return 0;
294*042d53a7SEvalZero     }
295*042d53a7SEvalZero #endif
296*042d53a7SEvalZero 
297*042d53a7SEvalZero     rc = ble_hs_hci_util_rand(&master_id->rand_val, sizeof master_id->rand_val);
298*042d53a7SEvalZero     if (rc != 0) {
299*042d53a7SEvalZero         return rc;
300*042d53a7SEvalZero     }
301*042d53a7SEvalZero 
302*042d53a7SEvalZero     return 0;
303*042d53a7SEvalZero }
304*042d53a7SEvalZero 
305*042d53a7SEvalZero static int
ble_sm_gen_ltk(struct ble_sm_proc * proc,uint8_t * ltk)306*042d53a7SEvalZero ble_sm_gen_ltk(struct ble_sm_proc *proc, uint8_t *ltk)
307*042d53a7SEvalZero {
308*042d53a7SEvalZero     int rc;
309*042d53a7SEvalZero 
310*042d53a7SEvalZero #if MYNEWT_VAL(BLE_HS_DEBUG)
311*042d53a7SEvalZero     if (ble_sm_dbg_next_ltk_set) {
312*042d53a7SEvalZero         ble_sm_dbg_next_ltk_set = 0;
313*042d53a7SEvalZero         memcpy(ltk, ble_sm_dbg_next_ltk,
314*042d53a7SEvalZero                sizeof ble_sm_dbg_next_ltk);
315*042d53a7SEvalZero         return 0;
316*042d53a7SEvalZero     }
317*042d53a7SEvalZero #endif
318*042d53a7SEvalZero 
319*042d53a7SEvalZero     rc = ble_hs_hci_util_rand(ltk, proc->key_size);
320*042d53a7SEvalZero     if (rc != 0) {
321*042d53a7SEvalZero         return rc;
322*042d53a7SEvalZero     }
323*042d53a7SEvalZero 
324*042d53a7SEvalZero     /* Ensure proper key size */
325*042d53a7SEvalZero     memset(ltk + proc->key_size, 0, sizeof proc->ltk - proc->key_size);
326*042d53a7SEvalZero 
327*042d53a7SEvalZero     return 0;
328*042d53a7SEvalZero }
329*042d53a7SEvalZero 
330*042d53a7SEvalZero static int
ble_sm_gen_csrk(struct ble_sm_proc * proc,uint8_t * csrk)331*042d53a7SEvalZero ble_sm_gen_csrk(struct ble_sm_proc *proc, uint8_t *csrk)
332*042d53a7SEvalZero {
333*042d53a7SEvalZero     int rc;
334*042d53a7SEvalZero 
335*042d53a7SEvalZero #if MYNEWT_VAL(BLE_HS_DEBUG)
336*042d53a7SEvalZero     if (ble_sm_dbg_next_csrk_set) {
337*042d53a7SEvalZero         ble_sm_dbg_next_csrk_set = 0;
338*042d53a7SEvalZero         memcpy(csrk, ble_sm_dbg_next_csrk,
339*042d53a7SEvalZero                sizeof ble_sm_dbg_next_csrk);
340*042d53a7SEvalZero         return 0;
341*042d53a7SEvalZero     }
342*042d53a7SEvalZero #endif
343*042d53a7SEvalZero 
344*042d53a7SEvalZero     rc = ble_hs_hci_util_rand(csrk, 16);
345*042d53a7SEvalZero     if (rc != 0) {
346*042d53a7SEvalZero         return rc;
347*042d53a7SEvalZero     }
348*042d53a7SEvalZero 
349*042d53a7SEvalZero     return 0;
350*042d53a7SEvalZero }
351*042d53a7SEvalZero 
352*042d53a7SEvalZero static void
ble_sm_proc_set_timer(struct ble_sm_proc * proc)353*042d53a7SEvalZero ble_sm_proc_set_timer(struct ble_sm_proc *proc)
354*042d53a7SEvalZero {
355*042d53a7SEvalZero     proc->exp_os_ticks = ble_npl_time_get() +
356*042d53a7SEvalZero                          ble_npl_time_ms_to_ticks32(BLE_SM_TIMEOUT_MS);
357*042d53a7SEvalZero     ble_hs_timer_resched();
358*042d53a7SEvalZero }
359*042d53a7SEvalZero 
360*042d53a7SEvalZero static ble_sm_rx_fn *
ble_sm_dispatch_get(uint8_t op)361*042d53a7SEvalZero ble_sm_dispatch_get(uint8_t op)
362*042d53a7SEvalZero {
363*042d53a7SEvalZero     if (op >= sizeof ble_sm_dispatch / sizeof ble_sm_dispatch[0]) {
364*042d53a7SEvalZero         return NULL;
365*042d53a7SEvalZero     }
366*042d53a7SEvalZero 
367*042d53a7SEvalZero     return ble_sm_dispatch[op];
368*042d53a7SEvalZero }
369*042d53a7SEvalZero 
370*042d53a7SEvalZero /**
371*042d53a7SEvalZero  * Allocates a proc entry.
372*042d53a7SEvalZero  *
373*042d53a7SEvalZero  * @return                      An entry on success; null on failure.
374*042d53a7SEvalZero  */
375*042d53a7SEvalZero static struct ble_sm_proc *
ble_sm_proc_alloc(void)376*042d53a7SEvalZero ble_sm_proc_alloc(void)
377*042d53a7SEvalZero {
378*042d53a7SEvalZero     struct ble_sm_proc *proc;
379*042d53a7SEvalZero 
380*042d53a7SEvalZero     proc = os_memblock_get(&ble_sm_proc_pool);
381*042d53a7SEvalZero     if (proc != NULL) {
382*042d53a7SEvalZero         memset(proc, 0, sizeof *proc);
383*042d53a7SEvalZero     }
384*042d53a7SEvalZero 
385*042d53a7SEvalZero     return proc;
386*042d53a7SEvalZero }
387*042d53a7SEvalZero 
388*042d53a7SEvalZero /**
389*042d53a7SEvalZero  * Frees the specified proc entry.  No-state if passed a null pointer.
390*042d53a7SEvalZero  */
391*042d53a7SEvalZero static void
ble_sm_proc_free(struct ble_sm_proc * proc)392*042d53a7SEvalZero ble_sm_proc_free(struct ble_sm_proc *proc)
393*042d53a7SEvalZero {
394*042d53a7SEvalZero     int rc;
395*042d53a7SEvalZero 
396*042d53a7SEvalZero     if (proc != NULL) {
397*042d53a7SEvalZero         ble_sm_dbg_assert_not_inserted(proc);
398*042d53a7SEvalZero #if MYNEWT_VAL(BLE_HS_DEBUG)
399*042d53a7SEvalZero         memset(proc, 0xff, sizeof *proc);
400*042d53a7SEvalZero #endif
401*042d53a7SEvalZero         rc = os_memblock_put(&ble_sm_proc_pool, proc);
402*042d53a7SEvalZero         BLE_HS_DBG_ASSERT_EVAL(rc == 0);
403*042d53a7SEvalZero     }
404*042d53a7SEvalZero }
405*042d53a7SEvalZero 
406*042d53a7SEvalZero static void
ble_sm_proc_remove(struct ble_sm_proc * proc,struct ble_sm_proc * prev)407*042d53a7SEvalZero ble_sm_proc_remove(struct ble_sm_proc *proc,
408*042d53a7SEvalZero                          struct ble_sm_proc *prev)
409*042d53a7SEvalZero {
410*042d53a7SEvalZero     if (prev == NULL) {
411*042d53a7SEvalZero         BLE_HS_DBG_ASSERT(STAILQ_FIRST(&ble_sm_procs) == proc);
412*042d53a7SEvalZero         STAILQ_REMOVE_HEAD(&ble_sm_procs, next);
413*042d53a7SEvalZero     } else {
414*042d53a7SEvalZero         BLE_HS_DBG_ASSERT(STAILQ_NEXT(prev, next) == proc);
415*042d53a7SEvalZero         STAILQ_REMOVE_AFTER(&ble_sm_procs, prev, next);
416*042d53a7SEvalZero     }
417*042d53a7SEvalZero 
418*042d53a7SEvalZero     ble_sm_dbg_assert_no_cycles();
419*042d53a7SEvalZero }
420*042d53a7SEvalZero 
421*042d53a7SEvalZero static void
ble_sm_update_sec_state(uint16_t conn_handle,int encrypted,int authenticated,int bonded,int key_size)422*042d53a7SEvalZero ble_sm_update_sec_state(uint16_t conn_handle, int encrypted,
423*042d53a7SEvalZero                         int authenticated, int bonded, int key_size)
424*042d53a7SEvalZero {
425*042d53a7SEvalZero     struct ble_hs_conn *conn;
426*042d53a7SEvalZero 
427*042d53a7SEvalZero     conn = ble_hs_conn_find(conn_handle);
428*042d53a7SEvalZero     if (conn != NULL) {
429*042d53a7SEvalZero         conn->bhc_sec_state.encrypted = encrypted;
430*042d53a7SEvalZero 
431*042d53a7SEvalZero         /* Authentication and bonding are never revoked from a secure link */
432*042d53a7SEvalZero         if (authenticated) {
433*042d53a7SEvalZero             conn->bhc_sec_state.authenticated = 1;
434*042d53a7SEvalZero         }
435*042d53a7SEvalZero         if (bonded) {
436*042d53a7SEvalZero             conn->bhc_sec_state.bonded = 1;
437*042d53a7SEvalZero         }
438*042d53a7SEvalZero 
439*042d53a7SEvalZero         if (key_size) {
440*042d53a7SEvalZero             conn->bhc_sec_state.key_size = key_size;
441*042d53a7SEvalZero         }
442*042d53a7SEvalZero     }
443*042d53a7SEvalZero }
444*042d53a7SEvalZero 
445*042d53a7SEvalZero static void
ble_sm_fill_store_value(const ble_addr_t * peer_addr,int authenticated,int sc,struct ble_sm_keys * keys,struct ble_store_value_sec * value_sec)446*042d53a7SEvalZero ble_sm_fill_store_value(const ble_addr_t *peer_addr,
447*042d53a7SEvalZero                         int authenticated,
448*042d53a7SEvalZero                         int sc,
449*042d53a7SEvalZero                         struct ble_sm_keys *keys,
450*042d53a7SEvalZero                         struct ble_store_value_sec *value_sec)
451*042d53a7SEvalZero {
452*042d53a7SEvalZero     memset(value_sec, 0, sizeof *value_sec);
453*042d53a7SEvalZero 
454*042d53a7SEvalZero     value_sec->peer_addr = *peer_addr;
455*042d53a7SEvalZero 
456*042d53a7SEvalZero     if (keys->ediv_rand_valid && keys->ltk_valid) {
457*042d53a7SEvalZero         value_sec->key_size = keys->key_size;
458*042d53a7SEvalZero         value_sec->ediv = keys->ediv;
459*042d53a7SEvalZero         value_sec->rand_num = keys->rand_val;
460*042d53a7SEvalZero 
461*042d53a7SEvalZero         memcpy(value_sec->ltk, keys->ltk, sizeof value_sec->ltk);
462*042d53a7SEvalZero         value_sec->ltk_present = 1;
463*042d53a7SEvalZero 
464*042d53a7SEvalZero         value_sec->authenticated = !!authenticated;
465*042d53a7SEvalZero         value_sec->sc = !!sc;
466*042d53a7SEvalZero     }
467*042d53a7SEvalZero 
468*042d53a7SEvalZero     if (keys->irk_valid) {
469*042d53a7SEvalZero         memcpy(value_sec->irk, keys->irk, sizeof value_sec->irk);
470*042d53a7SEvalZero         value_sec->irk_present = 1;
471*042d53a7SEvalZero     }
472*042d53a7SEvalZero 
473*042d53a7SEvalZero     if (keys->csrk_valid) {
474*042d53a7SEvalZero         memcpy(value_sec->csrk, keys->csrk, sizeof value_sec->csrk);
475*042d53a7SEvalZero         value_sec->csrk_present = 1;
476*042d53a7SEvalZero     }
477*042d53a7SEvalZero }
478*042d53a7SEvalZero 
479*042d53a7SEvalZero void
ble_sm_ia_ra(struct ble_sm_proc * proc,uint8_t * out_iat,uint8_t * out_ia,uint8_t * out_rat,uint8_t * out_ra)480*042d53a7SEvalZero ble_sm_ia_ra(struct ble_sm_proc *proc,
481*042d53a7SEvalZero              uint8_t *out_iat, uint8_t *out_ia,
482*042d53a7SEvalZero              uint8_t *out_rat, uint8_t *out_ra)
483*042d53a7SEvalZero {
484*042d53a7SEvalZero     struct ble_hs_conn_addrs addrs;
485*042d53a7SEvalZero     struct ble_hs_conn *conn;
486*042d53a7SEvalZero 
487*042d53a7SEvalZero     conn = ble_hs_conn_find_assert(proc->conn_handle);
488*042d53a7SEvalZero 
489*042d53a7SEvalZero     ble_hs_conn_addrs(conn, &addrs);
490*042d53a7SEvalZero 
491*042d53a7SEvalZero     if (proc->flags & BLE_SM_PROC_F_INITIATOR) {
492*042d53a7SEvalZero         *out_iat = addrs.our_ota_addr.type;
493*042d53a7SEvalZero         memcpy(out_ia, addrs.our_ota_addr.val, 6);
494*042d53a7SEvalZero 
495*042d53a7SEvalZero         *out_rat = addrs.peer_ota_addr.type;
496*042d53a7SEvalZero         memcpy(out_ra, addrs.peer_ota_addr.val, 6);
497*042d53a7SEvalZero     } else {
498*042d53a7SEvalZero         *out_iat = addrs.peer_ota_addr.type;
499*042d53a7SEvalZero         memcpy(out_ia, addrs.peer_ota_addr.val, 6);
500*042d53a7SEvalZero 
501*042d53a7SEvalZero         *out_rat = addrs.our_ota_addr.type;
502*042d53a7SEvalZero         memcpy(out_ra, addrs.our_ota_addr.val, 6);
503*042d53a7SEvalZero     }
504*042d53a7SEvalZero }
505*042d53a7SEvalZero 
506*042d53a7SEvalZero static void
ble_sm_persist_keys(struct ble_sm_proc * proc)507*042d53a7SEvalZero ble_sm_persist_keys(struct ble_sm_proc *proc)
508*042d53a7SEvalZero {
509*042d53a7SEvalZero     struct ble_store_value_sec value_sec;
510*042d53a7SEvalZero     struct ble_hs_conn *conn;
511*042d53a7SEvalZero     ble_addr_t peer_addr;
512*042d53a7SEvalZero     int authenticated;
513*042d53a7SEvalZero     int identity_ev = 0;
514*042d53a7SEvalZero     int sc;
515*042d53a7SEvalZero 
516*042d53a7SEvalZero     ble_hs_lock();
517*042d53a7SEvalZero 
518*042d53a7SEvalZero     conn = ble_hs_conn_find(proc->conn_handle);
519*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(conn != NULL);
520*042d53a7SEvalZero 
521*042d53a7SEvalZero     /* If we got an identity address, use that for key storage. */
522*042d53a7SEvalZero     if (proc->peer_keys.addr_valid) {
523*042d53a7SEvalZero         peer_addr.type = proc->peer_keys.addr_type;
524*042d53a7SEvalZero         memcpy(peer_addr.val, proc->peer_keys.addr, sizeof peer_addr.val);
525*042d53a7SEvalZero 
526*042d53a7SEvalZero         conn->bhc_peer_addr = peer_addr;
527*042d53a7SEvalZero         /* Update identity address in conn.
528*042d53a7SEvalZero          * If peer's address was an RPA, we store it as RPA since peer's address
529*042d53a7SEvalZero          * will not be an identity address. The peer's address type has to be
530*042d53a7SEvalZero          * set as 'ID' to allow resolve 'id' and 'ota' addresses properly in
531*042d53a7SEvalZero          * conn info.
532*042d53a7SEvalZero          */
533*042d53a7SEvalZero         if (BLE_ADDR_IS_RPA(&conn->bhc_peer_addr)) {
534*042d53a7SEvalZero             conn->bhc_peer_rpa_addr = conn->bhc_peer_addr;
535*042d53a7SEvalZero 
536*042d53a7SEvalZero             switch (peer_addr.type) {
537*042d53a7SEvalZero             case BLE_ADDR_PUBLIC:
538*042d53a7SEvalZero             case BLE_ADDR_PUBLIC_ID:
539*042d53a7SEvalZero                 conn->bhc_peer_addr.type = BLE_ADDR_PUBLIC_ID;
540*042d53a7SEvalZero                 break;
541*042d53a7SEvalZero 
542*042d53a7SEvalZero             case BLE_ADDR_RANDOM:
543*042d53a7SEvalZero             case BLE_ADDR_RANDOM_ID:
544*042d53a7SEvalZero                 conn->bhc_peer_addr.type = BLE_ADDR_RANDOM_ID;
545*042d53a7SEvalZero                 break;
546*042d53a7SEvalZero             }
547*042d53a7SEvalZero         }
548*042d53a7SEvalZero 
549*042d53a7SEvalZero         identity_ev = 1;
550*042d53a7SEvalZero     } else {
551*042d53a7SEvalZero         peer_addr = conn->bhc_peer_addr;
552*042d53a7SEvalZero         peer_addr.type = ble_hs_misc_addr_type_to_id(conn->bhc_peer_addr.type);
553*042d53a7SEvalZero     }
554*042d53a7SEvalZero 
555*042d53a7SEvalZero     ble_hs_unlock();
556*042d53a7SEvalZero 
557*042d53a7SEvalZero     if (identity_ev) {
558*042d53a7SEvalZero         ble_gap_identity_event(proc->conn_handle);
559*042d53a7SEvalZero     }
560*042d53a7SEvalZero 
561*042d53a7SEvalZero     authenticated = proc->flags & BLE_SM_PROC_F_AUTHENTICATED;
562*042d53a7SEvalZero     sc = proc->flags & BLE_SM_PROC_F_SC;
563*042d53a7SEvalZero 
564*042d53a7SEvalZero     ble_sm_fill_store_value(&peer_addr, authenticated, sc, &proc->our_keys,
565*042d53a7SEvalZero                             &value_sec);
566*042d53a7SEvalZero     ble_store_write_our_sec(&value_sec);
567*042d53a7SEvalZero 
568*042d53a7SEvalZero     ble_sm_fill_store_value(&peer_addr, authenticated, sc, &proc->peer_keys,
569*042d53a7SEvalZero                             &value_sec);
570*042d53a7SEvalZero     ble_store_write_peer_sec(&value_sec);
571*042d53a7SEvalZero }
572*042d53a7SEvalZero 
573*042d53a7SEvalZero static int
ble_sm_proc_matches(struct ble_sm_proc * proc,uint16_t conn_handle,uint8_t state,int is_initiator)574*042d53a7SEvalZero ble_sm_proc_matches(struct ble_sm_proc *proc, uint16_t conn_handle,
575*042d53a7SEvalZero                     uint8_t state, int is_initiator)
576*042d53a7SEvalZero {
577*042d53a7SEvalZero     int proc_is_initiator;
578*042d53a7SEvalZero 
579*042d53a7SEvalZero     if (conn_handle != proc->conn_handle) {
580*042d53a7SEvalZero         return 0;
581*042d53a7SEvalZero     }
582*042d53a7SEvalZero 
583*042d53a7SEvalZero     if (state != BLE_SM_PROC_STATE_NONE && state != proc->state) {
584*042d53a7SEvalZero         return 0;
585*042d53a7SEvalZero     }
586*042d53a7SEvalZero 
587*042d53a7SEvalZero     proc_is_initiator = !!(proc->flags & BLE_SM_PROC_F_INITIATOR);
588*042d53a7SEvalZero     if (is_initiator != -1 && is_initiator != proc_is_initiator) {
589*042d53a7SEvalZero         return 0;
590*042d53a7SEvalZero     }
591*042d53a7SEvalZero 
592*042d53a7SEvalZero     return 1;
593*042d53a7SEvalZero }
594*042d53a7SEvalZero 
595*042d53a7SEvalZero /**
596*042d53a7SEvalZero  * Searches the main proc list for an entry whose connection handle and state
597*042d53a7SEvalZero  * code match those specified.
598*042d53a7SEvalZero  *
599*042d53a7SEvalZero  * @param conn_handle           The connection handle to match against.
600*042d53a7SEvalZero  * @param state                 The state code to match against.
601*042d53a7SEvalZero  * @param is_initiator          Matches on the proc's initiator flag:
602*042d53a7SEvalZero  *                                   0=non-initiator only
603*042d53a7SEvalZero  *                                   1=initiator only
604*042d53a7SEvalZero  *                                  -1=don't care
605*042d53a7SEvalZero  * @param out_prev              On success, the entry previous to the result is
606*042d53a7SEvalZero  *                                  written here.
607*042d53a7SEvalZero  *
608*042d53a7SEvalZero  * @return                      The matching proc entry on success;
609*042d53a7SEvalZero  *                                  null on failure.
610*042d53a7SEvalZero  */
611*042d53a7SEvalZero struct ble_sm_proc *
ble_sm_proc_find(uint16_t conn_handle,uint8_t state,int is_initiator,struct ble_sm_proc ** out_prev)612*042d53a7SEvalZero ble_sm_proc_find(uint16_t conn_handle, uint8_t state, int is_initiator,
613*042d53a7SEvalZero                  struct ble_sm_proc **out_prev)
614*042d53a7SEvalZero {
615*042d53a7SEvalZero     struct ble_sm_proc *proc;
616*042d53a7SEvalZero     struct ble_sm_proc *prev;
617*042d53a7SEvalZero 
618*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task());
619*042d53a7SEvalZero 
620*042d53a7SEvalZero     prev = NULL;
621*042d53a7SEvalZero     STAILQ_FOREACH(proc, &ble_sm_procs, next) {
622*042d53a7SEvalZero         if (ble_sm_proc_matches(proc, conn_handle, state, is_initiator)) {
623*042d53a7SEvalZero             if (out_prev != NULL) {
624*042d53a7SEvalZero                 *out_prev = prev;
625*042d53a7SEvalZero             }
626*042d53a7SEvalZero             break;
627*042d53a7SEvalZero         }
628*042d53a7SEvalZero 
629*042d53a7SEvalZero         prev = proc;
630*042d53a7SEvalZero     }
631*042d53a7SEvalZero 
632*042d53a7SEvalZero     return proc;
633*042d53a7SEvalZero }
634*042d53a7SEvalZero 
635*042d53a7SEvalZero static void
ble_sm_insert(struct ble_sm_proc * proc)636*042d53a7SEvalZero ble_sm_insert(struct ble_sm_proc *proc)
637*042d53a7SEvalZero {
638*042d53a7SEvalZero #if MYNEWT_VAL(BLE_HS_DEBUG)
639*042d53a7SEvalZero     struct ble_sm_proc *cur;
640*042d53a7SEvalZero 
641*042d53a7SEvalZero     STAILQ_FOREACH(cur, &ble_sm_procs, next) {
642*042d53a7SEvalZero         BLE_HS_DBG_ASSERT(cur != proc);
643*042d53a7SEvalZero     }
644*042d53a7SEvalZero #endif
645*042d53a7SEvalZero 
646*042d53a7SEvalZero     STAILQ_INSERT_HEAD(&ble_sm_procs, proc, next);
647*042d53a7SEvalZero }
648*042d53a7SEvalZero 
649*042d53a7SEvalZero static int32_t
ble_sm_extract_expired(struct ble_sm_proc_list * dst_list)650*042d53a7SEvalZero ble_sm_extract_expired(struct ble_sm_proc_list *dst_list)
651*042d53a7SEvalZero {
652*042d53a7SEvalZero     struct ble_sm_proc *proc;
653*042d53a7SEvalZero     struct ble_sm_proc *prev;
654*042d53a7SEvalZero     struct ble_sm_proc *next;
655*042d53a7SEvalZero     ble_npl_time_t now;
656*042d53a7SEvalZero     ble_npl_stime_t next_exp_in;
657*042d53a7SEvalZero     ble_npl_stime_t time_diff;
658*042d53a7SEvalZero 
659*042d53a7SEvalZero     now = ble_npl_time_get();
660*042d53a7SEvalZero     STAILQ_INIT(dst_list);
661*042d53a7SEvalZero 
662*042d53a7SEvalZero     /* Assume each event is either expired or has infinite duration. */
663*042d53a7SEvalZero     next_exp_in = BLE_HS_FOREVER;
664*042d53a7SEvalZero 
665*042d53a7SEvalZero     ble_hs_lock();
666*042d53a7SEvalZero 
667*042d53a7SEvalZero     prev = NULL;
668*042d53a7SEvalZero     proc = STAILQ_FIRST(&ble_sm_procs);
669*042d53a7SEvalZero     while (proc != NULL) {
670*042d53a7SEvalZero         next = STAILQ_NEXT(proc, next);
671*042d53a7SEvalZero 
672*042d53a7SEvalZero         time_diff = proc->exp_os_ticks - now;
673*042d53a7SEvalZero         if (time_diff <= 0) {
674*042d53a7SEvalZero             /* Procedure has expired; move it to the destination list. */
675*042d53a7SEvalZero             if (prev == NULL) {
676*042d53a7SEvalZero                 STAILQ_REMOVE_HEAD(&ble_sm_procs, next);
677*042d53a7SEvalZero             } else {
678*042d53a7SEvalZero                 STAILQ_REMOVE_AFTER(&ble_sm_procs, prev, next);
679*042d53a7SEvalZero             }
680*042d53a7SEvalZero             STAILQ_INSERT_HEAD(dst_list, proc, next);
681*042d53a7SEvalZero         } else {
682*042d53a7SEvalZero             if (time_diff < next_exp_in) {
683*042d53a7SEvalZero                 next_exp_in = time_diff;
684*042d53a7SEvalZero             }
685*042d53a7SEvalZero         }
686*042d53a7SEvalZero 
687*042d53a7SEvalZero         prev = proc;
688*042d53a7SEvalZero         proc = next;
689*042d53a7SEvalZero     }
690*042d53a7SEvalZero 
691*042d53a7SEvalZero     ble_sm_dbg_assert_no_cycles();
692*042d53a7SEvalZero 
693*042d53a7SEvalZero     ble_hs_unlock();
694*042d53a7SEvalZero 
695*042d53a7SEvalZero     return next_exp_in;
696*042d53a7SEvalZero }
697*042d53a7SEvalZero 
698*042d53a7SEvalZero static void
ble_sm_rx_noop(uint16_t conn_handle,struct os_mbuf ** om,struct ble_sm_result * res)699*042d53a7SEvalZero ble_sm_rx_noop(uint16_t conn_handle, struct os_mbuf **om,
700*042d53a7SEvalZero                struct ble_sm_result *res)
701*042d53a7SEvalZero {
702*042d53a7SEvalZero     res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_CMD_NOT_SUPP);
703*042d53a7SEvalZero     res->sm_err = BLE_SM_ERR_CMD_NOT_SUPP;
704*042d53a7SEvalZero }
705*042d53a7SEvalZero 
706*042d53a7SEvalZero static uint8_t
ble_sm_build_authreq(void)707*042d53a7SEvalZero ble_sm_build_authreq(void)
708*042d53a7SEvalZero {
709*042d53a7SEvalZero     return ble_hs_cfg.sm_bonding << 0  |
710*042d53a7SEvalZero            ble_hs_cfg.sm_mitm << 2     |
711*042d53a7SEvalZero            ble_hs_cfg.sm_sc << 3       |
712*042d53a7SEvalZero            ble_hs_cfg.sm_keypress << 4;
713*042d53a7SEvalZero }
714*042d53a7SEvalZero 
715*042d53a7SEvalZero static int
ble_sm_io_action(struct ble_sm_proc * proc,uint8_t * action)716*042d53a7SEvalZero ble_sm_io_action(struct ble_sm_proc *proc, uint8_t *action)
717*042d53a7SEvalZero {
718*042d53a7SEvalZero     if (proc->flags & BLE_SM_PROC_F_SC) {
719*042d53a7SEvalZero         return ble_sm_sc_io_action(proc, action);
720*042d53a7SEvalZero     } else {
721*042d53a7SEvalZero         return ble_sm_lgcy_io_action(proc, action);
722*042d53a7SEvalZero     }
723*042d53a7SEvalZero }
724*042d53a7SEvalZero 
725*042d53a7SEvalZero int
ble_sm_ioact_state(uint8_t action)726*042d53a7SEvalZero ble_sm_ioact_state(uint8_t action)
727*042d53a7SEvalZero {
728*042d53a7SEvalZero     switch (action) {
729*042d53a7SEvalZero     case BLE_SM_IOACT_NONE:
730*042d53a7SEvalZero         return BLE_SM_PROC_STATE_NONE;
731*042d53a7SEvalZero 
732*042d53a7SEvalZero     case BLE_SM_IOACT_NUMCMP:
733*042d53a7SEvalZero         return BLE_SM_PROC_STATE_DHKEY_CHECK;
734*042d53a7SEvalZero 
735*042d53a7SEvalZero     case BLE_SM_IOACT_OOB:
736*042d53a7SEvalZero     case BLE_SM_IOACT_INPUT:
737*042d53a7SEvalZero     case BLE_SM_IOACT_DISP:
738*042d53a7SEvalZero         return BLE_SM_PROC_STATE_CONFIRM;
739*042d53a7SEvalZero 
740*042d53a7SEvalZero     default:
741*042d53a7SEvalZero         BLE_HS_DBG_ASSERT(0);
742*042d53a7SEvalZero         return BLE_SM_PROC_STATE_NONE;
743*042d53a7SEvalZero     }
744*042d53a7SEvalZero }
745*042d53a7SEvalZero 
746*042d53a7SEvalZero int
ble_sm_proc_can_advance(struct ble_sm_proc * proc)747*042d53a7SEvalZero ble_sm_proc_can_advance(struct ble_sm_proc *proc)
748*042d53a7SEvalZero {
749*042d53a7SEvalZero     uint8_t ioact;
750*042d53a7SEvalZero     int rc;
751*042d53a7SEvalZero 
752*042d53a7SEvalZero     rc = ble_sm_io_action(proc, &ioact);
753*042d53a7SEvalZero     if (rc != 0) {
754*042d53a7SEvalZero         BLE_HS_DBG_ASSERT(0);
755*042d53a7SEvalZero     }
756*042d53a7SEvalZero 
757*042d53a7SEvalZero     if (ble_sm_ioact_state(ioact) != proc->state) {
758*042d53a7SEvalZero         return 1;
759*042d53a7SEvalZero     }
760*042d53a7SEvalZero 
761*042d53a7SEvalZero     if (proc->flags & BLE_SM_PROC_F_IO_INJECTED &&
762*042d53a7SEvalZero         proc->flags & BLE_SM_PROC_F_ADVANCE_ON_IO) {
763*042d53a7SEvalZero 
764*042d53a7SEvalZero         return 1;
765*042d53a7SEvalZero     }
766*042d53a7SEvalZero 
767*042d53a7SEvalZero     return 0;
768*042d53a7SEvalZero }
769*042d53a7SEvalZero 
770*042d53a7SEvalZero static void
ble_sm_exec(struct ble_sm_proc * proc,struct ble_sm_result * res,void * arg)771*042d53a7SEvalZero ble_sm_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, void *arg)
772*042d53a7SEvalZero {
773*042d53a7SEvalZero     ble_sm_state_fn *cb;
774*042d53a7SEvalZero 
775*042d53a7SEvalZero     memset(res, 0, sizeof *res);
776*042d53a7SEvalZero 
777*042d53a7SEvalZero     if (!ble_hs_conn_exists(proc->conn_handle)) {
778*042d53a7SEvalZero         res->app_status = BLE_HS_ENOTCONN;
779*042d53a7SEvalZero     } else {
780*042d53a7SEvalZero         BLE_HS_DBG_ASSERT(proc->state < BLE_SM_PROC_STATE_CNT);
781*042d53a7SEvalZero         cb = ble_sm_state_dispatch[proc->state];
782*042d53a7SEvalZero         BLE_HS_DBG_ASSERT(cb != NULL);
783*042d53a7SEvalZero         cb(proc, res, arg);
784*042d53a7SEvalZero     }
785*042d53a7SEvalZero }
786*042d53a7SEvalZero 
787*042d53a7SEvalZero static void
ble_sm_pair_fail_tx(uint16_t conn_handle,uint8_t reason)788*042d53a7SEvalZero ble_sm_pair_fail_tx(uint16_t conn_handle, uint8_t reason)
789*042d53a7SEvalZero {
790*042d53a7SEvalZero     struct ble_sm_pair_fail *cmd;
791*042d53a7SEvalZero     struct os_mbuf *txom;
792*042d53a7SEvalZero 
793*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(reason > 0 && reason < BLE_SM_ERR_MAX_PLUS_1);
794*042d53a7SEvalZero 
795*042d53a7SEvalZero     cmd = ble_sm_cmd_get(BLE_SM_OP_PAIR_FAIL, sizeof(*cmd), &txom);
796*042d53a7SEvalZero     if (cmd) {
797*042d53a7SEvalZero         cmd->reason = reason;
798*042d53a7SEvalZero         ble_sm_tx(conn_handle, txom);
799*042d53a7SEvalZero     }
800*042d53a7SEvalZero }
801*042d53a7SEvalZero 
802*042d53a7SEvalZero /**
803*042d53a7SEvalZero  * Reads a bond from storage.
804*042d53a7SEvalZero  */
805*042d53a7SEvalZero static int
ble_sm_read_bond(uint16_t conn_handle,struct ble_store_value_sec * out_bond)806*042d53a7SEvalZero ble_sm_read_bond(uint16_t conn_handle, struct ble_store_value_sec *out_bond)
807*042d53a7SEvalZero {
808*042d53a7SEvalZero     struct ble_store_key_sec key_sec;
809*042d53a7SEvalZero     struct ble_gap_conn_desc desc;
810*042d53a7SEvalZero     int rc;
811*042d53a7SEvalZero 
812*042d53a7SEvalZero     rc = ble_gap_conn_find(conn_handle, &desc);
813*042d53a7SEvalZero     if (rc != 0) {
814*042d53a7SEvalZero         return rc;
815*042d53a7SEvalZero     }
816*042d53a7SEvalZero 
817*042d53a7SEvalZero     memset(&key_sec, 0, sizeof key_sec);
818*042d53a7SEvalZero     key_sec.peer_addr = desc.peer_id_addr;
819*042d53a7SEvalZero 
820*042d53a7SEvalZero     rc = ble_store_read_peer_sec(&key_sec, out_bond);
821*042d53a7SEvalZero     return rc;
822*042d53a7SEvalZero }
823*042d53a7SEvalZero 
824*042d53a7SEvalZero /**
825*042d53a7SEvalZero  * Checks if the specified peer is already bonded.  If it is, the application
826*042d53a7SEvalZero  * is queried about how to proceed: retry or ignore.  The application should
827*042d53a7SEvalZero  * only indicate a retry if it deleted the old bond.
828*042d53a7SEvalZero  *
829*042d53a7SEvalZero  * @param conn_handle           The handle of the connection over which the
830*042d53a7SEvalZero  *                                  pairing request was received.
831*042d53a7SEvalZero  * @param proc_flags            The security flags associated with the
832*042d53a7SEvalZero  *                                  conflicting SM procedure.
833*042d53a7SEvalZero  * @param key_size              The key size of the conflicting SM procedure.
834*042d53a7SEvalZero  *
835*042d53a7SEvalZero  * @return                      0 if the procedure should continue;
836*042d53a7SEvalZero  *                              nonzero if the request should be ignored.
837*042d53a7SEvalZero  */
838*042d53a7SEvalZero static int
ble_sm_chk_repeat_pairing(uint16_t conn_handle,ble_sm_proc_flags proc_flags,uint8_t key_size)839*042d53a7SEvalZero ble_sm_chk_repeat_pairing(uint16_t conn_handle,
840*042d53a7SEvalZero                           ble_sm_proc_flags proc_flags,
841*042d53a7SEvalZero                           uint8_t key_size)
842*042d53a7SEvalZero {
843*042d53a7SEvalZero     struct ble_gap_repeat_pairing rp;
844*042d53a7SEvalZero     struct ble_store_value_sec bond;
845*042d53a7SEvalZero     int rc;
846*042d53a7SEvalZero 
847*042d53a7SEvalZero     do {
848*042d53a7SEvalZero         /* If the peer isn't bonded, indicate that the pairing procedure should
849*042d53a7SEvalZero          * continue.
850*042d53a7SEvalZero          */
851*042d53a7SEvalZero         rc = ble_sm_read_bond(conn_handle, &bond);
852*042d53a7SEvalZero         switch (rc) {
853*042d53a7SEvalZero         case 0:
854*042d53a7SEvalZero             break;
855*042d53a7SEvalZero         case BLE_HS_ENOENT:
856*042d53a7SEvalZero             return 0;
857*042d53a7SEvalZero         default:
858*042d53a7SEvalZero             return rc;
859*042d53a7SEvalZero         }
860*042d53a7SEvalZero 
861*042d53a7SEvalZero         /* Peer is already bonded.  Ask the application what to do about it. */
862*042d53a7SEvalZero         rp.conn_handle = conn_handle;
863*042d53a7SEvalZero         rp.cur_key_size = bond.key_size;
864*042d53a7SEvalZero         rp.cur_authenticated = bond.authenticated;
865*042d53a7SEvalZero         rp.cur_sc = bond.sc;
866*042d53a7SEvalZero 
867*042d53a7SEvalZero         rp.new_key_size = key_size;
868*042d53a7SEvalZero         rp.new_authenticated = !!(proc_flags & BLE_SM_PROC_F_AUTHENTICATED);
869*042d53a7SEvalZero         rp.new_sc = !!(proc_flags & BLE_SM_PROC_F_SC);
870*042d53a7SEvalZero         rp.new_bonding = !!(proc_flags & BLE_SM_PROC_F_BONDING);
871*042d53a7SEvalZero 
872*042d53a7SEvalZero         rc = ble_gap_repeat_pairing_event(&rp);
873*042d53a7SEvalZero     } while (rc == BLE_GAP_REPEAT_PAIRING_RETRY);
874*042d53a7SEvalZero 
875*042d53a7SEvalZero     BLE_HS_LOG(DEBUG, "silently ignoring pair request from bonded peer");
876*042d53a7SEvalZero 
877*042d53a7SEvalZero     return BLE_HS_EALREADY;
878*042d53a7SEvalZero }
879*042d53a7SEvalZero 
880*042d53a7SEvalZero void
ble_sm_process_result(uint16_t conn_handle,struct ble_sm_result * res)881*042d53a7SEvalZero ble_sm_process_result(uint16_t conn_handle, struct ble_sm_result *res)
882*042d53a7SEvalZero {
883*042d53a7SEvalZero     struct ble_sm_proc *prev;
884*042d53a7SEvalZero     struct ble_sm_proc *proc;
885*042d53a7SEvalZero     int rm;
886*042d53a7SEvalZero 
887*042d53a7SEvalZero     rm = 0;
888*042d53a7SEvalZero 
889*042d53a7SEvalZero     while (1) {
890*042d53a7SEvalZero         ble_hs_lock();
891*042d53a7SEvalZero         proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_NONE, -1,
892*042d53a7SEvalZero                                 &prev);
893*042d53a7SEvalZero 
894*042d53a7SEvalZero         if (proc != NULL) {
895*042d53a7SEvalZero             if (res->execute) {
896*042d53a7SEvalZero                 ble_sm_exec(proc, res, res->state_arg);
897*042d53a7SEvalZero             }
898*042d53a7SEvalZero 
899*042d53a7SEvalZero             if (res->app_status != 0) {
900*042d53a7SEvalZero                 rm = 1;
901*042d53a7SEvalZero             }
902*042d53a7SEvalZero 
903*042d53a7SEvalZero             if (proc->state == BLE_SM_PROC_STATE_NONE) {
904*042d53a7SEvalZero                 rm = 1;
905*042d53a7SEvalZero             }
906*042d53a7SEvalZero 
907*042d53a7SEvalZero             if (rm) {
908*042d53a7SEvalZero                 ble_sm_proc_remove(proc, prev);
909*042d53a7SEvalZero             } else {
910*042d53a7SEvalZero                 ble_sm_proc_set_timer(proc);
911*042d53a7SEvalZero             }
912*042d53a7SEvalZero         }
913*042d53a7SEvalZero 
914*042d53a7SEvalZero         if (res->sm_err != 0) {
915*042d53a7SEvalZero             ble_sm_pair_fail_tx(conn_handle, res->sm_err);
916*042d53a7SEvalZero         }
917*042d53a7SEvalZero 
918*042d53a7SEvalZero         ble_hs_unlock();
919*042d53a7SEvalZero 
920*042d53a7SEvalZero         if (proc == NULL) {
921*042d53a7SEvalZero             break;
922*042d53a7SEvalZero         }
923*042d53a7SEvalZero 
924*042d53a7SEvalZero         if (res->enc_cb) {
925*042d53a7SEvalZero             BLE_HS_DBG_ASSERT(proc == NULL || rm);
926*042d53a7SEvalZero             ble_gap_enc_event(conn_handle, res->app_status, res->restore);
927*042d53a7SEvalZero         }
928*042d53a7SEvalZero 
929*042d53a7SEvalZero         if (res->app_status == 0 &&
930*042d53a7SEvalZero             res->passkey_params.action != BLE_SM_IOACT_NONE) {
931*042d53a7SEvalZero 
932*042d53a7SEvalZero             ble_gap_passkey_event(conn_handle, &res->passkey_params);
933*042d53a7SEvalZero         }
934*042d53a7SEvalZero 
935*042d53a7SEvalZero         /* Persist keys if bonding has successfully completed. */
936*042d53a7SEvalZero         if (res->app_status == 0    &&
937*042d53a7SEvalZero             rm                      &&
938*042d53a7SEvalZero             proc->flags & BLE_SM_PROC_F_BONDING) {
939*042d53a7SEvalZero 
940*042d53a7SEvalZero             ble_sm_persist_keys(proc);
941*042d53a7SEvalZero         }
942*042d53a7SEvalZero 
943*042d53a7SEvalZero         if (rm) {
944*042d53a7SEvalZero             ble_sm_proc_free(proc);
945*042d53a7SEvalZero             break;
946*042d53a7SEvalZero         }
947*042d53a7SEvalZero 
948*042d53a7SEvalZero         if (!res->execute) {
949*042d53a7SEvalZero             break;
950*042d53a7SEvalZero         }
951*042d53a7SEvalZero 
952*042d53a7SEvalZero         memset(res, 0, sizeof *res);
953*042d53a7SEvalZero         res->execute = 1;
954*042d53a7SEvalZero     }
955*042d53a7SEvalZero }
956*042d53a7SEvalZero 
957*042d53a7SEvalZero static void
ble_sm_key_dist(struct ble_sm_proc * proc,uint8_t * out_init_key_dist,uint8_t * out_resp_key_dist)958*042d53a7SEvalZero ble_sm_key_dist(struct ble_sm_proc *proc,
959*042d53a7SEvalZero                 uint8_t *out_init_key_dist, uint8_t *out_resp_key_dist)
960*042d53a7SEvalZero {
961*042d53a7SEvalZero     struct ble_sm_pair_cmd *pair_rsp;
962*042d53a7SEvalZero 
963*042d53a7SEvalZero     pair_rsp = (struct ble_sm_pair_cmd *) &proc->pair_rsp[1];
964*042d53a7SEvalZero 
965*042d53a7SEvalZero     *out_init_key_dist = pair_rsp->init_key_dist;
966*042d53a7SEvalZero     *out_resp_key_dist = pair_rsp->resp_key_dist;
967*042d53a7SEvalZero 
968*042d53a7SEvalZero     /* Encryption info and master ID are only sent in legacy pairing. */
969*042d53a7SEvalZero     if (proc->flags & BLE_SM_PROC_F_SC) {
970*042d53a7SEvalZero         *out_init_key_dist &= ~BLE_SM_PAIR_KEY_DIST_ENC;
971*042d53a7SEvalZero         *out_resp_key_dist &= ~BLE_SM_PAIR_KEY_DIST_ENC;
972*042d53a7SEvalZero     }
973*042d53a7SEvalZero }
974*042d53a7SEvalZero 
975*042d53a7SEvalZero static int
ble_sm_chk_store_overflow_by_type(int obj_type,uint16_t conn_handle)976*042d53a7SEvalZero ble_sm_chk_store_overflow_by_type(int obj_type, uint16_t conn_handle)
977*042d53a7SEvalZero {
978*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_SM_BONDING)
979*042d53a7SEvalZero     return 0;
980*042d53a7SEvalZero #endif
981*042d53a7SEvalZero 
982*042d53a7SEvalZero     int count;
983*042d53a7SEvalZero     int rc;
984*042d53a7SEvalZero 
985*042d53a7SEvalZero     rc = ble_store_util_count(obj_type, &count);
986*042d53a7SEvalZero     if (rc != 0) {
987*042d53a7SEvalZero         return rc;
988*042d53a7SEvalZero     }
989*042d53a7SEvalZero 
990*042d53a7SEvalZero     /* Pessimistically assume all active procs will persist bonds. */
991*042d53a7SEvalZero     ble_hs_lock();
992*042d53a7SEvalZero     count += ble_sm_num_procs();
993*042d53a7SEvalZero     ble_hs_unlock();
994*042d53a7SEvalZero 
995*042d53a7SEvalZero     if (count < MYNEWT_VAL(BLE_STORE_MAX_BONDS)) {
996*042d53a7SEvalZero         /* There is sufficient capacity for another bond. */
997*042d53a7SEvalZero         return 0;
998*042d53a7SEvalZero     }
999*042d53a7SEvalZero 
1000*042d53a7SEvalZero     /* No capacity for an additional bond.  Tell the application to make
1001*042d53a7SEvalZero      * room.
1002*042d53a7SEvalZero      */
1003*042d53a7SEvalZero     rc = ble_store_full_event(obj_type, conn_handle);
1004*042d53a7SEvalZero     if (rc != 0) {
1005*042d53a7SEvalZero         return rc;
1006*042d53a7SEvalZero     }
1007*042d53a7SEvalZero 
1008*042d53a7SEvalZero     return 0;
1009*042d53a7SEvalZero }
1010*042d53a7SEvalZero 
1011*042d53a7SEvalZero static int
ble_sm_chk_store_overflow(uint16_t conn_handle)1012*042d53a7SEvalZero ble_sm_chk_store_overflow(uint16_t conn_handle)
1013*042d53a7SEvalZero {
1014*042d53a7SEvalZero     int rc;
1015*042d53a7SEvalZero 
1016*042d53a7SEvalZero     rc = ble_sm_chk_store_overflow_by_type(BLE_STORE_OBJ_TYPE_PEER_SEC,
1017*042d53a7SEvalZero                                            conn_handle);
1018*042d53a7SEvalZero     if (rc != 0) {
1019*042d53a7SEvalZero         return rc;
1020*042d53a7SEvalZero     }
1021*042d53a7SEvalZero 
1022*042d53a7SEvalZero     rc = ble_sm_chk_store_overflow_by_type(BLE_STORE_OBJ_TYPE_OUR_SEC,
1023*042d53a7SEvalZero                                            conn_handle);
1024*042d53a7SEvalZero     if (rc != 0) {
1025*042d53a7SEvalZero         return rc;
1026*042d53a7SEvalZero     }
1027*042d53a7SEvalZero 
1028*042d53a7SEvalZero     return 0;
1029*042d53a7SEvalZero }
1030*042d53a7SEvalZero 
1031*042d53a7SEvalZero /*****************************************************************************
1032*042d53a7SEvalZero  * $enc                                                                      *
1033*042d53a7SEvalZero  *****************************************************************************/
1034*042d53a7SEvalZero 
1035*042d53a7SEvalZero static int
ble_sm_start_encrypt_tx(struct hci_start_encrypt * cmd)1036*042d53a7SEvalZero ble_sm_start_encrypt_tx(struct hci_start_encrypt *cmd)
1037*042d53a7SEvalZero {
1038*042d53a7SEvalZero     uint8_t buf[BLE_HCI_LE_START_ENCRYPT_LEN];
1039*042d53a7SEvalZero     int rc;
1040*042d53a7SEvalZero 
1041*042d53a7SEvalZero     ble_hs_hci_cmd_build_le_start_encrypt(cmd, buf, sizeof buf);
1042*042d53a7SEvalZero     rc = ble_hs_hci_cmd_tx_empty_ack(BLE_HCI_OP(BLE_HCI_OGF_LE,
1043*042d53a7SEvalZero                                                 BLE_HCI_OCF_LE_START_ENCRYPT),
1044*042d53a7SEvalZero                                           buf, sizeof(buf));
1045*042d53a7SEvalZero     if (rc != 0) {
1046*042d53a7SEvalZero         return rc;
1047*042d53a7SEvalZero     }
1048*042d53a7SEvalZero 
1049*042d53a7SEvalZero     return 0;
1050*042d53a7SEvalZero }
1051*042d53a7SEvalZero 
1052*042d53a7SEvalZero static void
ble_sm_enc_start_exec(struct ble_sm_proc * proc,struct ble_sm_result * res,void * arg)1053*042d53a7SEvalZero ble_sm_enc_start_exec(struct ble_sm_proc *proc, struct ble_sm_result *res,
1054*042d53a7SEvalZero                       void *arg)
1055*042d53a7SEvalZero {
1056*042d53a7SEvalZero     struct hci_start_encrypt cmd;
1057*042d53a7SEvalZero     int rc;
1058*042d53a7SEvalZero 
1059*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(proc->flags & BLE_SM_PROC_F_INITIATOR);
1060*042d53a7SEvalZero 
1061*042d53a7SEvalZero     cmd.connection_handle = proc->conn_handle;
1062*042d53a7SEvalZero     cmd.encrypted_diversifier = 0;
1063*042d53a7SEvalZero     cmd.random_number = 0;
1064*042d53a7SEvalZero     memcpy(cmd.long_term_key, proc->ltk, sizeof cmd.long_term_key);
1065*042d53a7SEvalZero 
1066*042d53a7SEvalZero     rc = ble_sm_start_encrypt_tx(&cmd);
1067*042d53a7SEvalZero     if (rc != 0) {
1068*042d53a7SEvalZero         res->sm_err = BLE_SM_ERR_UNSPECIFIED;
1069*042d53a7SEvalZero         res->app_status = rc;
1070*042d53a7SEvalZero         res->enc_cb = 1;
1071*042d53a7SEvalZero     }
1072*042d53a7SEvalZero }
1073*042d53a7SEvalZero 
1074*042d53a7SEvalZero static void
ble_sm_enc_restore_exec(struct ble_sm_proc * proc,struct ble_sm_result * res,void * arg)1075*042d53a7SEvalZero ble_sm_enc_restore_exec(struct ble_sm_proc *proc, struct ble_sm_result *res,
1076*042d53a7SEvalZero                         void *arg)
1077*042d53a7SEvalZero {
1078*042d53a7SEvalZero     struct hci_start_encrypt *cmd;
1079*042d53a7SEvalZero 
1080*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(proc->flags & BLE_SM_PROC_F_INITIATOR);
1081*042d53a7SEvalZero 
1082*042d53a7SEvalZero     cmd = arg;
1083*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(cmd != NULL);
1084*042d53a7SEvalZero 
1085*042d53a7SEvalZero     res->app_status = ble_sm_start_encrypt_tx(cmd);
1086*042d53a7SEvalZero }
1087*042d53a7SEvalZero 
1088*042d53a7SEvalZero static void
ble_sm_enc_event_rx(uint16_t conn_handle,uint8_t evt_status,int encrypted)1089*042d53a7SEvalZero ble_sm_enc_event_rx(uint16_t conn_handle, uint8_t evt_status, int encrypted)
1090*042d53a7SEvalZero {
1091*042d53a7SEvalZero     struct ble_sm_result res;
1092*042d53a7SEvalZero     struct ble_sm_proc *proc;
1093*042d53a7SEvalZero     int authenticated;
1094*042d53a7SEvalZero     int bonded;
1095*042d53a7SEvalZero     int key_size;
1096*042d53a7SEvalZero 
1097*042d53a7SEvalZero     memset(&res, 0, sizeof res);
1098*042d53a7SEvalZero 
1099*042d53a7SEvalZero     /* Assume no change in authenticated and bonded statuses. */
1100*042d53a7SEvalZero     authenticated = 0;
1101*042d53a7SEvalZero     bonded = 0;
1102*042d53a7SEvalZero     key_size = 0;
1103*042d53a7SEvalZero 
1104*042d53a7SEvalZero     ble_hs_lock();
1105*042d53a7SEvalZero 
1106*042d53a7SEvalZero     proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_NONE, -1, NULL);
1107*042d53a7SEvalZero     if (proc != NULL) {
1108*042d53a7SEvalZero         switch (proc->state) {
1109*042d53a7SEvalZero         case BLE_SM_PROC_STATE_ENC_START:
1110*042d53a7SEvalZero             /* We are completing a pairing procedure; keys may need to be
1111*042d53a7SEvalZero              * exchanged.
1112*042d53a7SEvalZero              */
1113*042d53a7SEvalZero             if (evt_status == 0) {
1114*042d53a7SEvalZero                 /* If the responder has any keys to send, it sends them
1115*042d53a7SEvalZero                  * first.
1116*042d53a7SEvalZero                  */
1117*042d53a7SEvalZero                 proc->state = BLE_SM_PROC_STATE_KEY_EXCH;
1118*042d53a7SEvalZero                 if (!(proc->flags & BLE_SM_PROC_F_INITIATOR) ||
1119*042d53a7SEvalZero                     proc->rx_key_flags == 0) {
1120*042d53a7SEvalZero 
1121*042d53a7SEvalZero                     res.execute = 1;
1122*042d53a7SEvalZero                 }
1123*042d53a7SEvalZero 
1124*042d53a7SEvalZero                 key_size = proc->key_size;
1125*042d53a7SEvalZero             } else {
1126*042d53a7SEvalZero                 /* Failure or no keys to exchange; procedure is complete. */
1127*042d53a7SEvalZero                 proc->state = BLE_SM_PROC_STATE_NONE;
1128*042d53a7SEvalZero             }
1129*042d53a7SEvalZero             if (proc->flags & BLE_SM_PROC_F_AUTHENTICATED) {
1130*042d53a7SEvalZero                 authenticated = 1;
1131*042d53a7SEvalZero             }
1132*042d53a7SEvalZero             break;
1133*042d53a7SEvalZero 
1134*042d53a7SEvalZero         case BLE_SM_PROC_STATE_ENC_RESTORE:
1135*042d53a7SEvalZero             /* A secure link is being restored via the encryption
1136*042d53a7SEvalZero              * procedure.  Keys were exchanged during pairing; they don't
1137*042d53a7SEvalZero              * get exchanged again now.  Procedure is complete.
1138*042d53a7SEvalZero              */
1139*042d53a7SEvalZero             BLE_HS_DBG_ASSERT(proc->rx_key_flags == 0);
1140*042d53a7SEvalZero             proc->state = BLE_SM_PROC_STATE_NONE;
1141*042d53a7SEvalZero             if (proc->flags & BLE_SM_PROC_F_AUTHENTICATED) {
1142*042d53a7SEvalZero                 authenticated = 1;
1143*042d53a7SEvalZero             }
1144*042d53a7SEvalZero             bonded = 1;
1145*042d53a7SEvalZero             res.restore = 1;
1146*042d53a7SEvalZero 
1147*042d53a7SEvalZero             key_size = proc->key_size;
1148*042d53a7SEvalZero             break;
1149*042d53a7SEvalZero 
1150*042d53a7SEvalZero         default:
1151*042d53a7SEvalZero             /* The encryption change event is unexpected.  We take the
1152*042d53a7SEvalZero              * controller at its word that the state has changed and we
1153*042d53a7SEvalZero              * terminate the procedure.
1154*042d53a7SEvalZero              */
1155*042d53a7SEvalZero             proc->state = BLE_SM_PROC_STATE_NONE;
1156*042d53a7SEvalZero             res.sm_err = BLE_SM_ERR_UNSPECIFIED;
1157*042d53a7SEvalZero             break;
1158*042d53a7SEvalZero         }
1159*042d53a7SEvalZero     }
1160*042d53a7SEvalZero 
1161*042d53a7SEvalZero     if (evt_status == 0) {
1162*042d53a7SEvalZero         /* Set the encrypted state of the connection as indicated in the
1163*042d53a7SEvalZero          * event.
1164*042d53a7SEvalZero          */
1165*042d53a7SEvalZero         ble_sm_update_sec_state(conn_handle, encrypted, authenticated, bonded,
1166*042d53a7SEvalZero                                 key_size);
1167*042d53a7SEvalZero     }
1168*042d53a7SEvalZero 
1169*042d53a7SEvalZero     /* Unless keys need to be exchanged, notify the application of the security
1170*042d53a7SEvalZero      * change.  If key exchange is pending, the application callback is
1171*042d53a7SEvalZero      * triggered after exchange completes.
1172*042d53a7SEvalZero      */
1173*042d53a7SEvalZero     if (proc == NULL || proc->state == BLE_SM_PROC_STATE_NONE) {
1174*042d53a7SEvalZero         res.enc_cb = 1;
1175*042d53a7SEvalZero         res.app_status = BLE_HS_HCI_ERR(evt_status);
1176*042d53a7SEvalZero     }
1177*042d53a7SEvalZero 
1178*042d53a7SEvalZero     ble_hs_unlock();
1179*042d53a7SEvalZero 
1180*042d53a7SEvalZero     ble_sm_process_result(conn_handle, &res);
1181*042d53a7SEvalZero }
1182*042d53a7SEvalZero 
1183*042d53a7SEvalZero void
ble_sm_enc_change_rx(struct hci_encrypt_change * evt)1184*042d53a7SEvalZero ble_sm_enc_change_rx(struct hci_encrypt_change *evt)
1185*042d53a7SEvalZero {
1186*042d53a7SEvalZero     /* For encrypted state: read LE-encryption bit; ignore BR/EDR and reserved
1187*042d53a7SEvalZero      * bits.
1188*042d53a7SEvalZero      */
1189*042d53a7SEvalZero     ble_sm_enc_event_rx(evt->connection_handle, evt->status,
1190*042d53a7SEvalZero                         evt->encryption_enabled & 0x01);
1191*042d53a7SEvalZero }
1192*042d53a7SEvalZero 
1193*042d53a7SEvalZero void
ble_sm_enc_key_refresh_rx(struct hci_encrypt_key_refresh * evt)1194*042d53a7SEvalZero ble_sm_enc_key_refresh_rx(struct hci_encrypt_key_refresh *evt)
1195*042d53a7SEvalZero {
1196*042d53a7SEvalZero     ble_sm_enc_event_rx(evt->connection_handle, evt->status, 1);
1197*042d53a7SEvalZero }
1198*042d53a7SEvalZero 
1199*042d53a7SEvalZero /*****************************************************************************
1200*042d53a7SEvalZero  * $ltk                                                                      *
1201*042d53a7SEvalZero  *****************************************************************************/
1202*042d53a7SEvalZero 
1203*042d53a7SEvalZero static int
ble_sm_retrieve_ltk(struct hci_le_lt_key_req * evt,uint8_t peer_addr_type,uint8_t * peer_addr,struct ble_store_value_sec * value_sec)1204*042d53a7SEvalZero ble_sm_retrieve_ltk(struct hci_le_lt_key_req *evt, uint8_t peer_addr_type,
1205*042d53a7SEvalZero                     uint8_t *peer_addr, struct ble_store_value_sec *value_sec)
1206*042d53a7SEvalZero {
1207*042d53a7SEvalZero     struct ble_store_key_sec key_sec;
1208*042d53a7SEvalZero     int rc;
1209*042d53a7SEvalZero 
1210*042d53a7SEvalZero     /* Tell applicaiton to look up LTK by peer address and ediv/rand pair. */
1211*042d53a7SEvalZero     memset(&key_sec, 0, sizeof key_sec);
1212*042d53a7SEvalZero     key_sec.peer_addr.type = peer_addr_type;
1213*042d53a7SEvalZero     memcpy(key_sec.peer_addr.val, peer_addr, 6);
1214*042d53a7SEvalZero     key_sec.ediv = evt->encrypted_diversifier;
1215*042d53a7SEvalZero     key_sec.rand_num = evt->random_number;
1216*042d53a7SEvalZero     key_sec.ediv_rand_present = 1;
1217*042d53a7SEvalZero 
1218*042d53a7SEvalZero     rc = ble_store_read_our_sec(&key_sec, value_sec);
1219*042d53a7SEvalZero     return rc;
1220*042d53a7SEvalZero }
1221*042d53a7SEvalZero 
1222*042d53a7SEvalZero static int
ble_sm_ltk_req_reply_tx(uint16_t conn_handle,uint8_t * ltk)1223*042d53a7SEvalZero ble_sm_ltk_req_reply_tx(uint16_t conn_handle, uint8_t *ltk)
1224*042d53a7SEvalZero {
1225*042d53a7SEvalZero     struct hci_lt_key_req_reply cmd;
1226*042d53a7SEvalZero     uint16_t ack_conn_handle;
1227*042d53a7SEvalZero     uint8_t buf[BLE_HCI_LT_KEY_REQ_REPLY_LEN];
1228*042d53a7SEvalZero     uint8_t ack_params_len;
1229*042d53a7SEvalZero     int rc;
1230*042d53a7SEvalZero 
1231*042d53a7SEvalZero     cmd.conn_handle = conn_handle;
1232*042d53a7SEvalZero     memcpy(cmd.long_term_key, ltk, 16);
1233*042d53a7SEvalZero 
1234*042d53a7SEvalZero     ble_hs_hci_cmd_build_le_lt_key_req_reply(&cmd, buf, sizeof buf);
1235*042d53a7SEvalZero     rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
1236*042d53a7SEvalZero                                       BLE_HCI_OCF_LE_LT_KEY_REQ_REPLY),
1237*042d53a7SEvalZero                            buf, sizeof(buf), &ack_conn_handle,
1238*042d53a7SEvalZero                            sizeof(ack_conn_handle), &ack_params_len);
1239*042d53a7SEvalZero     if (rc != 0) {
1240*042d53a7SEvalZero         return rc;
1241*042d53a7SEvalZero     }
1242*042d53a7SEvalZero     if (ack_params_len != BLE_HCI_LT_KEY_REQ_REPLY_ACK_PARAM_LEN) {
1243*042d53a7SEvalZero         return BLE_HS_ECONTROLLER;
1244*042d53a7SEvalZero     }
1245*042d53a7SEvalZero 
1246*042d53a7SEvalZero     if (le16toh(ack_conn_handle) != conn_handle) {
1247*042d53a7SEvalZero         return BLE_HS_ECONTROLLER;
1248*042d53a7SEvalZero     }
1249*042d53a7SEvalZero 
1250*042d53a7SEvalZero     return 0;
1251*042d53a7SEvalZero }
1252*042d53a7SEvalZero 
1253*042d53a7SEvalZero static int
ble_sm_ltk_req_neg_reply_tx(uint16_t conn_handle)1254*042d53a7SEvalZero ble_sm_ltk_req_neg_reply_tx(uint16_t conn_handle)
1255*042d53a7SEvalZero {
1256*042d53a7SEvalZero     uint16_t ack_conn_handle;
1257*042d53a7SEvalZero     uint8_t buf[BLE_HCI_LT_KEY_REQ_NEG_REPLY_LEN];
1258*042d53a7SEvalZero     uint8_t ack_params_len;
1259*042d53a7SEvalZero     int rc;
1260*042d53a7SEvalZero 
1261*042d53a7SEvalZero     ble_hs_hci_cmd_build_le_lt_key_req_neg_reply(conn_handle, buf, sizeof buf);
1262*042d53a7SEvalZero     rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
1263*042d53a7SEvalZero                                       BLE_HCI_OCF_LE_LT_KEY_REQ_NEG_REPLY),
1264*042d53a7SEvalZero                            buf, sizeof(buf), &ack_conn_handle,
1265*042d53a7SEvalZero                            sizeof(ack_conn_handle), &ack_params_len);
1266*042d53a7SEvalZero     if (rc != 0) {
1267*042d53a7SEvalZero         return rc;
1268*042d53a7SEvalZero     }
1269*042d53a7SEvalZero     if (ack_params_len != BLE_HCI_LT_KEY_REQ_NEG_REPLY_ACK_PARAM_LEN) {
1270*042d53a7SEvalZero         return BLE_HS_ECONTROLLER;
1271*042d53a7SEvalZero     }
1272*042d53a7SEvalZero 
1273*042d53a7SEvalZero     if (le16toh(ack_conn_handle) != conn_handle) {
1274*042d53a7SEvalZero         return BLE_HS_ECONTROLLER;
1275*042d53a7SEvalZero     }
1276*042d53a7SEvalZero 
1277*042d53a7SEvalZero     return 0;
1278*042d53a7SEvalZero }
1279*042d53a7SEvalZero 
1280*042d53a7SEvalZero static void
ble_sm_ltk_start_exec(struct ble_sm_proc * proc,struct ble_sm_result * res,void * arg)1281*042d53a7SEvalZero ble_sm_ltk_start_exec(struct ble_sm_proc *proc, struct ble_sm_result *res,
1282*042d53a7SEvalZero                       void *arg)
1283*042d53a7SEvalZero {
1284*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(!(proc->flags & BLE_SM_PROC_F_INITIATOR));
1285*042d53a7SEvalZero 
1286*042d53a7SEvalZero     res->app_status = ble_sm_ltk_req_reply_tx(proc->conn_handle, proc->ltk);
1287*042d53a7SEvalZero     if (res->app_status == 0) {
1288*042d53a7SEvalZero         proc->state = BLE_SM_PROC_STATE_ENC_START;
1289*042d53a7SEvalZero     } else {
1290*042d53a7SEvalZero         res->enc_cb = 1;
1291*042d53a7SEvalZero     }
1292*042d53a7SEvalZero }
1293*042d53a7SEvalZero 
1294*042d53a7SEvalZero static void
ble_sm_ltk_restore_exec(struct ble_sm_proc * proc,struct ble_sm_result * res,void * arg)1295*042d53a7SEvalZero ble_sm_ltk_restore_exec(struct ble_sm_proc *proc, struct ble_sm_result *res,
1296*042d53a7SEvalZero                         void *arg)
1297*042d53a7SEvalZero {
1298*042d53a7SEvalZero     struct ble_store_value_sec *value_sec;
1299*042d53a7SEvalZero 
1300*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(!(proc->flags & BLE_SM_PROC_F_INITIATOR));
1301*042d53a7SEvalZero 
1302*042d53a7SEvalZero     value_sec = arg;
1303*042d53a7SEvalZero 
1304*042d53a7SEvalZero     if (value_sec != NULL) {
1305*042d53a7SEvalZero         /* Store provided a key; send it to the controller. */
1306*042d53a7SEvalZero         res->app_status = ble_sm_ltk_req_reply_tx(
1307*042d53a7SEvalZero             proc->conn_handle, value_sec->ltk);
1308*042d53a7SEvalZero 
1309*042d53a7SEvalZero         if (res->app_status == 0) {
1310*042d53a7SEvalZero             if (value_sec->authenticated) {
1311*042d53a7SEvalZero                 proc->flags |= BLE_SM_PROC_F_AUTHENTICATED;
1312*042d53a7SEvalZero             }
1313*042d53a7SEvalZero         } else {
1314*042d53a7SEvalZero             /* Notify the app if it provided a key and the procedure failed. */
1315*042d53a7SEvalZero             res->enc_cb = 1;
1316*042d53a7SEvalZero         }
1317*042d53a7SEvalZero     } else {
1318*042d53a7SEvalZero         /* Application does not have the requested key in its database.  Send a
1319*042d53a7SEvalZero          * negative reply to the controller.
1320*042d53a7SEvalZero          */
1321*042d53a7SEvalZero         ble_sm_ltk_req_neg_reply_tx(proc->conn_handle);
1322*042d53a7SEvalZero         res->app_status = BLE_HS_ENOENT;
1323*042d53a7SEvalZero     }
1324*042d53a7SEvalZero 
1325*042d53a7SEvalZero     if (res->app_status == 0) {
1326*042d53a7SEvalZero         proc->state = BLE_SM_PROC_STATE_ENC_RESTORE;
1327*042d53a7SEvalZero     }
1328*042d53a7SEvalZero }
1329*042d53a7SEvalZero 
1330*042d53a7SEvalZero int
ble_sm_ltk_req_rx(struct hci_le_lt_key_req * evt)1331*042d53a7SEvalZero ble_sm_ltk_req_rx(struct hci_le_lt_key_req *evt)
1332*042d53a7SEvalZero {
1333*042d53a7SEvalZero     struct ble_store_value_sec value_sec;
1334*042d53a7SEvalZero     struct ble_hs_conn_addrs addrs;
1335*042d53a7SEvalZero     struct ble_sm_result res;
1336*042d53a7SEvalZero     struct ble_sm_proc *proc;
1337*042d53a7SEvalZero     struct ble_hs_conn *conn;
1338*042d53a7SEvalZero     uint8_t peer_id_addr[6];
1339*042d53a7SEvalZero     int store_rc;
1340*042d53a7SEvalZero     int restore;
1341*042d53a7SEvalZero 
1342*042d53a7SEvalZero     memset(&res, 0, sizeof res);
1343*042d53a7SEvalZero 
1344*042d53a7SEvalZero     ble_hs_lock();
1345*042d53a7SEvalZero     proc = ble_sm_proc_find(evt->connection_handle, BLE_SM_PROC_STATE_NONE,
1346*042d53a7SEvalZero                             0, NULL);
1347*042d53a7SEvalZero     if (proc == NULL) {
1348*042d53a7SEvalZero         /* The peer is attempting to restore a encrypted connection via the
1349*042d53a7SEvalZero          * encryption procedure.  Create a proc entry to indicate that security
1350*042d53a7SEvalZero          * establishment is in progress and execute the procedure after the
1351*042d53a7SEvalZero          * mutex gets unlocked.
1352*042d53a7SEvalZero          */
1353*042d53a7SEvalZero         restore = 1;
1354*042d53a7SEvalZero         proc = ble_sm_proc_alloc();
1355*042d53a7SEvalZero         if (proc == NULL) {
1356*042d53a7SEvalZero             res.app_status = BLE_HS_ENOMEM;
1357*042d53a7SEvalZero         } else {
1358*042d53a7SEvalZero             proc->conn_handle = evt->connection_handle;
1359*042d53a7SEvalZero             proc->state = BLE_SM_PROC_STATE_LTK_RESTORE;
1360*042d53a7SEvalZero             ble_sm_insert(proc);
1361*042d53a7SEvalZero 
1362*042d53a7SEvalZero             res.execute = 1;
1363*042d53a7SEvalZero         }
1364*042d53a7SEvalZero     } else if (proc->state == BLE_SM_PROC_STATE_SEC_REQ) {
1365*042d53a7SEvalZero         /* Same as above, except we solicited the encryption procedure by
1366*042d53a7SEvalZero          * sending a security request.
1367*042d53a7SEvalZero          */
1368*042d53a7SEvalZero         restore = 1;
1369*042d53a7SEvalZero         proc->state = BLE_SM_PROC_STATE_LTK_RESTORE;
1370*042d53a7SEvalZero         res.execute = 1;
1371*042d53a7SEvalZero     } else if (proc->state == BLE_SM_PROC_STATE_LTK_START) {
1372*042d53a7SEvalZero         /* Legacy pairing just completed.  Send the short term key to the
1373*042d53a7SEvalZero          * controller.
1374*042d53a7SEvalZero          */
1375*042d53a7SEvalZero         restore = 0;
1376*042d53a7SEvalZero         res.execute = 1;
1377*042d53a7SEvalZero     } else {
1378*042d53a7SEvalZero         /* The request is unexpected; nack and forget. */
1379*042d53a7SEvalZero         restore = 0;
1380*042d53a7SEvalZero         ble_sm_ltk_req_neg_reply_tx(evt->connection_handle);
1381*042d53a7SEvalZero         proc = NULL;
1382*042d53a7SEvalZero     }
1383*042d53a7SEvalZero 
1384*042d53a7SEvalZero     if (restore) {
1385*042d53a7SEvalZero         conn = ble_hs_conn_find_assert(evt->connection_handle);
1386*042d53a7SEvalZero         ble_hs_conn_addrs(conn, &addrs);
1387*042d53a7SEvalZero         memcpy(peer_id_addr, addrs.peer_id_addr.val, 6);
1388*042d53a7SEvalZero     }
1389*042d53a7SEvalZero 
1390*042d53a7SEvalZero     ble_hs_unlock();
1391*042d53a7SEvalZero 
1392*042d53a7SEvalZero     if (proc == NULL) {
1393*042d53a7SEvalZero         return res.app_status;
1394*042d53a7SEvalZero     }
1395*042d53a7SEvalZero 
1396*042d53a7SEvalZero     if (res.app_status == 0) {
1397*042d53a7SEvalZero         if (restore) {
1398*042d53a7SEvalZero             store_rc = ble_sm_retrieve_ltk(evt, addrs.peer_id_addr.type,
1399*042d53a7SEvalZero                                            peer_id_addr, &value_sec);
1400*042d53a7SEvalZero             if (store_rc == 0) {
1401*042d53a7SEvalZero                 /* Send the key to the controller. */
1402*042d53a7SEvalZero                 res.state_arg = &value_sec;
1403*042d53a7SEvalZero             } else {
1404*042d53a7SEvalZero                 /* Send a nack to the controller. */
1405*042d53a7SEvalZero                 res.state_arg = NULL;
1406*042d53a7SEvalZero             }
1407*042d53a7SEvalZero         }
1408*042d53a7SEvalZero     }
1409*042d53a7SEvalZero 
1410*042d53a7SEvalZero     ble_sm_process_result(evt->connection_handle, &res);
1411*042d53a7SEvalZero 
1412*042d53a7SEvalZero     return 0;
1413*042d53a7SEvalZero }
1414*042d53a7SEvalZero 
1415*042d53a7SEvalZero /*****************************************************************************
1416*042d53a7SEvalZero  * $random                                                                   *
1417*042d53a7SEvalZero  *****************************************************************************/
1418*042d53a7SEvalZero 
1419*042d53a7SEvalZero uint8_t *
ble_sm_our_pair_rand(struct ble_sm_proc * proc)1420*042d53a7SEvalZero ble_sm_our_pair_rand(struct ble_sm_proc *proc)
1421*042d53a7SEvalZero {
1422*042d53a7SEvalZero     if (proc->flags & BLE_SM_PROC_F_INITIATOR) {
1423*042d53a7SEvalZero         return proc->randm;
1424*042d53a7SEvalZero     } else {
1425*042d53a7SEvalZero         return proc->rands;
1426*042d53a7SEvalZero     }
1427*042d53a7SEvalZero }
1428*042d53a7SEvalZero 
1429*042d53a7SEvalZero uint8_t *
ble_sm_peer_pair_rand(struct ble_sm_proc * proc)1430*042d53a7SEvalZero ble_sm_peer_pair_rand(struct ble_sm_proc *proc)
1431*042d53a7SEvalZero {
1432*042d53a7SEvalZero     if (proc->flags & BLE_SM_PROC_F_INITIATOR) {
1433*042d53a7SEvalZero         return proc->rands;
1434*042d53a7SEvalZero     } else {
1435*042d53a7SEvalZero         return proc->randm;
1436*042d53a7SEvalZero     }
1437*042d53a7SEvalZero }
1438*042d53a7SEvalZero 
1439*042d53a7SEvalZero static void
ble_sm_random_exec(struct ble_sm_proc * proc,struct ble_sm_result * res,void * arg)1440*042d53a7SEvalZero ble_sm_random_exec(struct ble_sm_proc *proc, struct ble_sm_result *res,
1441*042d53a7SEvalZero                    void *arg)
1442*042d53a7SEvalZero {
1443*042d53a7SEvalZero     if (proc->flags & BLE_SM_PROC_F_SC) {
1444*042d53a7SEvalZero         ble_sm_sc_random_exec(proc, res);
1445*042d53a7SEvalZero     } else {
1446*042d53a7SEvalZero         ble_sm_lgcy_random_exec(proc, res);
1447*042d53a7SEvalZero     }
1448*042d53a7SEvalZero }
1449*042d53a7SEvalZero 
1450*042d53a7SEvalZero static void
ble_sm_random_rx(uint16_t conn_handle,struct os_mbuf ** om,struct ble_sm_result * res)1451*042d53a7SEvalZero ble_sm_random_rx(uint16_t conn_handle, struct os_mbuf **om,
1452*042d53a7SEvalZero                  struct ble_sm_result *res)
1453*042d53a7SEvalZero {
1454*042d53a7SEvalZero     struct ble_sm_pair_random *cmd;
1455*042d53a7SEvalZero     struct ble_sm_proc *proc;
1456*042d53a7SEvalZero 
1457*042d53a7SEvalZero     res->app_status = ble_hs_mbuf_pullup_base(om, sizeof(*cmd));
1458*042d53a7SEvalZero     if (res->app_status != 0) {
1459*042d53a7SEvalZero         res->sm_err = BLE_SM_ERR_UNSPECIFIED;
1460*042d53a7SEvalZero         res->enc_cb = 1;
1461*042d53a7SEvalZero         return;
1462*042d53a7SEvalZero     }
1463*042d53a7SEvalZero 
1464*042d53a7SEvalZero     cmd = (struct ble_sm_pair_random *)(*om)->om_data;
1465*042d53a7SEvalZero 
1466*042d53a7SEvalZero     BLE_SM_LOG_CMD(0, "random", conn_handle, ble_sm_pair_random_log, cmd);
1467*042d53a7SEvalZero 
1468*042d53a7SEvalZero     ble_hs_lock();
1469*042d53a7SEvalZero     proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_RANDOM, -1, NULL);
1470*042d53a7SEvalZero     if (proc == NULL) {
1471*042d53a7SEvalZero         res->app_status = BLE_HS_ENOENT;
1472*042d53a7SEvalZero     } else {
1473*042d53a7SEvalZero         memcpy(ble_sm_peer_pair_rand(proc), cmd->value, 16);
1474*042d53a7SEvalZero 
1475*042d53a7SEvalZero         if (proc->flags & BLE_SM_PROC_F_SC) {
1476*042d53a7SEvalZero             ble_sm_sc_random_rx(proc, res);
1477*042d53a7SEvalZero         } else {
1478*042d53a7SEvalZero             ble_sm_lgcy_random_rx(proc, res);
1479*042d53a7SEvalZero         }
1480*042d53a7SEvalZero     }
1481*042d53a7SEvalZero     ble_hs_unlock();
1482*042d53a7SEvalZero }
1483*042d53a7SEvalZero 
1484*042d53a7SEvalZero /*****************************************************************************
1485*042d53a7SEvalZero  * $confirm                                                                  *
1486*042d53a7SEvalZero  *****************************************************************************/
1487*042d53a7SEvalZero 
1488*042d53a7SEvalZero static void
ble_sm_confirm_exec(struct ble_sm_proc * proc,struct ble_sm_result * res,void * arg)1489*042d53a7SEvalZero ble_sm_confirm_exec(struct ble_sm_proc *proc, struct ble_sm_result *res,
1490*042d53a7SEvalZero                     void *arg)
1491*042d53a7SEvalZero {
1492*042d53a7SEvalZero     if (!(proc->flags & BLE_SM_PROC_F_SC)) {
1493*042d53a7SEvalZero         ble_sm_lgcy_confirm_exec(proc, res);
1494*042d53a7SEvalZero     } else {
1495*042d53a7SEvalZero         ble_sm_sc_confirm_exec(proc, res);
1496*042d53a7SEvalZero     }
1497*042d53a7SEvalZero }
1498*042d53a7SEvalZero 
1499*042d53a7SEvalZero static void
ble_sm_confirm_rx(uint16_t conn_handle,struct os_mbuf ** om,struct ble_sm_result * res)1500*042d53a7SEvalZero ble_sm_confirm_rx(uint16_t conn_handle, struct os_mbuf **om,
1501*042d53a7SEvalZero                   struct ble_sm_result *res)
1502*042d53a7SEvalZero {
1503*042d53a7SEvalZero     struct ble_sm_pair_confirm *cmd;
1504*042d53a7SEvalZero     struct ble_sm_proc *proc;
1505*042d53a7SEvalZero     uint8_t ioact;
1506*042d53a7SEvalZero 
1507*042d53a7SEvalZero     res->app_status = ble_hs_mbuf_pullup_base(om, sizeof(*cmd));
1508*042d53a7SEvalZero     if (res->app_status != 0) {
1509*042d53a7SEvalZero         res->sm_err = BLE_SM_ERR_UNSPECIFIED;
1510*042d53a7SEvalZero         res->enc_cb = 1;
1511*042d53a7SEvalZero         return;
1512*042d53a7SEvalZero     }
1513*042d53a7SEvalZero 
1514*042d53a7SEvalZero     cmd = (struct ble_sm_pair_confirm *)(*om)->om_data;
1515*042d53a7SEvalZero 
1516*042d53a7SEvalZero     BLE_SM_LOG_CMD(0, "confirm", conn_handle, ble_sm_pair_confirm_log, cmd);
1517*042d53a7SEvalZero 
1518*042d53a7SEvalZero     ble_hs_lock();
1519*042d53a7SEvalZero     proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_CONFIRM, -1, NULL);
1520*042d53a7SEvalZero     if (proc == NULL) {
1521*042d53a7SEvalZero         res->app_status = BLE_HS_ENOENT;
1522*042d53a7SEvalZero     } else {
1523*042d53a7SEvalZero         memcpy(proc->confirm_peer, cmd->value, 16);
1524*042d53a7SEvalZero 
1525*042d53a7SEvalZero         if (proc->flags & BLE_SM_PROC_F_INITIATOR) {
1526*042d53a7SEvalZero             proc->state = BLE_SM_PROC_STATE_RANDOM;
1527*042d53a7SEvalZero             res->execute = 1;
1528*042d53a7SEvalZero         } else {
1529*042d53a7SEvalZero             int rc;
1530*042d53a7SEvalZero 
1531*042d53a7SEvalZero             rc = ble_sm_io_action(proc, &ioact);
1532*042d53a7SEvalZero             if (rc != 0) {
1533*042d53a7SEvalZero                 BLE_HS_DBG_ASSERT(0);
1534*042d53a7SEvalZero             }
1535*042d53a7SEvalZero 
1536*042d53a7SEvalZero             if (ble_sm_ioact_state(ioact) == proc->state) {
1537*042d53a7SEvalZero                 proc->flags |= BLE_SM_PROC_F_ADVANCE_ON_IO;
1538*042d53a7SEvalZero             }
1539*042d53a7SEvalZero             if (ble_sm_proc_can_advance(proc)) {
1540*042d53a7SEvalZero                 res->execute = 1;
1541*042d53a7SEvalZero             }
1542*042d53a7SEvalZero         }
1543*042d53a7SEvalZero     }
1544*042d53a7SEvalZero     ble_hs_unlock();
1545*042d53a7SEvalZero }
1546*042d53a7SEvalZero 
1547*042d53a7SEvalZero /*****************************************************************************
1548*042d53a7SEvalZero  * $pair                                                                     *
1549*042d53a7SEvalZero  *****************************************************************************/
1550*042d53a7SEvalZero 
1551*042d53a7SEvalZero static uint8_t
ble_sm_state_after_pair(struct ble_sm_proc * proc)1552*042d53a7SEvalZero ble_sm_state_after_pair(struct ble_sm_proc *proc)
1553*042d53a7SEvalZero {
1554*042d53a7SEvalZero     if (proc->flags & BLE_SM_PROC_F_SC) {
1555*042d53a7SEvalZero         return BLE_SM_PROC_STATE_PUBLIC_KEY;
1556*042d53a7SEvalZero     } else {
1557*042d53a7SEvalZero         return BLE_SM_PROC_STATE_CONFIRM;
1558*042d53a7SEvalZero     }
1559*042d53a7SEvalZero }
1560*042d53a7SEvalZero 
1561*042d53a7SEvalZero static void
ble_sm_pair_cfg(struct ble_sm_proc * proc)1562*042d53a7SEvalZero ble_sm_pair_cfg(struct ble_sm_proc *proc)
1563*042d53a7SEvalZero {
1564*042d53a7SEvalZero     struct ble_sm_pair_cmd *pair_req, *pair_rsp;
1565*042d53a7SEvalZero     uint8_t init_key_dist;
1566*042d53a7SEvalZero     uint8_t resp_key_dist;
1567*042d53a7SEvalZero     uint8_t rx_key_dist;
1568*042d53a7SEvalZero     uint8_t ioact;
1569*042d53a7SEvalZero     int rc;
1570*042d53a7SEvalZero 
1571*042d53a7SEvalZero     pair_req = (struct ble_sm_pair_cmd *) &proc->pair_req[1];
1572*042d53a7SEvalZero     pair_rsp = (struct ble_sm_pair_cmd *) &proc->pair_rsp[1];
1573*042d53a7SEvalZero 
1574*042d53a7SEvalZero     if (pair_req->authreq & BLE_SM_PAIR_AUTHREQ_SC &&
1575*042d53a7SEvalZero         pair_rsp->authreq & BLE_SM_PAIR_AUTHREQ_SC) {
1576*042d53a7SEvalZero 
1577*042d53a7SEvalZero         proc->flags |= BLE_SM_PROC_F_SC;
1578*042d53a7SEvalZero     }
1579*042d53a7SEvalZero 
1580*042d53a7SEvalZero     ble_sm_key_dist(proc, &init_key_dist, &resp_key_dist);
1581*042d53a7SEvalZero     if (proc->flags & BLE_SM_PROC_F_INITIATOR) {
1582*042d53a7SEvalZero         rx_key_dist = resp_key_dist;
1583*042d53a7SEvalZero     } else {
1584*042d53a7SEvalZero         rx_key_dist = init_key_dist;
1585*042d53a7SEvalZero     }
1586*042d53a7SEvalZero 
1587*042d53a7SEvalZero     if (pair_req->authreq & BLE_SM_PAIR_AUTHREQ_BOND &&
1588*042d53a7SEvalZero         pair_rsp->authreq & BLE_SM_PAIR_AUTHREQ_BOND) {
1589*042d53a7SEvalZero 
1590*042d53a7SEvalZero         proc->flags |= BLE_SM_PROC_F_BONDING;
1591*042d53a7SEvalZero     }
1592*042d53a7SEvalZero 
1593*042d53a7SEvalZero     /* In legacy mode, bonding requires the exchange of keys.  If no key
1594*042d53a7SEvalZero      * exchange was specified, pretend bonding is not enabled.
1595*042d53a7SEvalZero      */
1596*042d53a7SEvalZero     if (!(proc->flags & BLE_SM_PROC_F_SC) &&
1597*042d53a7SEvalZero         (init_key_dist == 0 || resp_key_dist == 0)) {
1598*042d53a7SEvalZero 
1599*042d53a7SEvalZero         proc->flags &= ~BLE_SM_PROC_F_BONDING;
1600*042d53a7SEvalZero     }
1601*042d53a7SEvalZero 
1602*042d53a7SEvalZero     proc->rx_key_flags = 0;
1603*042d53a7SEvalZero     if (rx_key_dist & BLE_SM_PAIR_KEY_DIST_ENC) {
1604*042d53a7SEvalZero         proc->rx_key_flags |= BLE_SM_KE_F_ENC_INFO |
1605*042d53a7SEvalZero                               BLE_SM_KE_F_MASTER_ID;
1606*042d53a7SEvalZero     }
1607*042d53a7SEvalZero     if (rx_key_dist & BLE_SM_PAIR_KEY_DIST_ID) {
1608*042d53a7SEvalZero         proc->rx_key_flags |= BLE_SM_KE_F_ID_INFO |
1609*042d53a7SEvalZero                               BLE_SM_KE_F_ADDR_INFO;
1610*042d53a7SEvalZero     }
1611*042d53a7SEvalZero     if (rx_key_dist & BLE_SM_PAIR_KEY_DIST_SIGN) {
1612*042d53a7SEvalZero         proc->rx_key_flags |= BLE_SM_KE_F_SIGN_INFO;
1613*042d53a7SEvalZero     }
1614*042d53a7SEvalZero 
1615*042d53a7SEvalZero     proc->key_size = min(pair_req->max_enc_key_size,
1616*042d53a7SEvalZero                          pair_rsp->max_enc_key_size);
1617*042d53a7SEvalZero 
1618*042d53a7SEvalZero     rc = ble_sm_io_action(proc, &ioact);
1619*042d53a7SEvalZero     BLE_HS_DBG_ASSERT_EVAL(rc == 0);
1620*042d53a7SEvalZero }
1621*042d53a7SEvalZero 
1622*042d53a7SEvalZero static void
ble_sm_pair_base_fill(struct ble_sm_pair_cmd * cmd)1623*042d53a7SEvalZero ble_sm_pair_base_fill(struct ble_sm_pair_cmd *cmd)
1624*042d53a7SEvalZero {
1625*042d53a7SEvalZero     cmd->io_cap = ble_hs_cfg.sm_io_cap;
1626*042d53a7SEvalZero     cmd->oob_data_flag = ble_hs_cfg.sm_oob_data_flag;
1627*042d53a7SEvalZero     cmd->authreq = ble_sm_build_authreq();
1628*042d53a7SEvalZero     cmd->max_enc_key_size = BLE_SM_PAIR_KEY_SZ_MAX;
1629*042d53a7SEvalZero }
1630*042d53a7SEvalZero 
1631*042d53a7SEvalZero static void
ble_sm_pair_req_fill(struct ble_sm_proc * proc)1632*042d53a7SEvalZero ble_sm_pair_req_fill(struct ble_sm_proc *proc)
1633*042d53a7SEvalZero {
1634*042d53a7SEvalZero     struct ble_sm_pair_cmd *req;
1635*042d53a7SEvalZero 
1636*042d53a7SEvalZero     req = (void *)(proc->pair_req + 1);
1637*042d53a7SEvalZero 
1638*042d53a7SEvalZero     proc->pair_req[0] = BLE_SM_OP_PAIR_REQ;
1639*042d53a7SEvalZero     ble_sm_pair_base_fill(req);
1640*042d53a7SEvalZero     req->init_key_dist = ble_hs_cfg.sm_our_key_dist;
1641*042d53a7SEvalZero     req->resp_key_dist = ble_hs_cfg.sm_their_key_dist;
1642*042d53a7SEvalZero }
1643*042d53a7SEvalZero 
1644*042d53a7SEvalZero static void
ble_sm_pair_rsp_fill(struct ble_sm_proc * proc)1645*042d53a7SEvalZero ble_sm_pair_rsp_fill(struct ble_sm_proc *proc)
1646*042d53a7SEvalZero {
1647*042d53a7SEvalZero     const struct ble_sm_pair_cmd *req;
1648*042d53a7SEvalZero     struct ble_sm_pair_cmd *rsp;
1649*042d53a7SEvalZero 
1650*042d53a7SEvalZero     req = (void *)(proc->pair_req + 1);
1651*042d53a7SEvalZero     rsp = (void *)(proc->pair_rsp + 1);
1652*042d53a7SEvalZero 
1653*042d53a7SEvalZero     proc->pair_rsp[0] = BLE_SM_OP_PAIR_RSP;
1654*042d53a7SEvalZero     ble_sm_pair_base_fill(rsp);
1655*042d53a7SEvalZero 
1656*042d53a7SEvalZero     /* The response's key distribution flags field is the intersection of
1657*042d53a7SEvalZero      * the peer's preferences and our capabilities.
1658*042d53a7SEvalZero      */
1659*042d53a7SEvalZero     rsp->init_key_dist = req->init_key_dist &
1660*042d53a7SEvalZero                          ble_hs_cfg.sm_their_key_dist;
1661*042d53a7SEvalZero     rsp->resp_key_dist = req->resp_key_dist &
1662*042d53a7SEvalZero                          ble_hs_cfg.sm_our_key_dist;
1663*042d53a7SEvalZero }
1664*042d53a7SEvalZero 
1665*042d53a7SEvalZero static void
ble_sm_pair_exec(struct ble_sm_proc * proc,struct ble_sm_result * res,void * arg)1666*042d53a7SEvalZero ble_sm_pair_exec(struct ble_sm_proc *proc, struct ble_sm_result *res,
1667*042d53a7SEvalZero                  void *arg)
1668*042d53a7SEvalZero {
1669*042d53a7SEvalZero     struct ble_sm_pair_cmd *cmd;
1670*042d53a7SEvalZero     struct os_mbuf *txom;
1671*042d53a7SEvalZero     uint8_t ioact;
1672*042d53a7SEvalZero     int is_req;
1673*042d53a7SEvalZero     int rc;
1674*042d53a7SEvalZero 
1675*042d53a7SEvalZero     is_req = proc->flags & BLE_SM_PROC_F_INITIATOR;
1676*042d53a7SEvalZero 
1677*042d53a7SEvalZero     cmd = ble_sm_cmd_get(is_req ? BLE_SM_OP_PAIR_REQ : BLE_SM_OP_PAIR_RSP,
1678*042d53a7SEvalZero                          sizeof(*cmd), &txom);
1679*042d53a7SEvalZero     if (cmd == NULL) {
1680*042d53a7SEvalZero         rc = BLE_HS_ENOMEM;
1681*042d53a7SEvalZero         goto err;
1682*042d53a7SEvalZero     }
1683*042d53a7SEvalZero 
1684*042d53a7SEvalZero     if (is_req) {
1685*042d53a7SEvalZero         ble_sm_pair_req_fill(proc);
1686*042d53a7SEvalZero         memcpy(cmd, proc->pair_req + 1, sizeof(*cmd));
1687*042d53a7SEvalZero     } else {
1688*042d53a7SEvalZero         /* The response was already generated when we processed the incoming
1689*042d53a7SEvalZero          * request.
1690*042d53a7SEvalZero          */
1691*042d53a7SEvalZero         memcpy(cmd, proc->pair_rsp + 1, sizeof(*cmd));
1692*042d53a7SEvalZero 
1693*042d53a7SEvalZero         proc->state = ble_sm_state_after_pair(proc);
1694*042d53a7SEvalZero 
1695*042d53a7SEvalZero         rc = ble_sm_io_action(proc, &ioact);
1696*042d53a7SEvalZero         BLE_HS_DBG_ASSERT(rc == 0);
1697*042d53a7SEvalZero 
1698*042d53a7SEvalZero         if (ble_sm_ioact_state(ioact) == proc->state) {
1699*042d53a7SEvalZero             res->passkey_params.action = ioact;
1700*042d53a7SEvalZero         }
1701*042d53a7SEvalZero     }
1702*042d53a7SEvalZero 
1703*042d53a7SEvalZero     rc = ble_sm_tx(proc->conn_handle, txom);
1704*042d53a7SEvalZero     if (rc != 0) {
1705*042d53a7SEvalZero         goto err;
1706*042d53a7SEvalZero     }
1707*042d53a7SEvalZero 
1708*042d53a7SEvalZero     res->app_status = ble_sm_gen_pair_rand(ble_sm_our_pair_rand(proc));
1709*042d53a7SEvalZero     if (res->app_status != 0) {
1710*042d53a7SEvalZero         res->sm_err = BLE_SM_ERR_UNSPECIFIED;
1711*042d53a7SEvalZero         res->enc_cb = 1;
1712*042d53a7SEvalZero         return;
1713*042d53a7SEvalZero     }
1714*042d53a7SEvalZero 
1715*042d53a7SEvalZero     return;
1716*042d53a7SEvalZero 
1717*042d53a7SEvalZero err:
1718*042d53a7SEvalZero     res->app_status = rc;
1719*042d53a7SEvalZero 
1720*042d53a7SEvalZero     if (!is_req) {
1721*042d53a7SEvalZero         res->sm_err = BLE_SM_ERR_UNSPECIFIED;
1722*042d53a7SEvalZero     }
1723*042d53a7SEvalZero }
1724*042d53a7SEvalZero 
1725*042d53a7SEvalZero static void
ble_sm_pair_req_rx(uint16_t conn_handle,struct os_mbuf ** om,struct ble_sm_result * res)1726*042d53a7SEvalZero ble_sm_pair_req_rx(uint16_t conn_handle, struct os_mbuf **om,
1727*042d53a7SEvalZero                    struct ble_sm_result *res)
1728*042d53a7SEvalZero {
1729*042d53a7SEvalZero     struct ble_sm_pair_cmd *req;
1730*042d53a7SEvalZero     struct ble_sm_proc *proc;
1731*042d53a7SEvalZero     struct ble_sm_proc *prev;
1732*042d53a7SEvalZero     struct ble_hs_conn *conn;
1733*042d53a7SEvalZero     ble_sm_proc_flags proc_flags;
1734*042d53a7SEvalZero     uint8_t key_size;
1735*042d53a7SEvalZero     int rc;
1736*042d53a7SEvalZero 
1737*042d53a7SEvalZero     /* Silence spurious unused-variable warnings. */
1738*042d53a7SEvalZero     proc_flags = 0;
1739*042d53a7SEvalZero     key_size = 0;
1740*042d53a7SEvalZero 
1741*042d53a7SEvalZero     res->app_status = ble_hs_mbuf_pullup_base(om, sizeof(*req));
1742*042d53a7SEvalZero     if (res->app_status != 0) {
1743*042d53a7SEvalZero         return;
1744*042d53a7SEvalZero     }
1745*042d53a7SEvalZero 
1746*042d53a7SEvalZero     req = (struct ble_sm_pair_cmd *)(*om)->om_data;
1747*042d53a7SEvalZero 
1748*042d53a7SEvalZero     BLE_SM_LOG_CMD(0, "pair req", conn_handle, ble_sm_pair_cmd_log, req);
1749*042d53a7SEvalZero 
1750*042d53a7SEvalZero     ble_hs_lock();
1751*042d53a7SEvalZero 
1752*042d53a7SEvalZero     /* XXX: Check connection state; reject if not appropriate. */
1753*042d53a7SEvalZero     /* XXX: Ensure enough time has passed since the previous failed pairing
1754*042d53a7SEvalZero      * attempt.
1755*042d53a7SEvalZero      */
1756*042d53a7SEvalZero     proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_NONE, -1, &prev);
1757*042d53a7SEvalZero     if (proc != NULL) {
1758*042d53a7SEvalZero         /* Pairing already in progress; abort old procedure and start new. */
1759*042d53a7SEvalZero         /* XXX: Check the spec on this. */
1760*042d53a7SEvalZero         ble_sm_proc_remove(proc, prev);
1761*042d53a7SEvalZero         ble_sm_proc_free(proc);
1762*042d53a7SEvalZero     }
1763*042d53a7SEvalZero 
1764*042d53a7SEvalZero     ble_hs_unlock();
1765*042d53a7SEvalZero 
1766*042d53a7SEvalZero     /* Check if there is storage capacity for a new bond.  If there isn't, ask
1767*042d53a7SEvalZero      * the application to make room.
1768*042d53a7SEvalZero      */
1769*042d53a7SEvalZero     rc = ble_sm_chk_store_overflow(conn_handle);
1770*042d53a7SEvalZero     if (rc != 0) {
1771*042d53a7SEvalZero         res->sm_err = BLE_SM_ERR_UNSPECIFIED;
1772*042d53a7SEvalZero         res->app_status = rc;
1773*042d53a7SEvalZero         return;
1774*042d53a7SEvalZero     }
1775*042d53a7SEvalZero 
1776*042d53a7SEvalZero     ble_hs_lock();
1777*042d53a7SEvalZero 
1778*042d53a7SEvalZero     proc = ble_sm_proc_alloc();
1779*042d53a7SEvalZero     if (proc != NULL) {
1780*042d53a7SEvalZero         proc->conn_handle = conn_handle;
1781*042d53a7SEvalZero         proc->state = BLE_SM_PROC_STATE_PAIR;
1782*042d53a7SEvalZero         ble_sm_insert(proc);
1783*042d53a7SEvalZero 
1784*042d53a7SEvalZero         proc->pair_req[0] = BLE_SM_OP_PAIR_REQ;
1785*042d53a7SEvalZero         memcpy(proc->pair_req + 1, req, sizeof(*req));
1786*042d53a7SEvalZero 
1787*042d53a7SEvalZero         conn = ble_hs_conn_find_assert(proc->conn_handle);
1788*042d53a7SEvalZero         if (conn->bhc_flags & BLE_HS_CONN_F_MASTER) {
1789*042d53a7SEvalZero             res->sm_err = BLE_SM_ERR_CMD_NOT_SUPP;
1790*042d53a7SEvalZero             res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_CMD_NOT_SUPP);
1791*042d53a7SEvalZero         } else if (req->max_enc_key_size < BLE_SM_PAIR_KEY_SZ_MIN) {
1792*042d53a7SEvalZero             res->sm_err = BLE_SM_ERR_ENC_KEY_SZ;
1793*042d53a7SEvalZero             res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_ENC_KEY_SZ);
1794*042d53a7SEvalZero         } else if (req->max_enc_key_size > BLE_SM_PAIR_KEY_SZ_MAX) {
1795*042d53a7SEvalZero             res->sm_err = BLE_SM_ERR_INVAL;
1796*042d53a7SEvalZero             res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_INVAL);
1797*042d53a7SEvalZero         } else {
1798*042d53a7SEvalZero             /* The request looks good.  Precalculate our pairing response and
1799*042d53a7SEvalZero              * determine some properties of the imminent link.  We need this
1800*042d53a7SEvalZero              * information in case this is a repeated pairing attempt (i.e., we
1801*042d53a7SEvalZero              * are already bonded to this peer).  In that case, we include the
1802*042d53a7SEvalZero              * information in a notification to the app.
1803*042d53a7SEvalZero              */
1804*042d53a7SEvalZero             ble_sm_pair_rsp_fill(proc);
1805*042d53a7SEvalZero             ble_sm_pair_cfg(proc);
1806*042d53a7SEvalZero 
1807*042d53a7SEvalZero             proc_flags = proc->flags;
1808*042d53a7SEvalZero             key_size = proc->key_size;
1809*042d53a7SEvalZero             res->execute = 1;
1810*042d53a7SEvalZero         }
1811*042d53a7SEvalZero     }
1812*042d53a7SEvalZero 
1813*042d53a7SEvalZero     ble_hs_unlock();
1814*042d53a7SEvalZero 
1815*042d53a7SEvalZero     /* Check if we are already bonded to this peer.  If so, give the
1816*042d53a7SEvalZero      * application an opportunity to delete the old bond.
1817*042d53a7SEvalZero      */
1818*042d53a7SEvalZero     if (res->app_status == 0) {
1819*042d53a7SEvalZero         rc = ble_sm_chk_repeat_pairing(conn_handle, proc_flags, key_size);
1820*042d53a7SEvalZero         if (rc != 0) {
1821*042d53a7SEvalZero             /* The app indicated that the pairing request should be ignored. */
1822*042d53a7SEvalZero             res->app_status = rc;
1823*042d53a7SEvalZero             res->execute = 0;
1824*042d53a7SEvalZero         }
1825*042d53a7SEvalZero     }
1826*042d53a7SEvalZero }
1827*042d53a7SEvalZero 
1828*042d53a7SEvalZero static void
ble_sm_pair_rsp_rx(uint16_t conn_handle,struct os_mbuf ** om,struct ble_sm_result * res)1829*042d53a7SEvalZero ble_sm_pair_rsp_rx(uint16_t conn_handle, struct os_mbuf **om,
1830*042d53a7SEvalZero                    struct ble_sm_result *res)
1831*042d53a7SEvalZero {
1832*042d53a7SEvalZero     struct ble_sm_pair_cmd *rsp;
1833*042d53a7SEvalZero     struct ble_sm_proc *proc;
1834*042d53a7SEvalZero     uint8_t ioact;
1835*042d53a7SEvalZero     int rc;
1836*042d53a7SEvalZero 
1837*042d53a7SEvalZero     res->app_status = ble_hs_mbuf_pullup_base(om, sizeof(*rsp));
1838*042d53a7SEvalZero     if (res->app_status != 0) {
1839*042d53a7SEvalZero         res->enc_cb = 1;
1840*042d53a7SEvalZero         return;
1841*042d53a7SEvalZero     }
1842*042d53a7SEvalZero 
1843*042d53a7SEvalZero     rsp = (struct ble_sm_pair_cmd *)(*om)->om_data;
1844*042d53a7SEvalZero 
1845*042d53a7SEvalZero     BLE_SM_LOG_CMD(0, "pair rsp", conn_handle, ble_sm_pair_cmd_log, rsp);
1846*042d53a7SEvalZero 
1847*042d53a7SEvalZero     ble_hs_lock();
1848*042d53a7SEvalZero     proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_PAIR, 1, NULL);
1849*042d53a7SEvalZero     if (proc != NULL) {
1850*042d53a7SEvalZero         proc->pair_rsp[0] = BLE_SM_OP_PAIR_RSP;
1851*042d53a7SEvalZero         memcpy(proc->pair_rsp + 1, rsp, sizeof(*rsp));
1852*042d53a7SEvalZero 
1853*042d53a7SEvalZero         if (rsp->max_enc_key_size < BLE_SM_PAIR_KEY_SZ_MIN) {
1854*042d53a7SEvalZero             res->sm_err = BLE_SM_ERR_ENC_KEY_SZ;
1855*042d53a7SEvalZero             res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_ENC_KEY_SZ);
1856*042d53a7SEvalZero         } else if (rsp->max_enc_key_size > BLE_SM_PAIR_KEY_SZ_MAX) {
1857*042d53a7SEvalZero             res->sm_err = BLE_SM_ERR_INVAL;
1858*042d53a7SEvalZero             res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_INVAL);
1859*042d53a7SEvalZero         } else {
1860*042d53a7SEvalZero             ble_sm_pair_cfg(proc);
1861*042d53a7SEvalZero 
1862*042d53a7SEvalZero             rc = ble_sm_io_action(proc, &ioact);
1863*042d53a7SEvalZero             if (rc != 0) {
1864*042d53a7SEvalZero                 res->sm_err = BLE_SM_ERR_AUTHREQ;
1865*042d53a7SEvalZero                 res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_AUTHREQ);
1866*042d53a7SEvalZero                 res->enc_cb = 1;
1867*042d53a7SEvalZero             } else {
1868*042d53a7SEvalZero                 proc->state = ble_sm_state_after_pair(proc);
1869*042d53a7SEvalZero                 if (ble_sm_ioact_state(ioact) == proc->state) {
1870*042d53a7SEvalZero                     res->passkey_params.action = ioact;
1871*042d53a7SEvalZero                 }
1872*042d53a7SEvalZero                 if (ble_sm_proc_can_advance(proc)) {
1873*042d53a7SEvalZero                     res->execute = 1;
1874*042d53a7SEvalZero                 }
1875*042d53a7SEvalZero             }
1876*042d53a7SEvalZero         }
1877*042d53a7SEvalZero     }
1878*042d53a7SEvalZero 
1879*042d53a7SEvalZero     ble_hs_unlock();
1880*042d53a7SEvalZero }
1881*042d53a7SEvalZero 
1882*042d53a7SEvalZero /*****************************************************************************
1883*042d53a7SEvalZero  * $security request                                                         *
1884*042d53a7SEvalZero  *****************************************************************************/
1885*042d53a7SEvalZero 
1886*042d53a7SEvalZero static void
ble_sm_sec_req_exec(struct ble_sm_proc * proc,struct ble_sm_result * res,void * arg)1887*042d53a7SEvalZero ble_sm_sec_req_exec(struct ble_sm_proc *proc, struct ble_sm_result *res,
1888*042d53a7SEvalZero                     void *arg)
1889*042d53a7SEvalZero {
1890*042d53a7SEvalZero     struct ble_sm_sec_req *cmd;
1891*042d53a7SEvalZero     struct os_mbuf *txom;
1892*042d53a7SEvalZero     int rc;
1893*042d53a7SEvalZero 
1894*042d53a7SEvalZero     cmd = ble_sm_cmd_get(BLE_SM_OP_SEC_REQ, sizeof(*cmd), &txom);
1895*042d53a7SEvalZero     if (!cmd) {
1896*042d53a7SEvalZero         res->app_status = BLE_HS_ENOMEM;
1897*042d53a7SEvalZero         return;
1898*042d53a7SEvalZero     }
1899*042d53a7SEvalZero 
1900*042d53a7SEvalZero     cmd->authreq = ble_sm_build_authreq();
1901*042d53a7SEvalZero     rc = ble_sm_tx(proc->conn_handle, txom);
1902*042d53a7SEvalZero     if (rc != 0) {
1903*042d53a7SEvalZero         res->app_status = rc;
1904*042d53a7SEvalZero         return;
1905*042d53a7SEvalZero     }
1906*042d53a7SEvalZero }
1907*042d53a7SEvalZero 
1908*042d53a7SEvalZero static void
ble_sm_sec_req_rx(uint16_t conn_handle,struct os_mbuf ** om,struct ble_sm_result * res)1909*042d53a7SEvalZero ble_sm_sec_req_rx(uint16_t conn_handle, struct os_mbuf **om,
1910*042d53a7SEvalZero                   struct ble_sm_result *res)
1911*042d53a7SEvalZero {
1912*042d53a7SEvalZero     struct ble_store_value_sec value_sec;
1913*042d53a7SEvalZero     struct ble_store_key_sec key_sec;
1914*042d53a7SEvalZero     struct ble_hs_conn_addrs addrs;
1915*042d53a7SEvalZero     struct ble_sm_sec_req *cmd;
1916*042d53a7SEvalZero     struct ble_hs_conn *conn;
1917*042d53a7SEvalZero     int authreq_mitm;
1918*042d53a7SEvalZero 
1919*042d53a7SEvalZero     res->app_status = ble_hs_mbuf_pullup_base(om, sizeof(*cmd));
1920*042d53a7SEvalZero     if (res->app_status != 0) {
1921*042d53a7SEvalZero         return;
1922*042d53a7SEvalZero     }
1923*042d53a7SEvalZero 
1924*042d53a7SEvalZero     cmd = (struct ble_sm_sec_req *)(*om)->om_data;
1925*042d53a7SEvalZero     BLE_SM_LOG_CMD(0, "sec req", conn_handle, ble_sm_sec_req_log, cmd);
1926*042d53a7SEvalZero 
1927*042d53a7SEvalZero     /* XXX: Reject if:
1928*042d53a7SEvalZero      *     o authreq-reserved flags set?
1929*042d53a7SEvalZero      */
1930*042d53a7SEvalZero 
1931*042d53a7SEvalZero     ble_hs_lock();
1932*042d53a7SEvalZero 
1933*042d53a7SEvalZero     conn = ble_hs_conn_find_assert(conn_handle);
1934*042d53a7SEvalZero     if (!(conn->bhc_flags & BLE_HS_CONN_F_MASTER)) {
1935*042d53a7SEvalZero         res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_CMD_NOT_SUPP);
1936*042d53a7SEvalZero         res->sm_err = BLE_SM_ERR_CMD_NOT_SUPP;
1937*042d53a7SEvalZero     } else {
1938*042d53a7SEvalZero         /* We will be querying the SM database for a key corresponding to the
1939*042d53a7SEvalZero          * sender; remember the sender's address while the connection list is
1940*042d53a7SEvalZero          * locked.
1941*042d53a7SEvalZero          */
1942*042d53a7SEvalZero         ble_hs_conn_addrs(conn, &addrs);
1943*042d53a7SEvalZero         memset(&key_sec, 0, sizeof key_sec);
1944*042d53a7SEvalZero         key_sec.peer_addr = addrs.peer_id_addr;
1945*042d53a7SEvalZero     }
1946*042d53a7SEvalZero 
1947*042d53a7SEvalZero     ble_hs_unlock();
1948*042d53a7SEvalZero 
1949*042d53a7SEvalZero     if (res->app_status == 0) {
1950*042d53a7SEvalZero         /* If the peer is requesting a bonded connection, query database for an
1951*042d53a7SEvalZero          * LTK corresponding to the sender.
1952*042d53a7SEvalZero          */
1953*042d53a7SEvalZero         if (cmd->authreq & BLE_SM_PAIR_AUTHREQ_BOND) {
1954*042d53a7SEvalZero             res->app_status = ble_store_read_peer_sec(&key_sec, &value_sec);
1955*042d53a7SEvalZero         } else {
1956*042d53a7SEvalZero             res->app_status = BLE_HS_ENOENT;
1957*042d53a7SEvalZero         }
1958*042d53a7SEvalZero         if (res->app_status == 0) {
1959*042d53a7SEvalZero             /* Found a key corresponding to this peer.  Make sure it meets the
1960*042d53a7SEvalZero              * requested minimum authreq.
1961*042d53a7SEvalZero              */
1962*042d53a7SEvalZero             authreq_mitm = cmd->authreq & BLE_SM_PAIR_AUTHREQ_MITM;
1963*042d53a7SEvalZero             if ((!authreq_mitm && value_sec.authenticated) ||
1964*042d53a7SEvalZero                 (authreq_mitm && !value_sec.authenticated)) {
1965*042d53a7SEvalZero 
1966*042d53a7SEvalZero                 res->app_status = BLE_HS_EREJECT;
1967*042d53a7SEvalZero             }
1968*042d53a7SEvalZero         }
1969*042d53a7SEvalZero 
1970*042d53a7SEvalZero         if (res->app_status == 0) {
1971*042d53a7SEvalZero             res->app_status = ble_sm_enc_initiate(conn_handle, value_sec.ltk,
1972*042d53a7SEvalZero                                                   value_sec.ediv,
1973*042d53a7SEvalZero                                                   value_sec.rand_num,
1974*042d53a7SEvalZero                                                   value_sec.authenticated);
1975*042d53a7SEvalZero         } else {
1976*042d53a7SEvalZero             res->app_status = ble_sm_pair_initiate(conn_handle);
1977*042d53a7SEvalZero         }
1978*042d53a7SEvalZero     }
1979*042d53a7SEvalZero }
1980*042d53a7SEvalZero 
1981*042d53a7SEvalZero /*****************************************************************************
1982*042d53a7SEvalZero  * $key exchange                                                             *
1983*042d53a7SEvalZero  *****************************************************************************/
1984*042d53a7SEvalZero 
1985*042d53a7SEvalZero static void
ble_sm_key_exch_success(struct ble_sm_proc * proc,struct ble_sm_result * res)1986*042d53a7SEvalZero ble_sm_key_exch_success(struct ble_sm_proc *proc, struct ble_sm_result *res)
1987*042d53a7SEvalZero {
1988*042d53a7SEvalZero     /* The procedure is now complete.  Update connection bonded state and
1989*042d53a7SEvalZero      * terminate procedure.
1990*042d53a7SEvalZero      */
1991*042d53a7SEvalZero     ble_sm_update_sec_state(proc->conn_handle, 1, 0, 1, proc->key_size);
1992*042d53a7SEvalZero     proc->state = BLE_SM_PROC_STATE_NONE;
1993*042d53a7SEvalZero 
1994*042d53a7SEvalZero     res->app_status = 0;
1995*042d53a7SEvalZero     res->enc_cb = 1;
1996*042d53a7SEvalZero }
1997*042d53a7SEvalZero 
1998*042d53a7SEvalZero static void
ble_sm_key_exch_exec(struct ble_sm_proc * proc,struct ble_sm_result * res,void * arg)1999*042d53a7SEvalZero ble_sm_key_exch_exec(struct ble_sm_proc *proc, struct ble_sm_result *res,
2000*042d53a7SEvalZero                      void *arg)
2001*042d53a7SEvalZero {
2002*042d53a7SEvalZero     struct ble_sm_id_addr_info *addr_info;
2003*042d53a7SEvalZero     struct ble_hs_conn_addrs addrs;
2004*042d53a7SEvalZero     struct ble_sm_sign_info *sign_info;
2005*042d53a7SEvalZero     struct ble_sm_master_id *master_id;
2006*042d53a7SEvalZero     struct ble_sm_enc_info *enc_info;
2007*042d53a7SEvalZero     struct ble_sm_id_info *id_info;
2008*042d53a7SEvalZero     struct ble_hs_conn *conn;
2009*042d53a7SEvalZero     uint8_t init_key_dist;
2010*042d53a7SEvalZero     uint8_t resp_key_dist;
2011*042d53a7SEvalZero     uint8_t our_key_dist;
2012*042d53a7SEvalZero     struct os_mbuf *txom;
2013*042d53a7SEvalZero     const uint8_t *irk;
2014*042d53a7SEvalZero     int rc;
2015*042d53a7SEvalZero 
2016*042d53a7SEvalZero     ble_sm_key_dist(proc, &init_key_dist, &resp_key_dist);
2017*042d53a7SEvalZero     if (proc->flags & BLE_SM_PROC_F_INITIATOR) {
2018*042d53a7SEvalZero         our_key_dist = init_key_dist;
2019*042d53a7SEvalZero     } else {
2020*042d53a7SEvalZero         our_key_dist = resp_key_dist;
2021*042d53a7SEvalZero     }
2022*042d53a7SEvalZero 
2023*042d53a7SEvalZero     if (our_key_dist & BLE_SM_PAIR_KEY_DIST_ENC) {
2024*042d53a7SEvalZero         /* Send encryption information. */
2025*042d53a7SEvalZero         enc_info = ble_sm_cmd_get(BLE_SM_OP_ENC_INFO, sizeof(*enc_info), &txom);
2026*042d53a7SEvalZero         if (!enc_info) {
2027*042d53a7SEvalZero             rc = BLE_HS_ENOMEM;
2028*042d53a7SEvalZero             goto err;
2029*042d53a7SEvalZero         }
2030*042d53a7SEvalZero 
2031*042d53a7SEvalZero         rc = ble_sm_gen_ltk(proc, enc_info->ltk);
2032*042d53a7SEvalZero         if (rc != 0) {
2033*042d53a7SEvalZero             os_mbuf_free_chain(txom);
2034*042d53a7SEvalZero             goto err;
2035*042d53a7SEvalZero         }
2036*042d53a7SEvalZero 
2037*042d53a7SEvalZero         /* store LTK before sending since ble_sm_tx consumes tx mbuf */
2038*042d53a7SEvalZero         memcpy(proc->our_keys.ltk, enc_info->ltk, 16);
2039*042d53a7SEvalZero         proc->our_keys.ltk_valid = 1;
2040*042d53a7SEvalZero 
2041*042d53a7SEvalZero         rc = ble_sm_tx(proc->conn_handle, txom);
2042*042d53a7SEvalZero         if (rc != 0) {
2043*042d53a7SEvalZero             goto err;
2044*042d53a7SEvalZero         }
2045*042d53a7SEvalZero 
2046*042d53a7SEvalZero         /* Send master identification. */
2047*042d53a7SEvalZero         master_id = ble_sm_cmd_get(BLE_SM_OP_MASTER_ID, sizeof(*master_id),
2048*042d53a7SEvalZero                                    &txom);
2049*042d53a7SEvalZero         if (!master_id) {
2050*042d53a7SEvalZero             rc = BLE_HS_ENOMEM;
2051*042d53a7SEvalZero             goto err;
2052*042d53a7SEvalZero         }
2053*042d53a7SEvalZero 
2054*042d53a7SEvalZero         rc = ble_sm_gen_ediv(master_id);
2055*042d53a7SEvalZero         if (rc != 0) {
2056*042d53a7SEvalZero             os_mbuf_free_chain(txom);
2057*042d53a7SEvalZero             goto err;
2058*042d53a7SEvalZero         }
2059*042d53a7SEvalZero         rc = ble_sm_gen_master_id_rand(master_id);
2060*042d53a7SEvalZero         if (rc != 0) {
2061*042d53a7SEvalZero             os_mbuf_free_chain(txom);
2062*042d53a7SEvalZero             goto err;
2063*042d53a7SEvalZero         }
2064*042d53a7SEvalZero 
2065*042d53a7SEvalZero         proc->our_keys.ediv_rand_valid = 1;
2066*042d53a7SEvalZero         proc->our_keys.rand_val = master_id->rand_val;
2067*042d53a7SEvalZero         proc->our_keys.ediv = master_id->ediv;
2068*042d53a7SEvalZero 
2069*042d53a7SEvalZero         rc = ble_sm_tx(proc->conn_handle, txom);
2070*042d53a7SEvalZero         if (rc != 0) {
2071*042d53a7SEvalZero             goto err;
2072*042d53a7SEvalZero         }
2073*042d53a7SEvalZero     }
2074*042d53a7SEvalZero 
2075*042d53a7SEvalZero     if (our_key_dist & BLE_SM_PAIR_KEY_DIST_ID) {
2076*042d53a7SEvalZero         /* Send identity information. */
2077*042d53a7SEvalZero         id_info = ble_sm_cmd_get(BLE_SM_OP_IDENTITY_INFO, sizeof(*id_info),
2078*042d53a7SEvalZero                                  &txom);
2079*042d53a7SEvalZero         if (!id_info) {
2080*042d53a7SEvalZero             rc = BLE_HS_ENOMEM;
2081*042d53a7SEvalZero             goto err;
2082*042d53a7SEvalZero         }
2083*042d53a7SEvalZero 
2084*042d53a7SEvalZero         rc = ble_hs_pvcy_our_irk(&irk);
2085*042d53a7SEvalZero         if (rc != 0) {
2086*042d53a7SEvalZero             os_mbuf_free_chain(txom);
2087*042d53a7SEvalZero             goto err;
2088*042d53a7SEvalZero         }
2089*042d53a7SEvalZero 
2090*042d53a7SEvalZero         memcpy(id_info->irk, irk, 16);
2091*042d53a7SEvalZero         proc->our_keys.irk_valid = 1;
2092*042d53a7SEvalZero 
2093*042d53a7SEvalZero         rc = ble_sm_tx(proc->conn_handle, txom);
2094*042d53a7SEvalZero         if (rc != 0) {
2095*042d53a7SEvalZero             goto err;
2096*042d53a7SEvalZero         }
2097*042d53a7SEvalZero 
2098*042d53a7SEvalZero         /* Send identity address information. */
2099*042d53a7SEvalZero         addr_info = ble_sm_cmd_get(BLE_SM_OP_IDENTITY_ADDR_INFO,
2100*042d53a7SEvalZero                                    sizeof(*addr_info), &txom);
2101*042d53a7SEvalZero         if (!addr_info) {
2102*042d53a7SEvalZero             rc = BLE_HS_ENOMEM;
2103*042d53a7SEvalZero             goto err;
2104*042d53a7SEvalZero         }
2105*042d53a7SEvalZero 
2106*042d53a7SEvalZero         conn = ble_hs_conn_find_assert(proc->conn_handle);
2107*042d53a7SEvalZero         ble_hs_conn_addrs(conn, &addrs);
2108*042d53a7SEvalZero 
2109*042d53a7SEvalZero         addr_info->addr_type = addrs.our_id_addr.type;
2110*042d53a7SEvalZero         memcpy(addr_info->bd_addr, addrs.our_id_addr.val, 6);
2111*042d53a7SEvalZero 
2112*042d53a7SEvalZero         proc->our_keys.addr_valid = 1;
2113*042d53a7SEvalZero         memcpy(proc->our_keys.irk, irk, 16);
2114*042d53a7SEvalZero         proc->our_keys.addr_type = addr_info->addr_type;
2115*042d53a7SEvalZero         memcpy(proc->our_keys.addr, addr_info->bd_addr, 6);
2116*042d53a7SEvalZero 
2117*042d53a7SEvalZero         rc = ble_sm_tx(proc->conn_handle, txom);
2118*042d53a7SEvalZero         if (rc != 0) {
2119*042d53a7SEvalZero             goto err;
2120*042d53a7SEvalZero         }
2121*042d53a7SEvalZero     }
2122*042d53a7SEvalZero 
2123*042d53a7SEvalZero     if (our_key_dist & BLE_SM_PAIR_KEY_DIST_SIGN) {
2124*042d53a7SEvalZero         /* Send signing information. */
2125*042d53a7SEvalZero         sign_info = ble_sm_cmd_get(BLE_SM_OP_SIGN_INFO, sizeof(*sign_info),
2126*042d53a7SEvalZero                                    &txom);
2127*042d53a7SEvalZero         if (!sign_info) {
2128*042d53a7SEvalZero             rc = BLE_HS_ENOMEM;
2129*042d53a7SEvalZero             goto err;
2130*042d53a7SEvalZero         }
2131*042d53a7SEvalZero 
2132*042d53a7SEvalZero         rc = ble_sm_gen_csrk(proc, sign_info->sig_key);
2133*042d53a7SEvalZero         if (rc != 0) {
2134*042d53a7SEvalZero             os_mbuf_free_chain(txom);
2135*042d53a7SEvalZero             goto err;
2136*042d53a7SEvalZero         }
2137*042d53a7SEvalZero 
2138*042d53a7SEvalZero         proc->our_keys.csrk_valid = 1;
2139*042d53a7SEvalZero         memcpy(proc->our_keys.csrk, sign_info->sig_key, 16);
2140*042d53a7SEvalZero 
2141*042d53a7SEvalZero         rc = ble_sm_tx(proc->conn_handle, txom);
2142*042d53a7SEvalZero         if (rc != 0) {
2143*042d53a7SEvalZero             goto err;
2144*042d53a7SEvalZero         }
2145*042d53a7SEvalZero     }
2146*042d53a7SEvalZero 
2147*042d53a7SEvalZero     if (proc->flags & BLE_SM_PROC_F_INITIATOR || proc->rx_key_flags == 0) {
2148*042d53a7SEvalZero         /* The procedure is now complete. */
2149*042d53a7SEvalZero         ble_sm_key_exch_success(proc, res);
2150*042d53a7SEvalZero     }
2151*042d53a7SEvalZero 
2152*042d53a7SEvalZero     return;
2153*042d53a7SEvalZero 
2154*042d53a7SEvalZero err:
2155*042d53a7SEvalZero     res->app_status = rc;
2156*042d53a7SEvalZero     res->sm_err = BLE_SM_ERR_UNSPECIFIED;
2157*042d53a7SEvalZero     res->enc_cb = 1;
2158*042d53a7SEvalZero }
2159*042d53a7SEvalZero 
2160*042d53a7SEvalZero static void
ble_sm_key_rxed(struct ble_sm_proc * proc,struct ble_sm_result * res)2161*042d53a7SEvalZero ble_sm_key_rxed(struct ble_sm_proc *proc, struct ble_sm_result *res)
2162*042d53a7SEvalZero {
2163*042d53a7SEvalZero     BLE_HS_LOG(DEBUG, "rx_key_flags=0x%02x\n", proc->rx_key_flags);
2164*042d53a7SEvalZero 
2165*042d53a7SEvalZero     if (proc->rx_key_flags == 0) {
2166*042d53a7SEvalZero         /* The peer is done sending keys.  If we are the initiator, we need to
2167*042d53a7SEvalZero          * send ours.  If we are the responder, the procedure is complete.
2168*042d53a7SEvalZero          */
2169*042d53a7SEvalZero         if (proc->flags & BLE_SM_PROC_F_INITIATOR) {
2170*042d53a7SEvalZero             res->execute = 1;
2171*042d53a7SEvalZero         } else {
2172*042d53a7SEvalZero             ble_sm_key_exch_success(proc, res);
2173*042d53a7SEvalZero         }
2174*042d53a7SEvalZero     }
2175*042d53a7SEvalZero }
2176*042d53a7SEvalZero 
2177*042d53a7SEvalZero static void
ble_sm_enc_info_rx(uint16_t conn_handle,struct os_mbuf ** om,struct ble_sm_result * res)2178*042d53a7SEvalZero ble_sm_enc_info_rx(uint16_t conn_handle, struct os_mbuf **om,
2179*042d53a7SEvalZero                    struct ble_sm_result *res)
2180*042d53a7SEvalZero {
2181*042d53a7SEvalZero     struct ble_sm_enc_info *cmd;
2182*042d53a7SEvalZero     struct ble_sm_proc *proc;
2183*042d53a7SEvalZero 
2184*042d53a7SEvalZero     res->app_status = ble_hs_mbuf_pullup_base(om, sizeof(*cmd));
2185*042d53a7SEvalZero     if (res->app_status != 0) {
2186*042d53a7SEvalZero         res->sm_err = BLE_SM_ERR_UNSPECIFIED;
2187*042d53a7SEvalZero         res->enc_cb = 1;
2188*042d53a7SEvalZero         return;
2189*042d53a7SEvalZero     }
2190*042d53a7SEvalZero 
2191*042d53a7SEvalZero     cmd = (struct ble_sm_enc_info *)(*om)->om_data;
2192*042d53a7SEvalZero     BLE_SM_LOG_CMD(0, "enc info", conn_handle, ble_sm_enc_info_log, cmd);
2193*042d53a7SEvalZero 
2194*042d53a7SEvalZero     ble_hs_lock();
2195*042d53a7SEvalZero 
2196*042d53a7SEvalZero     proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_KEY_EXCH, -1, NULL);
2197*042d53a7SEvalZero     if (proc == NULL) {
2198*042d53a7SEvalZero         res->app_status = BLE_HS_ENOENT;
2199*042d53a7SEvalZero         res->sm_err = BLE_SM_ERR_UNSPECIFIED;
2200*042d53a7SEvalZero     } else {
2201*042d53a7SEvalZero         proc->rx_key_flags &= ~BLE_SM_KE_F_ENC_INFO;
2202*042d53a7SEvalZero         proc->peer_keys.ltk_valid = 1;
2203*042d53a7SEvalZero         memcpy(proc->peer_keys.ltk, cmd->ltk, 16);
2204*042d53a7SEvalZero 
2205*042d53a7SEvalZero         ble_sm_key_rxed(proc, res);
2206*042d53a7SEvalZero     }
2207*042d53a7SEvalZero 
2208*042d53a7SEvalZero     ble_hs_unlock();
2209*042d53a7SEvalZero }
2210*042d53a7SEvalZero 
2211*042d53a7SEvalZero static void
ble_sm_master_id_rx(uint16_t conn_handle,struct os_mbuf ** om,struct ble_sm_result * res)2212*042d53a7SEvalZero ble_sm_master_id_rx(uint16_t conn_handle, struct os_mbuf **om,
2213*042d53a7SEvalZero                     struct ble_sm_result *res)
2214*042d53a7SEvalZero {
2215*042d53a7SEvalZero     struct ble_sm_master_id *cmd;
2216*042d53a7SEvalZero     struct ble_sm_proc *proc;
2217*042d53a7SEvalZero 
2218*042d53a7SEvalZero     res->app_status = ble_hs_mbuf_pullup_base(om, sizeof(*cmd));
2219*042d53a7SEvalZero     if (res->app_status != 0) {
2220*042d53a7SEvalZero         res->sm_err = BLE_SM_ERR_UNSPECIFIED;
2221*042d53a7SEvalZero         res->enc_cb = 1;
2222*042d53a7SEvalZero         return;
2223*042d53a7SEvalZero     }
2224*042d53a7SEvalZero 
2225*042d53a7SEvalZero     cmd = (struct ble_sm_master_id *)(*om)->om_data;
2226*042d53a7SEvalZero     BLE_SM_LOG_CMD(0, "master id", conn_handle, ble_sm_master_id_log, cmd);
2227*042d53a7SEvalZero 
2228*042d53a7SEvalZero     ble_hs_lock();
2229*042d53a7SEvalZero 
2230*042d53a7SEvalZero     proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_KEY_EXCH, -1, NULL);
2231*042d53a7SEvalZero     if (proc == NULL) {
2232*042d53a7SEvalZero         res->app_status = BLE_HS_ENOENT;
2233*042d53a7SEvalZero         res->sm_err = BLE_SM_ERR_UNSPECIFIED;
2234*042d53a7SEvalZero     } else {
2235*042d53a7SEvalZero         proc->rx_key_flags &= ~BLE_SM_KE_F_MASTER_ID;
2236*042d53a7SEvalZero         proc->peer_keys.ediv_rand_valid = 1;
2237*042d53a7SEvalZero 
2238*042d53a7SEvalZero         proc->peer_keys.ediv = le16toh(cmd->ediv);
2239*042d53a7SEvalZero         proc->peer_keys.rand_val = le64toh(cmd->rand_val);
2240*042d53a7SEvalZero 
2241*042d53a7SEvalZero         ble_sm_key_rxed(proc, res);
2242*042d53a7SEvalZero     }
2243*042d53a7SEvalZero 
2244*042d53a7SEvalZero     ble_hs_unlock();
2245*042d53a7SEvalZero }
2246*042d53a7SEvalZero 
2247*042d53a7SEvalZero static void
ble_sm_id_info_rx(uint16_t conn_handle,struct os_mbuf ** om,struct ble_sm_result * res)2248*042d53a7SEvalZero ble_sm_id_info_rx(uint16_t conn_handle, struct os_mbuf **om,
2249*042d53a7SEvalZero                   struct ble_sm_result *res)
2250*042d53a7SEvalZero {
2251*042d53a7SEvalZero     struct ble_sm_id_info *cmd;
2252*042d53a7SEvalZero     struct ble_sm_proc *proc;
2253*042d53a7SEvalZero 
2254*042d53a7SEvalZero     res->app_status = ble_hs_mbuf_pullup_base(om, sizeof(*cmd));
2255*042d53a7SEvalZero     if (res->app_status != 0) {
2256*042d53a7SEvalZero         res->sm_err = BLE_SM_ERR_UNSPECIFIED;
2257*042d53a7SEvalZero         res->enc_cb = 1;
2258*042d53a7SEvalZero         return;
2259*042d53a7SEvalZero     }
2260*042d53a7SEvalZero 
2261*042d53a7SEvalZero     cmd = (struct ble_sm_id_info *)(*om)->om_data;
2262*042d53a7SEvalZero     BLE_SM_LOG_CMD(0, "id info", conn_handle, ble_sm_id_info_log, cmd);
2263*042d53a7SEvalZero 
2264*042d53a7SEvalZero     ble_hs_lock();
2265*042d53a7SEvalZero 
2266*042d53a7SEvalZero     proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_KEY_EXCH, -1, NULL);
2267*042d53a7SEvalZero     if (proc == NULL) {
2268*042d53a7SEvalZero         res->app_status = BLE_HS_ENOENT;
2269*042d53a7SEvalZero         res->sm_err = BLE_SM_ERR_UNSPECIFIED;
2270*042d53a7SEvalZero     } else {
2271*042d53a7SEvalZero         proc->rx_key_flags &= ~BLE_SM_KE_F_ID_INFO;
2272*042d53a7SEvalZero 
2273*042d53a7SEvalZero         memcpy(proc->peer_keys.irk, cmd->irk, 16);
2274*042d53a7SEvalZero         proc->peer_keys.irk_valid = 1;
2275*042d53a7SEvalZero 
2276*042d53a7SEvalZero         ble_sm_key_rxed(proc, res);
2277*042d53a7SEvalZero     }
2278*042d53a7SEvalZero 
2279*042d53a7SEvalZero     ble_hs_unlock();
2280*042d53a7SEvalZero }
2281*042d53a7SEvalZero 
2282*042d53a7SEvalZero static void
ble_sm_id_addr_info_rx(uint16_t conn_handle,struct os_mbuf ** om,struct ble_sm_result * res)2283*042d53a7SEvalZero ble_sm_id_addr_info_rx(uint16_t conn_handle, struct os_mbuf **om,
2284*042d53a7SEvalZero                        struct ble_sm_result *res)
2285*042d53a7SEvalZero {
2286*042d53a7SEvalZero     struct ble_sm_id_addr_info *cmd;
2287*042d53a7SEvalZero     struct ble_sm_proc *proc;
2288*042d53a7SEvalZero 
2289*042d53a7SEvalZero     res->app_status = ble_hs_mbuf_pullup_base(om, sizeof(*cmd));
2290*042d53a7SEvalZero     if (res->app_status != 0) {
2291*042d53a7SEvalZero         res->sm_err = BLE_SM_ERR_UNSPECIFIED;
2292*042d53a7SEvalZero         res->enc_cb = 1;
2293*042d53a7SEvalZero         return;
2294*042d53a7SEvalZero     }
2295*042d53a7SEvalZero 
2296*042d53a7SEvalZero     cmd = (struct ble_sm_id_addr_info *)(*om)->om_data;
2297*042d53a7SEvalZero     BLE_SM_LOG_CMD(0, "id addr info", conn_handle, ble_sm_id_addr_info_log,
2298*042d53a7SEvalZero                    cmd);
2299*042d53a7SEvalZero 
2300*042d53a7SEvalZero     ble_hs_lock();
2301*042d53a7SEvalZero 
2302*042d53a7SEvalZero     proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_KEY_EXCH, -1, NULL);
2303*042d53a7SEvalZero     if (proc == NULL) {
2304*042d53a7SEvalZero         res->app_status = BLE_HS_ENOENT;
2305*042d53a7SEvalZero         res->sm_err = BLE_SM_ERR_UNSPECIFIED;
2306*042d53a7SEvalZero     } else {
2307*042d53a7SEvalZero         proc->rx_key_flags &= ~BLE_SM_KE_F_ADDR_INFO;
2308*042d53a7SEvalZero         proc->peer_keys.addr_valid = 1;
2309*042d53a7SEvalZero         proc->peer_keys.addr_type = cmd->addr_type;
2310*042d53a7SEvalZero         memcpy(proc->peer_keys.addr, cmd->bd_addr, 6);
2311*042d53a7SEvalZero 
2312*042d53a7SEvalZero         ble_sm_key_rxed(proc, res);
2313*042d53a7SEvalZero     }
2314*042d53a7SEvalZero 
2315*042d53a7SEvalZero     ble_hs_unlock();
2316*042d53a7SEvalZero }
2317*042d53a7SEvalZero 
2318*042d53a7SEvalZero static void
ble_sm_sign_info_rx(uint16_t conn_handle,struct os_mbuf ** om,struct ble_sm_result * res)2319*042d53a7SEvalZero ble_sm_sign_info_rx(uint16_t conn_handle, struct os_mbuf **om,
2320*042d53a7SEvalZero                     struct ble_sm_result *res)
2321*042d53a7SEvalZero {
2322*042d53a7SEvalZero     struct ble_sm_sign_info *cmd;
2323*042d53a7SEvalZero     struct ble_sm_proc *proc;
2324*042d53a7SEvalZero 
2325*042d53a7SEvalZero     res->app_status = ble_hs_mbuf_pullup_base(om, sizeof(*cmd));
2326*042d53a7SEvalZero     if (res->app_status != 0) {
2327*042d53a7SEvalZero         res->sm_err = BLE_SM_ERR_UNSPECIFIED;
2328*042d53a7SEvalZero         res->enc_cb = 1;
2329*042d53a7SEvalZero         return;
2330*042d53a7SEvalZero     }
2331*042d53a7SEvalZero 
2332*042d53a7SEvalZero     cmd = (struct ble_sm_sign_info *)(*om)->om_data;
2333*042d53a7SEvalZero     BLE_SM_LOG_CMD(0, "sign info", conn_handle, ble_sm_sign_info_log, cmd);
2334*042d53a7SEvalZero 
2335*042d53a7SEvalZero     ble_hs_lock();
2336*042d53a7SEvalZero 
2337*042d53a7SEvalZero     proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_KEY_EXCH, -1, NULL);
2338*042d53a7SEvalZero     if (proc == NULL) {
2339*042d53a7SEvalZero         res->app_status = BLE_HS_ENOENT;
2340*042d53a7SEvalZero         res->sm_err = BLE_SM_ERR_UNSPECIFIED;
2341*042d53a7SEvalZero     } else {
2342*042d53a7SEvalZero         proc->rx_key_flags &= ~BLE_SM_KE_F_SIGN_INFO;
2343*042d53a7SEvalZero 
2344*042d53a7SEvalZero         memcpy(proc->peer_keys.csrk, cmd->sig_key, 16);
2345*042d53a7SEvalZero         proc->peer_keys.csrk_valid = 1;
2346*042d53a7SEvalZero 
2347*042d53a7SEvalZero         ble_sm_key_rxed(proc, res);
2348*042d53a7SEvalZero     }
2349*042d53a7SEvalZero 
2350*042d53a7SEvalZero     ble_hs_unlock();
2351*042d53a7SEvalZero }
2352*042d53a7SEvalZero 
2353*042d53a7SEvalZero /*****************************************************************************
2354*042d53a7SEvalZero  * $fail                                                                     *
2355*042d53a7SEvalZero  *****************************************************************************/
2356*042d53a7SEvalZero 
2357*042d53a7SEvalZero static void
ble_sm_fail_rx(uint16_t conn_handle,struct os_mbuf ** om,struct ble_sm_result * res)2358*042d53a7SEvalZero ble_sm_fail_rx(uint16_t conn_handle, struct os_mbuf **om,
2359*042d53a7SEvalZero                struct ble_sm_result *res)
2360*042d53a7SEvalZero {
2361*042d53a7SEvalZero     struct ble_sm_pair_fail *cmd;
2362*042d53a7SEvalZero 
2363*042d53a7SEvalZero     res->enc_cb = 1;
2364*042d53a7SEvalZero 
2365*042d53a7SEvalZero     res->app_status = ble_hs_mbuf_pullup_base(om, sizeof(*cmd));
2366*042d53a7SEvalZero     if (res->app_status == 0) {
2367*042d53a7SEvalZero         cmd = (struct ble_sm_pair_fail *)(*om)->om_data;
2368*042d53a7SEvalZero         BLE_SM_LOG_CMD(0, "fail", conn_handle, ble_sm_pair_fail_log, cmd);
2369*042d53a7SEvalZero 
2370*042d53a7SEvalZero         res->app_status = BLE_HS_SM_PEER_ERR(cmd->reason);
2371*042d53a7SEvalZero     }
2372*042d53a7SEvalZero }
2373*042d53a7SEvalZero 
2374*042d53a7SEvalZero /*****************************************************************************
2375*042d53a7SEvalZero  * $api                                                                      *
2376*042d53a7SEvalZero  *****************************************************************************/
2377*042d53a7SEvalZero 
2378*042d53a7SEvalZero /**
2379*042d53a7SEvalZero  * Times out expired SM procedures.
2380*042d53a7SEvalZero  *
2381*042d53a7SEvalZero  * @return                      The number of ticks until this function should
2382*042d53a7SEvalZero  *                                  be called again.
2383*042d53a7SEvalZero  */
2384*042d53a7SEvalZero int32_t
ble_sm_timer(void)2385*042d53a7SEvalZero ble_sm_timer(void)
2386*042d53a7SEvalZero {
2387*042d53a7SEvalZero     struct ble_sm_proc_list exp_list;
2388*042d53a7SEvalZero     struct ble_sm_proc *proc;
2389*042d53a7SEvalZero     int32_t ticks_until_exp;
2390*042d53a7SEvalZero 
2391*042d53a7SEvalZero     /* Remove timed-out procedures from the main list and insert them into a
2392*042d53a7SEvalZero      * temporary list.  This function also calculates the number of ticks until
2393*042d53a7SEvalZero      * the next expiration will occur.
2394*042d53a7SEvalZero      */
2395*042d53a7SEvalZero     ticks_until_exp = ble_sm_extract_expired(&exp_list);
2396*042d53a7SEvalZero 
2397*042d53a7SEvalZero     /* Notify application of each failure and free the corresponding procedure
2398*042d53a7SEvalZero      * object.
2399*042d53a7SEvalZero      * XXX: Mark connection as tainted; don't allow any subsequent SMP
2400*042d53a7SEvalZero      * procedures without reconnect.
2401*042d53a7SEvalZero      */
2402*042d53a7SEvalZero     while ((proc = STAILQ_FIRST(&exp_list)) != NULL) {
2403*042d53a7SEvalZero         ble_gap_enc_event(proc->conn_handle, BLE_HS_ETIMEOUT, 0);
2404*042d53a7SEvalZero 
2405*042d53a7SEvalZero         STAILQ_REMOVE_HEAD(&exp_list, next);
2406*042d53a7SEvalZero         ble_sm_proc_free(proc);
2407*042d53a7SEvalZero     }
2408*042d53a7SEvalZero 
2409*042d53a7SEvalZero     return ticks_until_exp;
2410*042d53a7SEvalZero }
2411*042d53a7SEvalZero 
2412*042d53a7SEvalZero /**
2413*042d53a7SEvalZero  * Initiates the pairing procedure for the specified connection.
2414*042d53a7SEvalZero  */
2415*042d53a7SEvalZero int
ble_sm_pair_initiate(uint16_t conn_handle)2416*042d53a7SEvalZero ble_sm_pair_initiate(uint16_t conn_handle)
2417*042d53a7SEvalZero {
2418*042d53a7SEvalZero     struct ble_sm_result res;
2419*042d53a7SEvalZero     struct ble_sm_proc *proc;
2420*042d53a7SEvalZero     int rc;
2421*042d53a7SEvalZero 
2422*042d53a7SEvalZero     memset(&res, 0, sizeof(res));
2423*042d53a7SEvalZero 
2424*042d53a7SEvalZero     /* Make sure a procedure isn't already in progress for this connection. */
2425*042d53a7SEvalZero     ble_hs_lock();
2426*042d53a7SEvalZero     proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_NONE, -1, NULL);
2427*042d53a7SEvalZero     ble_hs_unlock();
2428*042d53a7SEvalZero 
2429*042d53a7SEvalZero     if (proc != NULL) {
2430*042d53a7SEvalZero         res.app_status = BLE_HS_EALREADY;
2431*042d53a7SEvalZero         return BLE_HS_EALREADY;
2432*042d53a7SEvalZero     }
2433*042d53a7SEvalZero 
2434*042d53a7SEvalZero     /* Check if there is storage capacity for a new bond.  If there isn't, ask
2435*042d53a7SEvalZero      * the application to make room.
2436*042d53a7SEvalZero      */
2437*042d53a7SEvalZero     rc = ble_sm_chk_store_overflow(conn_handle);
2438*042d53a7SEvalZero     if (rc != 0) {
2439*042d53a7SEvalZero         return rc;
2440*042d53a7SEvalZero     }
2441*042d53a7SEvalZero 
2442*042d53a7SEvalZero     proc = ble_sm_proc_alloc();
2443*042d53a7SEvalZero     if (proc == NULL) {
2444*042d53a7SEvalZero         res.app_status = BLE_HS_ENOMEM;
2445*042d53a7SEvalZero     } else {
2446*042d53a7SEvalZero         proc->conn_handle = conn_handle;
2447*042d53a7SEvalZero         proc->state = BLE_SM_PROC_STATE_PAIR;
2448*042d53a7SEvalZero         proc->flags |= BLE_SM_PROC_F_INITIATOR;
2449*042d53a7SEvalZero 
2450*042d53a7SEvalZero         ble_hs_lock();
2451*042d53a7SEvalZero         ble_sm_insert(proc);
2452*042d53a7SEvalZero         ble_hs_unlock();
2453*042d53a7SEvalZero 
2454*042d53a7SEvalZero         res.execute = 1;
2455*042d53a7SEvalZero     }
2456*042d53a7SEvalZero 
2457*042d53a7SEvalZero     if (proc != NULL) {
2458*042d53a7SEvalZero         ble_sm_process_result(conn_handle, &res);
2459*042d53a7SEvalZero     }
2460*042d53a7SEvalZero 
2461*042d53a7SEvalZero     return res.app_status;
2462*042d53a7SEvalZero }
2463*042d53a7SEvalZero 
2464*042d53a7SEvalZero int
ble_sm_slave_initiate(uint16_t conn_handle)2465*042d53a7SEvalZero ble_sm_slave_initiate(uint16_t conn_handle)
2466*042d53a7SEvalZero {
2467*042d53a7SEvalZero     struct ble_sm_result res;
2468*042d53a7SEvalZero     struct ble_sm_proc *proc;
2469*042d53a7SEvalZero 
2470*042d53a7SEvalZero     memset(&res, 0, sizeof(res));
2471*042d53a7SEvalZero 
2472*042d53a7SEvalZero     ble_hs_lock();
2473*042d53a7SEvalZero 
2474*042d53a7SEvalZero     /* Make sure a procedure isn't already in progress for this connection. */
2475*042d53a7SEvalZero     proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_NONE, -1, NULL);
2476*042d53a7SEvalZero     if (proc != NULL) {
2477*042d53a7SEvalZero         res.app_status = BLE_HS_EALREADY;
2478*042d53a7SEvalZero 
2479*042d53a7SEvalZero         /* Set pointer to null so that existing entry doesn't get freed. */
2480*042d53a7SEvalZero         proc = NULL;
2481*042d53a7SEvalZero     } else {
2482*042d53a7SEvalZero         proc = ble_sm_proc_alloc();
2483*042d53a7SEvalZero         if (proc == NULL) {
2484*042d53a7SEvalZero             res.app_status = BLE_HS_ENOMEM;
2485*042d53a7SEvalZero         } else {
2486*042d53a7SEvalZero             proc->conn_handle = conn_handle;
2487*042d53a7SEvalZero             proc->state = BLE_SM_PROC_STATE_SEC_REQ;
2488*042d53a7SEvalZero             ble_sm_insert(proc);
2489*042d53a7SEvalZero 
2490*042d53a7SEvalZero             res.execute = 1;
2491*042d53a7SEvalZero         }
2492*042d53a7SEvalZero     }
2493*042d53a7SEvalZero 
2494*042d53a7SEvalZero     ble_hs_unlock();
2495*042d53a7SEvalZero 
2496*042d53a7SEvalZero     if (proc != NULL) {
2497*042d53a7SEvalZero         ble_sm_process_result(conn_handle, &res);
2498*042d53a7SEvalZero     }
2499*042d53a7SEvalZero 
2500*042d53a7SEvalZero     return res.app_status;
2501*042d53a7SEvalZero }
2502*042d53a7SEvalZero 
2503*042d53a7SEvalZero /**
2504*042d53a7SEvalZero  * Initiates the encryption procedure for the specified connection.
2505*042d53a7SEvalZero  */
2506*042d53a7SEvalZero int
ble_sm_enc_initiate(uint16_t conn_handle,const uint8_t * ltk,uint16_t ediv,uint64_t rand_val,int auth)2507*042d53a7SEvalZero ble_sm_enc_initiate(uint16_t conn_handle, const uint8_t *ltk, uint16_t ediv,
2508*042d53a7SEvalZero                     uint64_t rand_val, int auth)
2509*042d53a7SEvalZero {
2510*042d53a7SEvalZero     struct ble_sm_result res;
2511*042d53a7SEvalZero     struct ble_sm_proc *proc;
2512*042d53a7SEvalZero     struct hci_start_encrypt cmd;
2513*042d53a7SEvalZero 
2514*042d53a7SEvalZero     memset(&res, 0, sizeof res);
2515*042d53a7SEvalZero 
2516*042d53a7SEvalZero     /* Make sure a procedure isn't already in progress for this connection. */
2517*042d53a7SEvalZero     ble_hs_lock();
2518*042d53a7SEvalZero     proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_NONE, -1, NULL);
2519*042d53a7SEvalZero     if (proc != NULL) {
2520*042d53a7SEvalZero         res.app_status = BLE_HS_EALREADY;
2521*042d53a7SEvalZero 
2522*042d53a7SEvalZero         /* Set pointer to null so that existing entry doesn't get freed. */
2523*042d53a7SEvalZero         proc = NULL;
2524*042d53a7SEvalZero     } else {
2525*042d53a7SEvalZero         proc = ble_sm_proc_alloc();
2526*042d53a7SEvalZero         if (proc == NULL) {
2527*042d53a7SEvalZero             res.app_status = BLE_HS_ENOMEM;
2528*042d53a7SEvalZero         } else {
2529*042d53a7SEvalZero             proc->conn_handle = conn_handle;
2530*042d53a7SEvalZero             proc->state = BLE_SM_PROC_STATE_ENC_RESTORE;
2531*042d53a7SEvalZero             proc->flags |= BLE_SM_PROC_F_INITIATOR;
2532*042d53a7SEvalZero             if (auth) {
2533*042d53a7SEvalZero                 proc->flags |= BLE_SM_PROC_F_AUTHENTICATED;
2534*042d53a7SEvalZero             }
2535*042d53a7SEvalZero             ble_sm_insert(proc);
2536*042d53a7SEvalZero 
2537*042d53a7SEvalZero             cmd.connection_handle = conn_handle;
2538*042d53a7SEvalZero             cmd.encrypted_diversifier = ediv;
2539*042d53a7SEvalZero             cmd.random_number = rand_val;
2540*042d53a7SEvalZero             memcpy(cmd.long_term_key, ltk, sizeof cmd.long_term_key);
2541*042d53a7SEvalZero 
2542*042d53a7SEvalZero             res.execute = 1;
2543*042d53a7SEvalZero             res.state_arg = &cmd;
2544*042d53a7SEvalZero         }
2545*042d53a7SEvalZero     }
2546*042d53a7SEvalZero 
2547*042d53a7SEvalZero     ble_hs_unlock();
2548*042d53a7SEvalZero 
2549*042d53a7SEvalZero     ble_sm_process_result(conn_handle, &res);
2550*042d53a7SEvalZero 
2551*042d53a7SEvalZero     return res.app_status;
2552*042d53a7SEvalZero }
2553*042d53a7SEvalZero 
2554*042d53a7SEvalZero static int
ble_sm_rx(struct ble_l2cap_chan * chan)2555*042d53a7SEvalZero ble_sm_rx(struct ble_l2cap_chan *chan)
2556*042d53a7SEvalZero {
2557*042d53a7SEvalZero     struct ble_sm_result res;
2558*042d53a7SEvalZero     ble_sm_rx_fn *rx_cb;
2559*042d53a7SEvalZero     uint8_t op;
2560*042d53a7SEvalZero     uint16_t conn_handle;
2561*042d53a7SEvalZero     struct os_mbuf **om;
2562*042d53a7SEvalZero     int rc;
2563*042d53a7SEvalZero 
2564*042d53a7SEvalZero     STATS_INC(ble_l2cap_stats, sm_rx);
2565*042d53a7SEvalZero 
2566*042d53a7SEvalZero     conn_handle = ble_l2cap_get_conn_handle(chan);
2567*042d53a7SEvalZero     if (conn_handle == BLE_HS_CONN_HANDLE_NONE) {
2568*042d53a7SEvalZero         return BLE_HS_ENOTCONN;
2569*042d53a7SEvalZero     }
2570*042d53a7SEvalZero 
2571*042d53a7SEvalZero     om = &chan->rx_buf;
2572*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(*om != NULL);
2573*042d53a7SEvalZero 
2574*042d53a7SEvalZero     rc = os_mbuf_copydata(*om, 0, 1, &op);
2575*042d53a7SEvalZero     if (rc != 0) {
2576*042d53a7SEvalZero         return BLE_HS_EBADDATA;
2577*042d53a7SEvalZero     }
2578*042d53a7SEvalZero 
2579*042d53a7SEvalZero     /* Strip L2CAP SM header from the front of the mbuf. */
2580*042d53a7SEvalZero     os_mbuf_adj(*om, 1);
2581*042d53a7SEvalZero 
2582*042d53a7SEvalZero     rx_cb = ble_sm_dispatch_get(op);
2583*042d53a7SEvalZero     if (rx_cb != NULL) {
2584*042d53a7SEvalZero         memset(&res, 0, sizeof res);
2585*042d53a7SEvalZero 
2586*042d53a7SEvalZero         rx_cb(conn_handle, om, &res);
2587*042d53a7SEvalZero         ble_sm_process_result(conn_handle, &res);
2588*042d53a7SEvalZero         rc = res.app_status;
2589*042d53a7SEvalZero     } else {
2590*042d53a7SEvalZero         rc = BLE_HS_ENOTSUP;
2591*042d53a7SEvalZero     }
2592*042d53a7SEvalZero 
2593*042d53a7SEvalZero     return rc;
2594*042d53a7SEvalZero }
2595*042d53a7SEvalZero 
2596*042d53a7SEvalZero int
ble_sm_inject_io(uint16_t conn_handle,struct ble_sm_io * pkey)2597*042d53a7SEvalZero ble_sm_inject_io(uint16_t conn_handle, struct ble_sm_io *pkey)
2598*042d53a7SEvalZero {
2599*042d53a7SEvalZero     struct ble_sm_result res;
2600*042d53a7SEvalZero     struct ble_sm_proc *proc;
2601*042d53a7SEvalZero     int rc;
2602*042d53a7SEvalZero     uint8_t action;
2603*042d53a7SEvalZero 
2604*042d53a7SEvalZero     memset(&res, 0, sizeof res);
2605*042d53a7SEvalZero 
2606*042d53a7SEvalZero     ble_hs_lock();
2607*042d53a7SEvalZero 
2608*042d53a7SEvalZero     proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_NONE, -1, NULL);
2609*042d53a7SEvalZero     if (proc == NULL) {
2610*042d53a7SEvalZero         rc = BLE_HS_ENOENT;
2611*042d53a7SEvalZero     } else if (proc->flags & BLE_SM_PROC_F_IO_INJECTED) {
2612*042d53a7SEvalZero         rc = BLE_HS_EALREADY;
2613*042d53a7SEvalZero     } else if ((ble_sm_io_action(proc, &action) == 0) && pkey->action != action) {
2614*042d53a7SEvalZero         /* Application provided incorrect IO type. */
2615*042d53a7SEvalZero         rc = BLE_HS_EINVAL;
2616*042d53a7SEvalZero     } else if (ble_sm_ioact_state(pkey->action) != proc->state) {
2617*042d53a7SEvalZero         /* Procedure is not ready for user input. */
2618*042d53a7SEvalZero         rc = BLE_HS_EINVAL;
2619*042d53a7SEvalZero     } else {
2620*042d53a7SEvalZero         /* Assume valid input. */
2621*042d53a7SEvalZero         rc = 0;
2622*042d53a7SEvalZero 
2623*042d53a7SEvalZero         switch (pkey->action) {
2624*042d53a7SEvalZero         case BLE_SM_IOACT_OOB:
2625*042d53a7SEvalZero             proc->flags |= BLE_SM_PROC_F_IO_INJECTED;
2626*042d53a7SEvalZero             memcpy(proc->tk, pkey->oob, 16);
2627*042d53a7SEvalZero             if ((proc->flags & BLE_SM_PROC_F_INITIATOR) ||
2628*042d53a7SEvalZero                 (proc->flags & BLE_SM_PROC_F_ADVANCE_ON_IO)) {
2629*042d53a7SEvalZero 
2630*042d53a7SEvalZero                 res.execute = 1;
2631*042d53a7SEvalZero             }
2632*042d53a7SEvalZero             break;
2633*042d53a7SEvalZero 
2634*042d53a7SEvalZero         case BLE_SM_IOACT_INPUT:
2635*042d53a7SEvalZero         case BLE_SM_IOACT_DISP:
2636*042d53a7SEvalZero             if (pkey->passkey > 999999) {
2637*042d53a7SEvalZero                 rc = BLE_HS_EINVAL;
2638*042d53a7SEvalZero             } else {
2639*042d53a7SEvalZero                 proc->flags |= BLE_SM_PROC_F_IO_INJECTED;
2640*042d53a7SEvalZero                 memset(proc->tk, 0, 16);
2641*042d53a7SEvalZero                 proc->tk[0] = (pkey->passkey >> 0) & 0xff;
2642*042d53a7SEvalZero                 proc->tk[1] = (pkey->passkey >> 8) & 0xff;
2643*042d53a7SEvalZero                 proc->tk[2] = (pkey->passkey >> 16) & 0xff;
2644*042d53a7SEvalZero                 proc->tk[3] = (pkey->passkey >> 24) & 0xff;
2645*042d53a7SEvalZero                 if ((proc->flags & BLE_SM_PROC_F_INITIATOR) ||
2646*042d53a7SEvalZero                     (proc->flags & BLE_SM_PROC_F_ADVANCE_ON_IO)) {
2647*042d53a7SEvalZero 
2648*042d53a7SEvalZero                     res.execute = 1;
2649*042d53a7SEvalZero                 }
2650*042d53a7SEvalZero             }
2651*042d53a7SEvalZero             break;
2652*042d53a7SEvalZero 
2653*042d53a7SEvalZero         case BLE_SM_IOACT_NUMCMP:
2654*042d53a7SEvalZero             if (!pkey->numcmp_accept) {
2655*042d53a7SEvalZero                 res.app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_NUMCMP);
2656*042d53a7SEvalZero                 res.sm_err = BLE_SM_ERR_NUMCMP;
2657*042d53a7SEvalZero             } else {
2658*042d53a7SEvalZero                 proc->flags |= BLE_SM_PROC_F_IO_INJECTED;
2659*042d53a7SEvalZero                 if (proc->flags & BLE_SM_PROC_F_INITIATOR ||
2660*042d53a7SEvalZero                     proc->flags & BLE_SM_PROC_F_ADVANCE_ON_IO) {
2661*042d53a7SEvalZero 
2662*042d53a7SEvalZero                     res.execute = 1;
2663*042d53a7SEvalZero                 }
2664*042d53a7SEvalZero             }
2665*042d53a7SEvalZero             break;
2666*042d53a7SEvalZero 
2667*042d53a7SEvalZero         default:
2668*042d53a7SEvalZero             BLE_HS_DBG_ASSERT(0);
2669*042d53a7SEvalZero             rc = BLE_HS_EINVAL;
2670*042d53a7SEvalZero             break;
2671*042d53a7SEvalZero         }
2672*042d53a7SEvalZero     }
2673*042d53a7SEvalZero 
2674*042d53a7SEvalZero     ble_hs_unlock();
2675*042d53a7SEvalZero 
2676*042d53a7SEvalZero     /* If application provided invalid input, return error without modifying
2677*042d53a7SEvalZero      * SMP state.
2678*042d53a7SEvalZero      */
2679*042d53a7SEvalZero     if (rc != 0) {
2680*042d53a7SEvalZero         return rc;
2681*042d53a7SEvalZero     }
2682*042d53a7SEvalZero 
2683*042d53a7SEvalZero     ble_sm_process_result(conn_handle, &res);
2684*042d53a7SEvalZero     return res.app_status;
2685*042d53a7SEvalZero }
2686*042d53a7SEvalZero 
2687*042d53a7SEvalZero void
ble_sm_connection_broken(uint16_t conn_handle)2688*042d53a7SEvalZero ble_sm_connection_broken(uint16_t conn_handle)
2689*042d53a7SEvalZero {
2690*042d53a7SEvalZero     struct ble_sm_result res;
2691*042d53a7SEvalZero 
2692*042d53a7SEvalZero     memset(&res, 0, sizeof res);
2693*042d53a7SEvalZero     res.app_status = BLE_HS_ENOTCONN;
2694*042d53a7SEvalZero     res.enc_cb = 1;
2695*042d53a7SEvalZero 
2696*042d53a7SEvalZero     ble_sm_process_result(conn_handle, &res);
2697*042d53a7SEvalZero }
2698*042d53a7SEvalZero 
2699*042d53a7SEvalZero int
ble_sm_init(void)2700*042d53a7SEvalZero ble_sm_init(void)
2701*042d53a7SEvalZero {
2702*042d53a7SEvalZero     int rc;
2703*042d53a7SEvalZero 
2704*042d53a7SEvalZero     STAILQ_INIT(&ble_sm_procs);
2705*042d53a7SEvalZero 
2706*042d53a7SEvalZero     rc = os_mempool_init(&ble_sm_proc_pool,
2707*042d53a7SEvalZero                          MYNEWT_VAL(BLE_SM_MAX_PROCS),
2708*042d53a7SEvalZero                          sizeof (struct ble_sm_proc),
2709*042d53a7SEvalZero                          ble_sm_proc_mem,
2710*042d53a7SEvalZero                          "ble_sm_proc_pool");
2711*042d53a7SEvalZero     if (rc != 0) {
2712*042d53a7SEvalZero         return rc;
2713*042d53a7SEvalZero     }
2714*042d53a7SEvalZero 
2715*042d53a7SEvalZero     ble_sm_sc_init();
2716*042d53a7SEvalZero 
2717*042d53a7SEvalZero     return 0;
2718*042d53a7SEvalZero }
2719*042d53a7SEvalZero #else
2720*042d53a7SEvalZero /* if pairing is not supported it is only needed to reply with Pairing
2721*042d53a7SEvalZero  * Failed with 'Pairing not Supported' reason so this function can be very
2722*042d53a7SEvalZero  * simple
2723*042d53a7SEvalZero  */
2724*042d53a7SEvalZero static int
ble_sm_rx(struct ble_l2cap_chan * chan)2725*042d53a7SEvalZero ble_sm_rx(struct ble_l2cap_chan *chan)
2726*042d53a7SEvalZero {
2727*042d53a7SEvalZero     struct ble_sm_pair_fail *cmd;
2728*042d53a7SEvalZero     struct os_mbuf *txom;
2729*042d53a7SEvalZero     uint16_t handle;
2730*042d53a7SEvalZero 
2731*042d53a7SEvalZero     handle = ble_l2cap_get_conn_handle(chan);
2732*042d53a7SEvalZero     if (!handle) {
2733*042d53a7SEvalZero         return BLE_HS_ENOTCONN;
2734*042d53a7SEvalZero     }
2735*042d53a7SEvalZero 
2736*042d53a7SEvalZero     cmd = ble_sm_cmd_get(BLE_SM_OP_PAIR_FAIL, sizeof(*cmd), &txom);
2737*042d53a7SEvalZero     if (cmd == NULL) {
2738*042d53a7SEvalZero         return BLE_HS_ENOMEM;
2739*042d53a7SEvalZero     }
2740*042d53a7SEvalZero 
2741*042d53a7SEvalZero     cmd->reason = BLE_SM_ERR_PAIR_NOT_SUPP;
2742*042d53a7SEvalZero 
2743*042d53a7SEvalZero     return ble_sm_tx(handle, txom);
2744*042d53a7SEvalZero }
2745*042d53a7SEvalZero #endif
2746*042d53a7SEvalZero 
2747*042d53a7SEvalZero struct ble_l2cap_chan *
ble_sm_create_chan(uint16_t conn_handle)2748*042d53a7SEvalZero ble_sm_create_chan(uint16_t conn_handle)
2749*042d53a7SEvalZero {
2750*042d53a7SEvalZero     struct ble_l2cap_chan *chan;
2751*042d53a7SEvalZero 
2752*042d53a7SEvalZero     chan = ble_l2cap_chan_alloc(conn_handle);
2753*042d53a7SEvalZero     if (chan == NULL) {
2754*042d53a7SEvalZero         return NULL;
2755*042d53a7SEvalZero     }
2756*042d53a7SEvalZero 
2757*042d53a7SEvalZero     chan->scid = BLE_L2CAP_CID_SM;
2758*042d53a7SEvalZero     chan->dcid = BLE_L2CAP_CID_SM;
2759*042d53a7SEvalZero     chan->my_mtu = BLE_SM_MTU;
2760*042d53a7SEvalZero     chan->rx_fn = ble_sm_rx;
2761*042d53a7SEvalZero 
2762*042d53a7SEvalZero     return chan;
2763*042d53a7SEvalZero }
2764