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