xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/host/src/ble_gap.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
1*042d53a7SEvalZero /*
2*042d53a7SEvalZero  * Licensed to the Apache Software Foundation (ASF) under one
3*042d53a7SEvalZero  * or more contributor license agreements.  See the NOTICE file
4*042d53a7SEvalZero  * distributed with this work for additional information
5*042d53a7SEvalZero  * regarding copyright ownership.  The ASF licenses this file
6*042d53a7SEvalZero  * to you under the Apache License, Version 2.0 (the
7*042d53a7SEvalZero  * "License"); you may not use this file except in compliance
8*042d53a7SEvalZero  * with the License.  You may obtain a copy of the License at
9*042d53a7SEvalZero  *
10*042d53a7SEvalZero  *  http://www.apache.org/licenses/LICENSE-2.0
11*042d53a7SEvalZero  *
12*042d53a7SEvalZero  * Unless required by applicable law or agreed to in writing,
13*042d53a7SEvalZero  * software distributed under the License is distributed on an
14*042d53a7SEvalZero  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15*042d53a7SEvalZero  * KIND, either express or implied.  See the License for the
16*042d53a7SEvalZero  * specific language governing permissions and limitations
17*042d53a7SEvalZero  * under the License.
18*042d53a7SEvalZero  */
19*042d53a7SEvalZero 
20*042d53a7SEvalZero #include <assert.h>
21*042d53a7SEvalZero #include <string.h>
22*042d53a7SEvalZero #include <errno.h>
23*042d53a7SEvalZero #include "nimble/nimble_opt.h"
24*042d53a7SEvalZero #include "host/ble_hs_adv.h"
25*042d53a7SEvalZero #include "host/ble_hs_hci.h"
26*042d53a7SEvalZero #include "ble_hs_priv.h"
27*042d53a7SEvalZero 
28*042d53a7SEvalZero #if MYNEWT
29*042d53a7SEvalZero #include "bsp/bsp.h"
30*042d53a7SEvalZero #else
31*042d53a7SEvalZero #define bssnz_t
32*042d53a7SEvalZero #endif
33*042d53a7SEvalZero 
34*042d53a7SEvalZero /**
35*042d53a7SEvalZero  * GAP - Generic Access Profile.
36*042d53a7SEvalZero  *
37*042d53a7SEvalZero  * Design overview:
38*042d53a7SEvalZero  *
39*042d53a7SEvalZero  * GAP procedures are initiated by the application via function calls.  Such
40*042d53a7SEvalZero  * functions return when either of the following happens:
41*042d53a7SEvalZero  *
42*042d53a7SEvalZero  * (1) The procedure completes (success or failure).
43*042d53a7SEvalZero  * (2) The procedure cannot proceed until a BLE peer responds.
44*042d53a7SEvalZero  *
45*042d53a7SEvalZero  * For (1), the result of the procedure if fully indicated by the function
46*042d53a7SEvalZero  * return code.
47*042d53a7SEvalZero  * For (2), the procedure result is indicated by an application-configured
48*042d53a7SEvalZero  * callback.  The callback is executed when the procedure completes.
49*042d53a7SEvalZero  *
50*042d53a7SEvalZero  * The GAP is always in one of two states:
51*042d53a7SEvalZero  * 1. Free
52*042d53a7SEvalZero  * 2. Preempted
53*042d53a7SEvalZero  *
54*042d53a7SEvalZero  * While GAP is in the free state, new procedures can be started at will.
55*042d53a7SEvalZero  * While GAP is in the preempted state, no new procedures are allowed.  The
56*042d53a7SEvalZero  * host sets GAP to the preempted state when it needs to ensure no ongoing
57*042d53a7SEvalZero  * procedures, a condition required for some HCI commands to succeed.  The host
58*042d53a7SEvalZero  * must take care to take GAP out of the preempted state as soon as possible.
59*042d53a7SEvalZero  *
60*042d53a7SEvalZero  * Notes on thread-safety:
61*042d53a7SEvalZero  * 1. The ble_hs mutex must always be unlocked when an application callback is
62*042d53a7SEvalZero  *    executed.  The purpose of this requirement is to allow callbacks to
63*042d53a7SEvalZero  *    initiate additional host procedures, which may require locking of the
64*042d53a7SEvalZero  *    mutex.
65*042d53a7SEvalZero  * 2. Functions called directly by the application never call callbacks.
66*042d53a7SEvalZero  *    Generally, these functions lock the ble_hs mutex at the start, and only
67*042d53a7SEvalZero  *    unlock it at return.
68*042d53a7SEvalZero  * 3. Functions which do call callbacks (receive handlers and timer
69*042d53a7SEvalZero  *    expirations) generally only lock the mutex long enough to modify
70*042d53a7SEvalZero  *    affected state and make copies of data needed for the callback.  A copy
71*042d53a7SEvalZero  *    of various pieces of data is called a "snapshot" (struct
72*042d53a7SEvalZero  *    ble_gap_snapshot).  The sole purpose of snapshots is to allow callbacks
73*042d53a7SEvalZero  *    to be executed after unlocking the mutex.
74*042d53a7SEvalZero  */
75*042d53a7SEvalZero 
76*042d53a7SEvalZero /** GAP procedure op codes. */
77*042d53a7SEvalZero #define BLE_GAP_OP_NULL                         0
78*042d53a7SEvalZero #define BLE_GAP_OP_M_DISC                       1
79*042d53a7SEvalZero #define BLE_GAP_OP_M_CONN                       2
80*042d53a7SEvalZero #define BLE_GAP_OP_S_ADV                        1
81*042d53a7SEvalZero 
82*042d53a7SEvalZero /**
83*042d53a7SEvalZero  * If an attempt to cancel an active procedure fails, the attempt is retried
84*042d53a7SEvalZero  * at this rate (ms).
85*042d53a7SEvalZero  */
86*042d53a7SEvalZero #define BLE_GAP_CANCEL_RETRY_TIMEOUT_MS         100 /* ms */
87*042d53a7SEvalZero 
88*042d53a7SEvalZero #define BLE_GAP_UPDATE_TIMEOUT_MS               30000 /* ms */
89*042d53a7SEvalZero 
90*042d53a7SEvalZero static const struct ble_gap_conn_params ble_gap_conn_params_dflt = {
91*042d53a7SEvalZero     .scan_itvl = 0x0010,
92*042d53a7SEvalZero     .scan_window = 0x0010,
93*042d53a7SEvalZero     .itvl_min = BLE_GAP_INITIAL_CONN_ITVL_MIN,
94*042d53a7SEvalZero     .itvl_max = BLE_GAP_INITIAL_CONN_ITVL_MAX,
95*042d53a7SEvalZero     .latency = BLE_GAP_INITIAL_CONN_LATENCY,
96*042d53a7SEvalZero     .supervision_timeout = BLE_GAP_INITIAL_SUPERVISION_TIMEOUT,
97*042d53a7SEvalZero     .min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN,
98*042d53a7SEvalZero     .max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN,
99*042d53a7SEvalZero };
100*042d53a7SEvalZero 
101*042d53a7SEvalZero /**
102*042d53a7SEvalZero  * The state of the in-progress master connection.  If no master connection is
103*042d53a7SEvalZero  * currently in progress, then the op field is set to BLE_GAP_OP_NULL.
104*042d53a7SEvalZero  */
105*042d53a7SEvalZero struct ble_gap_master_state {
106*042d53a7SEvalZero     uint8_t op;
107*042d53a7SEvalZero 
108*042d53a7SEvalZero     uint8_t exp_set:1;
109*042d53a7SEvalZero     ble_npl_time_t exp_os_ticks;
110*042d53a7SEvalZero 
111*042d53a7SEvalZero     ble_gap_event_fn *cb;
112*042d53a7SEvalZero     void *cb_arg;
113*042d53a7SEvalZero 
114*042d53a7SEvalZero     /**
115*042d53a7SEvalZero      * Indicates the type of master procedure that was preempted, or
116*042d53a7SEvalZero      * BLE_GAP_OP_NULL if no procedure was preempted.
117*042d53a7SEvalZero      */
118*042d53a7SEvalZero     uint8_t preempted_op;
119*042d53a7SEvalZero 
120*042d53a7SEvalZero     union {
121*042d53a7SEvalZero         struct {
122*042d53a7SEvalZero             uint8_t using_wl:1;
123*042d53a7SEvalZero             uint8_t our_addr_type:2;
124*042d53a7SEvalZero             uint8_t cancel:1;
125*042d53a7SEvalZero         } conn;
126*042d53a7SEvalZero 
127*042d53a7SEvalZero         struct {
128*042d53a7SEvalZero             uint8_t limited:1;
129*042d53a7SEvalZero         } disc;
130*042d53a7SEvalZero     };
131*042d53a7SEvalZero };
132*042d53a7SEvalZero static bssnz_t struct ble_gap_master_state ble_gap_master;
133*042d53a7SEvalZero 
134*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MESH)
135*042d53a7SEvalZero struct ble_gap_mesh_state {
136*042d53a7SEvalZero     ble_gap_event_fn *cb;
137*042d53a7SEvalZero     void *cb_arg;
138*042d53a7SEvalZero } ble_gap_mesh;
139*042d53a7SEvalZero #endif
140*042d53a7SEvalZero 
141*042d53a7SEvalZero /**
142*042d53a7SEvalZero  * The state of the in-progress slave connection.  If no slave connection is
143*042d53a7SEvalZero  * currently in progress, then the op field is set to BLE_GAP_OP_NULL.
144*042d53a7SEvalZero  */
145*042d53a7SEvalZero struct ble_gap_slave_state {
146*042d53a7SEvalZero     uint8_t op;
147*042d53a7SEvalZero 
148*042d53a7SEvalZero     unsigned int our_addr_type:2;
149*042d53a7SEvalZero     unsigned int preempted:1;  /** Set to 1 if advertising was preempted. */
150*042d53a7SEvalZero     unsigned int connectable:1;
151*042d53a7SEvalZero 
152*042d53a7SEvalZero #if MYNEWT_VAL(BLE_EXT_ADV)
153*042d53a7SEvalZero     unsigned int configured:1; /** If instance is configured */
154*042d53a7SEvalZero     unsigned int scannable:1;
155*042d53a7SEvalZero     unsigned int directed:1;
156*042d53a7SEvalZero     unsigned int legacy_pdu:1;
157*042d53a7SEvalZero     unsigned int rnd_addr_set:1;
158*042d53a7SEvalZero     uint8_t rnd_addr[6];
159*042d53a7SEvalZero #else
160*042d53a7SEvalZero /* timer is used only with legacy advertising */
161*042d53a7SEvalZero     unsigned int exp_set:1;
162*042d53a7SEvalZero     ble_npl_time_t exp_os_ticks;
163*042d53a7SEvalZero #endif
164*042d53a7SEvalZero 
165*042d53a7SEvalZero     ble_gap_event_fn *cb;
166*042d53a7SEvalZero     void *cb_arg;
167*042d53a7SEvalZero };
168*042d53a7SEvalZero 
169*042d53a7SEvalZero static bssnz_t struct ble_gap_slave_state ble_gap_slave[BLE_ADV_INSTANCES];
170*042d53a7SEvalZero 
171*042d53a7SEvalZero struct ble_gap_update_entry {
172*042d53a7SEvalZero     SLIST_ENTRY(ble_gap_update_entry) next;
173*042d53a7SEvalZero     struct ble_gap_upd_params params;
174*042d53a7SEvalZero     ble_npl_time_t exp_os_ticks;
175*042d53a7SEvalZero     uint16_t conn_handle;
176*042d53a7SEvalZero };
177*042d53a7SEvalZero SLIST_HEAD(ble_gap_update_entry_list, ble_gap_update_entry);
178*042d53a7SEvalZero 
179*042d53a7SEvalZero struct ble_gap_snapshot {
180*042d53a7SEvalZero     struct ble_gap_conn_desc *desc;
181*042d53a7SEvalZero     ble_gap_event_fn *cb;
182*042d53a7SEvalZero     void *cb_arg;
183*042d53a7SEvalZero };
184*042d53a7SEvalZero 
185*042d53a7SEvalZero static SLIST_HEAD(ble_gap_hook_list, ble_gap_event_listener) ble_gap_event_listener_list;
186*042d53a7SEvalZero 
187*042d53a7SEvalZero static os_membuf_t ble_gap_update_entry_mem[
188*042d53a7SEvalZero                         OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_GAP_MAX_PENDING_CONN_PARAM_UPDATE),
189*042d53a7SEvalZero                                         sizeof (struct ble_gap_update_entry))];
190*042d53a7SEvalZero static struct os_mempool ble_gap_update_entry_pool;
191*042d53a7SEvalZero static struct ble_gap_update_entry_list ble_gap_update_entries;
192*042d53a7SEvalZero 
193*042d53a7SEvalZero static void ble_gap_update_entry_free(struct ble_gap_update_entry *entry);
194*042d53a7SEvalZero static struct ble_gap_update_entry *
195*042d53a7SEvalZero ble_gap_update_entry_find(uint16_t conn_handle,
196*042d53a7SEvalZero                           struct ble_gap_update_entry **out_prev);
197*042d53a7SEvalZero static struct ble_gap_update_entry *
198*042d53a7SEvalZero ble_gap_update_entry_remove(uint16_t conn_handle);
199*042d53a7SEvalZero static void
200*042d53a7SEvalZero ble_gap_update_l2cap_cb(uint16_t conn_handle, int status, void *arg);
201*042d53a7SEvalZero 
202*042d53a7SEvalZero static int ble_gap_adv_enable_tx(int enable);
203*042d53a7SEvalZero static int ble_gap_conn_cancel_tx(void);
204*042d53a7SEvalZero 
205*042d53a7SEvalZero #if NIMBLE_BLE_SCAN && !MYNEWT_VAL(BLE_EXT_ADV)
206*042d53a7SEvalZero static int ble_gap_disc_enable_tx(int enable, int filter_duplicates);
207*042d53a7SEvalZero #endif
208*042d53a7SEvalZero 
209*042d53a7SEvalZero STATS_SECT_DECL(ble_gap_stats) ble_gap_stats;
210*042d53a7SEvalZero STATS_NAME_START(ble_gap_stats)
STATS_NAME(ble_gap_stats,wl_set)211*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, wl_set)
212*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, wl_set_fail)
213*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, adv_stop)
214*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, adv_stop_fail)
215*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, adv_start)
216*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, adv_start_fail)
217*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, adv_set_data)
218*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, adv_set_data_fail)
219*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, adv_rsp_set_data)
220*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, adv_rsp_set_data_fail)
221*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, discover)
222*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, discover_fail)
223*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, initiate)
224*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, initiate_fail)
225*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, terminate)
226*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, terminate_fail)
227*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, cancel)
228*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, cancel_fail)
229*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, update)
230*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, update_fail)
231*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, connect_mst)
232*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, connect_slv)
233*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, disconnect)
234*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, rx_disconnect)
235*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, rx_update_complete)
236*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, rx_adv_report)
237*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, rx_conn_complete)
238*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, discover_cancel)
239*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, discover_cancel_fail)
240*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, security_initiate)
241*042d53a7SEvalZero     STATS_NAME(ble_gap_stats, security_initiate_fail)
242*042d53a7SEvalZero STATS_NAME_END(ble_gap_stats)
243*042d53a7SEvalZero 
244*042d53a7SEvalZero /*****************************************************************************
245*042d53a7SEvalZero  * $debug                                                                    *
246*042d53a7SEvalZero  *****************************************************************************/
247*042d53a7SEvalZero 
248*042d53a7SEvalZero #if MYNEWT_VAL(BLE_HS_DEBUG)
249*042d53a7SEvalZero int
250*042d53a7SEvalZero ble_gap_dbg_update_active(uint16_t conn_handle)
251*042d53a7SEvalZero {
252*042d53a7SEvalZero     const struct ble_gap_update_entry *entry;
253*042d53a7SEvalZero 
254*042d53a7SEvalZero     ble_hs_lock();
255*042d53a7SEvalZero     entry = ble_gap_update_entry_find(conn_handle, NULL);
256*042d53a7SEvalZero     ble_hs_unlock();
257*042d53a7SEvalZero 
258*042d53a7SEvalZero     return entry != NULL;
259*042d53a7SEvalZero }
260*042d53a7SEvalZero #endif
261*042d53a7SEvalZero 
262*042d53a7SEvalZero /*****************************************************************************
263*042d53a7SEvalZero  * $log                                                                      *
264*042d53a7SEvalZero  *****************************************************************************/
265*042d53a7SEvalZero 
266*042d53a7SEvalZero #if NIMBLE_BLE_SCAN && !MYNEWT_VAL(BLE_EXT_ADV)
267*042d53a7SEvalZero static void
ble_gap_log_duration(int32_t duration_ms)268*042d53a7SEvalZero ble_gap_log_duration(int32_t duration_ms)
269*042d53a7SEvalZero {
270*042d53a7SEvalZero     if (duration_ms == BLE_HS_FOREVER) {
271*042d53a7SEvalZero         BLE_HS_LOG(INFO, "duration=forever");
272*042d53a7SEvalZero     } else {
273*042d53a7SEvalZero         BLE_HS_LOG(INFO, "duration=%dms", duration_ms);
274*042d53a7SEvalZero     }
275*042d53a7SEvalZero }
276*042d53a7SEvalZero #endif
277*042d53a7SEvalZero 
278*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_EXT_ADV)
279*042d53a7SEvalZero static void
ble_gap_log_conn(uint8_t own_addr_type,const ble_addr_t * peer_addr,const struct ble_gap_conn_params * params)280*042d53a7SEvalZero ble_gap_log_conn(uint8_t own_addr_type, const ble_addr_t *peer_addr,
281*042d53a7SEvalZero                  const struct ble_gap_conn_params *params)
282*042d53a7SEvalZero {
283*042d53a7SEvalZero     if (peer_addr != NULL) {
284*042d53a7SEvalZero         BLE_HS_LOG(INFO, "peer_addr_type=%d peer_addr=", peer_addr->type);
285*042d53a7SEvalZero         BLE_HS_LOG_ADDR(INFO, peer_addr->val);
286*042d53a7SEvalZero     }
287*042d53a7SEvalZero 
288*042d53a7SEvalZero     BLE_HS_LOG(INFO, " scan_itvl=%d scan_window=%d itvl_min=%d itvl_max=%d "
289*042d53a7SEvalZero                      "latency=%d supervision_timeout=%d min_ce_len=%d "
290*042d53a7SEvalZero                      "max_ce_len=%d own_addr_type=%d",
291*042d53a7SEvalZero                params->scan_itvl, params->scan_window, params->itvl_min,
292*042d53a7SEvalZero                params->itvl_max, params->latency, params->supervision_timeout,
293*042d53a7SEvalZero                params->min_ce_len, params->max_ce_len, own_addr_type);
294*042d53a7SEvalZero }
295*042d53a7SEvalZero #endif
296*042d53a7SEvalZero 
297*042d53a7SEvalZero #if NIMBLE_BLE_SCAN && !MYNEWT_VAL(BLE_EXT_ADV)
298*042d53a7SEvalZero static void
ble_gap_log_disc(uint8_t own_addr_type,int32_t duration_ms,const struct ble_gap_disc_params * disc_params)299*042d53a7SEvalZero ble_gap_log_disc(uint8_t own_addr_type, int32_t duration_ms,
300*042d53a7SEvalZero                  const struct ble_gap_disc_params *disc_params)
301*042d53a7SEvalZero {
302*042d53a7SEvalZero     BLE_HS_LOG(INFO, "own_addr_type=%d filter_policy=%d passive=%d limited=%d "
303*042d53a7SEvalZero                      "filter_duplicates=%d ",
304*042d53a7SEvalZero                own_addr_type, disc_params->filter_policy, disc_params->passive,
305*042d53a7SEvalZero                disc_params->limited, disc_params->filter_duplicates);
306*042d53a7SEvalZero     ble_gap_log_duration(duration_ms);
307*042d53a7SEvalZero }
308*042d53a7SEvalZero #endif
309*042d53a7SEvalZero 
310*042d53a7SEvalZero static void
ble_gap_log_update(uint16_t conn_handle,const struct ble_gap_upd_params * params)311*042d53a7SEvalZero ble_gap_log_update(uint16_t conn_handle,
312*042d53a7SEvalZero                    const struct ble_gap_upd_params *params)
313*042d53a7SEvalZero {
314*042d53a7SEvalZero     BLE_HS_LOG(INFO, "connection parameter update; "
315*042d53a7SEvalZero                      "conn_handle=%d itvl_min=%d itvl_max=%d latency=%d "
316*042d53a7SEvalZero                      "supervision_timeout=%d min_ce_len=%d max_ce_len=%d",
317*042d53a7SEvalZero                conn_handle, params->itvl_min, params->itvl_max,
318*042d53a7SEvalZero                params->latency, params->supervision_timeout,
319*042d53a7SEvalZero                params->min_ce_len, params->max_ce_len);
320*042d53a7SEvalZero }
321*042d53a7SEvalZero 
322*042d53a7SEvalZero static void
ble_gap_log_wl(const ble_addr_t * addr,uint8_t white_list_count)323*042d53a7SEvalZero ble_gap_log_wl(const ble_addr_t *addr, uint8_t white_list_count)
324*042d53a7SEvalZero {
325*042d53a7SEvalZero     int i;
326*042d53a7SEvalZero 
327*042d53a7SEvalZero     BLE_HS_LOG(INFO, "count=%d ", white_list_count);
328*042d53a7SEvalZero 
329*042d53a7SEvalZero     for (i = 0; i < white_list_count; i++, addr++) {
330*042d53a7SEvalZero         BLE_HS_LOG(INFO, "entry-%d={addr_type=%d addr=", i, addr->type);
331*042d53a7SEvalZero         BLE_HS_LOG_ADDR(INFO, addr->val);
332*042d53a7SEvalZero         BLE_HS_LOG(INFO, "} ");
333*042d53a7SEvalZero     }
334*042d53a7SEvalZero }
335*042d53a7SEvalZero 
336*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_EXT_ADV)
337*042d53a7SEvalZero static void
ble_gap_log_adv(uint8_t own_addr_type,const ble_addr_t * direct_addr,const struct ble_gap_adv_params * adv_params)338*042d53a7SEvalZero ble_gap_log_adv(uint8_t own_addr_type, const ble_addr_t *direct_addr,
339*042d53a7SEvalZero                 const struct ble_gap_adv_params *adv_params)
340*042d53a7SEvalZero {
341*042d53a7SEvalZero     BLE_HS_LOG(INFO, "disc_mode=%d", adv_params->disc_mode);
342*042d53a7SEvalZero     if (direct_addr) {
343*042d53a7SEvalZero         BLE_HS_LOG(INFO, " direct_addr_type=%d direct_addr=",
344*042d53a7SEvalZero                    direct_addr->type);
345*042d53a7SEvalZero         BLE_HS_LOG_ADDR(INFO, direct_addr->val);
346*042d53a7SEvalZero     }
347*042d53a7SEvalZero     BLE_HS_LOG(INFO, " adv_channel_map=%d own_addr_type=%d "
348*042d53a7SEvalZero                      "adv_filter_policy=%d adv_itvl_min=%d adv_itvl_max=%d",
349*042d53a7SEvalZero                adv_params->channel_map,
350*042d53a7SEvalZero                own_addr_type,
351*042d53a7SEvalZero                adv_params->filter_policy,
352*042d53a7SEvalZero                adv_params->itvl_min,
353*042d53a7SEvalZero                adv_params->itvl_max);
354*042d53a7SEvalZero }
355*042d53a7SEvalZero #endif
356*042d53a7SEvalZero 
357*042d53a7SEvalZero /*****************************************************************************
358*042d53a7SEvalZero  * $snapshot                                                                 *
359*042d53a7SEvalZero  *****************************************************************************/
360*042d53a7SEvalZero 
361*042d53a7SEvalZero static void
ble_gap_fill_conn_desc(struct ble_hs_conn * conn,struct ble_gap_conn_desc * desc)362*042d53a7SEvalZero ble_gap_fill_conn_desc(struct ble_hs_conn *conn,
363*042d53a7SEvalZero                        struct ble_gap_conn_desc *desc)
364*042d53a7SEvalZero {
365*042d53a7SEvalZero     struct ble_hs_conn_addrs addrs;
366*042d53a7SEvalZero 
367*042d53a7SEvalZero     ble_hs_conn_addrs(conn, &addrs);
368*042d53a7SEvalZero 
369*042d53a7SEvalZero     desc->our_id_addr = addrs.our_id_addr;
370*042d53a7SEvalZero     desc->peer_id_addr = addrs.peer_id_addr;
371*042d53a7SEvalZero     desc->our_ota_addr = addrs.our_ota_addr;
372*042d53a7SEvalZero     desc->peer_ota_addr = addrs.peer_ota_addr;
373*042d53a7SEvalZero 
374*042d53a7SEvalZero     desc->conn_handle = conn->bhc_handle;
375*042d53a7SEvalZero     desc->conn_itvl = conn->bhc_itvl;
376*042d53a7SEvalZero     desc->conn_latency = conn->bhc_latency;
377*042d53a7SEvalZero     desc->supervision_timeout = conn->bhc_supervision_timeout;
378*042d53a7SEvalZero     desc->master_clock_accuracy = conn->bhc_master_clock_accuracy;
379*042d53a7SEvalZero     desc->sec_state = conn->bhc_sec_state;
380*042d53a7SEvalZero 
381*042d53a7SEvalZero     if (conn->bhc_flags & BLE_HS_CONN_F_MASTER) {
382*042d53a7SEvalZero         desc->role = BLE_GAP_ROLE_MASTER;
383*042d53a7SEvalZero     } else {
384*042d53a7SEvalZero         desc->role = BLE_GAP_ROLE_SLAVE;
385*042d53a7SEvalZero     }
386*042d53a7SEvalZero }
387*042d53a7SEvalZero 
388*042d53a7SEvalZero static void
ble_gap_conn_to_snapshot(struct ble_hs_conn * conn,struct ble_gap_snapshot * snap)389*042d53a7SEvalZero ble_gap_conn_to_snapshot(struct ble_hs_conn *conn,
390*042d53a7SEvalZero                          struct ble_gap_snapshot *snap)
391*042d53a7SEvalZero {
392*042d53a7SEvalZero     ble_gap_fill_conn_desc(conn, snap->desc);
393*042d53a7SEvalZero     snap->cb = conn->bhc_cb;
394*042d53a7SEvalZero     snap->cb_arg = conn->bhc_cb_arg;
395*042d53a7SEvalZero }
396*042d53a7SEvalZero 
397*042d53a7SEvalZero static int
ble_gap_find_snapshot(uint16_t handle,struct ble_gap_snapshot * snap)398*042d53a7SEvalZero ble_gap_find_snapshot(uint16_t handle, struct ble_gap_snapshot *snap)
399*042d53a7SEvalZero {
400*042d53a7SEvalZero     struct ble_hs_conn *conn;
401*042d53a7SEvalZero 
402*042d53a7SEvalZero     ble_hs_lock();
403*042d53a7SEvalZero 
404*042d53a7SEvalZero     conn = ble_hs_conn_find(handle);
405*042d53a7SEvalZero     if (conn != NULL) {
406*042d53a7SEvalZero         ble_gap_conn_to_snapshot(conn, snap);
407*042d53a7SEvalZero     }
408*042d53a7SEvalZero 
409*042d53a7SEvalZero     ble_hs_unlock();
410*042d53a7SEvalZero 
411*042d53a7SEvalZero     if (conn == NULL) {
412*042d53a7SEvalZero         return BLE_HS_ENOTCONN;
413*042d53a7SEvalZero     } else {
414*042d53a7SEvalZero         return 0;
415*042d53a7SEvalZero     }
416*042d53a7SEvalZero }
417*042d53a7SEvalZero 
418*042d53a7SEvalZero int
ble_gap_conn_find(uint16_t handle,struct ble_gap_conn_desc * out_desc)419*042d53a7SEvalZero ble_gap_conn_find(uint16_t handle, struct ble_gap_conn_desc *out_desc)
420*042d53a7SEvalZero {
421*042d53a7SEvalZero     struct ble_hs_conn *conn;
422*042d53a7SEvalZero 
423*042d53a7SEvalZero     ble_hs_lock();
424*042d53a7SEvalZero 
425*042d53a7SEvalZero     conn = ble_hs_conn_find(handle);
426*042d53a7SEvalZero     if (conn != NULL && out_desc != NULL) {
427*042d53a7SEvalZero         ble_gap_fill_conn_desc(conn, out_desc);
428*042d53a7SEvalZero     }
429*042d53a7SEvalZero 
430*042d53a7SEvalZero     ble_hs_unlock();
431*042d53a7SEvalZero 
432*042d53a7SEvalZero     if (conn == NULL) {
433*042d53a7SEvalZero         return BLE_HS_ENOTCONN;
434*042d53a7SEvalZero     } else {
435*042d53a7SEvalZero         return 0;
436*042d53a7SEvalZero     }
437*042d53a7SEvalZero }
438*042d53a7SEvalZero 
439*042d53a7SEvalZero int
ble_gap_conn_find_by_addr(const ble_addr_t * addr,struct ble_gap_conn_desc * out_desc)440*042d53a7SEvalZero ble_gap_conn_find_by_addr(const ble_addr_t *addr,
441*042d53a7SEvalZero                           struct ble_gap_conn_desc *out_desc)
442*042d53a7SEvalZero {
443*042d53a7SEvalZero 	struct ble_hs_conn *conn;
444*042d53a7SEvalZero 
445*042d53a7SEvalZero 	ble_hs_lock();
446*042d53a7SEvalZero 
447*042d53a7SEvalZero 	conn = ble_hs_conn_find_by_addr(addr);
448*042d53a7SEvalZero 	if (conn != NULL && out_desc != NULL) {
449*042d53a7SEvalZero 		ble_gap_fill_conn_desc(conn, out_desc);
450*042d53a7SEvalZero 	}
451*042d53a7SEvalZero 
452*042d53a7SEvalZero 	ble_hs_unlock();
453*042d53a7SEvalZero 
454*042d53a7SEvalZero 	if (conn == NULL) {
455*042d53a7SEvalZero 		return BLE_HS_ENOTCONN;
456*042d53a7SEvalZero 	}
457*042d53a7SEvalZero 
458*042d53a7SEvalZero 	return 0;
459*042d53a7SEvalZero }
460*042d53a7SEvalZero 
461*042d53a7SEvalZero static int
ble_gap_extract_conn_cb(uint16_t conn_handle,ble_gap_event_fn ** out_cb,void ** out_cb_arg)462*042d53a7SEvalZero ble_gap_extract_conn_cb(uint16_t conn_handle,
463*042d53a7SEvalZero                         ble_gap_event_fn **out_cb, void **out_cb_arg)
464*042d53a7SEvalZero {
465*042d53a7SEvalZero     const struct ble_hs_conn *conn;
466*042d53a7SEvalZero 
467*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(conn_handle <= BLE_HCI_LE_CONN_HANDLE_MAX);
468*042d53a7SEvalZero 
469*042d53a7SEvalZero     ble_hs_lock();
470*042d53a7SEvalZero 
471*042d53a7SEvalZero     conn = ble_hs_conn_find(conn_handle);
472*042d53a7SEvalZero     if (conn != NULL) {
473*042d53a7SEvalZero         *out_cb = conn->bhc_cb;
474*042d53a7SEvalZero         *out_cb_arg = conn->bhc_cb_arg;
475*042d53a7SEvalZero     } else {
476*042d53a7SEvalZero         *out_cb = NULL;
477*042d53a7SEvalZero         *out_cb_arg = NULL;
478*042d53a7SEvalZero     }
479*042d53a7SEvalZero 
480*042d53a7SEvalZero     ble_hs_unlock();
481*042d53a7SEvalZero 
482*042d53a7SEvalZero     if (conn == NULL) {
483*042d53a7SEvalZero         return BLE_HS_ENOTCONN;
484*042d53a7SEvalZero     } else {
485*042d53a7SEvalZero         return 0;
486*042d53a7SEvalZero     }
487*042d53a7SEvalZero }
488*042d53a7SEvalZero 
489*042d53a7SEvalZero int
ble_gap_set_priv_mode(const ble_addr_t * peer_addr,uint8_t priv_mode)490*042d53a7SEvalZero ble_gap_set_priv_mode(const ble_addr_t *peer_addr, uint8_t priv_mode)
491*042d53a7SEvalZero {
492*042d53a7SEvalZero     return ble_hs_pvcy_set_mode(peer_addr, priv_mode);
493*042d53a7SEvalZero }
494*042d53a7SEvalZero 
495*042d53a7SEvalZero int
ble_gap_read_le_phy(uint16_t conn_handle,uint8_t * tx_phy,uint8_t * rx_phy)496*042d53a7SEvalZero ble_gap_read_le_phy(uint16_t conn_handle, uint8_t *tx_phy, uint8_t *rx_phy)
497*042d53a7SEvalZero {
498*042d53a7SEvalZero     struct ble_hs_conn *conn;
499*042d53a7SEvalZero     uint8_t buf[BLE_HCI_LE_RD_PHY_LEN];
500*042d53a7SEvalZero     uint8_t rspbuf[4];
501*042d53a7SEvalZero     uint8_t rsplen;
502*042d53a7SEvalZero     int rc;
503*042d53a7SEvalZero 
504*042d53a7SEvalZero     ble_hs_lock();
505*042d53a7SEvalZero     conn = ble_hs_conn_find(conn_handle);
506*042d53a7SEvalZero     ble_hs_unlock();
507*042d53a7SEvalZero 
508*042d53a7SEvalZero     if (conn == NULL) {
509*042d53a7SEvalZero         return BLE_HS_ENOTCONN;
510*042d53a7SEvalZero     }
511*042d53a7SEvalZero 
512*042d53a7SEvalZero     rc = ble_hs_hci_cmd_build_le_read_phy(conn_handle, buf, sizeof(buf));
513*042d53a7SEvalZero     if (rc != 0) {
514*042d53a7SEvalZero         return rc;
515*042d53a7SEvalZero     }
516*042d53a7SEvalZero 
517*042d53a7SEvalZero     rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RD_PHY),
518*042d53a7SEvalZero                            buf, sizeof(buf), rspbuf, sizeof(rspbuf), &rsplen);
519*042d53a7SEvalZero     if (rc != 0) {
520*042d53a7SEvalZero         return rc;
521*042d53a7SEvalZero     }
522*042d53a7SEvalZero 
523*042d53a7SEvalZero     if (rsplen != sizeof(rspbuf)) {
524*042d53a7SEvalZero         return BLE_HS_ECONTROLLER;
525*042d53a7SEvalZero     }
526*042d53a7SEvalZero 
527*042d53a7SEvalZero     /* First two octets is conn_handle. We can ignore it */
528*042d53a7SEvalZero 
529*042d53a7SEvalZero     *tx_phy = rspbuf[2];
530*042d53a7SEvalZero     *rx_phy = rspbuf[3];
531*042d53a7SEvalZero 
532*042d53a7SEvalZero     return 0;
533*042d53a7SEvalZero }
534*042d53a7SEvalZero 
535*042d53a7SEvalZero int
ble_gap_set_prefered_default_le_phy(uint8_t tx_phys_mask,uint8_t rx_phys_mask)536*042d53a7SEvalZero ble_gap_set_prefered_default_le_phy(uint8_t tx_phys_mask, uint8_t rx_phys_mask)
537*042d53a7SEvalZero {
538*042d53a7SEvalZero     uint8_t buf[BLE_HCI_LE_SET_DEFAULT_PHY_LEN];
539*042d53a7SEvalZero     int rc;
540*042d53a7SEvalZero 
541*042d53a7SEvalZero     rc = ble_hs_hci_cmd_build_le_set_default_phy(tx_phys_mask, rx_phys_mask,
542*042d53a7SEvalZero                                                  buf, sizeof(buf));
543*042d53a7SEvalZero     if (rc != 0) {
544*042d53a7SEvalZero         return rc;
545*042d53a7SEvalZero     }
546*042d53a7SEvalZero 
547*042d53a7SEvalZero     return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
548*042d53a7SEvalZero                                         BLE_HCI_OCF_LE_SET_DEFAULT_PHY),
549*042d53a7SEvalZero                             buf, sizeof(buf), NULL, 0, NULL);
550*042d53a7SEvalZero }
551*042d53a7SEvalZero 
552*042d53a7SEvalZero int
ble_gap_set_prefered_le_phy(uint16_t conn_handle,uint8_t tx_phys_mask,uint8_t rx_phys_mask,uint16_t phy_opts)553*042d53a7SEvalZero ble_gap_set_prefered_le_phy(uint16_t conn_handle, uint8_t tx_phys_mask,
554*042d53a7SEvalZero                    uint8_t rx_phys_mask, uint16_t phy_opts)
555*042d53a7SEvalZero {
556*042d53a7SEvalZero     struct ble_hs_conn *conn;
557*042d53a7SEvalZero     uint8_t buf[BLE_HCI_LE_SET_PHY_LEN];
558*042d53a7SEvalZero     int rc;
559*042d53a7SEvalZero 
560*042d53a7SEvalZero     ble_hs_lock();
561*042d53a7SEvalZero     conn = ble_hs_conn_find(conn_handle);
562*042d53a7SEvalZero     ble_hs_unlock();
563*042d53a7SEvalZero 
564*042d53a7SEvalZero     if (conn == NULL) {
565*042d53a7SEvalZero         return BLE_HS_ENOTCONN;
566*042d53a7SEvalZero     }
567*042d53a7SEvalZero 
568*042d53a7SEvalZero     rc = ble_hs_hci_cmd_build_le_set_phy(conn_handle, tx_phys_mask,
569*042d53a7SEvalZero                                          rx_phys_mask, phy_opts, buf,
570*042d53a7SEvalZero                                          sizeof(buf));
571*042d53a7SEvalZero     if (rc != 0) {
572*042d53a7SEvalZero         return rc;
573*042d53a7SEvalZero     }
574*042d53a7SEvalZero 
575*042d53a7SEvalZero     return ble_hs_hci_cmd_tx(
576*042d53a7SEvalZero         BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_PHY),
577*042d53a7SEvalZero         buf, sizeof(buf), NULL, 0, NULL);
578*042d53a7SEvalZero }
579*042d53a7SEvalZero 
580*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MESH)
581*042d53a7SEvalZero int
ble_gap_mesh_cb_register(ble_gap_event_fn * cb,void * cb_arg)582*042d53a7SEvalZero ble_gap_mesh_cb_register(ble_gap_event_fn *cb, void *cb_arg)
583*042d53a7SEvalZero {
584*042d53a7SEvalZero     ble_gap_mesh.cb = cb;
585*042d53a7SEvalZero     ble_gap_mesh.cb_arg = cb_arg;
586*042d53a7SEvalZero 
587*042d53a7SEvalZero     return 0;
588*042d53a7SEvalZero }
589*042d53a7SEvalZero #endif
590*042d53a7SEvalZero 
591*042d53a7SEvalZero /*****************************************************************************
592*042d53a7SEvalZero  * $misc                                                                     *
593*042d53a7SEvalZero  *****************************************************************************/
594*042d53a7SEvalZero 
595*042d53a7SEvalZero static int
596*042d53a7SEvalZero ble_gap_event_listener_call(struct ble_gap_event *event);
597*042d53a7SEvalZero 
598*042d53a7SEvalZero static int
ble_gap_call_event_cb(struct ble_gap_event * event,ble_gap_event_fn * cb,void * cb_arg)599*042d53a7SEvalZero ble_gap_call_event_cb(struct ble_gap_event *event,
600*042d53a7SEvalZero                       ble_gap_event_fn *cb, void *cb_arg)
601*042d53a7SEvalZero {
602*042d53a7SEvalZero     int rc;
603*042d53a7SEvalZero 
604*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
605*042d53a7SEvalZero 
606*042d53a7SEvalZero     if (cb != NULL) {
607*042d53a7SEvalZero         rc = cb(event, cb_arg);
608*042d53a7SEvalZero     } else {
609*042d53a7SEvalZero         if (event->type == BLE_GAP_EVENT_CONN_UPDATE_REQ) {
610*042d53a7SEvalZero             /* Just copy peer parameters back into the reply. */
611*042d53a7SEvalZero             *event->conn_update_req.self_params =
612*042d53a7SEvalZero                 *event->conn_update_req.peer_params;
613*042d53a7SEvalZero         }
614*042d53a7SEvalZero         rc = 0;
615*042d53a7SEvalZero     }
616*042d53a7SEvalZero 
617*042d53a7SEvalZero     return rc;
618*042d53a7SEvalZero }
619*042d53a7SEvalZero 
620*042d53a7SEvalZero 
621*042d53a7SEvalZero static int
ble_gap_call_conn_event_cb(struct ble_gap_event * event,uint16_t conn_handle)622*042d53a7SEvalZero ble_gap_call_conn_event_cb(struct ble_gap_event *event, uint16_t conn_handle)
623*042d53a7SEvalZero {
624*042d53a7SEvalZero     ble_gap_event_fn *cb;
625*042d53a7SEvalZero     void *cb_arg;
626*042d53a7SEvalZero     int rc;
627*042d53a7SEvalZero 
628*042d53a7SEvalZero     rc = ble_gap_extract_conn_cb(conn_handle, &cb, &cb_arg);
629*042d53a7SEvalZero     if (rc != 0) {
630*042d53a7SEvalZero         return rc;
631*042d53a7SEvalZero     }
632*042d53a7SEvalZero 
633*042d53a7SEvalZero     rc = ble_gap_call_event_cb(event, cb, cb_arg);
634*042d53a7SEvalZero     if (rc != 0) {
635*042d53a7SEvalZero         return rc;
636*042d53a7SEvalZero     }
637*042d53a7SEvalZero 
638*042d53a7SEvalZero     return 0;
639*042d53a7SEvalZero }
640*042d53a7SEvalZero 
641*042d53a7SEvalZero static bool
ble_gap_is_preempted(void)642*042d53a7SEvalZero ble_gap_is_preempted(void)
643*042d53a7SEvalZero {
644*042d53a7SEvalZero     int i;
645*042d53a7SEvalZero 
646*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task());
647*042d53a7SEvalZero 
648*042d53a7SEvalZero     if (ble_gap_master.preempted_op != BLE_GAP_OP_NULL) {
649*042d53a7SEvalZero         return true;
650*042d53a7SEvalZero     }
651*042d53a7SEvalZero 
652*042d53a7SEvalZero     for (i = 0; i < BLE_ADV_INSTANCES; i++) {
653*042d53a7SEvalZero         if (ble_gap_slave[i].preempted) {
654*042d53a7SEvalZero             return true;
655*042d53a7SEvalZero         }
656*042d53a7SEvalZero     }
657*042d53a7SEvalZero 
658*042d53a7SEvalZero     return false;
659*042d53a7SEvalZero }
660*042d53a7SEvalZero 
661*042d53a7SEvalZero static void
ble_gap_master_reset_state(void)662*042d53a7SEvalZero ble_gap_master_reset_state(void)
663*042d53a7SEvalZero {
664*042d53a7SEvalZero     ble_gap_master.op = BLE_GAP_OP_NULL;
665*042d53a7SEvalZero     ble_gap_master.exp_set = 0;
666*042d53a7SEvalZero     ble_gap_master.conn.cancel = 0;
667*042d53a7SEvalZero 
668*042d53a7SEvalZero     ble_hs_timer_resched();
669*042d53a7SEvalZero }
670*042d53a7SEvalZero 
671*042d53a7SEvalZero static void
ble_gap_slave_reset_state(uint8_t instance)672*042d53a7SEvalZero ble_gap_slave_reset_state(uint8_t instance)
673*042d53a7SEvalZero {
674*042d53a7SEvalZero     ble_gap_slave[instance].op = BLE_GAP_OP_NULL;
675*042d53a7SEvalZero 
676*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_EXT_ADV)
677*042d53a7SEvalZero     ble_gap_slave[instance].exp_set = 0;
678*042d53a7SEvalZero     ble_hs_timer_resched();
679*042d53a7SEvalZero #endif
680*042d53a7SEvalZero }
681*042d53a7SEvalZero 
682*042d53a7SEvalZero static bool
ble_gap_has_client(struct ble_gap_master_state * out_state)683*042d53a7SEvalZero ble_gap_has_client(struct ble_gap_master_state *out_state)
684*042d53a7SEvalZero {
685*042d53a7SEvalZero     if (!out_state) {
686*042d53a7SEvalZero         return 0;
687*042d53a7SEvalZero     }
688*042d53a7SEvalZero 
689*042d53a7SEvalZero     return out_state->cb;
690*042d53a7SEvalZero }
691*042d53a7SEvalZero 
692*042d53a7SEvalZero static void
ble_gap_master_extract_state(struct ble_gap_master_state * out_state,int reset_state)693*042d53a7SEvalZero ble_gap_master_extract_state(struct ble_gap_master_state *out_state,
694*042d53a7SEvalZero                              int reset_state)
695*042d53a7SEvalZero {
696*042d53a7SEvalZero     ble_hs_lock();
697*042d53a7SEvalZero 
698*042d53a7SEvalZero     *out_state = ble_gap_master;
699*042d53a7SEvalZero 
700*042d53a7SEvalZero     if (reset_state) {
701*042d53a7SEvalZero         ble_gap_master_reset_state();
702*042d53a7SEvalZero         ble_gap_master.preempted_op = BLE_GAP_OP_NULL;
703*042d53a7SEvalZero     }
704*042d53a7SEvalZero 
705*042d53a7SEvalZero     ble_hs_unlock();
706*042d53a7SEvalZero }
707*042d53a7SEvalZero 
708*042d53a7SEvalZero static void
ble_gap_slave_extract_cb(uint8_t instance,ble_gap_event_fn ** out_cb,void ** out_cb_arg)709*042d53a7SEvalZero ble_gap_slave_extract_cb(uint8_t instance,
710*042d53a7SEvalZero                          ble_gap_event_fn **out_cb, void **out_cb_arg)
711*042d53a7SEvalZero {
712*042d53a7SEvalZero     ble_hs_lock();
713*042d53a7SEvalZero 
714*042d53a7SEvalZero     *out_cb = ble_gap_slave[instance].cb;
715*042d53a7SEvalZero     *out_cb_arg = ble_gap_slave[instance].cb_arg;
716*042d53a7SEvalZero     ble_gap_slave_reset_state(instance);
717*042d53a7SEvalZero 
718*042d53a7SEvalZero     ble_hs_unlock();
719*042d53a7SEvalZero }
720*042d53a7SEvalZero 
721*042d53a7SEvalZero static void
ble_gap_adv_finished(uint8_t instance,int reason,uint16_t conn_handle,uint8_t num_events)722*042d53a7SEvalZero ble_gap_adv_finished(uint8_t instance, int reason, uint16_t conn_handle,
723*042d53a7SEvalZero                      uint8_t num_events)
724*042d53a7SEvalZero {
725*042d53a7SEvalZero     struct ble_gap_event event;
726*042d53a7SEvalZero     ble_gap_event_fn *cb;
727*042d53a7SEvalZero     void *cb_arg;
728*042d53a7SEvalZero 
729*042d53a7SEvalZero     ble_gap_slave_extract_cb(instance, &cb, &cb_arg);
730*042d53a7SEvalZero     if (cb != NULL) {
731*042d53a7SEvalZero         memset(&event, 0, sizeof event);
732*042d53a7SEvalZero         event.type = BLE_GAP_EVENT_ADV_COMPLETE;
733*042d53a7SEvalZero         event.adv_complete.reason = reason;
734*042d53a7SEvalZero #if MYNEWT_VAL(BLE_EXT_ADV)
735*042d53a7SEvalZero         event.adv_complete.instance = instance;
736*042d53a7SEvalZero         event.adv_complete.conn_handle = conn_handle;
737*042d53a7SEvalZero         event.adv_complete.num_ext_adv_events = num_events;
738*042d53a7SEvalZero #endif
739*042d53a7SEvalZero         cb(&event, cb_arg);
740*042d53a7SEvalZero     }
741*042d53a7SEvalZero }
742*042d53a7SEvalZero 
743*042d53a7SEvalZero static int
ble_gap_master_connect_failure(int status)744*042d53a7SEvalZero ble_gap_master_connect_failure(int status)
745*042d53a7SEvalZero {
746*042d53a7SEvalZero     struct ble_gap_master_state state;
747*042d53a7SEvalZero     struct ble_gap_event event;
748*042d53a7SEvalZero     int rc;
749*042d53a7SEvalZero 
750*042d53a7SEvalZero     ble_gap_master_extract_state(&state, 1);
751*042d53a7SEvalZero     if (ble_gap_has_client(&state)) {
752*042d53a7SEvalZero         memset(&event, 0, sizeof event);
753*042d53a7SEvalZero         event.type = BLE_GAP_EVENT_CONNECT;
754*042d53a7SEvalZero         event.connect.status = status;
755*042d53a7SEvalZero 
756*042d53a7SEvalZero         rc = state.cb(&event, state.cb_arg);
757*042d53a7SEvalZero     } else {
758*042d53a7SEvalZero         rc = 0;
759*042d53a7SEvalZero     }
760*042d53a7SEvalZero 
761*042d53a7SEvalZero     return rc;
762*042d53a7SEvalZero }
763*042d53a7SEvalZero 
764*042d53a7SEvalZero static void
ble_gap_master_connect_cancelled(void)765*042d53a7SEvalZero ble_gap_master_connect_cancelled(void)
766*042d53a7SEvalZero {
767*042d53a7SEvalZero     struct ble_gap_master_state state;
768*042d53a7SEvalZero     struct ble_gap_event event;
769*042d53a7SEvalZero 
770*042d53a7SEvalZero     ble_gap_master_extract_state(&state, 1);
771*042d53a7SEvalZero     if (state.cb != NULL) {
772*042d53a7SEvalZero         memset(&event, 0, sizeof event);
773*042d53a7SEvalZero         event.type = BLE_GAP_EVENT_CONNECT;
774*042d53a7SEvalZero         event.connect.conn_handle = BLE_HS_CONN_HANDLE_NONE;
775*042d53a7SEvalZero         if (state.conn.cancel) {
776*042d53a7SEvalZero             /* Connect procedure successfully cancelled. */
777*042d53a7SEvalZero             event.connect.status = BLE_HS_EAPP;
778*042d53a7SEvalZero         } else {
779*042d53a7SEvalZero             /* Connect procedure timed out. */
780*042d53a7SEvalZero             event.connect.status = BLE_HS_ETIMEOUT;
781*042d53a7SEvalZero         }
782*042d53a7SEvalZero         state.cb(&event, state.cb_arg);
783*042d53a7SEvalZero     }
784*042d53a7SEvalZero }
785*042d53a7SEvalZero 
786*042d53a7SEvalZero static void
ble_gap_disc_report(void * desc)787*042d53a7SEvalZero ble_gap_disc_report(void *desc)
788*042d53a7SEvalZero {
789*042d53a7SEvalZero     struct ble_gap_master_state state;
790*042d53a7SEvalZero     struct ble_gap_event event;
791*042d53a7SEvalZero 
792*042d53a7SEvalZero     memset(&event, 0, sizeof event);
793*042d53a7SEvalZero #if MYNEWT_VAL(BLE_EXT_ADV)
794*042d53a7SEvalZero     event.type = BLE_GAP_EVENT_EXT_DISC;
795*042d53a7SEvalZero     event.ext_disc = *((struct ble_gap_ext_disc_desc *)desc);
796*042d53a7SEvalZero #else
797*042d53a7SEvalZero     event.type = BLE_GAP_EVENT_DISC;
798*042d53a7SEvalZero     event.disc = *((struct ble_gap_disc_desc *)desc);
799*042d53a7SEvalZero #endif
800*042d53a7SEvalZero 
801*042d53a7SEvalZero     ble_gap_master_extract_state(&state, 0);
802*042d53a7SEvalZero     if (ble_gap_has_client(&state)) {
803*042d53a7SEvalZero         state.cb(&event, state.cb_arg);
804*042d53a7SEvalZero     }
805*042d53a7SEvalZero 
806*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MESH)
807*042d53a7SEvalZero     if (ble_gap_mesh.cb) {
808*042d53a7SEvalZero         ble_gap_mesh.cb(&event, ble_gap_mesh.cb_arg);
809*042d53a7SEvalZero     }
810*042d53a7SEvalZero #endif
811*042d53a7SEvalZero }
812*042d53a7SEvalZero 
813*042d53a7SEvalZero #if NIMBLE_BLE_SCAN
814*042d53a7SEvalZero static void
ble_gap_disc_complete(void)815*042d53a7SEvalZero ble_gap_disc_complete(void)
816*042d53a7SEvalZero {
817*042d53a7SEvalZero     struct ble_gap_master_state state;
818*042d53a7SEvalZero     struct ble_gap_event event;
819*042d53a7SEvalZero 
820*042d53a7SEvalZero     memset(&event, 0, sizeof event);
821*042d53a7SEvalZero     event.type = BLE_GAP_EVENT_DISC_COMPLETE;
822*042d53a7SEvalZero     event.disc_complete.reason = 0;
823*042d53a7SEvalZero 
824*042d53a7SEvalZero     ble_gap_master_extract_state(&state, 1);
825*042d53a7SEvalZero     if (ble_gap_has_client(&state)) {
826*042d53a7SEvalZero         ble_gap_call_event_cb(&event, state.cb, state.cb_arg);
827*042d53a7SEvalZero     }
828*042d53a7SEvalZero 
829*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MESH)
830*042d53a7SEvalZero     if (ble_gap_mesh.cb) {
831*042d53a7SEvalZero         ble_gap_mesh.cb(&event, ble_gap_mesh.cb_arg);
832*042d53a7SEvalZero     }
833*042d53a7SEvalZero #endif
834*042d53a7SEvalZero }
835*042d53a7SEvalZero #endif
836*042d53a7SEvalZero 
837*042d53a7SEvalZero static void
ble_gap_update_notify(uint16_t conn_handle,int status)838*042d53a7SEvalZero ble_gap_update_notify(uint16_t conn_handle, int status)
839*042d53a7SEvalZero {
840*042d53a7SEvalZero     struct ble_gap_event event;
841*042d53a7SEvalZero 
842*042d53a7SEvalZero     memset(&event, 0, sizeof event);
843*042d53a7SEvalZero     event.type = BLE_GAP_EVENT_CONN_UPDATE;
844*042d53a7SEvalZero     event.conn_update.conn_handle = conn_handle;
845*042d53a7SEvalZero     event.conn_update.status = status;
846*042d53a7SEvalZero 
847*042d53a7SEvalZero     ble_gap_event_listener_call(&event);
848*042d53a7SEvalZero     ble_gap_call_conn_event_cb(&event, conn_handle);
849*042d53a7SEvalZero 
850*042d53a7SEvalZero     /* Terminate the connection on procedure timeout. */
851*042d53a7SEvalZero     if (status == BLE_HS_ETIMEOUT) {
852*042d53a7SEvalZero         ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM);
853*042d53a7SEvalZero     }
854*042d53a7SEvalZero }
855*042d53a7SEvalZero 
856*042d53a7SEvalZero static uint32_t
ble_gap_master_ticks_until_exp(void)857*042d53a7SEvalZero ble_gap_master_ticks_until_exp(void)
858*042d53a7SEvalZero {
859*042d53a7SEvalZero     ble_npl_stime_t ticks;
860*042d53a7SEvalZero 
861*042d53a7SEvalZero     if (ble_gap_master.op == BLE_GAP_OP_NULL || !ble_gap_master.exp_set) {
862*042d53a7SEvalZero         /* Timer not set; infinity ticks until next event. */
863*042d53a7SEvalZero         return BLE_HS_FOREVER;
864*042d53a7SEvalZero     }
865*042d53a7SEvalZero 
866*042d53a7SEvalZero     ticks = ble_gap_master.exp_os_ticks - ble_npl_time_get();
867*042d53a7SEvalZero     if (ticks > 0) {
868*042d53a7SEvalZero         /* Timer not expired yet. */
869*042d53a7SEvalZero         return ticks;
870*042d53a7SEvalZero     }
871*042d53a7SEvalZero 
872*042d53a7SEvalZero     /* Timer just expired. */
873*042d53a7SEvalZero     return 0;
874*042d53a7SEvalZero }
875*042d53a7SEvalZero 
876*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_EXT_ADV)
877*042d53a7SEvalZero static uint32_t
ble_gap_slave_ticks_until_exp(void)878*042d53a7SEvalZero ble_gap_slave_ticks_until_exp(void)
879*042d53a7SEvalZero {
880*042d53a7SEvalZero     ble_npl_stime_t ticks;
881*042d53a7SEvalZero 
882*042d53a7SEvalZero     if (ble_gap_slave[0].op == BLE_GAP_OP_NULL || !ble_gap_slave[0].exp_set) {
883*042d53a7SEvalZero         /* Timer not set; infinity ticks until next event. */
884*042d53a7SEvalZero         return BLE_HS_FOREVER;
885*042d53a7SEvalZero     }
886*042d53a7SEvalZero 
887*042d53a7SEvalZero     ticks = ble_gap_slave[0].exp_os_ticks - ble_npl_time_get();
888*042d53a7SEvalZero     if (ticks > 0) {
889*042d53a7SEvalZero         /* Timer not expired yet. */
890*042d53a7SEvalZero         return ticks;
891*042d53a7SEvalZero     }
892*042d53a7SEvalZero 
893*042d53a7SEvalZero     /* Timer just expired. */
894*042d53a7SEvalZero     return 0;
895*042d53a7SEvalZero }
896*042d53a7SEvalZero #endif
897*042d53a7SEvalZero 
898*042d53a7SEvalZero /**
899*042d53a7SEvalZero  * Finds the update procedure that expires soonest.
900*042d53a7SEvalZero  *
901*042d53a7SEvalZero  * @param out_ticks_from_now    On success, the ticks until the update
902*042d53a7SEvalZero  *                                  procedure's expiry time gets written here.
903*042d53a7SEvalZero  *
904*042d53a7SEvalZero  * @return                      The connection handle of the update procedure
905*042d53a7SEvalZero  *                                  that expires soonest, or
906*042d53a7SEvalZero  *                                  BLE_HS_CONN_HANDLE_NONE if there are no
907*042d53a7SEvalZero  *                                  active update procedures.
908*042d53a7SEvalZero  */
909*042d53a7SEvalZero static uint16_t
ble_gap_update_next_exp(int32_t * out_ticks_from_now)910*042d53a7SEvalZero ble_gap_update_next_exp(int32_t *out_ticks_from_now)
911*042d53a7SEvalZero {
912*042d53a7SEvalZero     struct ble_gap_update_entry *entry;
913*042d53a7SEvalZero     ble_npl_time_t now;
914*042d53a7SEvalZero     uint16_t conn_handle;
915*042d53a7SEvalZero     int32_t best_ticks;
916*042d53a7SEvalZero     int32_t ticks;
917*042d53a7SEvalZero 
918*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task());
919*042d53a7SEvalZero 
920*042d53a7SEvalZero     conn_handle = BLE_HS_CONN_HANDLE_NONE;
921*042d53a7SEvalZero     best_ticks = BLE_HS_FOREVER;
922*042d53a7SEvalZero     now = ble_npl_time_get();
923*042d53a7SEvalZero 
924*042d53a7SEvalZero     SLIST_FOREACH(entry, &ble_gap_update_entries, next) {
925*042d53a7SEvalZero         ticks = entry->exp_os_ticks - now;
926*042d53a7SEvalZero         if (ticks <= 0) {
927*042d53a7SEvalZero             ticks = 0;
928*042d53a7SEvalZero         }
929*042d53a7SEvalZero 
930*042d53a7SEvalZero         if (ticks < best_ticks) {
931*042d53a7SEvalZero             conn_handle = entry->conn_handle;
932*042d53a7SEvalZero             best_ticks = ticks;
933*042d53a7SEvalZero         }
934*042d53a7SEvalZero     }
935*042d53a7SEvalZero 
936*042d53a7SEvalZero     if (out_ticks_from_now != NULL) {
937*042d53a7SEvalZero         *out_ticks_from_now = best_ticks;
938*042d53a7SEvalZero     }
939*042d53a7SEvalZero 
940*042d53a7SEvalZero     return conn_handle;
941*042d53a7SEvalZero 
942*042d53a7SEvalZero }
943*042d53a7SEvalZero 
944*042d53a7SEvalZero static void
ble_gap_master_set_timer(uint32_t ticks_from_now)945*042d53a7SEvalZero ble_gap_master_set_timer(uint32_t ticks_from_now)
946*042d53a7SEvalZero {
947*042d53a7SEvalZero     ble_gap_master.exp_os_ticks = ble_npl_time_get() + ticks_from_now;
948*042d53a7SEvalZero     ble_gap_master.exp_set = 1;
949*042d53a7SEvalZero 
950*042d53a7SEvalZero     ble_hs_timer_resched();
951*042d53a7SEvalZero }
952*042d53a7SEvalZero 
953*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_EXT_ADV)
954*042d53a7SEvalZero static void
ble_gap_slave_set_timer(uint32_t ticks_from_now)955*042d53a7SEvalZero ble_gap_slave_set_timer(uint32_t ticks_from_now)
956*042d53a7SEvalZero {
957*042d53a7SEvalZero     ble_gap_slave[0].exp_os_ticks = ble_npl_time_get() + ticks_from_now;
958*042d53a7SEvalZero     ble_gap_slave[0].exp_set = 1;
959*042d53a7SEvalZero 
960*042d53a7SEvalZero     ble_hs_timer_resched();
961*042d53a7SEvalZero }
962*042d53a7SEvalZero #endif
963*042d53a7SEvalZero 
964*042d53a7SEvalZero /**
965*042d53a7SEvalZero  * Called when an error is encountered while the master-connection-fsm is
966*042d53a7SEvalZero  * active.
967*042d53a7SEvalZero  */
968*042d53a7SEvalZero static void
ble_gap_master_failed(int status)969*042d53a7SEvalZero ble_gap_master_failed(int status)
970*042d53a7SEvalZero {
971*042d53a7SEvalZero     switch (ble_gap_master.op) {
972*042d53a7SEvalZero     case BLE_GAP_OP_M_CONN:
973*042d53a7SEvalZero         STATS_INC(ble_gap_stats, initiate_fail);
974*042d53a7SEvalZero         ble_gap_master_connect_failure(status);
975*042d53a7SEvalZero         break;
976*042d53a7SEvalZero 
977*042d53a7SEvalZero     default:
978*042d53a7SEvalZero         BLE_HS_DBG_ASSERT(0);
979*042d53a7SEvalZero         break;
980*042d53a7SEvalZero     }
981*042d53a7SEvalZero }
982*042d53a7SEvalZero 
983*042d53a7SEvalZero static void
ble_gap_update_failed(uint16_t conn_handle,int status)984*042d53a7SEvalZero ble_gap_update_failed(uint16_t conn_handle, int status)
985*042d53a7SEvalZero {
986*042d53a7SEvalZero     struct ble_gap_update_entry *entry;
987*042d53a7SEvalZero 
988*042d53a7SEvalZero     STATS_INC(ble_gap_stats, update_fail);
989*042d53a7SEvalZero 
990*042d53a7SEvalZero     ble_hs_lock();
991*042d53a7SEvalZero     entry = ble_gap_update_entry_remove(conn_handle);
992*042d53a7SEvalZero     ble_hs_unlock();
993*042d53a7SEvalZero 
994*042d53a7SEvalZero     ble_gap_update_entry_free(entry);
995*042d53a7SEvalZero 
996*042d53a7SEvalZero     ble_gap_update_notify(conn_handle, status);
997*042d53a7SEvalZero }
998*042d53a7SEvalZero 
999*042d53a7SEvalZero void
ble_gap_conn_broken(uint16_t conn_handle,int reason)1000*042d53a7SEvalZero ble_gap_conn_broken(uint16_t conn_handle, int reason)
1001*042d53a7SEvalZero {
1002*042d53a7SEvalZero     struct ble_gap_update_entry *entry;
1003*042d53a7SEvalZero     struct ble_gap_snapshot snap;
1004*042d53a7SEvalZero     struct ble_gap_event event;
1005*042d53a7SEvalZero     int rc;
1006*042d53a7SEvalZero 
1007*042d53a7SEvalZero     memset(&event, 0, sizeof event);
1008*042d53a7SEvalZero     snap.desc = &event.disconnect.conn;
1009*042d53a7SEvalZero 
1010*042d53a7SEvalZero     rc = ble_gap_find_snapshot(conn_handle, &snap);
1011*042d53a7SEvalZero     if (rc != 0) {
1012*042d53a7SEvalZero         /* No longer connected. */
1013*042d53a7SEvalZero         return;
1014*042d53a7SEvalZero     }
1015*042d53a7SEvalZero 
1016*042d53a7SEvalZero     /* If there was a connection update in progress, indicate to the
1017*042d53a7SEvalZero      * application that it did not complete.
1018*042d53a7SEvalZero      */
1019*042d53a7SEvalZero     ble_hs_lock();
1020*042d53a7SEvalZero     entry = ble_gap_update_entry_remove(conn_handle);
1021*042d53a7SEvalZero     ble_hs_unlock();
1022*042d53a7SEvalZero 
1023*042d53a7SEvalZero     if (entry != NULL) {
1024*042d53a7SEvalZero         ble_gap_update_notify(conn_handle, reason);
1025*042d53a7SEvalZero         ble_gap_update_entry_free(entry);
1026*042d53a7SEvalZero     }
1027*042d53a7SEvalZero 
1028*042d53a7SEvalZero     /* Indicate the connection termination to each module.  The order matters
1029*042d53a7SEvalZero      * here: gatts must come before gattc to ensure the application does not
1030*042d53a7SEvalZero      * get informed of spurious notify-tx events.
1031*042d53a7SEvalZero      */
1032*042d53a7SEvalZero     ble_l2cap_sig_conn_broken(conn_handle, reason);
1033*042d53a7SEvalZero     ble_sm_connection_broken(conn_handle);
1034*042d53a7SEvalZero     ble_gatts_connection_broken(conn_handle);
1035*042d53a7SEvalZero     ble_gattc_connection_broken(conn_handle);
1036*042d53a7SEvalZero     ble_hs_flow_connection_broken(conn_handle);;
1037*042d53a7SEvalZero 
1038*042d53a7SEvalZero     ble_hs_atomic_conn_delete(conn_handle);
1039*042d53a7SEvalZero 
1040*042d53a7SEvalZero     event.type = BLE_GAP_EVENT_DISCONNECT;
1041*042d53a7SEvalZero     event.disconnect.reason = reason;
1042*042d53a7SEvalZero 
1043*042d53a7SEvalZero     ble_gap_event_listener_call(&event);
1044*042d53a7SEvalZero     ble_gap_call_event_cb(&event, snap.cb, snap.cb_arg);
1045*042d53a7SEvalZero 
1046*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MESH)
1047*042d53a7SEvalZero     if (ble_gap_mesh.cb) {
1048*042d53a7SEvalZero         ble_gap_mesh.cb(&event, ble_gap_mesh.cb_arg);
1049*042d53a7SEvalZero     }
1050*042d53a7SEvalZero #endif
1051*042d53a7SEvalZero 
1052*042d53a7SEvalZero     STATS_INC(ble_gap_stats, disconnect);
1053*042d53a7SEvalZero }
1054*042d53a7SEvalZero 
1055*042d53a7SEvalZero static void
ble_gap_update_to_l2cap(const struct ble_gap_upd_params * params,struct ble_l2cap_sig_update_params * l2cap_params)1056*042d53a7SEvalZero ble_gap_update_to_l2cap(const struct ble_gap_upd_params *params,
1057*042d53a7SEvalZero                         struct ble_l2cap_sig_update_params *l2cap_params)
1058*042d53a7SEvalZero {
1059*042d53a7SEvalZero     l2cap_params->itvl_min = params->itvl_min;
1060*042d53a7SEvalZero     l2cap_params->itvl_max = params->itvl_max;
1061*042d53a7SEvalZero     l2cap_params->slave_latency = params->latency;
1062*042d53a7SEvalZero     l2cap_params->timeout_multiplier = params->supervision_timeout;
1063*042d53a7SEvalZero }
1064*042d53a7SEvalZero 
1065*042d53a7SEvalZero void
ble_gap_rx_disconn_complete(struct hci_disconn_complete * evt)1066*042d53a7SEvalZero ble_gap_rx_disconn_complete(struct hci_disconn_complete *evt)
1067*042d53a7SEvalZero {
1068*042d53a7SEvalZero #if !NIMBLE_BLE_CONNECT
1069*042d53a7SEvalZero     return;
1070*042d53a7SEvalZero #endif
1071*042d53a7SEvalZero 
1072*042d53a7SEvalZero     struct ble_gap_event event;
1073*042d53a7SEvalZero 
1074*042d53a7SEvalZero     STATS_INC(ble_gap_stats, rx_disconnect);
1075*042d53a7SEvalZero 
1076*042d53a7SEvalZero     if (evt->status == 0) {
1077*042d53a7SEvalZero         ble_gap_conn_broken(evt->connection_handle,
1078*042d53a7SEvalZero                             BLE_HS_HCI_ERR(evt->reason));
1079*042d53a7SEvalZero     } else {
1080*042d53a7SEvalZero         memset(&event, 0, sizeof event);
1081*042d53a7SEvalZero         event.type = BLE_GAP_EVENT_TERM_FAILURE;
1082*042d53a7SEvalZero         event.term_failure.conn_handle = evt->connection_handle;
1083*042d53a7SEvalZero         event.term_failure.status = BLE_HS_HCI_ERR(evt->status);
1084*042d53a7SEvalZero 
1085*042d53a7SEvalZero         ble_gap_event_listener_call(&event);
1086*042d53a7SEvalZero         ble_gap_call_conn_event_cb(&event, evt->connection_handle);
1087*042d53a7SEvalZero     }
1088*042d53a7SEvalZero }
1089*042d53a7SEvalZero 
1090*042d53a7SEvalZero void
ble_gap_rx_update_complete(struct hci_le_conn_upd_complete * evt)1091*042d53a7SEvalZero ble_gap_rx_update_complete(struct hci_le_conn_upd_complete *evt)
1092*042d53a7SEvalZero {
1093*042d53a7SEvalZero #if !NIMBLE_BLE_CONNECT
1094*042d53a7SEvalZero     return;
1095*042d53a7SEvalZero #endif
1096*042d53a7SEvalZero 
1097*042d53a7SEvalZero     struct ble_gap_update_entry *entry;
1098*042d53a7SEvalZero     struct ble_l2cap_sig_update_params l2cap_params;
1099*042d53a7SEvalZero     struct ble_gap_event event;
1100*042d53a7SEvalZero     struct ble_hs_conn *conn;
1101*042d53a7SEvalZero     int cb_status;
1102*042d53a7SEvalZero     int call_cb;
1103*042d53a7SEvalZero     int rc;
1104*042d53a7SEvalZero 
1105*042d53a7SEvalZero     STATS_INC(ble_gap_stats, rx_update_complete);
1106*042d53a7SEvalZero 
1107*042d53a7SEvalZero     memset(&event, 0, sizeof event);
1108*042d53a7SEvalZero     memset(&l2cap_params, 0, sizeof l2cap_params);
1109*042d53a7SEvalZero 
1110*042d53a7SEvalZero     ble_hs_lock();
1111*042d53a7SEvalZero 
1112*042d53a7SEvalZero     conn = ble_hs_conn_find(evt->connection_handle);
1113*042d53a7SEvalZero     if (conn != NULL) {
1114*042d53a7SEvalZero         switch (evt->status) {
1115*042d53a7SEvalZero         case 0:
1116*042d53a7SEvalZero             /* Connection successfully updated. */
1117*042d53a7SEvalZero             conn->bhc_itvl = evt->conn_itvl;
1118*042d53a7SEvalZero             conn->bhc_latency = evt->conn_latency;
1119*042d53a7SEvalZero             conn->bhc_supervision_timeout = evt->supervision_timeout;
1120*042d53a7SEvalZero             break;
1121*042d53a7SEvalZero 
1122*042d53a7SEvalZero         case BLE_ERR_UNSUPP_REM_FEATURE:
1123*042d53a7SEvalZero             /* Peer reports that it doesn't support the procedure.  This should
1124*042d53a7SEvalZero              * only happen if our controller sent the 4.1 Connection Parameters
1125*042d53a7SEvalZero              * Request Procedure.  If we are the slave, fail over to the L2CAP
1126*042d53a7SEvalZero              * update procedure.
1127*042d53a7SEvalZero              */
1128*042d53a7SEvalZero             entry = ble_gap_update_entry_find(evt->connection_handle, NULL);
1129*042d53a7SEvalZero             if (entry != NULL && !(conn->bhc_flags & BLE_HS_CONN_F_MASTER)) {
1130*042d53a7SEvalZero                 ble_gap_update_to_l2cap(&entry->params, &l2cap_params);
1131*042d53a7SEvalZero             }
1132*042d53a7SEvalZero             break;
1133*042d53a7SEvalZero 
1134*042d53a7SEvalZero         default:
1135*042d53a7SEvalZero             break;
1136*042d53a7SEvalZero         }
1137*042d53a7SEvalZero     }
1138*042d53a7SEvalZero 
1139*042d53a7SEvalZero     /* We aren't failing over to L2CAP, the update procedure is complete. */
1140*042d53a7SEvalZero     if (l2cap_params.itvl_min == 0) {
1141*042d53a7SEvalZero         entry = ble_gap_update_entry_remove(evt->connection_handle);
1142*042d53a7SEvalZero         ble_gap_update_entry_free(entry);
1143*042d53a7SEvalZero     }
1144*042d53a7SEvalZero 
1145*042d53a7SEvalZero     ble_hs_unlock();
1146*042d53a7SEvalZero 
1147*042d53a7SEvalZero     if (l2cap_params.itvl_min != 0) {
1148*042d53a7SEvalZero         rc = ble_l2cap_sig_update(evt->connection_handle,
1149*042d53a7SEvalZero                                   &l2cap_params,
1150*042d53a7SEvalZero                                   ble_gap_update_l2cap_cb, NULL);
1151*042d53a7SEvalZero         if (rc == 0) {
1152*042d53a7SEvalZero             call_cb = 0;
1153*042d53a7SEvalZero         } else {
1154*042d53a7SEvalZero             call_cb = 1;
1155*042d53a7SEvalZero             cb_status = rc;
1156*042d53a7SEvalZero         }
1157*042d53a7SEvalZero     } else {
1158*042d53a7SEvalZero         call_cb = 1;
1159*042d53a7SEvalZero         cb_status = BLE_HS_HCI_ERR(evt->status);
1160*042d53a7SEvalZero     }
1161*042d53a7SEvalZero 
1162*042d53a7SEvalZero     if (call_cb) {
1163*042d53a7SEvalZero         ble_gap_update_notify(evt->connection_handle, cb_status);
1164*042d53a7SEvalZero     }
1165*042d53a7SEvalZero }
1166*042d53a7SEvalZero 
1167*042d53a7SEvalZero /**
1168*042d53a7SEvalZero  * Tells you if there is an active central GAP procedure (connect or discover).
1169*042d53a7SEvalZero  */
1170*042d53a7SEvalZero int
ble_gap_master_in_progress(void)1171*042d53a7SEvalZero ble_gap_master_in_progress(void)
1172*042d53a7SEvalZero {
1173*042d53a7SEvalZero     return ble_gap_master.op != BLE_GAP_OP_NULL;
1174*042d53a7SEvalZero }
1175*042d53a7SEvalZero 
1176*042d53a7SEvalZero static int
ble_gap_accept_master_conn(void)1177*042d53a7SEvalZero ble_gap_accept_master_conn(void)
1178*042d53a7SEvalZero {
1179*042d53a7SEvalZero     int rc;
1180*042d53a7SEvalZero 
1181*042d53a7SEvalZero     switch (ble_gap_master.op) {
1182*042d53a7SEvalZero     case BLE_GAP_OP_NULL:
1183*042d53a7SEvalZero     case BLE_GAP_OP_M_DISC:
1184*042d53a7SEvalZero         rc = BLE_HS_ENOENT;
1185*042d53a7SEvalZero         break;
1186*042d53a7SEvalZero 
1187*042d53a7SEvalZero     case BLE_GAP_OP_M_CONN:
1188*042d53a7SEvalZero         rc = 0;
1189*042d53a7SEvalZero         break;
1190*042d53a7SEvalZero 
1191*042d53a7SEvalZero     default:
1192*042d53a7SEvalZero         BLE_HS_DBG_ASSERT(0);
1193*042d53a7SEvalZero         rc = BLE_HS_ENOENT;
1194*042d53a7SEvalZero         break;
1195*042d53a7SEvalZero     }
1196*042d53a7SEvalZero 
1197*042d53a7SEvalZero     if (rc == 0) {
1198*042d53a7SEvalZero         STATS_INC(ble_gap_stats, connect_mst);
1199*042d53a7SEvalZero     }
1200*042d53a7SEvalZero 
1201*042d53a7SEvalZero     return rc;
1202*042d53a7SEvalZero }
1203*042d53a7SEvalZero 
1204*042d53a7SEvalZero static int
ble_gap_adv_active_instance(uint8_t instance)1205*042d53a7SEvalZero ble_gap_adv_active_instance(uint8_t instance)
1206*042d53a7SEvalZero {
1207*042d53a7SEvalZero     /* Assume read is atomic; mutex not necessary. */
1208*042d53a7SEvalZero     return ble_gap_slave[instance].op == BLE_GAP_OP_S_ADV;
1209*042d53a7SEvalZero }
1210*042d53a7SEvalZero 
1211*042d53a7SEvalZero static int
ble_gap_accept_slave_conn(uint8_t instance)1212*042d53a7SEvalZero ble_gap_accept_slave_conn(uint8_t instance)
1213*042d53a7SEvalZero {
1214*042d53a7SEvalZero     int rc;
1215*042d53a7SEvalZero 
1216*042d53a7SEvalZero     if (instance >= BLE_ADV_INSTANCES) {
1217*042d53a7SEvalZero        rc = BLE_HS_ENOENT;
1218*042d53a7SEvalZero     } else if (!ble_gap_adv_active_instance(instance)) {
1219*042d53a7SEvalZero         rc = BLE_HS_ENOENT;
1220*042d53a7SEvalZero     } else {
1221*042d53a7SEvalZero         if (ble_gap_slave[instance].connectable) {
1222*042d53a7SEvalZero             rc = 0;
1223*042d53a7SEvalZero         } else {
1224*042d53a7SEvalZero             rc = BLE_HS_ENOENT;
1225*042d53a7SEvalZero         }
1226*042d53a7SEvalZero     }
1227*042d53a7SEvalZero 
1228*042d53a7SEvalZero     if (rc == 0) {
1229*042d53a7SEvalZero         STATS_INC(ble_gap_stats, connect_slv);
1230*042d53a7SEvalZero     }
1231*042d53a7SEvalZero 
1232*042d53a7SEvalZero     return rc;
1233*042d53a7SEvalZero }
1234*042d53a7SEvalZero 
1235*042d53a7SEvalZero static int
ble_gap_rx_adv_report_sanity_check(uint8_t * adv_data,uint8_t adv_data_len)1236*042d53a7SEvalZero ble_gap_rx_adv_report_sanity_check(uint8_t *adv_data, uint8_t adv_data_len)
1237*042d53a7SEvalZero {
1238*042d53a7SEvalZero     const struct ble_hs_adv_field *flags;
1239*042d53a7SEvalZero     int rc;
1240*042d53a7SEvalZero 
1241*042d53a7SEvalZero     STATS_INC(ble_gap_stats, rx_adv_report);
1242*042d53a7SEvalZero 
1243*042d53a7SEvalZero     if (ble_gap_master.op != BLE_GAP_OP_M_DISC) {
1244*042d53a7SEvalZero         return -1;
1245*042d53a7SEvalZero     }
1246*042d53a7SEvalZero 
1247*042d53a7SEvalZero     /* If a limited discovery procedure is active, discard non-limited
1248*042d53a7SEvalZero      * advertisements.
1249*042d53a7SEvalZero      */
1250*042d53a7SEvalZero     if (ble_gap_master.disc.limited) {
1251*042d53a7SEvalZero         rc = ble_hs_adv_find_field(BLE_HS_ADV_TYPE_FLAGS, adv_data,
1252*042d53a7SEvalZero                                    adv_data_len, &flags);
1253*042d53a7SEvalZero         if ((rc == 0) && (flags->length == 2) &&
1254*042d53a7SEvalZero             !(flags->value[0] & BLE_HS_ADV_F_DISC_LTD)) {
1255*042d53a7SEvalZero             return -1;
1256*042d53a7SEvalZero         }
1257*042d53a7SEvalZero     }
1258*042d53a7SEvalZero 
1259*042d53a7SEvalZero     return 0;
1260*042d53a7SEvalZero }
1261*042d53a7SEvalZero 
1262*042d53a7SEvalZero void
ble_gap_rx_adv_report(struct ble_gap_disc_desc * desc)1263*042d53a7SEvalZero ble_gap_rx_adv_report(struct ble_gap_disc_desc *desc)
1264*042d53a7SEvalZero {
1265*042d53a7SEvalZero #if !NIMBLE_BLE_SCAN
1266*042d53a7SEvalZero     return;
1267*042d53a7SEvalZero #endif
1268*042d53a7SEvalZero 
1269*042d53a7SEvalZero     if (ble_gap_rx_adv_report_sanity_check(desc->data, desc->length_data)) {
1270*042d53a7SEvalZero         return;
1271*042d53a7SEvalZero     }
1272*042d53a7SEvalZero 
1273*042d53a7SEvalZero     ble_gap_disc_report(desc);
1274*042d53a7SEvalZero }
1275*042d53a7SEvalZero 
1276*042d53a7SEvalZero #if MYNEWT_VAL(BLE_EXT_ADV) && NIMBLE_BLE_SCAN
1277*042d53a7SEvalZero void
ble_gap_rx_le_scan_timeout(void)1278*042d53a7SEvalZero ble_gap_rx_le_scan_timeout(void)
1279*042d53a7SEvalZero {
1280*042d53a7SEvalZero     ble_gap_disc_complete();
1281*042d53a7SEvalZero }
1282*042d53a7SEvalZero #endif
1283*042d53a7SEvalZero 
1284*042d53a7SEvalZero #if MYNEWT_VAL(BLE_EXT_ADV)
1285*042d53a7SEvalZero void
ble_gap_rx_ext_adv_report(struct ble_gap_ext_disc_desc * desc)1286*042d53a7SEvalZero ble_gap_rx_ext_adv_report(struct ble_gap_ext_disc_desc *desc)
1287*042d53a7SEvalZero {
1288*042d53a7SEvalZero     if (ble_gap_rx_adv_report_sanity_check(desc->data, desc->length_data)) {
1289*042d53a7SEvalZero         return;
1290*042d53a7SEvalZero     }
1291*042d53a7SEvalZero 
1292*042d53a7SEvalZero     ble_gap_disc_report(desc);
1293*042d53a7SEvalZero }
1294*042d53a7SEvalZero 
1295*042d53a7SEvalZero void
ble_gap_rx_adv_set_terminated(struct hci_le_adv_set_terminated * evt)1296*042d53a7SEvalZero ble_gap_rx_adv_set_terminated(struct hci_le_adv_set_terminated *evt)
1297*042d53a7SEvalZero {
1298*042d53a7SEvalZero     uint16_t conn_handle;
1299*042d53a7SEvalZero     int reason;
1300*042d53a7SEvalZero 
1301*042d53a7SEvalZero     /* Currently spec allows only 0x3c and 0x43 when advertising was stopped
1302*042d53a7SEvalZero      * due to timeout or events limit, mp this for timeout error for now */
1303*042d53a7SEvalZero     if (evt->status) {
1304*042d53a7SEvalZero         reason = BLE_HS_ETIMEOUT;
1305*042d53a7SEvalZero         conn_handle = 0;
1306*042d53a7SEvalZero     } else {
1307*042d53a7SEvalZero         reason = 0;
1308*042d53a7SEvalZero         conn_handle = evt->conn_handle;
1309*042d53a7SEvalZero     }
1310*042d53a7SEvalZero 
1311*042d53a7SEvalZero     ble_gap_adv_finished(evt->adv_handle, reason, conn_handle,
1312*042d53a7SEvalZero                          evt->completed_events);
1313*042d53a7SEvalZero }
1314*042d53a7SEvalZero #endif
1315*042d53a7SEvalZero 
1316*042d53a7SEvalZero static int
ble_gap_rd_rem_sup_feat_tx(uint16_t handle)1317*042d53a7SEvalZero ble_gap_rd_rem_sup_feat_tx(uint16_t handle)
1318*042d53a7SEvalZero {
1319*042d53a7SEvalZero     uint8_t buf[BLE_HCI_CONN_RD_REM_FEAT_LEN];
1320*042d53a7SEvalZero     int rc;
1321*042d53a7SEvalZero 
1322*042d53a7SEvalZero     rc = ble_hs_hci_cmd_build_le_read_remote_feat(handle, buf, sizeof buf);
1323*042d53a7SEvalZero     if (rc != 0) {
1324*042d53a7SEvalZero         return BLE_HS_EUNKNOWN;
1325*042d53a7SEvalZero     }
1326*042d53a7SEvalZero 
1327*042d53a7SEvalZero     rc = ble_hs_hci_cmd_tx_empty_ack(BLE_HCI_OP(BLE_HCI_OGF_LE,
1328*042d53a7SEvalZero                                                 BLE_HCI_OCF_LE_RD_REM_FEAT),
1329*042d53a7SEvalZero                                      buf, sizeof(buf));
1330*042d53a7SEvalZero     if (rc != 0) {
1331*042d53a7SEvalZero         return rc;
1332*042d53a7SEvalZero     }
1333*042d53a7SEvalZero 
1334*042d53a7SEvalZero     return 0;
1335*042d53a7SEvalZero }
1336*042d53a7SEvalZero 
1337*042d53a7SEvalZero /**
1338*042d53a7SEvalZero  * Processes an incoming connection-complete HCI event.
1339*042d53a7SEvalZero  * instance parameter is valid only for slave connection.
1340*042d53a7SEvalZero  */
1341*042d53a7SEvalZero int
ble_gap_rx_conn_complete(struct hci_le_conn_complete * evt,uint8_t instance)1342*042d53a7SEvalZero ble_gap_rx_conn_complete(struct hci_le_conn_complete *evt, uint8_t instance)
1343*042d53a7SEvalZero {
1344*042d53a7SEvalZero #if !NIMBLE_BLE_CONNECT
1345*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
1346*042d53a7SEvalZero #endif
1347*042d53a7SEvalZero 
1348*042d53a7SEvalZero     struct ble_gap_event event;
1349*042d53a7SEvalZero     struct ble_hs_conn *conn;
1350*042d53a7SEvalZero     int rc;
1351*042d53a7SEvalZero 
1352*042d53a7SEvalZero     STATS_INC(ble_gap_stats, rx_conn_complete);
1353*042d53a7SEvalZero 
1354*042d53a7SEvalZero     /* in that case *only* status field is valid so we determine role
1355*042d53a7SEvalZero      * based on error code
1356*042d53a7SEvalZero      */
1357*042d53a7SEvalZero     if (evt->status != BLE_ERR_SUCCESS) {
1358*042d53a7SEvalZero         switch (evt->status) {
1359*042d53a7SEvalZero         case BLE_ERR_DIR_ADV_TMO:
1360*042d53a7SEvalZero             /* slave role (HD directed advertising)
1361*042d53a7SEvalZero              *
1362*042d53a7SEvalZero              * with ext advertising this is send from set terminated event
1363*042d53a7SEvalZero              */
1364*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_EXT_ADV)
1365*042d53a7SEvalZero             if (ble_gap_adv_active()) {
1366*042d53a7SEvalZero                 ble_gap_adv_finished(0, 0, 0, 0);
1367*042d53a7SEvalZero             }
1368*042d53a7SEvalZero #endif
1369*042d53a7SEvalZero             break;
1370*042d53a7SEvalZero         case BLE_ERR_UNK_CONN_ID:
1371*042d53a7SEvalZero             /* master role */
1372*042d53a7SEvalZero             if (ble_gap_master_in_progress()) {
1373*042d53a7SEvalZero                 /* Connect procedure successfully cancelled. */
1374*042d53a7SEvalZero                 if (ble_gap_master.preempted_op == BLE_GAP_OP_M_CONN) {
1375*042d53a7SEvalZero                     ble_gap_master_failed(BLE_HS_EPREEMPTED);
1376*042d53a7SEvalZero                 } else {
1377*042d53a7SEvalZero                     ble_gap_master_connect_cancelled();
1378*042d53a7SEvalZero                 }
1379*042d53a7SEvalZero             }
1380*042d53a7SEvalZero             break;
1381*042d53a7SEvalZero         default:
1382*042d53a7SEvalZero             /* this should never happen, unless controller is broken */
1383*042d53a7SEvalZero             BLE_HS_LOG(INFO, "controller reported invalid error code in conn"
1384*042d53a7SEvalZero                              "complete event: %u", evt->status);
1385*042d53a7SEvalZero             assert(0);
1386*042d53a7SEvalZero             break;
1387*042d53a7SEvalZero         }
1388*042d53a7SEvalZero         return 0;
1389*042d53a7SEvalZero     }
1390*042d53a7SEvalZero 
1391*042d53a7SEvalZero     /* Apply the event to the existing connection if it exists. */
1392*042d53a7SEvalZero     if (ble_hs_atomic_conn_flags(evt->connection_handle, NULL) == 0) {
1393*042d53a7SEvalZero         /* XXX: Does this ever happen? */
1394*042d53a7SEvalZero         return 0;
1395*042d53a7SEvalZero     }
1396*042d53a7SEvalZero 
1397*042d53a7SEvalZero     /* This event refers to a new connection. */
1398*042d53a7SEvalZero 
1399*042d53a7SEvalZero     switch (evt->role) {
1400*042d53a7SEvalZero     case BLE_HCI_LE_CONN_COMPLETE_ROLE_MASTER:
1401*042d53a7SEvalZero         rc = ble_gap_accept_master_conn();
1402*042d53a7SEvalZero         if (rc != 0) {
1403*042d53a7SEvalZero             return rc;
1404*042d53a7SEvalZero         }
1405*042d53a7SEvalZero         break;
1406*042d53a7SEvalZero 
1407*042d53a7SEvalZero     case BLE_HCI_LE_CONN_COMPLETE_ROLE_SLAVE:
1408*042d53a7SEvalZero         rc = ble_gap_accept_slave_conn(instance);
1409*042d53a7SEvalZero         if (rc != 0) {
1410*042d53a7SEvalZero             return rc;
1411*042d53a7SEvalZero         }
1412*042d53a7SEvalZero         break;
1413*042d53a7SEvalZero 
1414*042d53a7SEvalZero     default:
1415*042d53a7SEvalZero         BLE_HS_DBG_ASSERT(0);
1416*042d53a7SEvalZero         break;
1417*042d53a7SEvalZero     }
1418*042d53a7SEvalZero 
1419*042d53a7SEvalZero     /* We verified that there is a free connection when the procedure began. */
1420*042d53a7SEvalZero     conn = ble_hs_conn_alloc(evt->connection_handle);
1421*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(conn != NULL);
1422*042d53a7SEvalZero 
1423*042d53a7SEvalZero     conn->bhc_itvl = evt->conn_itvl;
1424*042d53a7SEvalZero     conn->bhc_latency = evt->conn_latency;
1425*042d53a7SEvalZero     conn->bhc_supervision_timeout = evt->supervision_timeout;
1426*042d53a7SEvalZero     conn->bhc_master_clock_accuracy = evt->master_clk_acc;
1427*042d53a7SEvalZero     if (evt->role == BLE_HCI_LE_CONN_COMPLETE_ROLE_MASTER) {
1428*042d53a7SEvalZero         conn->bhc_cb = ble_gap_master.cb;
1429*042d53a7SEvalZero         conn->bhc_cb_arg = ble_gap_master.cb_arg;
1430*042d53a7SEvalZero         conn->bhc_flags |= BLE_HS_CONN_F_MASTER;
1431*042d53a7SEvalZero         conn->bhc_our_addr_type = ble_gap_master.conn.our_addr_type;
1432*042d53a7SEvalZero         ble_gap_master_reset_state();
1433*042d53a7SEvalZero     } else {
1434*042d53a7SEvalZero         conn->bhc_cb = ble_gap_slave[instance].cb;
1435*042d53a7SEvalZero         conn->bhc_cb_arg = ble_gap_slave[instance].cb_arg;
1436*042d53a7SEvalZero         conn->bhc_our_addr_type = ble_gap_slave[instance].our_addr_type;
1437*042d53a7SEvalZero #if MYNEWT_VAL(BLE_EXT_ADV)
1438*042d53a7SEvalZero         memcpy(conn->bhc_our_rnd_addr, ble_gap_slave[instance].rnd_addr, 6);
1439*042d53a7SEvalZero #endif
1440*042d53a7SEvalZero         ble_gap_slave_reset_state(instance);
1441*042d53a7SEvalZero     }
1442*042d53a7SEvalZero 
1443*042d53a7SEvalZero     conn->bhc_peer_addr.type = evt->peer_addr_type;
1444*042d53a7SEvalZero     memcpy(conn->bhc_peer_addr.val, evt->peer_addr, 6);
1445*042d53a7SEvalZero 
1446*042d53a7SEvalZero     conn->bhc_our_rpa_addr.type = BLE_ADDR_RANDOM;
1447*042d53a7SEvalZero     memcpy(conn->bhc_our_rpa_addr.val, evt->local_rpa, 6);
1448*042d53a7SEvalZero 
1449*042d53a7SEvalZero     conn->bhc_peer_rpa_addr.type = BLE_ADDR_RANDOM;
1450*042d53a7SEvalZero     memcpy(conn->bhc_peer_rpa_addr.val, evt->peer_rpa, 6);
1451*042d53a7SEvalZero 
1452*042d53a7SEvalZero     ble_hs_lock();
1453*042d53a7SEvalZero 
1454*042d53a7SEvalZero     memset(&event, 0, sizeof event);
1455*042d53a7SEvalZero     ble_hs_conn_insert(conn);
1456*042d53a7SEvalZero 
1457*042d53a7SEvalZero     ble_hs_unlock();
1458*042d53a7SEvalZero 
1459*042d53a7SEvalZero     event.type = BLE_GAP_EVENT_CONNECT;
1460*042d53a7SEvalZero     event.connect.conn_handle = evt->connection_handle;
1461*042d53a7SEvalZero     event.connect.status = 0;
1462*042d53a7SEvalZero 
1463*042d53a7SEvalZero     ble_gap_event_listener_call(&event);
1464*042d53a7SEvalZero     ble_gap_call_conn_event_cb(&event, evt->connection_handle);
1465*042d53a7SEvalZero 
1466*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MESH)
1467*042d53a7SEvalZero     if (ble_gap_mesh.cb) {
1468*042d53a7SEvalZero         ble_gap_mesh.cb(&event, ble_gap_mesh.cb_arg);
1469*042d53a7SEvalZero     }
1470*042d53a7SEvalZero #endif
1471*042d53a7SEvalZero 
1472*042d53a7SEvalZero     ble_gap_rd_rem_sup_feat_tx(evt->connection_handle);
1473*042d53a7SEvalZero 
1474*042d53a7SEvalZero     return 0;
1475*042d53a7SEvalZero }
1476*042d53a7SEvalZero 
1477*042d53a7SEvalZero void
ble_gap_rx_rd_rem_sup_feat_complete(struct hci_le_rd_rem_supp_feat_complete * evt)1478*042d53a7SEvalZero ble_gap_rx_rd_rem_sup_feat_complete(
1479*042d53a7SEvalZero     struct hci_le_rd_rem_supp_feat_complete *evt)
1480*042d53a7SEvalZero {
1481*042d53a7SEvalZero #if !NIMBLE_BLE_CONNECT
1482*042d53a7SEvalZero     return;
1483*042d53a7SEvalZero #endif
1484*042d53a7SEvalZero 
1485*042d53a7SEvalZero     struct ble_hs_conn *conn;
1486*042d53a7SEvalZero 
1487*042d53a7SEvalZero     ble_hs_lock();
1488*042d53a7SEvalZero 
1489*042d53a7SEvalZero     conn = ble_hs_conn_find(evt->connection_handle);
1490*042d53a7SEvalZero     if (conn != NULL && evt->status == 0) {
1491*042d53a7SEvalZero             conn->supported_feat = get_le32(evt->features);
1492*042d53a7SEvalZero     }
1493*042d53a7SEvalZero 
1494*042d53a7SEvalZero     ble_hs_unlock();
1495*042d53a7SEvalZero }
1496*042d53a7SEvalZero 
1497*042d53a7SEvalZero int
ble_gap_rx_l2cap_update_req(uint16_t conn_handle,struct ble_gap_upd_params * params)1498*042d53a7SEvalZero ble_gap_rx_l2cap_update_req(uint16_t conn_handle,
1499*042d53a7SEvalZero                             struct ble_gap_upd_params *params)
1500*042d53a7SEvalZero {
1501*042d53a7SEvalZero     struct ble_gap_event event;
1502*042d53a7SEvalZero     int rc;
1503*042d53a7SEvalZero 
1504*042d53a7SEvalZero     memset(&event, 0, sizeof event);
1505*042d53a7SEvalZero     event.type = BLE_GAP_EVENT_L2CAP_UPDATE_REQ;
1506*042d53a7SEvalZero     event.conn_update_req.conn_handle = conn_handle;
1507*042d53a7SEvalZero     event.conn_update_req.peer_params = params;
1508*042d53a7SEvalZero 
1509*042d53a7SEvalZero     rc = ble_gap_call_conn_event_cb(&event, conn_handle);
1510*042d53a7SEvalZero     return rc;
1511*042d53a7SEvalZero }
1512*042d53a7SEvalZero 
1513*042d53a7SEvalZero void
ble_gap_rx_phy_update_complete(struct hci_le_phy_upd_complete * evt)1514*042d53a7SEvalZero ble_gap_rx_phy_update_complete(struct hci_le_phy_upd_complete *evt)
1515*042d53a7SEvalZero {
1516*042d53a7SEvalZero     struct ble_gap_event event;
1517*042d53a7SEvalZero 
1518*042d53a7SEvalZero     memset(&event, 0, sizeof event);
1519*042d53a7SEvalZero     event.type = BLE_GAP_EVENT_PHY_UPDATE_COMPLETE;
1520*042d53a7SEvalZero     event.phy_updated.status = evt->status;
1521*042d53a7SEvalZero     event.phy_updated.conn_handle = evt->connection_handle;
1522*042d53a7SEvalZero     event.phy_updated.tx_phy = evt->tx_phy;
1523*042d53a7SEvalZero     event.phy_updated.rx_phy = evt->rx_phy;
1524*042d53a7SEvalZero 
1525*042d53a7SEvalZero     ble_gap_event_listener_call(&event);
1526*042d53a7SEvalZero     ble_gap_call_conn_event_cb(&event, evt->connection_handle);
1527*042d53a7SEvalZero }
1528*042d53a7SEvalZero 
1529*042d53a7SEvalZero static int32_t
ble_gap_master_timer(void)1530*042d53a7SEvalZero ble_gap_master_timer(void)
1531*042d53a7SEvalZero {
1532*042d53a7SEvalZero     uint32_t ticks_until_exp;
1533*042d53a7SEvalZero     int rc;
1534*042d53a7SEvalZero 
1535*042d53a7SEvalZero     ticks_until_exp = ble_gap_master_ticks_until_exp();
1536*042d53a7SEvalZero     if (ticks_until_exp != 0) {
1537*042d53a7SEvalZero         /* Timer not expired yet. */
1538*042d53a7SEvalZero         return ticks_until_exp;
1539*042d53a7SEvalZero     }
1540*042d53a7SEvalZero 
1541*042d53a7SEvalZero     /*** Timer expired; process event. */
1542*042d53a7SEvalZero 
1543*042d53a7SEvalZero     switch (ble_gap_master.op) {
1544*042d53a7SEvalZero     case BLE_GAP_OP_M_CONN:
1545*042d53a7SEvalZero         rc = ble_gap_conn_cancel_tx();
1546*042d53a7SEvalZero         if (rc != 0) {
1547*042d53a7SEvalZero             /* Failed to stop connecting; try again in 100 ms. */
1548*042d53a7SEvalZero             return ble_npl_time_ms_to_ticks32(BLE_GAP_CANCEL_RETRY_TIMEOUT_MS);
1549*042d53a7SEvalZero         } else {
1550*042d53a7SEvalZero             /* Stop the timer now that the cancel command has been acked. */
1551*042d53a7SEvalZero             ble_gap_master.exp_set = 0;
1552*042d53a7SEvalZero 
1553*042d53a7SEvalZero             /* Timeout gets reported when we receive a connection complete
1554*042d53a7SEvalZero              * event indicating the connect procedure has been cancelled.
1555*042d53a7SEvalZero              */
1556*042d53a7SEvalZero             /* XXX: Set a timer to reset the controller if a connection
1557*042d53a7SEvalZero              * complete event isn't received within a reasonable interval.
1558*042d53a7SEvalZero              */
1559*042d53a7SEvalZero         }
1560*042d53a7SEvalZero         break;
1561*042d53a7SEvalZero 
1562*042d53a7SEvalZero     case BLE_GAP_OP_M_DISC:
1563*042d53a7SEvalZero #if NIMBLE_BLE_SCAN && !MYNEWT_VAL(BLE_EXT_ADV)
1564*042d53a7SEvalZero         /* When a discovery procedure times out, it is not a failure. */
1565*042d53a7SEvalZero         rc = ble_gap_disc_enable_tx(0, 0);
1566*042d53a7SEvalZero         if (rc != 0) {
1567*042d53a7SEvalZero             /* Failed to stop discovery; try again in 100 ms. */
1568*042d53a7SEvalZero             return ble_npl_time_ms_to_ticks32(BLE_GAP_CANCEL_RETRY_TIMEOUT_MS);
1569*042d53a7SEvalZero         }
1570*042d53a7SEvalZero 
1571*042d53a7SEvalZero         ble_gap_disc_complete();
1572*042d53a7SEvalZero #else
1573*042d53a7SEvalZero         assert(0);
1574*042d53a7SEvalZero #endif
1575*042d53a7SEvalZero         break;
1576*042d53a7SEvalZero 
1577*042d53a7SEvalZero     default:
1578*042d53a7SEvalZero         BLE_HS_DBG_ASSERT(0);
1579*042d53a7SEvalZero         break;
1580*042d53a7SEvalZero     }
1581*042d53a7SEvalZero 
1582*042d53a7SEvalZero     return BLE_HS_FOREVER;
1583*042d53a7SEvalZero }
1584*042d53a7SEvalZero 
1585*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_EXT_ADV)
1586*042d53a7SEvalZero static int32_t
ble_gap_slave_timer(void)1587*042d53a7SEvalZero ble_gap_slave_timer(void)
1588*042d53a7SEvalZero {
1589*042d53a7SEvalZero     uint32_t ticks_until_exp;
1590*042d53a7SEvalZero     int rc;
1591*042d53a7SEvalZero 
1592*042d53a7SEvalZero     ticks_until_exp = ble_gap_slave_ticks_until_exp();
1593*042d53a7SEvalZero     if (ticks_until_exp != 0) {
1594*042d53a7SEvalZero         /* Timer not expired yet. */
1595*042d53a7SEvalZero         return ticks_until_exp;
1596*042d53a7SEvalZero     }
1597*042d53a7SEvalZero 
1598*042d53a7SEvalZero     /*** Timer expired; process event. */
1599*042d53a7SEvalZero 
1600*042d53a7SEvalZero     /* Stop advertising. */
1601*042d53a7SEvalZero     rc = ble_gap_adv_enable_tx(0);
1602*042d53a7SEvalZero     if (rc != 0) {
1603*042d53a7SEvalZero         /* Failed to stop advertising; try again in 100 ms. */
1604*042d53a7SEvalZero         return 100;
1605*042d53a7SEvalZero     }
1606*042d53a7SEvalZero 
1607*042d53a7SEvalZero     /* Clear the timer and cancel the current procedure. */
1608*042d53a7SEvalZero     ble_gap_slave_reset_state(0);
1609*042d53a7SEvalZero 
1610*042d53a7SEvalZero     /* Indicate to application that advertising has stopped. */
1611*042d53a7SEvalZero     ble_gap_adv_finished(0, BLE_HS_ETIMEOUT, 0, 0);
1612*042d53a7SEvalZero 
1613*042d53a7SEvalZero     return BLE_HS_FOREVER;
1614*042d53a7SEvalZero }
1615*042d53a7SEvalZero #endif
1616*042d53a7SEvalZero 
1617*042d53a7SEvalZero static int32_t
ble_gap_update_timer(void)1618*042d53a7SEvalZero ble_gap_update_timer(void)
1619*042d53a7SEvalZero {
1620*042d53a7SEvalZero     struct ble_gap_update_entry *entry;
1621*042d53a7SEvalZero     int32_t ticks_until_exp;
1622*042d53a7SEvalZero     uint16_t conn_handle;
1623*042d53a7SEvalZero 
1624*042d53a7SEvalZero     do {
1625*042d53a7SEvalZero         ble_hs_lock();
1626*042d53a7SEvalZero 
1627*042d53a7SEvalZero         conn_handle = ble_gap_update_next_exp(&ticks_until_exp);
1628*042d53a7SEvalZero         if (ticks_until_exp == 0) {
1629*042d53a7SEvalZero             entry = ble_gap_update_entry_remove(conn_handle);
1630*042d53a7SEvalZero         } else {
1631*042d53a7SEvalZero             entry = NULL;
1632*042d53a7SEvalZero         }
1633*042d53a7SEvalZero 
1634*042d53a7SEvalZero         ble_hs_unlock();
1635*042d53a7SEvalZero 
1636*042d53a7SEvalZero         if (entry != NULL) {
1637*042d53a7SEvalZero             ble_gap_update_notify(conn_handle, BLE_HS_ETIMEOUT);
1638*042d53a7SEvalZero             ble_gap_update_entry_free(entry);
1639*042d53a7SEvalZero         }
1640*042d53a7SEvalZero     } while (entry != NULL);
1641*042d53a7SEvalZero 
1642*042d53a7SEvalZero     return ticks_until_exp;
1643*042d53a7SEvalZero }
1644*042d53a7SEvalZero 
1645*042d53a7SEvalZero int
ble_gap_set_event_cb(uint16_t conn_handle,ble_gap_event_fn * cb,void * cb_arg)1646*042d53a7SEvalZero ble_gap_set_event_cb(uint16_t conn_handle, ble_gap_event_fn *cb, void *cb_arg)
1647*042d53a7SEvalZero {
1648*042d53a7SEvalZero     struct ble_hs_conn *conn;
1649*042d53a7SEvalZero 
1650*042d53a7SEvalZero     ble_hs_lock();
1651*042d53a7SEvalZero 
1652*042d53a7SEvalZero     conn = ble_hs_conn_find(conn_handle);
1653*042d53a7SEvalZero     if (conn != NULL) {
1654*042d53a7SEvalZero         conn->bhc_cb = cb;
1655*042d53a7SEvalZero         conn->bhc_cb_arg = cb_arg;
1656*042d53a7SEvalZero     }
1657*042d53a7SEvalZero 
1658*042d53a7SEvalZero     ble_hs_unlock();
1659*042d53a7SEvalZero 
1660*042d53a7SEvalZero     if (conn == NULL) {
1661*042d53a7SEvalZero         return BLE_HS_ENOTCONN;
1662*042d53a7SEvalZero     }
1663*042d53a7SEvalZero 
1664*042d53a7SEvalZero     return 0;
1665*042d53a7SEvalZero }
1666*042d53a7SEvalZero 
1667*042d53a7SEvalZero /**
1668*042d53a7SEvalZero  * Handles timed-out GAP procedures.
1669*042d53a7SEvalZero  *
1670*042d53a7SEvalZero  * @return                      The number of ticks until this function should
1671*042d53a7SEvalZero  *                                  be called again.
1672*042d53a7SEvalZero  */
1673*042d53a7SEvalZero int32_t
ble_gap_timer(void)1674*042d53a7SEvalZero ble_gap_timer(void)
1675*042d53a7SEvalZero {
1676*042d53a7SEvalZero     int32_t update_ticks;
1677*042d53a7SEvalZero     int32_t master_ticks;
1678*042d53a7SEvalZero     int32_t min_ticks;
1679*042d53a7SEvalZero 
1680*042d53a7SEvalZero     master_ticks = ble_gap_master_timer();
1681*042d53a7SEvalZero     update_ticks = ble_gap_update_timer();
1682*042d53a7SEvalZero 
1683*042d53a7SEvalZero     min_ticks = min(master_ticks, update_ticks);
1684*042d53a7SEvalZero 
1685*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_EXT_ADV)
1686*042d53a7SEvalZero     min_ticks = min(min_ticks, ble_gap_slave_timer());
1687*042d53a7SEvalZero #endif
1688*042d53a7SEvalZero 
1689*042d53a7SEvalZero     return min_ticks;
1690*042d53a7SEvalZero }
1691*042d53a7SEvalZero 
1692*042d53a7SEvalZero /*****************************************************************************
1693*042d53a7SEvalZero  * $white list                                                               *
1694*042d53a7SEvalZero  *****************************************************************************/
1695*042d53a7SEvalZero 
1696*042d53a7SEvalZero static int
ble_gap_wl_busy(void)1697*042d53a7SEvalZero ble_gap_wl_busy(void)
1698*042d53a7SEvalZero {
1699*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_WHITELIST)
1700*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
1701*042d53a7SEvalZero #endif
1702*042d53a7SEvalZero 
1703*042d53a7SEvalZero     /* Check if an auto or selective connection establishment procedure is in
1704*042d53a7SEvalZero      * progress.
1705*042d53a7SEvalZero      */
1706*042d53a7SEvalZero     return ble_gap_master.op == BLE_GAP_OP_M_CONN &&
1707*042d53a7SEvalZero            ble_gap_master.conn.using_wl;
1708*042d53a7SEvalZero }
1709*042d53a7SEvalZero 
1710*042d53a7SEvalZero static int
ble_gap_wl_tx_add(const ble_addr_t * addr)1711*042d53a7SEvalZero ble_gap_wl_tx_add(const ble_addr_t *addr)
1712*042d53a7SEvalZero {
1713*042d53a7SEvalZero     uint8_t buf[BLE_HCI_ADD_WHITE_LIST_LEN];
1714*042d53a7SEvalZero     int rc;
1715*042d53a7SEvalZero 
1716*042d53a7SEvalZero     rc = ble_hs_hci_cmd_build_le_add_to_whitelist(addr->val, addr->type,
1717*042d53a7SEvalZero                                                   buf, sizeof buf);
1718*042d53a7SEvalZero     if (rc != 0) {
1719*042d53a7SEvalZero         return rc;
1720*042d53a7SEvalZero     }
1721*042d53a7SEvalZero 
1722*042d53a7SEvalZero     rc = ble_hs_hci_cmd_tx_empty_ack(BLE_HCI_OP(BLE_HCI_OGF_LE,
1723*042d53a7SEvalZero                                                 BLE_HCI_OCF_LE_ADD_WHITE_LIST),
1724*042d53a7SEvalZero                                      buf, sizeof(buf));
1725*042d53a7SEvalZero     if (rc != 0) {
1726*042d53a7SEvalZero         return rc;
1727*042d53a7SEvalZero     }
1728*042d53a7SEvalZero 
1729*042d53a7SEvalZero     return 0;
1730*042d53a7SEvalZero }
1731*042d53a7SEvalZero 
1732*042d53a7SEvalZero static int
ble_gap_wl_tx_clear(void)1733*042d53a7SEvalZero ble_gap_wl_tx_clear(void)
1734*042d53a7SEvalZero {
1735*042d53a7SEvalZero     int rc;
1736*042d53a7SEvalZero 
1737*042d53a7SEvalZero     rc = ble_hs_hci_cmd_tx_empty_ack(
1738*042d53a7SEvalZero         BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_CLEAR_WHITE_LIST),
1739*042d53a7SEvalZero         NULL, 0);
1740*042d53a7SEvalZero     if (rc != 0) {
1741*042d53a7SEvalZero         return rc;
1742*042d53a7SEvalZero     }
1743*042d53a7SEvalZero 
1744*042d53a7SEvalZero     return 0;
1745*042d53a7SEvalZero }
1746*042d53a7SEvalZero 
1747*042d53a7SEvalZero int
ble_gap_wl_set(const ble_addr_t * addrs,uint8_t white_list_count)1748*042d53a7SEvalZero ble_gap_wl_set(const ble_addr_t *addrs, uint8_t white_list_count)
1749*042d53a7SEvalZero {
1750*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_WHITELIST)
1751*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
1752*042d53a7SEvalZero #endif
1753*042d53a7SEvalZero 
1754*042d53a7SEvalZero     int rc;
1755*042d53a7SEvalZero     int i;
1756*042d53a7SEvalZero 
1757*042d53a7SEvalZero     STATS_INC(ble_gap_stats, wl_set);
1758*042d53a7SEvalZero 
1759*042d53a7SEvalZero     ble_hs_lock();
1760*042d53a7SEvalZero 
1761*042d53a7SEvalZero     if (white_list_count == 0) {
1762*042d53a7SEvalZero         rc = BLE_HS_EINVAL;
1763*042d53a7SEvalZero         goto done;
1764*042d53a7SEvalZero     }
1765*042d53a7SEvalZero 
1766*042d53a7SEvalZero     for (i = 0; i < white_list_count; i++) {
1767*042d53a7SEvalZero         if (addrs[i].type != BLE_ADDR_PUBLIC &&
1768*042d53a7SEvalZero             addrs[i].type != BLE_ADDR_RANDOM) {
1769*042d53a7SEvalZero 
1770*042d53a7SEvalZero             rc = BLE_HS_EINVAL;
1771*042d53a7SEvalZero             goto done;
1772*042d53a7SEvalZero         }
1773*042d53a7SEvalZero     }
1774*042d53a7SEvalZero 
1775*042d53a7SEvalZero     if (ble_gap_wl_busy()) {
1776*042d53a7SEvalZero         rc = BLE_HS_EBUSY;
1777*042d53a7SEvalZero         goto done;
1778*042d53a7SEvalZero     }
1779*042d53a7SEvalZero 
1780*042d53a7SEvalZero     BLE_HS_LOG(INFO, "GAP procedure initiated: set whitelist; ");
1781*042d53a7SEvalZero     ble_gap_log_wl(addrs, white_list_count);
1782*042d53a7SEvalZero     BLE_HS_LOG(INFO, "\n");
1783*042d53a7SEvalZero 
1784*042d53a7SEvalZero     rc = ble_gap_wl_tx_clear();
1785*042d53a7SEvalZero     if (rc != 0) {
1786*042d53a7SEvalZero         goto done;
1787*042d53a7SEvalZero     }
1788*042d53a7SEvalZero 
1789*042d53a7SEvalZero     for (i = 0; i < white_list_count; i++) {
1790*042d53a7SEvalZero         rc = ble_gap_wl_tx_add(addrs + i);
1791*042d53a7SEvalZero         if (rc != 0) {
1792*042d53a7SEvalZero             goto done;
1793*042d53a7SEvalZero         }
1794*042d53a7SEvalZero     }
1795*042d53a7SEvalZero 
1796*042d53a7SEvalZero     rc = 0;
1797*042d53a7SEvalZero 
1798*042d53a7SEvalZero done:
1799*042d53a7SEvalZero     ble_hs_unlock();
1800*042d53a7SEvalZero 
1801*042d53a7SEvalZero     if (rc != 0) {
1802*042d53a7SEvalZero         STATS_INC(ble_gap_stats, wl_set_fail);
1803*042d53a7SEvalZero     }
1804*042d53a7SEvalZero     return rc;
1805*042d53a7SEvalZero }
1806*042d53a7SEvalZero 
1807*042d53a7SEvalZero /*****************************************************************************
1808*042d53a7SEvalZero  * $stop advertise                                                           *
1809*042d53a7SEvalZero  *****************************************************************************/
1810*042d53a7SEvalZero 
1811*042d53a7SEvalZero static int
ble_gap_adv_enable_tx(int enable)1812*042d53a7SEvalZero ble_gap_adv_enable_tx(int enable)
1813*042d53a7SEvalZero {
1814*042d53a7SEvalZero     uint8_t buf[BLE_HCI_SET_ADV_ENABLE_LEN];
1815*042d53a7SEvalZero     uint16_t opcode;
1816*042d53a7SEvalZero     int rc;
1817*042d53a7SEvalZero 
1818*042d53a7SEvalZero     opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADV_ENABLE);
1819*042d53a7SEvalZero     ble_hs_hci_cmd_build_le_set_adv_enable(!!enable, buf, sizeof buf);
1820*042d53a7SEvalZero 
1821*042d53a7SEvalZero     rc = ble_hs_hci_cmd_tx_empty_ack(opcode, buf, sizeof(buf));
1822*042d53a7SEvalZero     if (rc != 0) {
1823*042d53a7SEvalZero         return rc;
1824*042d53a7SEvalZero     }
1825*042d53a7SEvalZero 
1826*042d53a7SEvalZero     return 0;
1827*042d53a7SEvalZero }
1828*042d53a7SEvalZero 
1829*042d53a7SEvalZero static int
ble_gap_adv_stop_no_lock(void)1830*042d53a7SEvalZero ble_gap_adv_stop_no_lock(void)
1831*042d53a7SEvalZero {
1832*042d53a7SEvalZero #if !NIMBLE_BLE_ADVERTISE
1833*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
1834*042d53a7SEvalZero #endif
1835*042d53a7SEvalZero 
1836*042d53a7SEvalZero     bool active;
1837*042d53a7SEvalZero     int rc;
1838*042d53a7SEvalZero 
1839*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task());
1840*042d53a7SEvalZero 
1841*042d53a7SEvalZero     STATS_INC(ble_gap_stats, adv_stop);
1842*042d53a7SEvalZero 
1843*042d53a7SEvalZero     active = ble_gap_adv_active();
1844*042d53a7SEvalZero 
1845*042d53a7SEvalZero     BLE_HS_LOG(INFO, "GAP procedure initiated: stop advertising.\n");
1846*042d53a7SEvalZero 
1847*042d53a7SEvalZero     rc = ble_gap_adv_enable_tx(0);
1848*042d53a7SEvalZero     if (rc != 0) {
1849*042d53a7SEvalZero         goto done;
1850*042d53a7SEvalZero     }
1851*042d53a7SEvalZero 
1852*042d53a7SEvalZero     ble_gap_slave_reset_state(0);
1853*042d53a7SEvalZero 
1854*042d53a7SEvalZero     if (!active) {
1855*042d53a7SEvalZero         rc = BLE_HS_EALREADY;
1856*042d53a7SEvalZero     } else {
1857*042d53a7SEvalZero         rc = 0;
1858*042d53a7SEvalZero     }
1859*042d53a7SEvalZero 
1860*042d53a7SEvalZero done:
1861*042d53a7SEvalZero     if (rc != 0) {
1862*042d53a7SEvalZero         STATS_INC(ble_gap_stats, adv_stop_fail);
1863*042d53a7SEvalZero     }
1864*042d53a7SEvalZero 
1865*042d53a7SEvalZero     return rc;
1866*042d53a7SEvalZero }
1867*042d53a7SEvalZero 
1868*042d53a7SEvalZero int
ble_gap_adv_stop(void)1869*042d53a7SEvalZero ble_gap_adv_stop(void)
1870*042d53a7SEvalZero {
1871*042d53a7SEvalZero #if !NIMBLE_BLE_ADVERTISE || MYNEWT_VAL(BLE_EXT_ADV)
1872*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
1873*042d53a7SEvalZero #endif
1874*042d53a7SEvalZero 
1875*042d53a7SEvalZero     int rc;
1876*042d53a7SEvalZero 
1877*042d53a7SEvalZero     ble_hs_lock();
1878*042d53a7SEvalZero     rc = ble_gap_adv_stop_no_lock();
1879*042d53a7SEvalZero     ble_hs_unlock();
1880*042d53a7SEvalZero 
1881*042d53a7SEvalZero     return rc;
1882*042d53a7SEvalZero }
1883*042d53a7SEvalZero 
1884*042d53a7SEvalZero /*****************************************************************************
1885*042d53a7SEvalZero  * $advertise                                                                *
1886*042d53a7SEvalZero  *****************************************************************************/
1887*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_EXT_ADV)
1888*042d53a7SEvalZero static int
ble_gap_adv_type(const struct ble_gap_adv_params * adv_params)1889*042d53a7SEvalZero ble_gap_adv_type(const struct ble_gap_adv_params *adv_params)
1890*042d53a7SEvalZero {
1891*042d53a7SEvalZero     switch (adv_params->conn_mode) {
1892*042d53a7SEvalZero     case BLE_GAP_CONN_MODE_NON:
1893*042d53a7SEvalZero         if (adv_params->disc_mode == BLE_GAP_DISC_MODE_NON) {
1894*042d53a7SEvalZero             return BLE_HCI_ADV_TYPE_ADV_NONCONN_IND;
1895*042d53a7SEvalZero         } else {
1896*042d53a7SEvalZero             return BLE_HCI_ADV_TYPE_ADV_SCAN_IND;
1897*042d53a7SEvalZero         }
1898*042d53a7SEvalZero 
1899*042d53a7SEvalZero     case BLE_GAP_CONN_MODE_UND:
1900*042d53a7SEvalZero         return BLE_HCI_ADV_TYPE_ADV_IND;
1901*042d53a7SEvalZero 
1902*042d53a7SEvalZero     case BLE_GAP_CONN_MODE_DIR:
1903*042d53a7SEvalZero         if (adv_params->high_duty_cycle) {
1904*042d53a7SEvalZero             return BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD;
1905*042d53a7SEvalZero         } else {
1906*042d53a7SEvalZero             return BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD;
1907*042d53a7SEvalZero         }
1908*042d53a7SEvalZero 
1909*042d53a7SEvalZero     default:
1910*042d53a7SEvalZero         BLE_HS_DBG_ASSERT(0);
1911*042d53a7SEvalZero         return BLE_HCI_ADV_TYPE_ADV_IND;
1912*042d53a7SEvalZero     }
1913*042d53a7SEvalZero }
1914*042d53a7SEvalZero 
1915*042d53a7SEvalZero static void
ble_gap_adv_dflt_itvls(uint8_t conn_mode,uint16_t * out_itvl_min,uint16_t * out_itvl_max)1916*042d53a7SEvalZero ble_gap_adv_dflt_itvls(uint8_t conn_mode,
1917*042d53a7SEvalZero                        uint16_t *out_itvl_min, uint16_t *out_itvl_max)
1918*042d53a7SEvalZero {
1919*042d53a7SEvalZero     switch (conn_mode) {
1920*042d53a7SEvalZero     case BLE_GAP_CONN_MODE_NON:
1921*042d53a7SEvalZero         *out_itvl_min = BLE_GAP_ADV_FAST_INTERVAL2_MIN;
1922*042d53a7SEvalZero         *out_itvl_max = BLE_GAP_ADV_FAST_INTERVAL2_MAX;
1923*042d53a7SEvalZero         break;
1924*042d53a7SEvalZero 
1925*042d53a7SEvalZero     case BLE_GAP_CONN_MODE_UND:
1926*042d53a7SEvalZero         *out_itvl_min = BLE_GAP_ADV_FAST_INTERVAL1_MIN;
1927*042d53a7SEvalZero         *out_itvl_max = BLE_GAP_ADV_FAST_INTERVAL1_MAX;
1928*042d53a7SEvalZero         break;
1929*042d53a7SEvalZero 
1930*042d53a7SEvalZero     case BLE_GAP_CONN_MODE_DIR:
1931*042d53a7SEvalZero         *out_itvl_min = BLE_GAP_ADV_FAST_INTERVAL1_MIN;
1932*042d53a7SEvalZero         *out_itvl_max = BLE_GAP_ADV_FAST_INTERVAL1_MAX;
1933*042d53a7SEvalZero         break;
1934*042d53a7SEvalZero 
1935*042d53a7SEvalZero     default:
1936*042d53a7SEvalZero         BLE_HS_DBG_ASSERT(0);
1937*042d53a7SEvalZero         break;
1938*042d53a7SEvalZero     }
1939*042d53a7SEvalZero }
1940*042d53a7SEvalZero 
1941*042d53a7SEvalZero static int
ble_gap_adv_params_tx(uint8_t own_addr_type,const ble_addr_t * peer_addr,const struct ble_gap_adv_params * adv_params)1942*042d53a7SEvalZero ble_gap_adv_params_tx(uint8_t own_addr_type, const ble_addr_t *peer_addr,
1943*042d53a7SEvalZero                       const struct ble_gap_adv_params *adv_params)
1944*042d53a7SEvalZero 
1945*042d53a7SEvalZero {
1946*042d53a7SEvalZero     const ble_addr_t *peer_any = BLE_ADDR_ANY;
1947*042d53a7SEvalZero     struct hci_adv_params hci_adv_params;
1948*042d53a7SEvalZero     uint8_t buf[BLE_HCI_SET_ADV_PARAM_LEN];
1949*042d53a7SEvalZero     int rc;
1950*042d53a7SEvalZero 
1951*042d53a7SEvalZero     if (peer_addr == NULL) {
1952*042d53a7SEvalZero         peer_addr = peer_any;
1953*042d53a7SEvalZero     }
1954*042d53a7SEvalZero 
1955*042d53a7SEvalZero     hci_adv_params.own_addr_type = own_addr_type;
1956*042d53a7SEvalZero     hci_adv_params.peer_addr_type = peer_addr->type;
1957*042d53a7SEvalZero     memcpy(hci_adv_params.peer_addr, peer_addr->val,
1958*042d53a7SEvalZero            sizeof hci_adv_params.peer_addr);
1959*042d53a7SEvalZero 
1960*042d53a7SEvalZero     /* Fill optional fields if application did not specify them. */
1961*042d53a7SEvalZero     if (adv_params->itvl_min == 0 && adv_params->itvl_max == 0) {
1962*042d53a7SEvalZero         ble_gap_adv_dflt_itvls(adv_params->conn_mode,
1963*042d53a7SEvalZero                                &hci_adv_params.adv_itvl_min,
1964*042d53a7SEvalZero                                &hci_adv_params.adv_itvl_max);
1965*042d53a7SEvalZero     } else {
1966*042d53a7SEvalZero         hci_adv_params.adv_itvl_min = adv_params->itvl_min;
1967*042d53a7SEvalZero         hci_adv_params.adv_itvl_max = adv_params->itvl_max;
1968*042d53a7SEvalZero     }
1969*042d53a7SEvalZero     if (adv_params->channel_map == 0) {
1970*042d53a7SEvalZero         hci_adv_params.adv_channel_map = BLE_GAP_ADV_DFLT_CHANNEL_MAP;
1971*042d53a7SEvalZero     } else {
1972*042d53a7SEvalZero         hci_adv_params.adv_channel_map = adv_params->channel_map;
1973*042d53a7SEvalZero     }
1974*042d53a7SEvalZero 
1975*042d53a7SEvalZero     /* Zero is the default value for filter policy and high duty cycle */
1976*042d53a7SEvalZero     hci_adv_params.adv_filter_policy = adv_params->filter_policy;
1977*042d53a7SEvalZero 
1978*042d53a7SEvalZero     hci_adv_params.adv_type = ble_gap_adv_type(adv_params);
1979*042d53a7SEvalZero     rc = ble_hs_hci_cmd_build_le_set_adv_params(&hci_adv_params,
1980*042d53a7SEvalZero                                                 buf, sizeof buf);
1981*042d53a7SEvalZero     if (rc != 0) {
1982*042d53a7SEvalZero         return BLE_HS_EINVAL;
1983*042d53a7SEvalZero     }
1984*042d53a7SEvalZero 
1985*042d53a7SEvalZero     rc = ble_hs_hci_cmd_tx_empty_ack(BLE_HCI_OP(BLE_HCI_OGF_LE,
1986*042d53a7SEvalZero                                                 BLE_HCI_OCF_LE_SET_ADV_PARAMS),
1987*042d53a7SEvalZero                                      buf, sizeof(buf));
1988*042d53a7SEvalZero     if (rc != 0) {
1989*042d53a7SEvalZero         return rc;
1990*042d53a7SEvalZero     }
1991*042d53a7SEvalZero 
1992*042d53a7SEvalZero     return 0;
1993*042d53a7SEvalZero }
1994*042d53a7SEvalZero 
1995*042d53a7SEvalZero static int
ble_gap_adv_validate(uint8_t own_addr_type,const ble_addr_t * peer_addr,const struct ble_gap_adv_params * adv_params)1996*042d53a7SEvalZero ble_gap_adv_validate(uint8_t own_addr_type, const ble_addr_t *peer_addr,
1997*042d53a7SEvalZero                      const struct ble_gap_adv_params *adv_params)
1998*042d53a7SEvalZero {
1999*042d53a7SEvalZero     if (adv_params == NULL) {
2000*042d53a7SEvalZero         return BLE_HS_EINVAL;
2001*042d53a7SEvalZero     }
2002*042d53a7SEvalZero 
2003*042d53a7SEvalZero     if (own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) {
2004*042d53a7SEvalZero         return BLE_HS_EINVAL;
2005*042d53a7SEvalZero     }
2006*042d53a7SEvalZero 
2007*042d53a7SEvalZero     if (adv_params->disc_mode >= BLE_GAP_DISC_MODE_MAX) {
2008*042d53a7SEvalZero         return BLE_HS_EINVAL;
2009*042d53a7SEvalZero     }
2010*042d53a7SEvalZero 
2011*042d53a7SEvalZero     if (ble_gap_slave[0].op != BLE_GAP_OP_NULL) {
2012*042d53a7SEvalZero         return BLE_HS_EALREADY;
2013*042d53a7SEvalZero     }
2014*042d53a7SEvalZero 
2015*042d53a7SEvalZero     switch (adv_params->conn_mode) {
2016*042d53a7SEvalZero     case BLE_GAP_CONN_MODE_NON:
2017*042d53a7SEvalZero         /* High duty cycle only allowed for directed advertising. */
2018*042d53a7SEvalZero         if (adv_params->high_duty_cycle) {
2019*042d53a7SEvalZero             return BLE_HS_EINVAL;
2020*042d53a7SEvalZero         }
2021*042d53a7SEvalZero         break;
2022*042d53a7SEvalZero 
2023*042d53a7SEvalZero     case BLE_GAP_CONN_MODE_UND:
2024*042d53a7SEvalZero         /* High duty cycle only allowed for directed advertising. */
2025*042d53a7SEvalZero         if (adv_params->high_duty_cycle) {
2026*042d53a7SEvalZero             return BLE_HS_EINVAL;
2027*042d53a7SEvalZero         }
2028*042d53a7SEvalZero 
2029*042d53a7SEvalZero         /* Don't allow connectable advertising if we won't be able to allocate
2030*042d53a7SEvalZero          * a new connection.
2031*042d53a7SEvalZero          */
2032*042d53a7SEvalZero         if (!ble_hs_conn_can_alloc()) {
2033*042d53a7SEvalZero             return BLE_HS_ENOMEM;
2034*042d53a7SEvalZero         }
2035*042d53a7SEvalZero         break;
2036*042d53a7SEvalZero 
2037*042d53a7SEvalZero     case BLE_GAP_CONN_MODE_DIR:
2038*042d53a7SEvalZero         if (peer_addr == NULL) {
2039*042d53a7SEvalZero             return BLE_HS_EINVAL;
2040*042d53a7SEvalZero         }
2041*042d53a7SEvalZero 
2042*042d53a7SEvalZero         if (peer_addr->type != BLE_ADDR_PUBLIC &&
2043*042d53a7SEvalZero             peer_addr->type != BLE_ADDR_RANDOM &&
2044*042d53a7SEvalZero             peer_addr->type != BLE_ADDR_PUBLIC_ID &&
2045*042d53a7SEvalZero             peer_addr->type != BLE_ADDR_RANDOM_ID) {
2046*042d53a7SEvalZero 
2047*042d53a7SEvalZero             return BLE_HS_EINVAL;
2048*042d53a7SEvalZero         }
2049*042d53a7SEvalZero 
2050*042d53a7SEvalZero         /* Don't allow connectable advertising if we won't be able to allocate
2051*042d53a7SEvalZero          * a new connection.
2052*042d53a7SEvalZero          */
2053*042d53a7SEvalZero         if (!ble_hs_conn_can_alloc()) {
2054*042d53a7SEvalZero             return BLE_HS_ENOMEM;
2055*042d53a7SEvalZero         }
2056*042d53a7SEvalZero         break;
2057*042d53a7SEvalZero 
2058*042d53a7SEvalZero     default:
2059*042d53a7SEvalZero         return BLE_HS_EINVAL;
2060*042d53a7SEvalZero     }
2061*042d53a7SEvalZero 
2062*042d53a7SEvalZero     return 0;
2063*042d53a7SEvalZero }
2064*042d53a7SEvalZero #endif
2065*042d53a7SEvalZero 
2066*042d53a7SEvalZero int
ble_gap_adv_start(uint8_t own_addr_type,const ble_addr_t * direct_addr,int32_t duration_ms,const struct ble_gap_adv_params * adv_params,ble_gap_event_fn * cb,void * cb_arg)2067*042d53a7SEvalZero ble_gap_adv_start(uint8_t own_addr_type, const ble_addr_t *direct_addr,
2068*042d53a7SEvalZero                   int32_t duration_ms,
2069*042d53a7SEvalZero                   const struct ble_gap_adv_params *adv_params,
2070*042d53a7SEvalZero                   ble_gap_event_fn *cb, void *cb_arg)
2071*042d53a7SEvalZero {
2072*042d53a7SEvalZero #if !NIMBLE_BLE_ADVERTISE || MYNEWT_VAL(BLE_EXT_ADV)
2073*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
2074*042d53a7SEvalZero #else
2075*042d53a7SEvalZero     uint32_t duration_ticks;
2076*042d53a7SEvalZero     int rc;
2077*042d53a7SEvalZero 
2078*042d53a7SEvalZero     STATS_INC(ble_gap_stats, adv_start);
2079*042d53a7SEvalZero 
2080*042d53a7SEvalZero     ble_hs_lock();
2081*042d53a7SEvalZero 
2082*042d53a7SEvalZero     rc = ble_gap_adv_validate(own_addr_type, direct_addr, adv_params);
2083*042d53a7SEvalZero     if (rc != 0) {
2084*042d53a7SEvalZero         goto done;
2085*042d53a7SEvalZero     }
2086*042d53a7SEvalZero 
2087*042d53a7SEvalZero     if (duration_ms != BLE_HS_FOREVER) {
2088*042d53a7SEvalZero         rc = ble_npl_time_ms_to_ticks(duration_ms, &duration_ticks);
2089*042d53a7SEvalZero         if (rc != 0) {
2090*042d53a7SEvalZero             /* Duration too great. */
2091*042d53a7SEvalZero             rc = BLE_HS_EINVAL;
2092*042d53a7SEvalZero             goto done;
2093*042d53a7SEvalZero         }
2094*042d53a7SEvalZero     }
2095*042d53a7SEvalZero 
2096*042d53a7SEvalZero     if (!ble_hs_is_enabled()) {
2097*042d53a7SEvalZero         rc = BLE_HS_EDISABLED;
2098*042d53a7SEvalZero         goto done;
2099*042d53a7SEvalZero     }
2100*042d53a7SEvalZero 
2101*042d53a7SEvalZero     if (ble_gap_is_preempted()) {
2102*042d53a7SEvalZero         rc = BLE_HS_EPREEMPTED;
2103*042d53a7SEvalZero         goto done;
2104*042d53a7SEvalZero     }
2105*042d53a7SEvalZero 
2106*042d53a7SEvalZero     rc = ble_hs_id_use_addr(own_addr_type);
2107*042d53a7SEvalZero     if (rc != 0) {
2108*042d53a7SEvalZero         goto done;
2109*042d53a7SEvalZero     }
2110*042d53a7SEvalZero 
2111*042d53a7SEvalZero     BLE_HS_LOG(INFO, "GAP procedure initiated: advertise; ");
2112*042d53a7SEvalZero     ble_gap_log_adv(own_addr_type, direct_addr, adv_params);
2113*042d53a7SEvalZero     BLE_HS_LOG(INFO, "\n");
2114*042d53a7SEvalZero 
2115*042d53a7SEvalZero     ble_gap_slave[0].cb = cb;
2116*042d53a7SEvalZero     ble_gap_slave[0].cb_arg = cb_arg;
2117*042d53a7SEvalZero     ble_gap_slave[0].our_addr_type = own_addr_type;
2118*042d53a7SEvalZero 
2119*042d53a7SEvalZero     if (adv_params->conn_mode != BLE_GAP_CONN_MODE_NON) {
2120*042d53a7SEvalZero         ble_gap_slave[0].connectable = 1;
2121*042d53a7SEvalZero     } else {
2122*042d53a7SEvalZero         ble_gap_slave[0].connectable = 0;
2123*042d53a7SEvalZero     }
2124*042d53a7SEvalZero 
2125*042d53a7SEvalZero     rc = ble_gap_adv_params_tx(own_addr_type, direct_addr, adv_params);
2126*042d53a7SEvalZero     if (rc != 0) {
2127*042d53a7SEvalZero         goto done;
2128*042d53a7SEvalZero     }
2129*042d53a7SEvalZero 
2130*042d53a7SEvalZero     ble_gap_slave[0].op = BLE_GAP_OP_S_ADV;
2131*042d53a7SEvalZero 
2132*042d53a7SEvalZero     rc = ble_gap_adv_enable_tx(1);
2133*042d53a7SEvalZero     if (rc != 0) {
2134*042d53a7SEvalZero         ble_gap_slave_reset_state(0);
2135*042d53a7SEvalZero         goto done;
2136*042d53a7SEvalZero     }
2137*042d53a7SEvalZero 
2138*042d53a7SEvalZero     if (duration_ms != BLE_HS_FOREVER) {
2139*042d53a7SEvalZero         ble_gap_slave_set_timer(duration_ticks);
2140*042d53a7SEvalZero     }
2141*042d53a7SEvalZero 
2142*042d53a7SEvalZero     rc = 0;
2143*042d53a7SEvalZero 
2144*042d53a7SEvalZero done:
2145*042d53a7SEvalZero     ble_hs_unlock();
2146*042d53a7SEvalZero 
2147*042d53a7SEvalZero     if (rc != 0) {
2148*042d53a7SEvalZero         STATS_INC(ble_gap_stats, adv_start_fail);
2149*042d53a7SEvalZero     }
2150*042d53a7SEvalZero     return rc;
2151*042d53a7SEvalZero #endif
2152*042d53a7SEvalZero }
2153*042d53a7SEvalZero 
2154*042d53a7SEvalZero int
ble_gap_adv_set_data(const uint8_t * data,int data_len)2155*042d53a7SEvalZero ble_gap_adv_set_data(const uint8_t *data, int data_len)
2156*042d53a7SEvalZero {
2157*042d53a7SEvalZero #if !NIMBLE_BLE_ADVERTISE || MYNEWT_VAL(BLE_EXT_ADV)
2158*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
2159*042d53a7SEvalZero #endif
2160*042d53a7SEvalZero 
2161*042d53a7SEvalZero     uint8_t buf[BLE_HCI_SET_ADV_DATA_LEN];
2162*042d53a7SEvalZero     uint16_t opcode;
2163*042d53a7SEvalZero     int rc;
2164*042d53a7SEvalZero 
2165*042d53a7SEvalZero     STATS_INC(ble_gap_stats, adv_set_data);
2166*042d53a7SEvalZero 
2167*042d53a7SEvalZero     ble_hs_lock();
2168*042d53a7SEvalZero 
2169*042d53a7SEvalZero     opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADV_DATA);
2170*042d53a7SEvalZero     rc = ble_hs_hci_cmd_build_le_set_adv_data(data, data_len, buf,
2171*042d53a7SEvalZero                                               sizeof(buf));
2172*042d53a7SEvalZero     if (rc != 0) {
2173*042d53a7SEvalZero         goto done;
2174*042d53a7SEvalZero     }
2175*042d53a7SEvalZero 
2176*042d53a7SEvalZero     rc = ble_hs_hci_cmd_tx_empty_ack(opcode, buf, sizeof(buf));
2177*042d53a7SEvalZero     if (rc != 0) {
2178*042d53a7SEvalZero         goto done;
2179*042d53a7SEvalZero     }
2180*042d53a7SEvalZero 
2181*042d53a7SEvalZero     rc = 0;
2182*042d53a7SEvalZero 
2183*042d53a7SEvalZero done:
2184*042d53a7SEvalZero     ble_hs_unlock();
2185*042d53a7SEvalZero     return rc;
2186*042d53a7SEvalZero }
2187*042d53a7SEvalZero 
2188*042d53a7SEvalZero int
ble_gap_adv_rsp_set_data(const uint8_t * data,int data_len)2189*042d53a7SEvalZero ble_gap_adv_rsp_set_data(const uint8_t *data, int data_len)
2190*042d53a7SEvalZero {
2191*042d53a7SEvalZero #if !NIMBLE_BLE_ADVERTISE || MYNEWT_VAL(BLE_EXT_ADV)
2192*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
2193*042d53a7SEvalZero #endif
2194*042d53a7SEvalZero 
2195*042d53a7SEvalZero     uint8_t buf[BLE_HCI_SET_SCAN_RSP_DATA_LEN];
2196*042d53a7SEvalZero     uint16_t opcode;
2197*042d53a7SEvalZero     int rc;
2198*042d53a7SEvalZero 
2199*042d53a7SEvalZero     ble_hs_lock();
2200*042d53a7SEvalZero 
2201*042d53a7SEvalZero     opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_SCAN_RSP_DATA);
2202*042d53a7SEvalZero     rc = ble_hs_hci_cmd_build_le_set_scan_rsp_data(data, data_len,
2203*042d53a7SEvalZero                                                    buf, sizeof(buf));
2204*042d53a7SEvalZero     if (rc != 0) {
2205*042d53a7SEvalZero         rc = BLE_HS_HCI_ERR(rc);
2206*042d53a7SEvalZero         goto done;
2207*042d53a7SEvalZero     }
2208*042d53a7SEvalZero 
2209*042d53a7SEvalZero     rc = ble_hs_hci_cmd_tx_empty_ack(opcode, buf, sizeof(buf));
2210*042d53a7SEvalZero     if (rc != 0) {
2211*042d53a7SEvalZero         goto done;
2212*042d53a7SEvalZero     }
2213*042d53a7SEvalZero 
2214*042d53a7SEvalZero     rc = 0;
2215*042d53a7SEvalZero 
2216*042d53a7SEvalZero done:
2217*042d53a7SEvalZero     ble_hs_unlock();
2218*042d53a7SEvalZero     return rc;
2219*042d53a7SEvalZero }
2220*042d53a7SEvalZero 
2221*042d53a7SEvalZero int
ble_gap_adv_set_fields(const struct ble_hs_adv_fields * adv_fields)2222*042d53a7SEvalZero ble_gap_adv_set_fields(const struct ble_hs_adv_fields *adv_fields)
2223*042d53a7SEvalZero {
2224*042d53a7SEvalZero #if !NIMBLE_BLE_ADVERTISE || MYNEWT_VAL(BLE_EXT_ADV)
2225*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
2226*042d53a7SEvalZero #endif
2227*042d53a7SEvalZero 
2228*042d53a7SEvalZero     uint8_t buf[BLE_HS_ADV_MAX_SZ];
2229*042d53a7SEvalZero     uint8_t buf_sz;
2230*042d53a7SEvalZero     int rc;
2231*042d53a7SEvalZero 
2232*042d53a7SEvalZero     rc = ble_hs_adv_set_fields(adv_fields, buf, &buf_sz, sizeof buf);
2233*042d53a7SEvalZero     if (rc != 0) {
2234*042d53a7SEvalZero         return rc;
2235*042d53a7SEvalZero     }
2236*042d53a7SEvalZero 
2237*042d53a7SEvalZero     rc = ble_gap_adv_set_data(buf, buf_sz);
2238*042d53a7SEvalZero     if (rc != 0) {
2239*042d53a7SEvalZero         return rc;
2240*042d53a7SEvalZero     }
2241*042d53a7SEvalZero 
2242*042d53a7SEvalZero     return 0;
2243*042d53a7SEvalZero }
2244*042d53a7SEvalZero 
2245*042d53a7SEvalZero int
ble_gap_adv_rsp_set_fields(const struct ble_hs_adv_fields * rsp_fields)2246*042d53a7SEvalZero ble_gap_adv_rsp_set_fields(const struct ble_hs_adv_fields *rsp_fields)
2247*042d53a7SEvalZero {
2248*042d53a7SEvalZero #if !NIMBLE_BLE_ADVERTISE || MYNEWT_VAL(BLE_EXT_ADV)
2249*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
2250*042d53a7SEvalZero #endif
2251*042d53a7SEvalZero 
2252*042d53a7SEvalZero     uint8_t buf[BLE_HS_ADV_MAX_SZ];
2253*042d53a7SEvalZero     uint8_t buf_sz;
2254*042d53a7SEvalZero     int rc;
2255*042d53a7SEvalZero 
2256*042d53a7SEvalZero     rc = ble_hs_adv_set_fields(rsp_fields, buf, &buf_sz, sizeof buf);
2257*042d53a7SEvalZero     if (rc != 0) {
2258*042d53a7SEvalZero         return rc;
2259*042d53a7SEvalZero     }
2260*042d53a7SEvalZero 
2261*042d53a7SEvalZero     rc = ble_gap_adv_rsp_set_data(buf, buf_sz);
2262*042d53a7SEvalZero     if (rc != 0) {
2263*042d53a7SEvalZero         return rc;
2264*042d53a7SEvalZero     }
2265*042d53a7SEvalZero 
2266*042d53a7SEvalZero     return 0;
2267*042d53a7SEvalZero }
2268*042d53a7SEvalZero 
2269*042d53a7SEvalZero int
ble_gap_adv_active(void)2270*042d53a7SEvalZero ble_gap_adv_active(void)
2271*042d53a7SEvalZero {
2272*042d53a7SEvalZero     return ble_gap_adv_active_instance(0);
2273*042d53a7SEvalZero }
2274*042d53a7SEvalZero 
2275*042d53a7SEvalZero #if MYNEWT_VAL(BLE_EXT_ADV)
2276*042d53a7SEvalZero static int
ble_gap_ext_adv_params_tx(uint8_t instance,const struct ble_gap_ext_adv_params * params,int8_t * selected_tx_power)2277*042d53a7SEvalZero ble_gap_ext_adv_params_tx(uint8_t instance,
2278*042d53a7SEvalZero                           const struct ble_gap_ext_adv_params *params,
2279*042d53a7SEvalZero                           int8_t *selected_tx_power)
2280*042d53a7SEvalZero 
2281*042d53a7SEvalZero {
2282*042d53a7SEvalZero     struct hci_ext_adv_params hci_adv_params;
2283*042d53a7SEvalZero     uint8_t buf[BLE_HCI_LE_SET_EXT_ADV_PARAM_LEN];
2284*042d53a7SEvalZero     uint8_t rsp;
2285*042d53a7SEvalZero     int rc;
2286*042d53a7SEvalZero 
2287*042d53a7SEvalZero     memset(&hci_adv_params, 0, sizeof(hci_adv_params));
2288*042d53a7SEvalZero 
2289*042d53a7SEvalZero     if (params->connectable) {
2290*042d53a7SEvalZero         hci_adv_params.properties |= BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE;
2291*042d53a7SEvalZero     }
2292*042d53a7SEvalZero     if (params->scannable) {
2293*042d53a7SEvalZero         hci_adv_params.properties |= BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE;
2294*042d53a7SEvalZero     }
2295*042d53a7SEvalZero     if (params->directed) {
2296*042d53a7SEvalZero         hci_adv_params.properties |= BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED;
2297*042d53a7SEvalZero         hci_adv_params.peer_addr_type = params->peer.type;
2298*042d53a7SEvalZero         memcpy(hci_adv_params.peer_addr, params->peer.val, 6);
2299*042d53a7SEvalZero     }
2300*042d53a7SEvalZero     if (params->high_duty_directed) {
2301*042d53a7SEvalZero         hci_adv_params.properties |= BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED;
2302*042d53a7SEvalZero     }
2303*042d53a7SEvalZero     if (params->legacy_pdu) {
2304*042d53a7SEvalZero         hci_adv_params.properties |= BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY;
2305*042d53a7SEvalZero     }
2306*042d53a7SEvalZero     if (params->anonymous) {
2307*042d53a7SEvalZero         hci_adv_params.properties |= BLE_HCI_LE_SET_EXT_ADV_PROP_ANON_ADV;
2308*042d53a7SEvalZero     }
2309*042d53a7SEvalZero     if (params->include_tx_power) {
2310*042d53a7SEvalZero         hci_adv_params.properties |= BLE_HCI_LE_SET_EXT_ADV_PROP_INC_TX_PWR;
2311*042d53a7SEvalZero     }
2312*042d53a7SEvalZero 
2313*042d53a7SEvalZero     /* Fill optional fields if application did not specify them. */
2314*042d53a7SEvalZero     if (params->itvl_min == 0 && params->itvl_max == 0) {
2315*042d53a7SEvalZero         /* TODO for now limited to legacy values*/
2316*042d53a7SEvalZero         hci_adv_params.min_interval = BLE_GAP_ADV_FAST_INTERVAL1_MIN;
2317*042d53a7SEvalZero         hci_adv_params.max_interval = BLE_GAP_ADV_FAST_INTERVAL2_MAX;
2318*042d53a7SEvalZero 
2319*042d53a7SEvalZero     } else {
2320*042d53a7SEvalZero         hci_adv_params.min_interval = params->itvl_min;
2321*042d53a7SEvalZero         hci_adv_params.max_interval = params->itvl_max;
2322*042d53a7SEvalZero     }
2323*042d53a7SEvalZero 
2324*042d53a7SEvalZero     if (params->channel_map == 0) {
2325*042d53a7SEvalZero         hci_adv_params.chan_map = BLE_GAP_ADV_DFLT_CHANNEL_MAP;
2326*042d53a7SEvalZero     } else {
2327*042d53a7SEvalZero         hci_adv_params.chan_map = params->channel_map;
2328*042d53a7SEvalZero     }
2329*042d53a7SEvalZero 
2330*042d53a7SEvalZero     /* Zero is the default value for filter policy and high duty cycle */
2331*042d53a7SEvalZero     hci_adv_params.filter_policy = params->filter_policy;
2332*042d53a7SEvalZero     hci_adv_params.tx_power = params->tx_power;
2333*042d53a7SEvalZero 
2334*042d53a7SEvalZero     if (params->legacy_pdu) {
2335*042d53a7SEvalZero         hci_adv_params.primary_phy = BLE_HCI_LE_PHY_1M;
2336*042d53a7SEvalZero         hci_adv_params.secondary_phy = BLE_HCI_LE_PHY_1M;
2337*042d53a7SEvalZero     } else {
2338*042d53a7SEvalZero         hci_adv_params.primary_phy = params->primary_phy;
2339*042d53a7SEvalZero         hci_adv_params.secondary_phy = params->secondary_phy;
2340*042d53a7SEvalZero     }
2341*042d53a7SEvalZero 
2342*042d53a7SEvalZero     hci_adv_params.own_addr_type = params->own_addr_type;
2343*042d53a7SEvalZero     hci_adv_params.max_skip = 0;
2344*042d53a7SEvalZero     hci_adv_params.sid = params->sid;
2345*042d53a7SEvalZero     hci_adv_params.scan_req_notif = params->scan_req_notif;
2346*042d53a7SEvalZero 
2347*042d53a7SEvalZero     rc = ble_hs_hci_cmd_build_le_ext_adv_params(instance, &hci_adv_params,
2348*042d53a7SEvalZero                                                 buf, sizeof(buf));
2349*042d53a7SEvalZero     if (rc != 0) {
2350*042d53a7SEvalZero         return rc;
2351*042d53a7SEvalZero     }
2352*042d53a7SEvalZero 
2353*042d53a7SEvalZero     rc = ble_hs_hci_cmd_tx(
2354*042d53a7SEvalZero             BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_EXT_ADV_PARAM),
2355*042d53a7SEvalZero             buf, sizeof(buf), &rsp, 1, NULL);
2356*042d53a7SEvalZero 
2357*042d53a7SEvalZero     if (rc != 0) {
2358*042d53a7SEvalZero         return rc;
2359*042d53a7SEvalZero     }
2360*042d53a7SEvalZero 
2361*042d53a7SEvalZero     if (selected_tx_power) {
2362*042d53a7SEvalZero         *selected_tx_power = rsp;
2363*042d53a7SEvalZero     }
2364*042d53a7SEvalZero 
2365*042d53a7SEvalZero     return 0;
2366*042d53a7SEvalZero }
2367*042d53a7SEvalZero 
2368*042d53a7SEvalZero static int
ble_gap_ext_adv_params_validate(const struct ble_gap_ext_adv_params * params)2369*042d53a7SEvalZero ble_gap_ext_adv_params_validate(const struct ble_gap_ext_adv_params *params)
2370*042d53a7SEvalZero {
2371*042d53a7SEvalZero     if (!params) {
2372*042d53a7SEvalZero         return BLE_HS_EINVAL;
2373*042d53a7SEvalZero     }
2374*042d53a7SEvalZero 
2375*042d53a7SEvalZero     if (params->own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) {
2376*042d53a7SEvalZero         return BLE_HS_EINVAL;
2377*042d53a7SEvalZero     }
2378*042d53a7SEvalZero 
2379*042d53a7SEvalZero     /* Don't allow connectable advertising if we won't be able to allocate
2380*042d53a7SEvalZero      * a new connection.
2381*042d53a7SEvalZero      */
2382*042d53a7SEvalZero     if (params->connectable && !ble_hs_conn_can_alloc()) {
2383*042d53a7SEvalZero         return BLE_HS_ENOMEM;
2384*042d53a7SEvalZero     }
2385*042d53a7SEvalZero 
2386*042d53a7SEvalZero     if (params->legacy_pdu) {
2387*042d53a7SEvalZero         /* not allowed for legacy PDUs */
2388*042d53a7SEvalZero         if (params->anonymous || params->include_tx_power) {
2389*042d53a7SEvalZero             return BLE_HS_EINVAL;
2390*042d53a7SEvalZero         }
2391*042d53a7SEvalZero     }
2392*042d53a7SEvalZero 
2393*042d53a7SEvalZero     if (params->directed) {
2394*042d53a7SEvalZero         if (params->scannable && params->connectable) {
2395*042d53a7SEvalZero             return BLE_HS_EINVAL;
2396*042d53a7SEvalZero         }
2397*042d53a7SEvalZero     }
2398*042d53a7SEvalZero 
2399*042d53a7SEvalZero     if (!params->legacy_pdu) {
2400*042d53a7SEvalZero         /* not allowed for extended advertising PDUs */
2401*042d53a7SEvalZero         if (params->connectable && params->scannable) {
2402*042d53a7SEvalZero             return BLE_HS_EINVAL;
2403*042d53a7SEvalZero         }
2404*042d53a7SEvalZero 
2405*042d53a7SEvalZero         /* HD directed advertising allowed only for legacy PDUs */
2406*042d53a7SEvalZero         if (params->high_duty_directed) {
2407*042d53a7SEvalZero             return BLE_HS_EINVAL;
2408*042d53a7SEvalZero         }
2409*042d53a7SEvalZero     }
2410*042d53a7SEvalZero 
2411*042d53a7SEvalZero     return 0;
2412*042d53a7SEvalZero }
2413*042d53a7SEvalZero 
2414*042d53a7SEvalZero int
ble_gap_ext_adv_configure(uint8_t instance,const struct ble_gap_ext_adv_params * params,int8_t * selected_tx_power,ble_gap_event_fn * cb,void * cb_arg)2415*042d53a7SEvalZero ble_gap_ext_adv_configure(uint8_t instance,
2416*042d53a7SEvalZero                           const struct ble_gap_ext_adv_params *params,
2417*042d53a7SEvalZero                           int8_t *selected_tx_power,
2418*042d53a7SEvalZero                           ble_gap_event_fn *cb, void *cb_arg)
2419*042d53a7SEvalZero {
2420*042d53a7SEvalZero     int rc;
2421*042d53a7SEvalZero 
2422*042d53a7SEvalZero     if (instance >= BLE_ADV_INSTANCES) {
2423*042d53a7SEvalZero         return EINVAL;
2424*042d53a7SEvalZero     }
2425*042d53a7SEvalZero 
2426*042d53a7SEvalZero     rc = ble_gap_ext_adv_params_validate(params);
2427*042d53a7SEvalZero     if (rc) {
2428*042d53a7SEvalZero         return rc;
2429*042d53a7SEvalZero     }
2430*042d53a7SEvalZero 
2431*042d53a7SEvalZero     ble_hs_lock();
2432*042d53a7SEvalZero 
2433*042d53a7SEvalZero     /* TODO should we allow to reconfigure existing instance? */
2434*042d53a7SEvalZero     if (ble_gap_slave[instance].configured) {
2435*042d53a7SEvalZero         ble_hs_unlock();
2436*042d53a7SEvalZero         return ENOMEM;
2437*042d53a7SEvalZero     }
2438*042d53a7SEvalZero 
2439*042d53a7SEvalZero     rc = ble_gap_ext_adv_params_tx(instance, params, selected_tx_power);
2440*042d53a7SEvalZero     if (rc) {
2441*042d53a7SEvalZero         ble_hs_unlock();
2442*042d53a7SEvalZero         return rc;
2443*042d53a7SEvalZero     }
2444*042d53a7SEvalZero 
2445*042d53a7SEvalZero     ble_gap_slave[instance].configured = 1;
2446*042d53a7SEvalZero     ble_gap_slave[instance].cb = cb;
2447*042d53a7SEvalZero     ble_gap_slave[instance].cb_arg = cb_arg;
2448*042d53a7SEvalZero     ble_gap_slave[instance].our_addr_type = params->own_addr_type;
2449*042d53a7SEvalZero 
2450*042d53a7SEvalZero     ble_gap_slave[instance].connectable = params->connectable;
2451*042d53a7SEvalZero     ble_gap_slave[instance].scannable = params->scannable;
2452*042d53a7SEvalZero     ble_gap_slave[instance].directed = params->directed;
2453*042d53a7SEvalZero     ble_gap_slave[instance].legacy_pdu = params->legacy_pdu;
2454*042d53a7SEvalZero 
2455*042d53a7SEvalZero     ble_hs_unlock();
2456*042d53a7SEvalZero     return 0;
2457*042d53a7SEvalZero }
2458*042d53a7SEvalZero 
2459*042d53a7SEvalZero static int
ble_gap_ext_adv_set_addr_no_lock(uint8_t instance,const uint8_t * addr)2460*042d53a7SEvalZero ble_gap_ext_adv_set_addr_no_lock(uint8_t instance, const uint8_t *addr)
2461*042d53a7SEvalZero {
2462*042d53a7SEvalZero     uint8_t buf[BLE_HCI_LE_SET_ADV_SET_RND_ADDR_LEN];
2463*042d53a7SEvalZero     int rc;
2464*042d53a7SEvalZero 
2465*042d53a7SEvalZero     rc = ble_hs_hci_cmd_build_le_ext_adv_set_random_addr(instance, addr, buf,
2466*042d53a7SEvalZero                                                          sizeof(buf));
2467*042d53a7SEvalZero     if (rc != 0) {
2468*042d53a7SEvalZero         return rc;
2469*042d53a7SEvalZero     }
2470*042d53a7SEvalZero 
2471*042d53a7SEvalZero     rc = ble_hs_hci_cmd_tx_empty_ack(BLE_HCI_OP(BLE_HCI_OGF_LE,
2472*042d53a7SEvalZero                                      BLE_HCI_OCF_LE_SET_ADV_SET_RND_ADDR),
2473*042d53a7SEvalZero                                      buf, sizeof(buf));
2474*042d53a7SEvalZero     if (rc != 0) {
2475*042d53a7SEvalZero         return rc;
2476*042d53a7SEvalZero     }
2477*042d53a7SEvalZero 
2478*042d53a7SEvalZero     ble_gap_slave[instance].rnd_addr_set = 1;
2479*042d53a7SEvalZero     memcpy(ble_gap_slave[instance].rnd_addr, addr, 6);
2480*042d53a7SEvalZero 
2481*042d53a7SEvalZero     return 0;
2482*042d53a7SEvalZero }
2483*042d53a7SEvalZero 
2484*042d53a7SEvalZero int
ble_gap_ext_adv_set_addr(uint8_t instance,const ble_addr_t * addr)2485*042d53a7SEvalZero ble_gap_ext_adv_set_addr(uint8_t instance, const ble_addr_t *addr)
2486*042d53a7SEvalZero {
2487*042d53a7SEvalZero     int rc;
2488*042d53a7SEvalZero 
2489*042d53a7SEvalZero     if (instance >= BLE_ADV_INSTANCES || addr->type != BLE_ADDR_RANDOM) {
2490*042d53a7SEvalZero         return BLE_HS_EINVAL;
2491*042d53a7SEvalZero     }
2492*042d53a7SEvalZero 
2493*042d53a7SEvalZero     ble_hs_lock();
2494*042d53a7SEvalZero     rc = ble_gap_ext_adv_set_addr_no_lock(instance, addr->val);
2495*042d53a7SEvalZero     ble_hs_unlock();
2496*042d53a7SEvalZero 
2497*042d53a7SEvalZero     return rc;
2498*042d53a7SEvalZero }
2499*042d53a7SEvalZero 
2500*042d53a7SEvalZero int
ble_gap_ext_adv_start(uint8_t instance,int duration,int max_events)2501*042d53a7SEvalZero ble_gap_ext_adv_start(uint8_t instance, int duration, int max_events)
2502*042d53a7SEvalZero {
2503*042d53a7SEvalZero     const uint8_t *rnd_addr;
2504*042d53a7SEvalZero     uint8_t buf[6];
2505*042d53a7SEvalZero     struct hci_ext_adv_set set;
2506*042d53a7SEvalZero     uint16_t opcode;
2507*042d53a7SEvalZero     int rc;
2508*042d53a7SEvalZero 
2509*042d53a7SEvalZero     if (instance >= BLE_ADV_INSTANCES) {
2510*042d53a7SEvalZero         return BLE_HS_EINVAL;
2511*042d53a7SEvalZero     }
2512*042d53a7SEvalZero 
2513*042d53a7SEvalZero     ble_hs_lock();
2514*042d53a7SEvalZero     if (!ble_gap_slave[instance].configured) {
2515*042d53a7SEvalZero         ble_hs_unlock();
2516*042d53a7SEvalZero         return BLE_HS_EINVAL;
2517*042d53a7SEvalZero     }
2518*042d53a7SEvalZero 
2519*042d53a7SEvalZero     if (ble_gap_slave[instance].op != BLE_GAP_OP_NULL) {
2520*042d53a7SEvalZero         ble_hs_unlock();
2521*042d53a7SEvalZero         return  BLE_HS_EALREADY;
2522*042d53a7SEvalZero     }
2523*042d53a7SEvalZero 
2524*042d53a7SEvalZero     if (ble_gap_slave[instance].directed && duration > 1280) {
2525*042d53a7SEvalZero         ble_hs_unlock();
2526*042d53a7SEvalZero         return BLE_HS_EINVAL;
2527*042d53a7SEvalZero     }
2528*042d53a7SEvalZero 
2529*042d53a7SEvalZero     /* verify own address type if random address for instance wasn't explicitly
2530*042d53a7SEvalZero      * set
2531*042d53a7SEvalZero      */
2532*042d53a7SEvalZero     switch (ble_gap_slave[instance].our_addr_type) {
2533*042d53a7SEvalZero     case BLE_OWN_ADDR_RANDOM:
2534*042d53a7SEvalZero     case BLE_OWN_ADDR_RPA_RANDOM_DEFAULT:
2535*042d53a7SEvalZero         if (ble_gap_slave[instance].rnd_addr_set) {
2536*042d53a7SEvalZero             break;
2537*042d53a7SEvalZero         }
2538*042d53a7SEvalZero         /* fall through */
2539*042d53a7SEvalZero     case BLE_OWN_ADDR_PUBLIC:
2540*042d53a7SEvalZero     case BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT:
2541*042d53a7SEvalZero     default:
2542*042d53a7SEvalZero         rc = ble_hs_id_use_addr(ble_gap_slave[instance].our_addr_type);
2543*042d53a7SEvalZero         if (rc) {
2544*042d53a7SEvalZero             ble_hs_unlock();
2545*042d53a7SEvalZero             return BLE_HS_EINVAL;
2546*042d53a7SEvalZero         }
2547*042d53a7SEvalZero         break;
2548*042d53a7SEvalZero     }
2549*042d53a7SEvalZero 
2550*042d53a7SEvalZero     /* fallback to ID static random address if using random address and instance
2551*042d53a7SEvalZero      * wasn't configured with own address
2552*042d53a7SEvalZero      */
2553*042d53a7SEvalZero     if (!ble_gap_slave[instance].rnd_addr_set) {
2554*042d53a7SEvalZero         switch (ble_gap_slave[instance].our_addr_type) {
2555*042d53a7SEvalZero         case BLE_OWN_ADDR_RANDOM:
2556*042d53a7SEvalZero         case BLE_OWN_ADDR_RPA_RANDOM_DEFAULT:
2557*042d53a7SEvalZero             rc = ble_hs_id_addr(BLE_ADDR_RANDOM, &rnd_addr, NULL);
2558*042d53a7SEvalZero             if (rc != 0) {
2559*042d53a7SEvalZero                 ble_hs_unlock();
2560*042d53a7SEvalZero                 return rc;
2561*042d53a7SEvalZero             }
2562*042d53a7SEvalZero 
2563*042d53a7SEvalZero             rc = ble_gap_ext_adv_set_addr_no_lock(instance, rnd_addr);
2564*042d53a7SEvalZero             if (rc != 0) {
2565*042d53a7SEvalZero                 ble_hs_unlock();
2566*042d53a7SEvalZero                 return rc;
2567*042d53a7SEvalZero             }
2568*042d53a7SEvalZero             break;
2569*042d53a7SEvalZero         default:
2570*042d53a7SEvalZero             break;
2571*042d53a7SEvalZero         }
2572*042d53a7SEvalZero     }
2573*042d53a7SEvalZero 
2574*042d53a7SEvalZero     opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_EXT_ADV_ENABLE);
2575*042d53a7SEvalZero 
2576*042d53a7SEvalZero     set.handle = instance;
2577*042d53a7SEvalZero     set.duration = duration;
2578*042d53a7SEvalZero     set.events = max_events;
2579*042d53a7SEvalZero 
2580*042d53a7SEvalZero     rc = ble_hs_hci_cmd_build_le_ext_adv_enable(1, 1, &set, buf, sizeof(buf));
2581*042d53a7SEvalZero     if (rc != 0) {
2582*042d53a7SEvalZero         ble_hs_unlock();
2583*042d53a7SEvalZero         return rc;
2584*042d53a7SEvalZero     }
2585*042d53a7SEvalZero 
2586*042d53a7SEvalZero     rc = ble_hs_hci_cmd_tx_empty_ack(opcode, buf, sizeof(buf));
2587*042d53a7SEvalZero     if (rc != 0) {
2588*042d53a7SEvalZero         ble_hs_unlock();
2589*042d53a7SEvalZero         return rc;
2590*042d53a7SEvalZero     }
2591*042d53a7SEvalZero 
2592*042d53a7SEvalZero     ble_gap_slave[instance].op = BLE_GAP_OP_S_ADV;
2593*042d53a7SEvalZero 
2594*042d53a7SEvalZero     ble_hs_unlock();
2595*042d53a7SEvalZero     return 0;
2596*042d53a7SEvalZero }
2597*042d53a7SEvalZero 
2598*042d53a7SEvalZero static int
ble_gap_ext_adv_stop_no_lock(uint8_t instance)2599*042d53a7SEvalZero ble_gap_ext_adv_stop_no_lock(uint8_t instance)
2600*042d53a7SEvalZero {
2601*042d53a7SEvalZero     uint8_t buf[6];
2602*042d53a7SEvalZero     struct hci_ext_adv_set set;
2603*042d53a7SEvalZero     uint16_t opcode;
2604*042d53a7SEvalZero     bool active;
2605*042d53a7SEvalZero     int rc;
2606*042d53a7SEvalZero 
2607*042d53a7SEvalZero     if (!ble_gap_slave[instance].configured) {
2608*042d53a7SEvalZero         return BLE_HS_EINVAL;
2609*042d53a7SEvalZero     }
2610*042d53a7SEvalZero 
2611*042d53a7SEvalZero     active = ble_gap_adv_active_instance(instance);
2612*042d53a7SEvalZero 
2613*042d53a7SEvalZero     opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_EXT_ADV_ENABLE);
2614*042d53a7SEvalZero 
2615*042d53a7SEvalZero     set.handle = instance;
2616*042d53a7SEvalZero     set.duration = 0;
2617*042d53a7SEvalZero     set.events = 0;
2618*042d53a7SEvalZero 
2619*042d53a7SEvalZero     rc = ble_hs_hci_cmd_build_le_ext_adv_enable(0, 1, &set, buf, sizeof(buf));
2620*042d53a7SEvalZero     if (rc != 0) {
2621*042d53a7SEvalZero         return rc;
2622*042d53a7SEvalZero     }
2623*042d53a7SEvalZero 
2624*042d53a7SEvalZero     rc = ble_hs_hci_cmd_tx_empty_ack(opcode, buf, sizeof(buf));
2625*042d53a7SEvalZero     if (rc != 0) {
2626*042d53a7SEvalZero         return rc;
2627*042d53a7SEvalZero     }
2628*042d53a7SEvalZero 
2629*042d53a7SEvalZero     ble_gap_slave[instance].op = BLE_GAP_OP_NULL;
2630*042d53a7SEvalZero 
2631*042d53a7SEvalZero     if (!active) {
2632*042d53a7SEvalZero         return BLE_HS_EALREADY;
2633*042d53a7SEvalZero     } else {
2634*042d53a7SEvalZero         return 0;
2635*042d53a7SEvalZero     }
2636*042d53a7SEvalZero }
2637*042d53a7SEvalZero 
2638*042d53a7SEvalZero int
ble_gap_ext_adv_stop(uint8_t instance)2639*042d53a7SEvalZero ble_gap_ext_adv_stop(uint8_t instance)
2640*042d53a7SEvalZero {
2641*042d53a7SEvalZero     int rc;
2642*042d53a7SEvalZero 
2643*042d53a7SEvalZero     if (instance >= BLE_ADV_INSTANCES) {
2644*042d53a7SEvalZero         return BLE_HS_EINVAL;
2645*042d53a7SEvalZero     }
2646*042d53a7SEvalZero 
2647*042d53a7SEvalZero     ble_hs_lock();
2648*042d53a7SEvalZero     rc = ble_gap_ext_adv_stop_no_lock(instance);
2649*042d53a7SEvalZero     ble_hs_unlock();
2650*042d53a7SEvalZero 
2651*042d53a7SEvalZero     return rc;
2652*042d53a7SEvalZero }
2653*042d53a7SEvalZero 
2654*042d53a7SEvalZero 
2655*042d53a7SEvalZero static int
ble_gap_ext_adv_set_data_validate(uint8_t instance,struct os_mbuf * data)2656*042d53a7SEvalZero ble_gap_ext_adv_set_data_validate(uint8_t instance, struct os_mbuf *data)
2657*042d53a7SEvalZero {
2658*042d53a7SEvalZero     uint16_t len = OS_MBUF_PKTLEN(data);
2659*042d53a7SEvalZero 
2660*042d53a7SEvalZero     if (!ble_gap_slave[instance].configured) {
2661*042d53a7SEvalZero         return BLE_HS_EINVAL;
2662*042d53a7SEvalZero     }
2663*042d53a7SEvalZero 
2664*042d53a7SEvalZero     /* not allowed with directed advertising for legacy*/
2665*042d53a7SEvalZero     if (ble_gap_slave[instance].legacy_pdu && ble_gap_slave[instance].directed) {
2666*042d53a7SEvalZero         return BLE_HS_EINVAL;
2667*042d53a7SEvalZero     }
2668*042d53a7SEvalZero 
2669*042d53a7SEvalZero     /* always allowed with legacy PDU but limited to legacy length */
2670*042d53a7SEvalZero     if (ble_gap_slave[instance].legacy_pdu) {
2671*042d53a7SEvalZero         if (len > BLE_HS_ADV_MAX_SZ) {
2672*042d53a7SEvalZero             return BLE_HS_EINVAL;
2673*042d53a7SEvalZero         }
2674*042d53a7SEvalZero 
2675*042d53a7SEvalZero         return 0;
2676*042d53a7SEvalZero     }
2677*042d53a7SEvalZero 
2678*042d53a7SEvalZero     /* if already advertising, data must fit in single HCI command */
2679*042d53a7SEvalZero     if (ble_gap_slave[instance].op == BLE_GAP_OP_S_ADV) {
2680*042d53a7SEvalZero         if (len > min(MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE), 251)) {
2681*042d53a7SEvalZero             return EINVAL;
2682*042d53a7SEvalZero         }
2683*042d53a7SEvalZero     }
2684*042d53a7SEvalZero 
2685*042d53a7SEvalZero     /* not allowed with scannable advertising */
2686*042d53a7SEvalZero     if (ble_gap_slave[instance].scannable) {
2687*042d53a7SEvalZero         return BLE_HS_EINVAL;
2688*042d53a7SEvalZero     }
2689*042d53a7SEvalZero 
2690*042d53a7SEvalZero     return 0;
2691*042d53a7SEvalZero }
2692*042d53a7SEvalZero 
2693*042d53a7SEvalZero static int
ble_gap_ext_adv_set(uint8_t instance,uint16_t opcode,struct os_mbuf ** data)2694*042d53a7SEvalZero ble_gap_ext_adv_set(uint8_t instance, uint16_t opcode, struct os_mbuf **data)
2695*042d53a7SEvalZero {
2696*042d53a7SEvalZero     /* in that case we always fit all data in single HCI command */
2697*042d53a7SEvalZero #if MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE) <= BLE_HCI_MAX_EXT_ADV_DATA_LEN
2698*042d53a7SEvalZero     static uint8_t buf[BLE_HCI_SET_EXT_ADV_DATA_HDR_LEN + \
2699*042d53a7SEvalZero                        MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE)];
2700*042d53a7SEvalZero     uint16_t len = OS_MBUF_PKTLEN(*data);
2701*042d53a7SEvalZero     int rc;
2702*042d53a7SEvalZero 
2703*042d53a7SEvalZero     opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, opcode);
2704*042d53a7SEvalZero 
2705*042d53a7SEvalZero     rc = ble_hs_hci_cmd_build_le_ext_adv_data(instance,
2706*042d53a7SEvalZero                                     BLE_HCI_LE_SET_EXT_ADV_DATA_OPER_COMPLETE,
2707*042d53a7SEvalZero                                     0, *data, len, buf, sizeof(buf));
2708*042d53a7SEvalZero     if (rc) {
2709*042d53a7SEvalZero         return rc;
2710*042d53a7SEvalZero     }
2711*042d53a7SEvalZero 
2712*042d53a7SEvalZero     os_mbuf_adj(*data, MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE));
2713*042d53a7SEvalZero     *data = os_mbuf_trim_front(*data);
2714*042d53a7SEvalZero 
2715*042d53a7SEvalZero     return ble_hs_hci_cmd_tx_empty_ack(opcode, buf,
2716*042d53a7SEvalZero                                        BLE_HCI_SET_EXT_ADV_DATA_HDR_LEN + len);
2717*042d53a7SEvalZero #else
2718*042d53a7SEvalZero     static uint8_t buf[BLE_HCI_SET_EXT_ADV_DATA_HDR_LEN + \
2719*042d53a7SEvalZero                        BLE_HCI_MAX_EXT_ADV_DATA_LEN];
2720*042d53a7SEvalZero     uint16_t len = OS_MBUF_PKTLEN(*data);
2721*042d53a7SEvalZero     uint8_t op;
2722*042d53a7SEvalZero     int rc;
2723*042d53a7SEvalZero 
2724*042d53a7SEvalZero     opcode =  BLE_HCI_OP(BLE_HCI_OGF_LE, opcode);
2725*042d53a7SEvalZero 
2726*042d53a7SEvalZero     /* complete data */
2727*042d53a7SEvalZero     if (len <= BLE_HCI_MAX_EXT_ADV_DATA_LEN) {
2728*042d53a7SEvalZero         rc = ble_hs_hci_cmd_build_le_ext_adv_data(instance,
2729*042d53a7SEvalZero                                     BLE_HCI_LE_SET_EXT_ADV_DATA_OPER_COMPLETE,
2730*042d53a7SEvalZero                                     0, *data, len, buf,sizeof(buf));
2731*042d53a7SEvalZero         if (rc) {
2732*042d53a7SEvalZero             return rc;
2733*042d53a7SEvalZero         }
2734*042d53a7SEvalZero 
2735*042d53a7SEvalZero         os_mbuf_adj(*data, len);
2736*042d53a7SEvalZero         *data = os_mbuf_trim_front(*data);
2737*042d53a7SEvalZero 
2738*042d53a7SEvalZero         return ble_hs_hci_cmd_tx_empty_ack(opcode, buf,
2739*042d53a7SEvalZero                                         BLE_HCI_SET_EXT_ADV_DATA_HDR_LEN + len);
2740*042d53a7SEvalZero     }
2741*042d53a7SEvalZero 
2742*042d53a7SEvalZero     /* first fragment  */
2743*042d53a7SEvalZero     op = BLE_HCI_LE_SET_EXT_ADV_DATA_OPER_FIRST;
2744*042d53a7SEvalZero 
2745*042d53a7SEvalZero     do {
2746*042d53a7SEvalZero         rc = ble_hs_hci_cmd_build_le_ext_adv_data(instance, op, 0, *data,
2747*042d53a7SEvalZero                                                   BLE_HCI_MAX_EXT_ADV_DATA_LEN,
2748*042d53a7SEvalZero                                                   buf, sizeof(buf));
2749*042d53a7SEvalZero         if (rc) {
2750*042d53a7SEvalZero             return rc;
2751*042d53a7SEvalZero         }
2752*042d53a7SEvalZero 
2753*042d53a7SEvalZero         os_mbuf_adj(*data, BLE_HCI_MAX_EXT_ADV_DATA_LEN);
2754*042d53a7SEvalZero         *data = os_mbuf_trim_front(*data);
2755*042d53a7SEvalZero 
2756*042d53a7SEvalZero         rc = ble_hs_hci_cmd_tx_empty_ack(opcode, buf, sizeof(buf));
2757*042d53a7SEvalZero         if (rc) {
2758*042d53a7SEvalZero             return rc;
2759*042d53a7SEvalZero         }
2760*042d53a7SEvalZero 
2761*042d53a7SEvalZero         len -= BLE_HCI_MAX_EXT_ADV_DATA_LEN;
2762*042d53a7SEvalZero         op = BLE_HCI_LE_SET_EXT_ADV_DATA_OPER_INT;
2763*042d53a7SEvalZero     } while (len > BLE_HCI_MAX_EXT_ADV_DATA_LEN);
2764*042d53a7SEvalZero 
2765*042d53a7SEvalZero     /* last fragment */
2766*042d53a7SEvalZero     rc = ble_hs_hci_cmd_build_le_ext_adv_data(instance,
2767*042d53a7SEvalZero                                         BLE_HCI_LE_SET_EXT_ADV_DATA_OPER_LAST,
2768*042d53a7SEvalZero                                         0, *data, len, buf, sizeof(buf));
2769*042d53a7SEvalZero     if (rc) {
2770*042d53a7SEvalZero         return rc;
2771*042d53a7SEvalZero     }
2772*042d53a7SEvalZero 
2773*042d53a7SEvalZero     os_mbuf_adj(*data, len);
2774*042d53a7SEvalZero     *data = os_mbuf_trim_front(*data);
2775*042d53a7SEvalZero 
2776*042d53a7SEvalZero     return ble_hs_hci_cmd_tx_empty_ack(opcode, buf,
2777*042d53a7SEvalZero                                        BLE_HCI_SET_EXT_ADV_DATA_HDR_LEN + len);
2778*042d53a7SEvalZero #endif
2779*042d53a7SEvalZero }
2780*042d53a7SEvalZero 
2781*042d53a7SEvalZero int
ble_gap_ext_adv_set_data(uint8_t instance,struct os_mbuf * data)2782*042d53a7SEvalZero ble_gap_ext_adv_set_data(uint8_t instance, struct os_mbuf *data)
2783*042d53a7SEvalZero {
2784*042d53a7SEvalZero     int rc;
2785*042d53a7SEvalZero 
2786*042d53a7SEvalZero     if (instance >= BLE_ADV_INSTANCES) {
2787*042d53a7SEvalZero         rc = BLE_HS_EINVAL;
2788*042d53a7SEvalZero         goto done;
2789*042d53a7SEvalZero     }
2790*042d53a7SEvalZero 
2791*042d53a7SEvalZero     ble_hs_lock();
2792*042d53a7SEvalZero     rc = ble_gap_ext_adv_set_data_validate(instance, data);
2793*042d53a7SEvalZero     if (rc != 0) {
2794*042d53a7SEvalZero         ble_hs_unlock();
2795*042d53a7SEvalZero         goto done;
2796*042d53a7SEvalZero     }
2797*042d53a7SEvalZero 
2798*042d53a7SEvalZero     rc = ble_gap_ext_adv_set(instance, BLE_HCI_OCF_LE_SET_EXT_ADV_DATA, &data);
2799*042d53a7SEvalZero 
2800*042d53a7SEvalZero     ble_hs_unlock();
2801*042d53a7SEvalZero 
2802*042d53a7SEvalZero done:
2803*042d53a7SEvalZero     os_mbuf_free_chain(data);
2804*042d53a7SEvalZero     return rc;
2805*042d53a7SEvalZero }
2806*042d53a7SEvalZero 
2807*042d53a7SEvalZero static int
ble_gap_ext_adv_rsp_set_validate(uint8_t instance,struct os_mbuf * data)2808*042d53a7SEvalZero ble_gap_ext_adv_rsp_set_validate(uint8_t instance,  struct os_mbuf *data)
2809*042d53a7SEvalZero {
2810*042d53a7SEvalZero     uint16_t len = OS_MBUF_PKTLEN(data);
2811*042d53a7SEvalZero 
2812*042d53a7SEvalZero     if (!ble_gap_slave[instance].configured) {
2813*042d53a7SEvalZero         return BLE_HS_EINVAL;
2814*042d53a7SEvalZero     }
2815*042d53a7SEvalZero 
2816*042d53a7SEvalZero     /* not allowed with directed advertising */
2817*042d53a7SEvalZero     if (ble_gap_slave[instance].directed && ble_gap_slave[instance].connectable) {
2818*042d53a7SEvalZero         return BLE_HS_EINVAL;
2819*042d53a7SEvalZero     }
2820*042d53a7SEvalZero 
2821*042d53a7SEvalZero     /* only allowed with scannable advertising */
2822*042d53a7SEvalZero     if (!ble_gap_slave[instance].scannable) {
2823*042d53a7SEvalZero         return BLE_HS_EINVAL;
2824*042d53a7SEvalZero     }
2825*042d53a7SEvalZero 
2826*042d53a7SEvalZero     /* with legacy PDU limited to legacy length */
2827*042d53a7SEvalZero     if (ble_gap_slave[instance].legacy_pdu) {
2828*042d53a7SEvalZero         if (len > BLE_HS_ADV_MAX_SZ) {
2829*042d53a7SEvalZero             return BLE_HS_EINVAL;
2830*042d53a7SEvalZero         }
2831*042d53a7SEvalZero 
2832*042d53a7SEvalZero         return 0;
2833*042d53a7SEvalZero     }
2834*042d53a7SEvalZero 
2835*042d53a7SEvalZero     /* if already advertising, data must fit in single HCI command */
2836*042d53a7SEvalZero     if (ble_gap_slave[instance].op == BLE_GAP_OP_S_ADV) {
2837*042d53a7SEvalZero         if (len > min(MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE), 251)) {
2838*042d53a7SEvalZero             return EINVAL;
2839*042d53a7SEvalZero         }
2840*042d53a7SEvalZero     }
2841*042d53a7SEvalZero 
2842*042d53a7SEvalZero     return 0;
2843*042d53a7SEvalZero }
2844*042d53a7SEvalZero 
2845*042d53a7SEvalZero int
ble_gap_ext_adv_rsp_set_data(uint8_t instance,struct os_mbuf * data)2846*042d53a7SEvalZero ble_gap_ext_adv_rsp_set_data(uint8_t instance, struct os_mbuf *data)
2847*042d53a7SEvalZero {
2848*042d53a7SEvalZero     int rc;
2849*042d53a7SEvalZero 
2850*042d53a7SEvalZero     if (instance >= BLE_ADV_INSTANCES) {
2851*042d53a7SEvalZero         rc = BLE_HS_EINVAL;
2852*042d53a7SEvalZero         goto done;
2853*042d53a7SEvalZero     }
2854*042d53a7SEvalZero 
2855*042d53a7SEvalZero     ble_hs_lock();
2856*042d53a7SEvalZero     rc = ble_gap_ext_adv_rsp_set_validate(instance, data);
2857*042d53a7SEvalZero     if (rc != 0) {
2858*042d53a7SEvalZero         ble_hs_unlock();
2859*042d53a7SEvalZero         goto done;
2860*042d53a7SEvalZero     }
2861*042d53a7SEvalZero 
2862*042d53a7SEvalZero     rc = ble_gap_ext_adv_set(instance, BLE_HCI_OCF_LE_SET_EXT_SCAN_RSP_DATA,
2863*042d53a7SEvalZero                              &data);
2864*042d53a7SEvalZero 
2865*042d53a7SEvalZero     ble_hs_unlock();
2866*042d53a7SEvalZero 
2867*042d53a7SEvalZero done:
2868*042d53a7SEvalZero     os_mbuf_free_chain(data);
2869*042d53a7SEvalZero     return rc;
2870*042d53a7SEvalZero }
2871*042d53a7SEvalZero 
2872*042d53a7SEvalZero int
ble_gap_ext_adv_remove(uint8_t instance)2873*042d53a7SEvalZero ble_gap_ext_adv_remove(uint8_t instance)
2874*042d53a7SEvalZero {
2875*042d53a7SEvalZero     uint8_t buf[BLE_HCI_LE_REMOVE_ADV_SET_LEN];
2876*042d53a7SEvalZero     uint16_t opcode;
2877*042d53a7SEvalZero     int rc;
2878*042d53a7SEvalZero 
2879*042d53a7SEvalZero     if (instance >= BLE_ADV_INSTANCES) {
2880*042d53a7SEvalZero         return BLE_HS_EINVAL;
2881*042d53a7SEvalZero     }
2882*042d53a7SEvalZero 
2883*042d53a7SEvalZero     ble_hs_lock();
2884*042d53a7SEvalZero     if (!ble_gap_slave[instance].configured) {
2885*042d53a7SEvalZero         ble_hs_unlock();
2886*042d53a7SEvalZero         return BLE_HS_EALREADY;
2887*042d53a7SEvalZero     }
2888*042d53a7SEvalZero 
2889*042d53a7SEvalZero     if (ble_gap_slave[instance].op == BLE_GAP_OP_S_ADV) {
2890*042d53a7SEvalZero         ble_hs_unlock();
2891*042d53a7SEvalZero         return BLE_HS_EBUSY;
2892*042d53a7SEvalZero     }
2893*042d53a7SEvalZero 
2894*042d53a7SEvalZero     opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_REMOVE_ADV_SET);
2895*042d53a7SEvalZero 
2896*042d53a7SEvalZero     rc = ble_hs_hci_cmd_build_le_ext_adv_remove(instance, buf, sizeof(buf));
2897*042d53a7SEvalZero     if (rc != 0) {
2898*042d53a7SEvalZero         ble_hs_unlock();
2899*042d53a7SEvalZero         return rc;
2900*042d53a7SEvalZero     }
2901*042d53a7SEvalZero 
2902*042d53a7SEvalZero     rc = ble_hs_hci_cmd_tx_empty_ack(opcode, buf, sizeof(buf));
2903*042d53a7SEvalZero     if (rc != 0) {
2904*042d53a7SEvalZero         ble_hs_unlock();
2905*042d53a7SEvalZero         return rc;
2906*042d53a7SEvalZero     }
2907*042d53a7SEvalZero 
2908*042d53a7SEvalZero     memset(&ble_gap_slave[instance], 0, sizeof(struct ble_gap_slave_state));
2909*042d53a7SEvalZero     ble_hs_unlock();
2910*042d53a7SEvalZero 
2911*042d53a7SEvalZero     return 0;
2912*042d53a7SEvalZero }
2913*042d53a7SEvalZero 
2914*042d53a7SEvalZero #endif
2915*042d53a7SEvalZero 
2916*042d53a7SEvalZero /*****************************************************************************
2917*042d53a7SEvalZero  * $discovery procedures                                                     *
2918*042d53a7SEvalZero  *****************************************************************************/
2919*042d53a7SEvalZero 
2920*042d53a7SEvalZero #if MYNEWT_VAL(BLE_EXT_ADV) && NIMBLE_BLE_SCAN
2921*042d53a7SEvalZero static int
ble_gap_ext_disc_tx_params(uint8_t own_addr_type,uint8_t filter_policy,const struct ble_hs_hci_ext_scan_param * uncoded_params,const struct ble_hs_hci_ext_scan_param * coded_params)2922*042d53a7SEvalZero ble_gap_ext_disc_tx_params(uint8_t own_addr_type, uint8_t filter_policy,
2923*042d53a7SEvalZero                        const struct ble_hs_hci_ext_scan_param *uncoded_params,
2924*042d53a7SEvalZero                        const struct ble_hs_hci_ext_scan_param *coded_params)
2925*042d53a7SEvalZero {
2926*042d53a7SEvalZero     uint8_t buf[BLE_HCI_LE_EXT_SCAN_BASE_LEN +
2927*042d53a7SEvalZero                 2 * BLE_HCI_LE_EXT_SCAN_SINGLE_PARAM_LEN];
2928*042d53a7SEvalZero     uint8_t phy_mask = 0;
2929*042d53a7SEvalZero     struct ble_hs_hci_ext_scan_param param[2] = {{0}};
2930*042d53a7SEvalZero     struct ble_hs_hci_ext_scan_param *p = param;
2931*042d53a7SEvalZero     int phy_count = 0;
2932*042d53a7SEvalZero     uint8_t len;
2933*042d53a7SEvalZero     int rc;
2934*042d53a7SEvalZero 
2935*042d53a7SEvalZero     if (uncoded_params) {
2936*042d53a7SEvalZero         phy_mask |= BLE_HCI_LE_PHY_1M_PREF_MASK;
2937*042d53a7SEvalZero         memcpy(&param[phy_count], uncoded_params, sizeof(*uncoded_params));
2938*042d53a7SEvalZero         phy_count++;
2939*042d53a7SEvalZero     }
2940*042d53a7SEvalZero 
2941*042d53a7SEvalZero     if (coded_params) {
2942*042d53a7SEvalZero         phy_mask |= BLE_HCI_LE_PHY_CODED_PREF_MASK;
2943*042d53a7SEvalZero         memcpy(&param[phy_count], coded_params, sizeof(*coded_params));
2944*042d53a7SEvalZero         phy_count++;
2945*042d53a7SEvalZero     }
2946*042d53a7SEvalZero 
2947*042d53a7SEvalZero     rc = ble_hs_hci_cmd_build_le_set_ext_scan_params(own_addr_type,
2948*042d53a7SEvalZero                                                      filter_policy,
2949*042d53a7SEvalZero                                                      phy_mask,
2950*042d53a7SEvalZero                                                      phy_count,
2951*042d53a7SEvalZero                                                      &p, buf, sizeof(buf));
2952*042d53a7SEvalZero 
2953*042d53a7SEvalZero     if (rc != 0) {
2954*042d53a7SEvalZero         return BLE_HS_EINVAL;
2955*042d53a7SEvalZero     }
2956*042d53a7SEvalZero 
2957*042d53a7SEvalZero     len = BLE_HCI_LE_EXT_SCAN_BASE_LEN +
2958*042d53a7SEvalZero           BLE_HCI_LE_EXT_SCAN_SINGLE_PARAM_LEN * phy_count;
2959*042d53a7SEvalZero 
2960*042d53a7SEvalZero     return ble_hs_hci_cmd_tx_empty_ack(BLE_HCI_OP(BLE_HCI_OGF_LE,
2961*042d53a7SEvalZero                                             BLE_HCI_OCF_LE_SET_EXT_SCAN_PARAM),
2962*042d53a7SEvalZero                                        buf, len);
2963*042d53a7SEvalZero }
2964*042d53a7SEvalZero 
2965*042d53a7SEvalZero static int
ble_gap_ext_disc_enable_tx(uint8_t enable,uint8_t filter_duplicates,uint16_t duration,uint16_t period)2966*042d53a7SEvalZero ble_gap_ext_disc_enable_tx(uint8_t enable, uint8_t filter_duplicates,
2967*042d53a7SEvalZero                            uint16_t duration, uint16_t period)
2968*042d53a7SEvalZero {
2969*042d53a7SEvalZero     uint8_t buf[BLE_HCI_LE_SET_EXT_SCAN_ENABLE_LEN];
2970*042d53a7SEvalZero 
2971*042d53a7SEvalZero     ble_hs_hci_cmd_build_le_set_ext_scan_enable(enable, filter_duplicates,
2972*042d53a7SEvalZero                                                 duration, period,
2973*042d53a7SEvalZero                                                 buf, sizeof buf);
2974*042d53a7SEvalZero 
2975*042d53a7SEvalZero     return ble_hs_hci_cmd_tx_empty_ack(
2976*042d53a7SEvalZero         BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_EXT_SCAN_ENABLE),
2977*042d53a7SEvalZero         buf, sizeof(buf));
2978*042d53a7SEvalZero }
2979*042d53a7SEvalZero #endif
2980*042d53a7SEvalZero 
2981*042d53a7SEvalZero #if NIMBLE_BLE_SCAN
2982*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_EXT_ADV)
2983*042d53a7SEvalZero static int
ble_gap_disc_enable_tx(int enable,int filter_duplicates)2984*042d53a7SEvalZero ble_gap_disc_enable_tx(int enable, int filter_duplicates)
2985*042d53a7SEvalZero {
2986*042d53a7SEvalZero     uint8_t buf[BLE_HCI_SET_SCAN_ENABLE_LEN];
2987*042d53a7SEvalZero     int rc;
2988*042d53a7SEvalZero 
2989*042d53a7SEvalZero     ble_hs_hci_cmd_build_le_set_scan_enable(!!enable, !!filter_duplicates,
2990*042d53a7SEvalZero                                             buf, sizeof buf);
2991*042d53a7SEvalZero     rc = ble_hs_hci_cmd_tx_empty_ack(
2992*042d53a7SEvalZero         BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_SCAN_ENABLE),
2993*042d53a7SEvalZero         buf, sizeof(buf));
2994*042d53a7SEvalZero     if (rc != 0) {
2995*042d53a7SEvalZero         return rc;
2996*042d53a7SEvalZero     }
2997*042d53a7SEvalZero 
2998*042d53a7SEvalZero     return 0;
2999*042d53a7SEvalZero }
3000*042d53a7SEvalZero 
3001*042d53a7SEvalZero static int
ble_gap_disc_tx_params(uint8_t own_addr_type,const struct ble_gap_disc_params * disc_params)3002*042d53a7SEvalZero ble_gap_disc_tx_params(uint8_t own_addr_type,
3003*042d53a7SEvalZero                        const struct ble_gap_disc_params *disc_params)
3004*042d53a7SEvalZero {
3005*042d53a7SEvalZero     uint8_t buf[BLE_HCI_SET_SCAN_PARAM_LEN];
3006*042d53a7SEvalZero     uint8_t scan_type;
3007*042d53a7SEvalZero     int rc;
3008*042d53a7SEvalZero 
3009*042d53a7SEvalZero     if (disc_params->passive) {
3010*042d53a7SEvalZero         scan_type = BLE_HCI_SCAN_TYPE_PASSIVE;
3011*042d53a7SEvalZero     } else {
3012*042d53a7SEvalZero         scan_type = BLE_HCI_SCAN_TYPE_ACTIVE;
3013*042d53a7SEvalZero     }
3014*042d53a7SEvalZero 
3015*042d53a7SEvalZero     rc = ble_hs_hci_cmd_build_le_set_scan_params(scan_type,
3016*042d53a7SEvalZero                                                  disc_params->itvl,
3017*042d53a7SEvalZero                                                  disc_params->window,
3018*042d53a7SEvalZero                                                  own_addr_type,
3019*042d53a7SEvalZero                                                  disc_params->filter_policy,
3020*042d53a7SEvalZero                                                  buf, sizeof buf);
3021*042d53a7SEvalZero     if (rc != 0) {
3022*042d53a7SEvalZero         return BLE_HS_EINVAL;
3023*042d53a7SEvalZero     }
3024*042d53a7SEvalZero 
3025*042d53a7SEvalZero     rc = ble_hs_hci_cmd_tx_empty_ack(
3026*042d53a7SEvalZero         BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_SCAN_PARAMS),
3027*042d53a7SEvalZero         buf, sizeof(buf));
3028*042d53a7SEvalZero     if (rc != 0) {
3029*042d53a7SEvalZero         return rc;
3030*042d53a7SEvalZero     }
3031*042d53a7SEvalZero 
3032*042d53a7SEvalZero     return 0;
3033*042d53a7SEvalZero }
3034*042d53a7SEvalZero #endif
3035*042d53a7SEvalZero 
3036*042d53a7SEvalZero static int
ble_gap_disc_disable_tx(void)3037*042d53a7SEvalZero ble_gap_disc_disable_tx(void)
3038*042d53a7SEvalZero {
3039*042d53a7SEvalZero #if MYNEWT_VAL(BLE_EXT_ADV)
3040*042d53a7SEvalZero     return ble_gap_ext_disc_enable_tx(0, 0, 0, 0);
3041*042d53a7SEvalZero #else
3042*042d53a7SEvalZero     return ble_gap_disc_enable_tx(0, 0);
3043*042d53a7SEvalZero #endif
3044*042d53a7SEvalZero }
3045*042d53a7SEvalZero 
3046*042d53a7SEvalZero static int
ble_gap_disc_cancel_no_lock(void)3047*042d53a7SEvalZero ble_gap_disc_cancel_no_lock(void)
3048*042d53a7SEvalZero {
3049*042d53a7SEvalZero     int rc;
3050*042d53a7SEvalZero 
3051*042d53a7SEvalZero     STATS_INC(ble_gap_stats, discover_cancel);
3052*042d53a7SEvalZero 
3053*042d53a7SEvalZero     if (!ble_gap_disc_active()) {
3054*042d53a7SEvalZero         rc = BLE_HS_EALREADY;
3055*042d53a7SEvalZero         goto done;
3056*042d53a7SEvalZero     }
3057*042d53a7SEvalZero 
3058*042d53a7SEvalZero     rc = ble_gap_disc_disable_tx();
3059*042d53a7SEvalZero     if (rc != 0) {
3060*042d53a7SEvalZero         goto done;
3061*042d53a7SEvalZero     }
3062*042d53a7SEvalZero 
3063*042d53a7SEvalZero     ble_gap_master_reset_state();
3064*042d53a7SEvalZero 
3065*042d53a7SEvalZero done:
3066*042d53a7SEvalZero     if (rc != 0) {
3067*042d53a7SEvalZero         STATS_INC(ble_gap_stats, discover_cancel_fail);
3068*042d53a7SEvalZero     }
3069*042d53a7SEvalZero 
3070*042d53a7SEvalZero     return rc;
3071*042d53a7SEvalZero }
3072*042d53a7SEvalZero #endif
3073*042d53a7SEvalZero 
3074*042d53a7SEvalZero int
ble_gap_disc_cancel(void)3075*042d53a7SEvalZero ble_gap_disc_cancel(void)
3076*042d53a7SEvalZero {
3077*042d53a7SEvalZero #if !NIMBLE_BLE_SCAN
3078*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
3079*042d53a7SEvalZero #else
3080*042d53a7SEvalZero 
3081*042d53a7SEvalZero     int rc;
3082*042d53a7SEvalZero 
3083*042d53a7SEvalZero     ble_hs_lock();
3084*042d53a7SEvalZero     rc = ble_gap_disc_cancel_no_lock();
3085*042d53a7SEvalZero     ble_hs_unlock();
3086*042d53a7SEvalZero 
3087*042d53a7SEvalZero     return rc;
3088*042d53a7SEvalZero #endif
3089*042d53a7SEvalZero }
3090*042d53a7SEvalZero 
3091*042d53a7SEvalZero #if NIMBLE_BLE_SCAN
3092*042d53a7SEvalZero static int
ble_gap_disc_ext_validate(uint8_t own_addr_type)3093*042d53a7SEvalZero ble_gap_disc_ext_validate(uint8_t own_addr_type)
3094*042d53a7SEvalZero {
3095*042d53a7SEvalZero     if (own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) {
3096*042d53a7SEvalZero         return BLE_HS_EINVAL;
3097*042d53a7SEvalZero     }
3098*042d53a7SEvalZero 
3099*042d53a7SEvalZero     if (ble_gap_conn_active()) {
3100*042d53a7SEvalZero         return BLE_HS_EBUSY;
3101*042d53a7SEvalZero     }
3102*042d53a7SEvalZero 
3103*042d53a7SEvalZero     if (ble_gap_disc_active()) {
3104*042d53a7SEvalZero         return BLE_HS_EALREADY;
3105*042d53a7SEvalZero     }
3106*042d53a7SEvalZero 
3107*042d53a7SEvalZero     if (!ble_hs_is_enabled()) {
3108*042d53a7SEvalZero         return BLE_HS_EDISABLED;
3109*042d53a7SEvalZero     }
3110*042d53a7SEvalZero 
3111*042d53a7SEvalZero     if (ble_gap_is_preempted()) {
3112*042d53a7SEvalZero         return BLE_HS_EPREEMPTED;
3113*042d53a7SEvalZero     }
3114*042d53a7SEvalZero 
3115*042d53a7SEvalZero     return 0;
3116*042d53a7SEvalZero }
3117*042d53a7SEvalZero #endif
3118*042d53a7SEvalZero 
3119*042d53a7SEvalZero #if MYNEWT_VAL(BLE_EXT_ADV) && NIMBLE_BLE_SCAN
3120*042d53a7SEvalZero static void
ble_gap_ext_disc_fill_dflts(uint8_t limited,struct ble_hs_hci_ext_scan_param * disc_params)3121*042d53a7SEvalZero ble_gap_ext_disc_fill_dflts(uint8_t limited,
3122*042d53a7SEvalZero                             struct ble_hs_hci_ext_scan_param *disc_params)
3123*042d53a7SEvalZero {
3124*042d53a7SEvalZero    if (disc_params->scan_itvl == 0) {
3125*042d53a7SEvalZero         if (limited) {
3126*042d53a7SEvalZero             disc_params->scan_itvl = BLE_GAP_LIM_DISC_SCAN_INT;
3127*042d53a7SEvalZero         } else {
3128*042d53a7SEvalZero             disc_params->scan_itvl = BLE_GAP_SCAN_FAST_INTERVAL_MIN;
3129*042d53a7SEvalZero         }
3130*042d53a7SEvalZero     }
3131*042d53a7SEvalZero 
3132*042d53a7SEvalZero     if (disc_params->scan_window == 0) {
3133*042d53a7SEvalZero         if (limited) {
3134*042d53a7SEvalZero             disc_params->scan_window = BLE_GAP_LIM_DISC_SCAN_WINDOW;
3135*042d53a7SEvalZero         } else {
3136*042d53a7SEvalZero             disc_params->scan_window = BLE_GAP_SCAN_FAST_WINDOW;
3137*042d53a7SEvalZero         }
3138*042d53a7SEvalZero     }
3139*042d53a7SEvalZero }
3140*042d53a7SEvalZero 
3141*042d53a7SEvalZero static void
ble_gap_ext_scan_params_to_hci(const struct ble_gap_ext_disc_params * params,struct ble_hs_hci_ext_scan_param * hci_params)3142*042d53a7SEvalZero ble_gap_ext_scan_params_to_hci(const struct ble_gap_ext_disc_params *params,
3143*042d53a7SEvalZero                                struct ble_hs_hci_ext_scan_param *hci_params)
3144*042d53a7SEvalZero {
3145*042d53a7SEvalZero 
3146*042d53a7SEvalZero     memset(hci_params, 0, sizeof(*hci_params));
3147*042d53a7SEvalZero 
3148*042d53a7SEvalZero     if (params->passive) {
3149*042d53a7SEvalZero         hci_params->scan_type =  BLE_HCI_SCAN_TYPE_PASSIVE;
3150*042d53a7SEvalZero     } else {
3151*042d53a7SEvalZero         hci_params->scan_type = BLE_HCI_SCAN_TYPE_ACTIVE;
3152*042d53a7SEvalZero     }
3153*042d53a7SEvalZero 
3154*042d53a7SEvalZero     hci_params->scan_itvl = params->itvl;
3155*042d53a7SEvalZero     hci_params->scan_window = params->window;
3156*042d53a7SEvalZero }
3157*042d53a7SEvalZero #endif
3158*042d53a7SEvalZero 
3159*042d53a7SEvalZero int
ble_gap_ext_disc(uint8_t own_addr_type,uint16_t duration,uint16_t period,uint8_t filter_duplicates,uint8_t filter_policy,uint8_t limited,const struct ble_gap_ext_disc_params * uncoded_params,const struct ble_gap_ext_disc_params * coded_params,ble_gap_event_fn * cb,void * cb_arg)3160*042d53a7SEvalZero ble_gap_ext_disc(uint8_t own_addr_type, uint16_t duration, uint16_t period,
3161*042d53a7SEvalZero                  uint8_t filter_duplicates, uint8_t filter_policy,
3162*042d53a7SEvalZero                  uint8_t limited,
3163*042d53a7SEvalZero                  const struct ble_gap_ext_disc_params *uncoded_params,
3164*042d53a7SEvalZero                  const struct ble_gap_ext_disc_params *coded_params,
3165*042d53a7SEvalZero                  ble_gap_event_fn *cb, void *cb_arg)
3166*042d53a7SEvalZero {
3167*042d53a7SEvalZero #if !NIMBLE_BLE_SCAN || !MYNEWT_VAL(BLE_EXT_ADV)
3168*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
3169*042d53a7SEvalZero #else
3170*042d53a7SEvalZero 
3171*042d53a7SEvalZero     struct ble_hs_hci_ext_scan_param ucp;
3172*042d53a7SEvalZero     struct ble_hs_hci_ext_scan_param cp;
3173*042d53a7SEvalZero     int rc;
3174*042d53a7SEvalZero 
3175*042d53a7SEvalZero     STATS_INC(ble_gap_stats, discover);
3176*042d53a7SEvalZero 
3177*042d53a7SEvalZero     ble_hs_lock();
3178*042d53a7SEvalZero 
3179*042d53a7SEvalZero     rc = ble_gap_disc_ext_validate(own_addr_type);
3180*042d53a7SEvalZero     if (rc != 0) {
3181*042d53a7SEvalZero         goto done;
3182*042d53a7SEvalZero     }
3183*042d53a7SEvalZero 
3184*042d53a7SEvalZero     /* Make a copy of the parameter structure and fill unspecified values with
3185*042d53a7SEvalZero      * defaults.
3186*042d53a7SEvalZero      */
3187*042d53a7SEvalZero 
3188*042d53a7SEvalZero     if (uncoded_params) {
3189*042d53a7SEvalZero         ble_gap_ext_scan_params_to_hci(uncoded_params, &ucp);
3190*042d53a7SEvalZero         ble_gap_ext_disc_fill_dflts(limited, &ucp);
3191*042d53a7SEvalZero 
3192*042d53a7SEvalZero         /* XXX: We should do it only once */
3193*042d53a7SEvalZero         if (!uncoded_params->passive) {
3194*042d53a7SEvalZero             rc = ble_hs_id_use_addr(own_addr_type);
3195*042d53a7SEvalZero             if (rc != 0) {
3196*042d53a7SEvalZero                 goto done;
3197*042d53a7SEvalZero             }
3198*042d53a7SEvalZero         }
3199*042d53a7SEvalZero     }
3200*042d53a7SEvalZero 
3201*042d53a7SEvalZero     if (coded_params) {
3202*042d53a7SEvalZero         ble_gap_ext_scan_params_to_hci(coded_params, &cp);
3203*042d53a7SEvalZero         ble_gap_ext_disc_fill_dflts(limited, &cp);
3204*042d53a7SEvalZero 
3205*042d53a7SEvalZero         /* XXX: We should do it only once */
3206*042d53a7SEvalZero         if (!coded_params->passive) {
3207*042d53a7SEvalZero             rc = ble_hs_id_use_addr(own_addr_type);
3208*042d53a7SEvalZero             if (rc != 0) {
3209*042d53a7SEvalZero                 goto done;
3210*042d53a7SEvalZero             }
3211*042d53a7SEvalZero         }
3212*042d53a7SEvalZero     }
3213*042d53a7SEvalZero 
3214*042d53a7SEvalZero     ble_gap_master.disc.limited = limited;
3215*042d53a7SEvalZero     ble_gap_master.cb = cb;
3216*042d53a7SEvalZero     ble_gap_master.cb_arg = cb_arg;
3217*042d53a7SEvalZero 
3218*042d53a7SEvalZero     rc = ble_gap_ext_disc_tx_params(own_addr_type, filter_policy,
3219*042d53a7SEvalZero                                     uncoded_params ? &ucp : NULL,
3220*042d53a7SEvalZero                                     coded_params ? &cp : NULL);
3221*042d53a7SEvalZero     if (rc != 0) {
3222*042d53a7SEvalZero         goto done;
3223*042d53a7SEvalZero     }
3224*042d53a7SEvalZero 
3225*042d53a7SEvalZero     ble_gap_master.op = BLE_GAP_OP_M_DISC;
3226*042d53a7SEvalZero 
3227*042d53a7SEvalZero     rc = ble_gap_ext_disc_enable_tx(1, filter_duplicates, duration, period);
3228*042d53a7SEvalZero     if (rc != 0) {
3229*042d53a7SEvalZero         ble_gap_master_reset_state();
3230*042d53a7SEvalZero         goto done;
3231*042d53a7SEvalZero     }
3232*042d53a7SEvalZero 
3233*042d53a7SEvalZero     rc = 0;
3234*042d53a7SEvalZero 
3235*042d53a7SEvalZero done:
3236*042d53a7SEvalZero     ble_hs_unlock();
3237*042d53a7SEvalZero 
3238*042d53a7SEvalZero     if (rc != 0) {
3239*042d53a7SEvalZero         STATS_INC(ble_gap_stats, discover_fail);
3240*042d53a7SEvalZero     }
3241*042d53a7SEvalZero     return rc;
3242*042d53a7SEvalZero #endif
3243*042d53a7SEvalZero }
3244*042d53a7SEvalZero 
3245*042d53a7SEvalZero #if NIMBLE_BLE_SCAN && !MYNEWT_VAL(BLE_EXT_ADV)
3246*042d53a7SEvalZero static void
ble_gap_disc_fill_dflts(struct ble_gap_disc_params * disc_params)3247*042d53a7SEvalZero ble_gap_disc_fill_dflts(struct ble_gap_disc_params *disc_params)
3248*042d53a7SEvalZero {
3249*042d53a7SEvalZero    if (disc_params->itvl == 0) {
3250*042d53a7SEvalZero         if (disc_params->limited) {
3251*042d53a7SEvalZero             disc_params->itvl = BLE_GAP_LIM_DISC_SCAN_INT;
3252*042d53a7SEvalZero         } else {
3253*042d53a7SEvalZero             disc_params->itvl = BLE_GAP_SCAN_FAST_INTERVAL_MIN;
3254*042d53a7SEvalZero         }
3255*042d53a7SEvalZero     }
3256*042d53a7SEvalZero 
3257*042d53a7SEvalZero     if (disc_params->window == 0) {
3258*042d53a7SEvalZero         if (disc_params->limited) {
3259*042d53a7SEvalZero             disc_params->window = BLE_GAP_LIM_DISC_SCAN_WINDOW;
3260*042d53a7SEvalZero         } else {
3261*042d53a7SEvalZero             disc_params->window = BLE_GAP_SCAN_FAST_WINDOW;
3262*042d53a7SEvalZero         }
3263*042d53a7SEvalZero     }
3264*042d53a7SEvalZero }
3265*042d53a7SEvalZero 
3266*042d53a7SEvalZero static int
ble_gap_disc_validate(uint8_t own_addr_type,const struct ble_gap_disc_params * disc_params)3267*042d53a7SEvalZero ble_gap_disc_validate(uint8_t own_addr_type,
3268*042d53a7SEvalZero                       const struct ble_gap_disc_params *disc_params)
3269*042d53a7SEvalZero {
3270*042d53a7SEvalZero     if (disc_params == NULL) {
3271*042d53a7SEvalZero         return BLE_HS_EINVAL;
3272*042d53a7SEvalZero     }
3273*042d53a7SEvalZero 
3274*042d53a7SEvalZero     return ble_gap_disc_ext_validate(own_addr_type);
3275*042d53a7SEvalZero }
3276*042d53a7SEvalZero #endif
3277*042d53a7SEvalZero 
3278*042d53a7SEvalZero int
ble_gap_disc(uint8_t own_addr_type,int32_t duration_ms,const struct ble_gap_disc_params * disc_params,ble_gap_event_fn * cb,void * cb_arg)3279*042d53a7SEvalZero ble_gap_disc(uint8_t own_addr_type, int32_t duration_ms,
3280*042d53a7SEvalZero              const struct ble_gap_disc_params *disc_params,
3281*042d53a7SEvalZero              ble_gap_event_fn *cb, void *cb_arg)
3282*042d53a7SEvalZero {
3283*042d53a7SEvalZero #if !NIMBLE_BLE_SCAN
3284*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
3285*042d53a7SEvalZero #else
3286*042d53a7SEvalZero 
3287*042d53a7SEvalZero #if MYNEWT_VAL(BLE_EXT_ADV)
3288*042d53a7SEvalZero     struct ble_gap_ext_disc_params p = {0};
3289*042d53a7SEvalZero 
3290*042d53a7SEvalZero     p.itvl = disc_params->itvl;
3291*042d53a7SEvalZero     p.passive = disc_params->passive;
3292*042d53a7SEvalZero     p.window = disc_params->window;
3293*042d53a7SEvalZero 
3294*042d53a7SEvalZero     return ble_gap_ext_disc(own_addr_type, duration_ms/10, 0,
3295*042d53a7SEvalZero                           disc_params->filter_duplicates,
3296*042d53a7SEvalZero                           disc_params->filter_policy, disc_params->limited,
3297*042d53a7SEvalZero                           &p, NULL, cb, cb_arg);
3298*042d53a7SEvalZero #else
3299*042d53a7SEvalZero     struct ble_gap_disc_params params;
3300*042d53a7SEvalZero     uint32_t duration_ticks = 0;
3301*042d53a7SEvalZero     int rc;
3302*042d53a7SEvalZero 
3303*042d53a7SEvalZero     STATS_INC(ble_gap_stats, discover);
3304*042d53a7SEvalZero 
3305*042d53a7SEvalZero     ble_hs_lock();
3306*042d53a7SEvalZero 
3307*042d53a7SEvalZero     /* Make a copy of the parameter strcuture and fill unspecified values with
3308*042d53a7SEvalZero      * defaults.
3309*042d53a7SEvalZero      */
3310*042d53a7SEvalZero     params = *disc_params;
3311*042d53a7SEvalZero     ble_gap_disc_fill_dflts(&params);
3312*042d53a7SEvalZero 
3313*042d53a7SEvalZero     rc = ble_gap_disc_validate(own_addr_type, &params);
3314*042d53a7SEvalZero     if (rc != 0) {
3315*042d53a7SEvalZero         goto done;
3316*042d53a7SEvalZero     }
3317*042d53a7SEvalZero 
3318*042d53a7SEvalZero     if (duration_ms == 0) {
3319*042d53a7SEvalZero         duration_ms = BLE_GAP_DISC_DUR_DFLT;
3320*042d53a7SEvalZero     }
3321*042d53a7SEvalZero 
3322*042d53a7SEvalZero     if (duration_ms != BLE_HS_FOREVER) {
3323*042d53a7SEvalZero         rc = ble_npl_time_ms_to_ticks(duration_ms, &duration_ticks);
3324*042d53a7SEvalZero         if (rc != 0) {
3325*042d53a7SEvalZero             /* Duration too great. */
3326*042d53a7SEvalZero             rc = BLE_HS_EINVAL;
3327*042d53a7SEvalZero             goto done;
3328*042d53a7SEvalZero         }
3329*042d53a7SEvalZero     }
3330*042d53a7SEvalZero 
3331*042d53a7SEvalZero     if (!params.passive) {
3332*042d53a7SEvalZero         rc = ble_hs_id_use_addr(own_addr_type);
3333*042d53a7SEvalZero         if (rc != 0) {
3334*042d53a7SEvalZero             goto done;
3335*042d53a7SEvalZero         }
3336*042d53a7SEvalZero     }
3337*042d53a7SEvalZero 
3338*042d53a7SEvalZero     ble_gap_master.disc.limited = params.limited;
3339*042d53a7SEvalZero     ble_gap_master.cb = cb;
3340*042d53a7SEvalZero     ble_gap_master.cb_arg = cb_arg;
3341*042d53a7SEvalZero 
3342*042d53a7SEvalZero     BLE_HS_LOG(INFO, "GAP procedure initiated: discovery; ");
3343*042d53a7SEvalZero     ble_gap_log_disc(own_addr_type, duration_ms, &params);
3344*042d53a7SEvalZero     BLE_HS_LOG(INFO, "\n");
3345*042d53a7SEvalZero 
3346*042d53a7SEvalZero     rc = ble_gap_disc_tx_params(own_addr_type, &params);
3347*042d53a7SEvalZero     if (rc != 0) {
3348*042d53a7SEvalZero         goto done;
3349*042d53a7SEvalZero     }
3350*042d53a7SEvalZero 
3351*042d53a7SEvalZero     ble_gap_master.op = BLE_GAP_OP_M_DISC;
3352*042d53a7SEvalZero 
3353*042d53a7SEvalZero     rc = ble_gap_disc_enable_tx(1, params.filter_duplicates);
3354*042d53a7SEvalZero     if (rc != 0) {
3355*042d53a7SEvalZero         ble_gap_master_reset_state();
3356*042d53a7SEvalZero         goto done;
3357*042d53a7SEvalZero     }
3358*042d53a7SEvalZero 
3359*042d53a7SEvalZero     if (duration_ms != BLE_HS_FOREVER) {
3360*042d53a7SEvalZero         ble_gap_master_set_timer(duration_ticks);
3361*042d53a7SEvalZero     }
3362*042d53a7SEvalZero 
3363*042d53a7SEvalZero     rc = 0;
3364*042d53a7SEvalZero 
3365*042d53a7SEvalZero done:
3366*042d53a7SEvalZero     ble_hs_unlock();
3367*042d53a7SEvalZero 
3368*042d53a7SEvalZero     if (rc != 0) {
3369*042d53a7SEvalZero         STATS_INC(ble_gap_stats, discover_fail);
3370*042d53a7SEvalZero     }
3371*042d53a7SEvalZero     return rc;
3372*042d53a7SEvalZero #endif
3373*042d53a7SEvalZero #endif
3374*042d53a7SEvalZero }
3375*042d53a7SEvalZero 
3376*042d53a7SEvalZero int
ble_gap_disc_active(void)3377*042d53a7SEvalZero ble_gap_disc_active(void)
3378*042d53a7SEvalZero {
3379*042d53a7SEvalZero     /* Assume read is atomic; mutex not necessary. */
3380*042d53a7SEvalZero     return ble_gap_master.op == BLE_GAP_OP_M_DISC;
3381*042d53a7SEvalZero }
3382*042d53a7SEvalZero 
3383*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_EXT_ADV)
3384*042d53a7SEvalZero /*****************************************************************************
3385*042d53a7SEvalZero  * $connection establishment procedures                                      *
3386*042d53a7SEvalZero  *****************************************************************************/
3387*042d53a7SEvalZero 
3388*042d53a7SEvalZero static int
ble_gap_conn_create_tx(uint8_t own_addr_type,const ble_addr_t * peer_addr,const struct ble_gap_conn_params * params)3389*042d53a7SEvalZero ble_gap_conn_create_tx(uint8_t own_addr_type, const ble_addr_t *peer_addr,
3390*042d53a7SEvalZero                        const struct ble_gap_conn_params *params)
3391*042d53a7SEvalZero {
3392*042d53a7SEvalZero     uint8_t buf[BLE_HCI_CREATE_CONN_LEN];
3393*042d53a7SEvalZero     struct hci_create_conn hcc;
3394*042d53a7SEvalZero     int rc;
3395*042d53a7SEvalZero 
3396*042d53a7SEvalZero     hcc.scan_itvl = params->scan_itvl;
3397*042d53a7SEvalZero     hcc.scan_window = params->scan_window;
3398*042d53a7SEvalZero 
3399*042d53a7SEvalZero     if (peer_addr == NULL) {
3400*042d53a7SEvalZero         /* Application wants to connect to any device in the white list.  The
3401*042d53a7SEvalZero          * peer address type and peer address fields are ignored by the
3402*042d53a7SEvalZero          * controller; fill them with dummy values.
3403*042d53a7SEvalZero          */
3404*042d53a7SEvalZero         hcc.filter_policy = BLE_HCI_CONN_FILT_USE_WL;
3405*042d53a7SEvalZero         hcc.peer_addr_type = 0;
3406*042d53a7SEvalZero         memset(hcc.peer_addr, 0, sizeof hcc.peer_addr);
3407*042d53a7SEvalZero     } else {
3408*042d53a7SEvalZero         hcc.filter_policy = BLE_HCI_CONN_FILT_NO_WL;
3409*042d53a7SEvalZero         hcc.peer_addr_type = peer_addr->type;
3410*042d53a7SEvalZero         memcpy(hcc.peer_addr, peer_addr->val, sizeof hcc.peer_addr);
3411*042d53a7SEvalZero     }
3412*042d53a7SEvalZero 
3413*042d53a7SEvalZero     hcc.own_addr_type = own_addr_type;
3414*042d53a7SEvalZero     hcc.conn_itvl_min = params->itvl_min;
3415*042d53a7SEvalZero     hcc.conn_itvl_max = params->itvl_max;
3416*042d53a7SEvalZero     hcc.conn_latency = params->latency;
3417*042d53a7SEvalZero     hcc.supervision_timeout = params->supervision_timeout;
3418*042d53a7SEvalZero     hcc.min_ce_len = params->min_ce_len;
3419*042d53a7SEvalZero     hcc.max_ce_len = params->max_ce_len;
3420*042d53a7SEvalZero 
3421*042d53a7SEvalZero     rc = ble_hs_hci_cmd_build_le_create_connection(&hcc, buf, sizeof buf);
3422*042d53a7SEvalZero     if (rc != 0) {
3423*042d53a7SEvalZero         return BLE_HS_EUNKNOWN;
3424*042d53a7SEvalZero     }
3425*042d53a7SEvalZero 
3426*042d53a7SEvalZero     rc = ble_hs_hci_cmd_tx_empty_ack(BLE_HCI_OP(BLE_HCI_OGF_LE,
3427*042d53a7SEvalZero                                                 BLE_HCI_OCF_LE_CREATE_CONN),
3428*042d53a7SEvalZero                                      buf, sizeof(buf));
3429*042d53a7SEvalZero     if (rc != 0) {
3430*042d53a7SEvalZero         return rc;
3431*042d53a7SEvalZero     }
3432*042d53a7SEvalZero 
3433*042d53a7SEvalZero     return 0;
3434*042d53a7SEvalZero }
3435*042d53a7SEvalZero #endif
3436*042d53a7SEvalZero 
3437*042d53a7SEvalZero #if MYNEWT_VAL(BLE_EXT_ADV)
3438*042d53a7SEvalZero static void
ble_gap_copy_params(struct hci_ext_conn_params * hcc_params,const struct ble_gap_conn_params * gap_params)3439*042d53a7SEvalZero ble_gap_copy_params(struct hci_ext_conn_params *hcc_params,
3440*042d53a7SEvalZero                     const struct ble_gap_conn_params *gap_params)
3441*042d53a7SEvalZero {
3442*042d53a7SEvalZero     hcc_params->scan_itvl = gap_params->scan_itvl;
3443*042d53a7SEvalZero     hcc_params->scan_window = gap_params->scan_window;
3444*042d53a7SEvalZero     hcc_params->conn_itvl_max = gap_params->itvl_max;
3445*042d53a7SEvalZero     hcc_params->conn_itvl_min = gap_params->itvl_min;
3446*042d53a7SEvalZero     hcc_params->max_ce_len = gap_params->max_ce_len;
3447*042d53a7SEvalZero     hcc_params->min_ce_len = gap_params->min_ce_len;
3448*042d53a7SEvalZero     hcc_params->conn_latency = gap_params->latency;
3449*042d53a7SEvalZero     hcc_params->supervision_timeout = gap_params->supervision_timeout;
3450*042d53a7SEvalZero }
3451*042d53a7SEvalZero 
3452*042d53a7SEvalZero static int
ble_gap_ext_conn_create_tx(uint8_t own_addr_type,const ble_addr_t * peer_addr,uint8_t phy_mask,const struct ble_gap_conn_params * phy_1m_conn_params,const struct ble_gap_conn_params * phy_2m_conn_params,const struct ble_gap_conn_params * phy_coded_conn_params)3453*042d53a7SEvalZero ble_gap_ext_conn_create_tx(
3454*042d53a7SEvalZero     uint8_t own_addr_type, const ble_addr_t *peer_addr, uint8_t phy_mask,
3455*042d53a7SEvalZero     const struct ble_gap_conn_params *phy_1m_conn_params,
3456*042d53a7SEvalZero     const struct ble_gap_conn_params *phy_2m_conn_params,
3457*042d53a7SEvalZero     const struct ble_gap_conn_params *phy_coded_conn_params)
3458*042d53a7SEvalZero {
3459*042d53a7SEvalZero     uint8_t buf[sizeof(struct hci_ext_create_conn)];
3460*042d53a7SEvalZero     struct hci_ext_create_conn hcc = {0};
3461*042d53a7SEvalZero     int rc;
3462*042d53a7SEvalZero 
3463*042d53a7SEvalZero     if (peer_addr == NULL) {
3464*042d53a7SEvalZero         /* Application wants to connect to any device in the white list.  The
3465*042d53a7SEvalZero          * peer address type and peer address fields are ignored by the
3466*042d53a7SEvalZero          * controller; fill them with dummy values.
3467*042d53a7SEvalZero          */
3468*042d53a7SEvalZero         hcc.filter_policy = BLE_HCI_CONN_FILT_USE_WL;
3469*042d53a7SEvalZero         hcc.peer_addr_type = 0;
3470*042d53a7SEvalZero         memset(hcc.peer_addr, 0, sizeof hcc.peer_addr);
3471*042d53a7SEvalZero     } else {
3472*042d53a7SEvalZero         hcc.filter_policy = BLE_HCI_CONN_FILT_NO_WL;
3473*042d53a7SEvalZero         hcc.peer_addr_type = peer_addr->type;;
3474*042d53a7SEvalZero         memcpy(hcc.peer_addr, peer_addr->val, sizeof hcc.peer_addr);
3475*042d53a7SEvalZero     }
3476*042d53a7SEvalZero 
3477*042d53a7SEvalZero     hcc.own_addr_type = own_addr_type;
3478*042d53a7SEvalZero 
3479*042d53a7SEvalZero     hcc.init_phy_mask = phy_mask;
3480*042d53a7SEvalZero 
3481*042d53a7SEvalZero     if (phy_mask & BLE_GAP_LE_PHY_1M_MASK) {
3482*042d53a7SEvalZero         /* XXX same structs */
3483*042d53a7SEvalZero         ble_gap_copy_params(&hcc.params[0], phy_1m_conn_params);
3484*042d53a7SEvalZero     }
3485*042d53a7SEvalZero 
3486*042d53a7SEvalZero     if (phy_mask & BLE_GAP_LE_PHY_2M_MASK) {
3487*042d53a7SEvalZero         /* XXX same structs */
3488*042d53a7SEvalZero         ble_gap_copy_params(&hcc.params[1], phy_2m_conn_params);
3489*042d53a7SEvalZero     }
3490*042d53a7SEvalZero 
3491*042d53a7SEvalZero     if (phy_mask & BLE_GAP_LE_PHY_CODED_MASK) {
3492*042d53a7SEvalZero         /* XXX same structs */
3493*042d53a7SEvalZero         ble_gap_copy_params(&hcc.params[2], phy_coded_conn_params);
3494*042d53a7SEvalZero     }
3495*042d53a7SEvalZero 
3496*042d53a7SEvalZero     rc = ble_hs_hci_cmd_build_le_ext_create_conn(&hcc, buf, sizeof buf);
3497*042d53a7SEvalZero     if (rc != 0) {
3498*042d53a7SEvalZero         return BLE_HS_EUNKNOWN;
3499*042d53a7SEvalZero     }
3500*042d53a7SEvalZero 
3501*042d53a7SEvalZero     rc = ble_hs_hci_cmd_tx_empty_ack(
3502*042d53a7SEvalZero         BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_EXT_CREATE_CONN),
3503*042d53a7SEvalZero         buf, sizeof(buf));
3504*042d53a7SEvalZero     if (rc != 0) {
3505*042d53a7SEvalZero         return rc;
3506*042d53a7SEvalZero     }
3507*042d53a7SEvalZero 
3508*042d53a7SEvalZero     return 0;
3509*042d53a7SEvalZero }
3510*042d53a7SEvalZero 
3511*042d53a7SEvalZero /**
3512*042d53a7SEvalZero  * Initiates a connect procedure.
3513*042d53a7SEvalZero  *
3514*042d53a7SEvalZero  * @param own_addr_type         The type of address the stack should use for
3515*042d53a7SEvalZero  *                                  itself during connection establishment.
3516*042d53a7SEvalZero  *                                      o BLE_OWN_ADDR_PUBLIC
3517*042d53a7SEvalZero  *                                      o BLE_OWN_ADDR_RANDOM
3518*042d53a7SEvalZero  *                                      o BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT
3519*042d53a7SEvalZero  *                                      o BLE_OWN_ADDR_RPA_RANDOM_DEFAULT
3520*042d53a7SEvalZero  * @param peer_addr             The address of the peer to connect to.
3521*042d53a7SEvalZero  *                                  If this parameter is NULL, the white list
3522*042d53a7SEvalZero  *                                  is used.
3523*042d53a7SEvalZero  * @param duration_ms           The duration of the discovery procedure.
3524*042d53a7SEvalZero  *                                  On expiration, the procedure ends and a
3525*042d53a7SEvalZero  *                                  BLE_GAP_EVENT_DISC_COMPLETE event is
3526*042d53a7SEvalZero  *                                  reported.  Units are milliseconds.
3527*042d53a7SEvalZero  * @param phy_mask              Define on which PHYs connection attempt should
3528*042d53a7SEvalZero  *                                  be done
3529*042d53a7SEvalZero  * @param phy_1m_conn_params     Additional arguments specifying the
3530*042d53a7SEvalZero  *                                  particulars of the connect procedure. When
3531*042d53a7SEvalZero  *                                  BLE_GAP_LE_PHY_1M_MASK is set in phy_mask
3532*042d53a7SEvalZero  *                                  this parameter can be specify to null for
3533*042d53a7SEvalZero  *                                  default values.
3534*042d53a7SEvalZero  * @param phy_2m_conn_params     Additional arguments specifying the
3535*042d53a7SEvalZero  *                                  particulars of the connect procedure. When
3536*042d53a7SEvalZero  *                                  BLE_GAP_LE_PHY_2M_MASK is set in phy_mask
3537*042d53a7SEvalZero  *                                  this parameter can be specify to null for
3538*042d53a7SEvalZero  *                                  default values.
3539*042d53a7SEvalZero  * @param phy_coded_conn_params  Additional arguments specifying the
3540*042d53a7SEvalZero  *                                  particulars of the connect procedure. When
3541*042d53a7SEvalZero  *                                  BLE_GAP_LE_PHY_CODED_MASK is set in
3542*042d53a7SEvalZero  *                                  phy_mask this parameter can be specify to
3543*042d53a7SEvalZero  *                                  null for default values.
3544*042d53a7SEvalZero  * @param cb                    The callback to associate with this connect
3545*042d53a7SEvalZero  *                                  procedure.  When the connect procedure
3546*042d53a7SEvalZero  *                                  completes, the result is reported through
3547*042d53a7SEvalZero  *                                  this callback.  If the connect procedure
3548*042d53a7SEvalZero  *                                  succeeds, the connection inherits this
3549*042d53a7SEvalZero  *                                  callback as its event-reporting mechanism.
3550*042d53a7SEvalZero  * @param cb_arg                The optional argument to pass to the callback
3551*042d53a7SEvalZero  *                                  function.
3552*042d53a7SEvalZero  *
3553*042d53a7SEvalZero  * @return                      0 on success;
3554*042d53a7SEvalZero  *                              BLE_HS_EALREADY if a connection attempt is
3555*042d53a7SEvalZero  *                                  already in progress;
3556*042d53a7SEvalZero  *                              BLE_HS_EBUSY if initiating a connection is not
3557*042d53a7SEvalZero  *                                  possible because scanning is in progress;
3558*042d53a7SEvalZero  *                              BLE_HS_EDONE if the specified peer is already
3559*042d53a7SEvalZero  *                                  connected;
3560*042d53a7SEvalZero  *                              Other nonzero on error.
3561*042d53a7SEvalZero  */
3562*042d53a7SEvalZero int
ble_gap_ext_connect(uint8_t own_addr_type,const ble_addr_t * peer_addr,int32_t duration_ms,uint8_t phy_mask,const struct ble_gap_conn_params * phy_1m_conn_params,const struct ble_gap_conn_params * phy_2m_conn_params,const struct ble_gap_conn_params * phy_coded_conn_params,ble_gap_event_fn * cb,void * cb_arg)3563*042d53a7SEvalZero ble_gap_ext_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr,
3564*042d53a7SEvalZero                 int32_t duration_ms, uint8_t phy_mask,
3565*042d53a7SEvalZero                 const struct ble_gap_conn_params *phy_1m_conn_params,
3566*042d53a7SEvalZero                 const struct ble_gap_conn_params *phy_2m_conn_params,
3567*042d53a7SEvalZero                 const struct ble_gap_conn_params *phy_coded_conn_params,
3568*042d53a7SEvalZero                 ble_gap_event_fn *cb, void *cb_arg)
3569*042d53a7SEvalZero {
3570*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_ROLE_CENTRAL)
3571*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
3572*042d53a7SEvalZero #endif
3573*042d53a7SEvalZero 
3574*042d53a7SEvalZero     ble_npl_time_t duration_ticks;
3575*042d53a7SEvalZero     int rc;
3576*042d53a7SEvalZero 
3577*042d53a7SEvalZero     STATS_INC(ble_gap_stats, initiate);
3578*042d53a7SEvalZero 
3579*042d53a7SEvalZero     ble_hs_lock();
3580*042d53a7SEvalZero 
3581*042d53a7SEvalZero     if (ble_gap_conn_active()) {
3582*042d53a7SEvalZero         rc = BLE_HS_EALREADY;
3583*042d53a7SEvalZero         goto done;
3584*042d53a7SEvalZero     }
3585*042d53a7SEvalZero 
3586*042d53a7SEvalZero     if (ble_gap_disc_active()) {
3587*042d53a7SEvalZero         rc = BLE_HS_EBUSY;
3588*042d53a7SEvalZero         goto done;
3589*042d53a7SEvalZero     }
3590*042d53a7SEvalZero 
3591*042d53a7SEvalZero     if (!ble_hs_is_enabled()) {
3592*042d53a7SEvalZero         return BLE_HS_EDISABLED;
3593*042d53a7SEvalZero     }
3594*042d53a7SEvalZero 
3595*042d53a7SEvalZero     if (ble_gap_is_preempted()) {
3596*042d53a7SEvalZero         rc = BLE_HS_EPREEMPTED;
3597*042d53a7SEvalZero         goto done;
3598*042d53a7SEvalZero     }
3599*042d53a7SEvalZero 
3600*042d53a7SEvalZero     if (!ble_hs_conn_can_alloc()) {
3601*042d53a7SEvalZero         rc = BLE_HS_ENOMEM;
3602*042d53a7SEvalZero         goto done;
3603*042d53a7SEvalZero     }
3604*042d53a7SEvalZero 
3605*042d53a7SEvalZero     if (peer_addr &&
3606*042d53a7SEvalZero         peer_addr->type != BLE_ADDR_PUBLIC &&
3607*042d53a7SEvalZero         peer_addr->type != BLE_ADDR_RANDOM &&
3608*042d53a7SEvalZero         peer_addr->type != BLE_ADDR_PUBLIC_ID &&
3609*042d53a7SEvalZero         peer_addr->type != BLE_ADDR_RANDOM_ID) {
3610*042d53a7SEvalZero 
3611*042d53a7SEvalZero         rc = BLE_HS_EINVAL;
3612*042d53a7SEvalZero         goto done;
3613*042d53a7SEvalZero     }
3614*042d53a7SEvalZero 
3615*042d53a7SEvalZero     if ((phy_mask & BLE_GAP_LE_PHY_1M_MASK) && phy_1m_conn_params == NULL) {
3616*042d53a7SEvalZero         phy_1m_conn_params = &ble_gap_conn_params_dflt;
3617*042d53a7SEvalZero     }
3618*042d53a7SEvalZero 
3619*042d53a7SEvalZero     if ((phy_mask & BLE_GAP_LE_PHY_2M_MASK) && phy_2m_conn_params == NULL) {
3620*042d53a7SEvalZero         phy_2m_conn_params = &ble_gap_conn_params_dflt;
3621*042d53a7SEvalZero     }
3622*042d53a7SEvalZero 
3623*042d53a7SEvalZero     if ((phy_mask & BLE_GAP_LE_PHY_CODED_MASK) &&
3624*042d53a7SEvalZero         phy_coded_conn_params == NULL) {
3625*042d53a7SEvalZero 
3626*042d53a7SEvalZero         phy_coded_conn_params = &ble_gap_conn_params_dflt;
3627*042d53a7SEvalZero     }
3628*042d53a7SEvalZero 
3629*042d53a7SEvalZero     if (duration_ms == 0) {
3630*042d53a7SEvalZero         duration_ms = BLE_GAP_CONN_DUR_DFLT;
3631*042d53a7SEvalZero     }
3632*042d53a7SEvalZero 
3633*042d53a7SEvalZero     if (duration_ms != BLE_HS_FOREVER) {
3634*042d53a7SEvalZero         rc = ble_npl_time_ms_to_ticks(duration_ms, &duration_ticks);
3635*042d53a7SEvalZero         if (rc != 0) {
3636*042d53a7SEvalZero             /* Duration too great. */
3637*042d53a7SEvalZero             rc = BLE_HS_EINVAL;
3638*042d53a7SEvalZero             goto done;
3639*042d53a7SEvalZero         }
3640*042d53a7SEvalZero     }
3641*042d53a7SEvalZero 
3642*042d53a7SEvalZero     /* Verify peer not already connected. */
3643*042d53a7SEvalZero     if (ble_hs_conn_find_by_addr(peer_addr) != NULL) {
3644*042d53a7SEvalZero         rc = BLE_HS_EDONE;
3645*042d53a7SEvalZero         goto done;
3646*042d53a7SEvalZero     }
3647*042d53a7SEvalZero 
3648*042d53a7SEvalZero     /* XXX: Verify conn_params. */
3649*042d53a7SEvalZero 
3650*042d53a7SEvalZero     rc = ble_hs_id_use_addr(own_addr_type);
3651*042d53a7SEvalZero     if (rc != 0) {
3652*042d53a7SEvalZero         goto done;
3653*042d53a7SEvalZero     }
3654*042d53a7SEvalZero 
3655*042d53a7SEvalZero     ble_gap_master.cb = cb;
3656*042d53a7SEvalZero     ble_gap_master.cb_arg = cb_arg;
3657*042d53a7SEvalZero     ble_gap_master.conn.using_wl = peer_addr == NULL;
3658*042d53a7SEvalZero     ble_gap_master.conn.our_addr_type = own_addr_type;
3659*042d53a7SEvalZero 
3660*042d53a7SEvalZero     ble_gap_master.op = BLE_GAP_OP_M_CONN;
3661*042d53a7SEvalZero 
3662*042d53a7SEvalZero     rc = ble_gap_ext_conn_create_tx(own_addr_type, peer_addr, phy_mask,
3663*042d53a7SEvalZero                                     phy_1m_conn_params, phy_2m_conn_params,
3664*042d53a7SEvalZero                                     phy_coded_conn_params);
3665*042d53a7SEvalZero     if (rc != 0) {
3666*042d53a7SEvalZero         ble_gap_master_reset_state();
3667*042d53a7SEvalZero         goto done;
3668*042d53a7SEvalZero     }
3669*042d53a7SEvalZero 
3670*042d53a7SEvalZero     if (duration_ms != BLE_HS_FOREVER) {
3671*042d53a7SEvalZero         ble_gap_master_set_timer(duration_ticks);
3672*042d53a7SEvalZero     }
3673*042d53a7SEvalZero 
3674*042d53a7SEvalZero     rc = 0;
3675*042d53a7SEvalZero 
3676*042d53a7SEvalZero done:
3677*042d53a7SEvalZero     ble_hs_unlock();
3678*042d53a7SEvalZero 
3679*042d53a7SEvalZero     if (rc != 0) {
3680*042d53a7SEvalZero         STATS_INC(ble_gap_stats, initiate_fail);
3681*042d53a7SEvalZero     }
3682*042d53a7SEvalZero     return rc;
3683*042d53a7SEvalZero }
3684*042d53a7SEvalZero #endif
3685*042d53a7SEvalZero 
3686*042d53a7SEvalZero int
ble_gap_connect(uint8_t own_addr_type,const ble_addr_t * peer_addr,int32_t duration_ms,const struct ble_gap_conn_params * conn_params,ble_gap_event_fn * cb,void * cb_arg)3687*042d53a7SEvalZero ble_gap_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr,
3688*042d53a7SEvalZero                 int32_t duration_ms,
3689*042d53a7SEvalZero                 const struct ble_gap_conn_params *conn_params,
3690*042d53a7SEvalZero                 ble_gap_event_fn *cb, void *cb_arg)
3691*042d53a7SEvalZero {
3692*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_ROLE_CENTRAL)
3693*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
3694*042d53a7SEvalZero #endif
3695*042d53a7SEvalZero 
3696*042d53a7SEvalZero #if MYNEWT_VAL(BLE_EXT_ADV)
3697*042d53a7SEvalZero     return ble_gap_ext_connect(own_addr_type, peer_addr, duration_ms,
3698*042d53a7SEvalZero                                BLE_GAP_LE_PHY_1M_MASK,
3699*042d53a7SEvalZero                                conn_params, NULL, NULL, cb, cb_arg);
3700*042d53a7SEvalZero #else
3701*042d53a7SEvalZero     uint32_t duration_ticks;
3702*042d53a7SEvalZero     int rc;
3703*042d53a7SEvalZero 
3704*042d53a7SEvalZero     STATS_INC(ble_gap_stats, initiate);
3705*042d53a7SEvalZero 
3706*042d53a7SEvalZero     ble_hs_lock();
3707*042d53a7SEvalZero 
3708*042d53a7SEvalZero     if (ble_gap_conn_active()) {
3709*042d53a7SEvalZero         rc = BLE_HS_EALREADY;
3710*042d53a7SEvalZero         goto done;
3711*042d53a7SEvalZero     }
3712*042d53a7SEvalZero 
3713*042d53a7SEvalZero     if (ble_gap_disc_active()) {
3714*042d53a7SEvalZero         rc = BLE_HS_EBUSY;
3715*042d53a7SEvalZero         goto done;
3716*042d53a7SEvalZero     }
3717*042d53a7SEvalZero 
3718*042d53a7SEvalZero     if (!ble_hs_is_enabled()) {
3719*042d53a7SEvalZero         rc = BLE_HS_EDISABLED;
3720*042d53a7SEvalZero         goto done;
3721*042d53a7SEvalZero     }
3722*042d53a7SEvalZero 
3723*042d53a7SEvalZero     if (ble_gap_is_preempted()) {
3724*042d53a7SEvalZero         rc = BLE_HS_EPREEMPTED;
3725*042d53a7SEvalZero         goto done;
3726*042d53a7SEvalZero     }
3727*042d53a7SEvalZero 
3728*042d53a7SEvalZero     if (!ble_hs_conn_can_alloc()) {
3729*042d53a7SEvalZero         rc = BLE_HS_ENOMEM;
3730*042d53a7SEvalZero         goto done;
3731*042d53a7SEvalZero     }
3732*042d53a7SEvalZero 
3733*042d53a7SEvalZero     if (peer_addr &&
3734*042d53a7SEvalZero         peer_addr->type != BLE_ADDR_PUBLIC &&
3735*042d53a7SEvalZero         peer_addr->type != BLE_ADDR_RANDOM &&
3736*042d53a7SEvalZero         peer_addr->type != BLE_ADDR_PUBLIC_ID &&
3737*042d53a7SEvalZero         peer_addr->type != BLE_ADDR_RANDOM_ID) {
3738*042d53a7SEvalZero 
3739*042d53a7SEvalZero         rc = BLE_HS_EINVAL;
3740*042d53a7SEvalZero         goto done;
3741*042d53a7SEvalZero     }
3742*042d53a7SEvalZero 
3743*042d53a7SEvalZero     if (conn_params == NULL) {
3744*042d53a7SEvalZero         conn_params = &ble_gap_conn_params_dflt;
3745*042d53a7SEvalZero     }
3746*042d53a7SEvalZero 
3747*042d53a7SEvalZero     if (duration_ms == 0) {
3748*042d53a7SEvalZero         duration_ms = BLE_GAP_CONN_DUR_DFLT;
3749*042d53a7SEvalZero     }
3750*042d53a7SEvalZero 
3751*042d53a7SEvalZero     if (duration_ms != BLE_HS_FOREVER) {
3752*042d53a7SEvalZero         rc = ble_npl_time_ms_to_ticks(duration_ms, &duration_ticks);
3753*042d53a7SEvalZero         if (rc != 0) {
3754*042d53a7SEvalZero             /* Duration too great. */
3755*042d53a7SEvalZero             rc = BLE_HS_EINVAL;
3756*042d53a7SEvalZero             goto done;
3757*042d53a7SEvalZero         }
3758*042d53a7SEvalZero     }
3759*042d53a7SEvalZero 
3760*042d53a7SEvalZero     /* Verify peer not already connected. */
3761*042d53a7SEvalZero     if (ble_hs_conn_find_by_addr(peer_addr) != NULL) {
3762*042d53a7SEvalZero         rc = BLE_HS_EDONE;
3763*042d53a7SEvalZero         goto done;
3764*042d53a7SEvalZero     }
3765*042d53a7SEvalZero 
3766*042d53a7SEvalZero     /* XXX: Verify conn_params. */
3767*042d53a7SEvalZero 
3768*042d53a7SEvalZero     rc = ble_hs_id_use_addr(own_addr_type);
3769*042d53a7SEvalZero     if (rc != 0) {
3770*042d53a7SEvalZero         goto done;
3771*042d53a7SEvalZero     }
3772*042d53a7SEvalZero 
3773*042d53a7SEvalZero     BLE_HS_LOG(INFO, "GAP procedure initiated: connect; ");
3774*042d53a7SEvalZero     ble_gap_log_conn(own_addr_type, peer_addr, conn_params);
3775*042d53a7SEvalZero     BLE_HS_LOG(INFO, "\n");
3776*042d53a7SEvalZero 
3777*042d53a7SEvalZero     ble_gap_master.cb = cb;
3778*042d53a7SEvalZero     ble_gap_master.cb_arg = cb_arg;
3779*042d53a7SEvalZero     ble_gap_master.conn.using_wl = peer_addr == NULL;
3780*042d53a7SEvalZero     ble_gap_master.conn.our_addr_type = own_addr_type;
3781*042d53a7SEvalZero 
3782*042d53a7SEvalZero     ble_gap_master.op = BLE_GAP_OP_M_CONN;
3783*042d53a7SEvalZero 
3784*042d53a7SEvalZero     rc = ble_gap_conn_create_tx(own_addr_type, peer_addr,
3785*042d53a7SEvalZero                                 conn_params);
3786*042d53a7SEvalZero     if (rc != 0) {
3787*042d53a7SEvalZero         ble_gap_master_reset_state();
3788*042d53a7SEvalZero         goto done;
3789*042d53a7SEvalZero     }
3790*042d53a7SEvalZero 
3791*042d53a7SEvalZero     if (duration_ms != BLE_HS_FOREVER) {
3792*042d53a7SEvalZero         ble_gap_master_set_timer(duration_ticks);
3793*042d53a7SEvalZero     }
3794*042d53a7SEvalZero 
3795*042d53a7SEvalZero     rc = 0;
3796*042d53a7SEvalZero 
3797*042d53a7SEvalZero done:
3798*042d53a7SEvalZero     ble_hs_unlock();
3799*042d53a7SEvalZero 
3800*042d53a7SEvalZero     if (rc != 0) {
3801*042d53a7SEvalZero         STATS_INC(ble_gap_stats, initiate_fail);
3802*042d53a7SEvalZero     }
3803*042d53a7SEvalZero     return rc;
3804*042d53a7SEvalZero #endif
3805*042d53a7SEvalZero }
3806*042d53a7SEvalZero 
3807*042d53a7SEvalZero int
ble_gap_conn_active(void)3808*042d53a7SEvalZero ble_gap_conn_active(void)
3809*042d53a7SEvalZero {
3810*042d53a7SEvalZero     /* Assume read is atomic; mutex not necessary. */
3811*042d53a7SEvalZero     return ble_gap_master.op == BLE_GAP_OP_M_CONN;
3812*042d53a7SEvalZero }
3813*042d53a7SEvalZero 
3814*042d53a7SEvalZero /*****************************************************************************
3815*042d53a7SEvalZero  * $terminate connection procedure                                           *
3816*042d53a7SEvalZero  *****************************************************************************/
3817*042d53a7SEvalZero 
3818*042d53a7SEvalZero int
ble_gap_terminate(uint16_t conn_handle,uint8_t hci_reason)3819*042d53a7SEvalZero ble_gap_terminate(uint16_t conn_handle, uint8_t hci_reason)
3820*042d53a7SEvalZero {
3821*042d53a7SEvalZero     uint8_t buf[BLE_HCI_DISCONNECT_CMD_LEN];
3822*042d53a7SEvalZero     struct ble_hs_conn *conn;
3823*042d53a7SEvalZero     int rc;
3824*042d53a7SEvalZero 
3825*042d53a7SEvalZero     STATS_INC(ble_gap_stats, terminate);
3826*042d53a7SEvalZero 
3827*042d53a7SEvalZero     ble_hs_lock();
3828*042d53a7SEvalZero 
3829*042d53a7SEvalZero     conn = ble_hs_conn_find(conn_handle);
3830*042d53a7SEvalZero     if (conn == NULL) {
3831*042d53a7SEvalZero         rc = BLE_HS_ENOTCONN;
3832*042d53a7SEvalZero         goto done;
3833*042d53a7SEvalZero     }
3834*042d53a7SEvalZero 
3835*042d53a7SEvalZero     if (conn->bhc_flags & BLE_HS_CONN_F_TERMINATING) {
3836*042d53a7SEvalZero         rc = BLE_HS_EALREADY;
3837*042d53a7SEvalZero         goto done;
3838*042d53a7SEvalZero     }
3839*042d53a7SEvalZero 
3840*042d53a7SEvalZero     BLE_HS_LOG(INFO, "GAP procedure initiated: terminate connection; "
3841*042d53a7SEvalZero                      "conn_handle=%d hci_reason=%d\n",
3842*042d53a7SEvalZero                conn_handle, hci_reason);
3843*042d53a7SEvalZero 
3844*042d53a7SEvalZero     ble_hs_hci_cmd_build_disconnect(conn_handle, hci_reason,
3845*042d53a7SEvalZero                                     buf, sizeof buf);
3846*042d53a7SEvalZero     rc = ble_hs_hci_cmd_tx_empty_ack(BLE_HCI_OP(BLE_HCI_OGF_LINK_CTRL,
3847*042d53a7SEvalZero                                                 BLE_HCI_OCF_DISCONNECT_CMD),
3848*042d53a7SEvalZero                                      buf, sizeof(buf));
3849*042d53a7SEvalZero     if (rc != 0) {
3850*042d53a7SEvalZero         goto done;
3851*042d53a7SEvalZero     }
3852*042d53a7SEvalZero 
3853*042d53a7SEvalZero     conn->bhc_flags |= BLE_HS_CONN_F_TERMINATING;
3854*042d53a7SEvalZero     rc = 0;
3855*042d53a7SEvalZero 
3856*042d53a7SEvalZero done:
3857*042d53a7SEvalZero     ble_hs_unlock();
3858*042d53a7SEvalZero 
3859*042d53a7SEvalZero     if (rc != 0) {
3860*042d53a7SEvalZero         STATS_INC(ble_gap_stats, terminate_fail);
3861*042d53a7SEvalZero     }
3862*042d53a7SEvalZero     return rc;
3863*042d53a7SEvalZero }
3864*042d53a7SEvalZero 
3865*042d53a7SEvalZero /*****************************************************************************
3866*042d53a7SEvalZero  * $cancel                                                                   *
3867*042d53a7SEvalZero  *****************************************************************************/
3868*042d53a7SEvalZero 
3869*042d53a7SEvalZero static int
ble_gap_conn_cancel_tx(void)3870*042d53a7SEvalZero ble_gap_conn_cancel_tx(void)
3871*042d53a7SEvalZero {
3872*042d53a7SEvalZero     int rc;
3873*042d53a7SEvalZero 
3874*042d53a7SEvalZero     rc = ble_hs_hci_cmd_tx_empty_ack(BLE_HCI_OP(BLE_HCI_OGF_LE,
3875*042d53a7SEvalZero                                             BLE_HCI_OCF_LE_CREATE_CONN_CANCEL),
3876*042d53a7SEvalZero                                      NULL, 0);
3877*042d53a7SEvalZero     if (rc != 0) {
3878*042d53a7SEvalZero         return rc;
3879*042d53a7SEvalZero     }
3880*042d53a7SEvalZero 
3881*042d53a7SEvalZero     return 0;
3882*042d53a7SEvalZero }
3883*042d53a7SEvalZero 
3884*042d53a7SEvalZero static int
ble_gap_conn_cancel_no_lock(void)3885*042d53a7SEvalZero ble_gap_conn_cancel_no_lock(void)
3886*042d53a7SEvalZero {
3887*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_ROLE_CENTRAL)
3888*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
3889*042d53a7SEvalZero #endif
3890*042d53a7SEvalZero 
3891*042d53a7SEvalZero     int rc;
3892*042d53a7SEvalZero 
3893*042d53a7SEvalZero     STATS_INC(ble_gap_stats, cancel);
3894*042d53a7SEvalZero 
3895*042d53a7SEvalZero     if (!ble_gap_conn_active()) {
3896*042d53a7SEvalZero         rc = BLE_HS_EALREADY;
3897*042d53a7SEvalZero         goto done;
3898*042d53a7SEvalZero     }
3899*042d53a7SEvalZero 
3900*042d53a7SEvalZero     BLE_HS_LOG(INFO, "GAP procedure initiated: cancel connection\n");
3901*042d53a7SEvalZero 
3902*042d53a7SEvalZero     rc = ble_gap_conn_cancel_tx();
3903*042d53a7SEvalZero     if (rc != 0) {
3904*042d53a7SEvalZero         goto done;
3905*042d53a7SEvalZero     }
3906*042d53a7SEvalZero 
3907*042d53a7SEvalZero     ble_gap_master.conn.cancel = 1;
3908*042d53a7SEvalZero     rc = 0;
3909*042d53a7SEvalZero 
3910*042d53a7SEvalZero done:
3911*042d53a7SEvalZero     if (rc != 0) {
3912*042d53a7SEvalZero         STATS_INC(ble_gap_stats, cancel_fail);
3913*042d53a7SEvalZero     }
3914*042d53a7SEvalZero 
3915*042d53a7SEvalZero     return rc;
3916*042d53a7SEvalZero }
3917*042d53a7SEvalZero 
3918*042d53a7SEvalZero int
ble_gap_conn_cancel(void)3919*042d53a7SEvalZero ble_gap_conn_cancel(void)
3920*042d53a7SEvalZero {
3921*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_ROLE_CENTRAL)
3922*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
3923*042d53a7SEvalZero #endif
3924*042d53a7SEvalZero 
3925*042d53a7SEvalZero     int rc;
3926*042d53a7SEvalZero 
3927*042d53a7SEvalZero     ble_hs_lock();
3928*042d53a7SEvalZero     rc = ble_gap_conn_cancel_no_lock();
3929*042d53a7SEvalZero     ble_hs_unlock();
3930*042d53a7SEvalZero 
3931*042d53a7SEvalZero     return rc;
3932*042d53a7SEvalZero }
3933*042d53a7SEvalZero 
3934*042d53a7SEvalZero /*****************************************************************************
3935*042d53a7SEvalZero  * $update connection parameters                                             *
3936*042d53a7SEvalZero  *****************************************************************************/
3937*042d53a7SEvalZero 
3938*042d53a7SEvalZero static struct ble_gap_update_entry *
ble_gap_update_entry_alloc(void)3939*042d53a7SEvalZero ble_gap_update_entry_alloc(void)
3940*042d53a7SEvalZero {
3941*042d53a7SEvalZero     struct ble_gap_update_entry *entry;
3942*042d53a7SEvalZero 
3943*042d53a7SEvalZero     entry = os_memblock_get(&ble_gap_update_entry_pool);
3944*042d53a7SEvalZero     if (entry != NULL) {
3945*042d53a7SEvalZero         memset(entry, 0, sizeof *entry);
3946*042d53a7SEvalZero     }
3947*042d53a7SEvalZero 
3948*042d53a7SEvalZero     return entry;
3949*042d53a7SEvalZero }
3950*042d53a7SEvalZero 
3951*042d53a7SEvalZero static void
ble_gap_update_entry_free(struct ble_gap_update_entry * entry)3952*042d53a7SEvalZero ble_gap_update_entry_free(struct ble_gap_update_entry *entry)
3953*042d53a7SEvalZero {
3954*042d53a7SEvalZero     int rc;
3955*042d53a7SEvalZero 
3956*042d53a7SEvalZero     if (entry != NULL) {
3957*042d53a7SEvalZero #if MYNEWT_VAL(BLE_HS_DEBUG)
3958*042d53a7SEvalZero         memset(entry, 0xff, sizeof *entry);
3959*042d53a7SEvalZero #endif
3960*042d53a7SEvalZero         rc = os_memblock_put(&ble_gap_update_entry_pool, entry);
3961*042d53a7SEvalZero         BLE_HS_DBG_ASSERT_EVAL(rc == 0);
3962*042d53a7SEvalZero     }
3963*042d53a7SEvalZero }
3964*042d53a7SEvalZero 
3965*042d53a7SEvalZero static struct ble_gap_update_entry *
ble_gap_update_entry_find(uint16_t conn_handle,struct ble_gap_update_entry ** out_prev)3966*042d53a7SEvalZero ble_gap_update_entry_find(uint16_t conn_handle,
3967*042d53a7SEvalZero                           struct ble_gap_update_entry **out_prev)
3968*042d53a7SEvalZero {
3969*042d53a7SEvalZero     struct ble_gap_update_entry *entry;
3970*042d53a7SEvalZero     struct ble_gap_update_entry *prev;
3971*042d53a7SEvalZero 
3972*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task());
3973*042d53a7SEvalZero 
3974*042d53a7SEvalZero     prev = NULL;
3975*042d53a7SEvalZero     SLIST_FOREACH(entry, &ble_gap_update_entries, next) {
3976*042d53a7SEvalZero         if (entry->conn_handle == conn_handle) {
3977*042d53a7SEvalZero             break;
3978*042d53a7SEvalZero         }
3979*042d53a7SEvalZero 
3980*042d53a7SEvalZero         prev = entry;
3981*042d53a7SEvalZero     }
3982*042d53a7SEvalZero 
3983*042d53a7SEvalZero     if (out_prev != NULL) {
3984*042d53a7SEvalZero         *out_prev = prev;
3985*042d53a7SEvalZero     }
3986*042d53a7SEvalZero 
3987*042d53a7SEvalZero     return entry;
3988*042d53a7SEvalZero }
3989*042d53a7SEvalZero 
3990*042d53a7SEvalZero static struct ble_gap_update_entry *
ble_gap_update_entry_remove(uint16_t conn_handle)3991*042d53a7SEvalZero ble_gap_update_entry_remove(uint16_t conn_handle)
3992*042d53a7SEvalZero {
3993*042d53a7SEvalZero     struct ble_gap_update_entry *entry;
3994*042d53a7SEvalZero     struct ble_gap_update_entry *prev;
3995*042d53a7SEvalZero 
3996*042d53a7SEvalZero     entry = ble_gap_update_entry_find(conn_handle, &prev);
3997*042d53a7SEvalZero     if (entry != NULL) {
3998*042d53a7SEvalZero         if (prev == NULL) {
3999*042d53a7SEvalZero             SLIST_REMOVE_HEAD(&ble_gap_update_entries, next);
4000*042d53a7SEvalZero         } else {
4001*042d53a7SEvalZero             SLIST_NEXT(prev, next) = SLIST_NEXT(entry, next);
4002*042d53a7SEvalZero         }
4003*042d53a7SEvalZero         ble_hs_timer_resched();
4004*042d53a7SEvalZero     }
4005*042d53a7SEvalZero 
4006*042d53a7SEvalZero     return entry;
4007*042d53a7SEvalZero }
4008*042d53a7SEvalZero 
4009*042d53a7SEvalZero static void
ble_gap_update_l2cap_cb(uint16_t conn_handle,int status,void * arg)4010*042d53a7SEvalZero ble_gap_update_l2cap_cb(uint16_t conn_handle, int status, void *arg)
4011*042d53a7SEvalZero {
4012*042d53a7SEvalZero     struct ble_gap_update_entry *entry;
4013*042d53a7SEvalZero 
4014*042d53a7SEvalZero     /* Report failures and rejections.  Success gets reported when the
4015*042d53a7SEvalZero      * controller sends the connection update complete event.
4016*042d53a7SEvalZero      */
4017*042d53a7SEvalZero     if (status != 0) {
4018*042d53a7SEvalZero         ble_hs_lock();
4019*042d53a7SEvalZero         entry = ble_gap_update_entry_remove(conn_handle);
4020*042d53a7SEvalZero         ble_hs_unlock();
4021*042d53a7SEvalZero 
4022*042d53a7SEvalZero         if (entry != NULL) {
4023*042d53a7SEvalZero             ble_gap_update_entry_free(entry);
4024*042d53a7SEvalZero             ble_gap_update_notify(conn_handle, status);
4025*042d53a7SEvalZero         }
4026*042d53a7SEvalZero     }
4027*042d53a7SEvalZero }
4028*042d53a7SEvalZero 
4029*042d53a7SEvalZero static int
ble_gap_tx_param_pos_reply(uint16_t conn_handle,struct ble_gap_upd_params * params)4030*042d53a7SEvalZero ble_gap_tx_param_pos_reply(uint16_t conn_handle,
4031*042d53a7SEvalZero                            struct ble_gap_upd_params *params)
4032*042d53a7SEvalZero {
4033*042d53a7SEvalZero     uint8_t buf[BLE_HCI_CONN_PARAM_REPLY_LEN];
4034*042d53a7SEvalZero     struct hci_conn_param_reply pos_reply;
4035*042d53a7SEvalZero     int rc;
4036*042d53a7SEvalZero 
4037*042d53a7SEvalZero     pos_reply.handle = conn_handle;
4038*042d53a7SEvalZero     pos_reply.conn_itvl_min = params->itvl_min;
4039*042d53a7SEvalZero     pos_reply.conn_itvl_max = params->itvl_max;
4040*042d53a7SEvalZero     pos_reply.conn_latency = params->latency;
4041*042d53a7SEvalZero     pos_reply.supervision_timeout = params->supervision_timeout;
4042*042d53a7SEvalZero     pos_reply.min_ce_len = params->min_ce_len;
4043*042d53a7SEvalZero     pos_reply.max_ce_len = params->max_ce_len;
4044*042d53a7SEvalZero 
4045*042d53a7SEvalZero     ble_hs_hci_cmd_build_le_conn_param_reply(&pos_reply, buf, sizeof buf);
4046*042d53a7SEvalZero     rc = ble_hs_hci_cmd_tx_empty_ack(
4047*042d53a7SEvalZero         BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_REM_CONN_PARAM_RR),
4048*042d53a7SEvalZero         buf, sizeof(buf));
4049*042d53a7SEvalZero     if (rc != 0) {
4050*042d53a7SEvalZero         return rc;
4051*042d53a7SEvalZero     }
4052*042d53a7SEvalZero 
4053*042d53a7SEvalZero     return 0;
4054*042d53a7SEvalZero }
4055*042d53a7SEvalZero 
4056*042d53a7SEvalZero static int
ble_gap_tx_param_neg_reply(uint16_t conn_handle,uint8_t reject_reason)4057*042d53a7SEvalZero ble_gap_tx_param_neg_reply(uint16_t conn_handle, uint8_t reject_reason)
4058*042d53a7SEvalZero {
4059*042d53a7SEvalZero     uint8_t buf[BLE_HCI_CONN_PARAM_NEG_REPLY_LEN];
4060*042d53a7SEvalZero     struct hci_conn_param_neg_reply neg_reply;
4061*042d53a7SEvalZero     int rc;
4062*042d53a7SEvalZero 
4063*042d53a7SEvalZero     neg_reply.handle = conn_handle;
4064*042d53a7SEvalZero     neg_reply.reason = reject_reason;
4065*042d53a7SEvalZero 
4066*042d53a7SEvalZero     ble_hs_hci_cmd_build_le_conn_param_neg_reply(&neg_reply, buf, sizeof buf);
4067*042d53a7SEvalZero     rc = ble_hs_hci_cmd_tx_empty_ack(BLE_HCI_OP(BLE_HCI_OGF_LE,
4068*042d53a7SEvalZero                                          BLE_HCI_OCF_LE_REM_CONN_PARAM_NRR),
4069*042d53a7SEvalZero                                      buf, sizeof(buf));
4070*042d53a7SEvalZero     if (rc != 0) {
4071*042d53a7SEvalZero         return rc;
4072*042d53a7SEvalZero     }
4073*042d53a7SEvalZero 
4074*042d53a7SEvalZero     return 0;
4075*042d53a7SEvalZero }
4076*042d53a7SEvalZero 
4077*042d53a7SEvalZero void
ble_gap_rx_param_req(struct hci_le_conn_param_req * evt)4078*042d53a7SEvalZero ble_gap_rx_param_req(struct hci_le_conn_param_req *evt)
4079*042d53a7SEvalZero {
4080*042d53a7SEvalZero #if !NIMBLE_BLE_CONNECT
4081*042d53a7SEvalZero     return;
4082*042d53a7SEvalZero #endif
4083*042d53a7SEvalZero 
4084*042d53a7SEvalZero     struct ble_gap_upd_params peer_params;
4085*042d53a7SEvalZero     struct ble_gap_upd_params self_params;
4086*042d53a7SEvalZero     struct ble_gap_event event;
4087*042d53a7SEvalZero     uint8_t reject_reason;
4088*042d53a7SEvalZero     int rc;
4089*042d53a7SEvalZero 
4090*042d53a7SEvalZero     reject_reason = 0; /* Silence warning. */
4091*042d53a7SEvalZero 
4092*042d53a7SEvalZero     memset(&event, 0, sizeof event);
4093*042d53a7SEvalZero 
4094*042d53a7SEvalZero     peer_params.itvl_min = evt->itvl_min;
4095*042d53a7SEvalZero     peer_params.itvl_max = evt->itvl_max;
4096*042d53a7SEvalZero     peer_params.latency = evt->latency;
4097*042d53a7SEvalZero     peer_params.supervision_timeout = evt->timeout;
4098*042d53a7SEvalZero     peer_params.min_ce_len = 0;
4099*042d53a7SEvalZero     peer_params.max_ce_len = 0;
4100*042d53a7SEvalZero 
4101*042d53a7SEvalZero     /* Copy the peer params into the self params to make it easy on the
4102*042d53a7SEvalZero      * application.  The application callback will change only the fields which
4103*042d53a7SEvalZero      * it finds unsuitable.
4104*042d53a7SEvalZero      */
4105*042d53a7SEvalZero     self_params = peer_params;
4106*042d53a7SEvalZero 
4107*042d53a7SEvalZero     memset(&event, 0, sizeof event);
4108*042d53a7SEvalZero     event.type = BLE_GAP_EVENT_CONN_UPDATE_REQ;
4109*042d53a7SEvalZero     event.conn_update_req.conn_handle = evt->connection_handle;
4110*042d53a7SEvalZero     event.conn_update_req.self_params = &self_params;
4111*042d53a7SEvalZero     event.conn_update_req.peer_params = &peer_params;
4112*042d53a7SEvalZero     rc = ble_gap_call_conn_event_cb(&event, evt->connection_handle);
4113*042d53a7SEvalZero     if (rc != 0) {
4114*042d53a7SEvalZero         reject_reason = rc;
4115*042d53a7SEvalZero     }
4116*042d53a7SEvalZero 
4117*042d53a7SEvalZero     if (rc == 0) {
4118*042d53a7SEvalZero         rc = ble_gap_tx_param_pos_reply(evt->connection_handle, &self_params);
4119*042d53a7SEvalZero         if (rc != 0) {
4120*042d53a7SEvalZero             ble_gap_update_failed(evt->connection_handle, rc);
4121*042d53a7SEvalZero         }
4122*042d53a7SEvalZero     } else {
4123*042d53a7SEvalZero         ble_gap_tx_param_neg_reply(evt->connection_handle, reject_reason);
4124*042d53a7SEvalZero     }
4125*042d53a7SEvalZero }
4126*042d53a7SEvalZero 
4127*042d53a7SEvalZero static int
ble_gap_update_tx(uint16_t conn_handle,const struct ble_gap_upd_params * params)4128*042d53a7SEvalZero ble_gap_update_tx(uint16_t conn_handle,
4129*042d53a7SEvalZero                   const struct ble_gap_upd_params *params)
4130*042d53a7SEvalZero {
4131*042d53a7SEvalZero     uint8_t buf[BLE_HCI_CONN_UPDATE_LEN];
4132*042d53a7SEvalZero     struct hci_conn_update cmd;
4133*042d53a7SEvalZero     int rc;
4134*042d53a7SEvalZero 
4135*042d53a7SEvalZero     cmd.handle = conn_handle;
4136*042d53a7SEvalZero     cmd.conn_itvl_min = params->itvl_min;
4137*042d53a7SEvalZero     cmd.conn_itvl_max = params->itvl_max;
4138*042d53a7SEvalZero     cmd.conn_latency = params->latency;
4139*042d53a7SEvalZero     cmd.supervision_timeout = params->supervision_timeout;
4140*042d53a7SEvalZero     cmd.min_ce_len = params->min_ce_len;
4141*042d53a7SEvalZero     cmd.max_ce_len = params->max_ce_len;
4142*042d53a7SEvalZero 
4143*042d53a7SEvalZero     rc = ble_hs_hci_cmd_build_le_conn_update(&cmd, buf, sizeof buf);
4144*042d53a7SEvalZero     if (rc != 0) {
4145*042d53a7SEvalZero         return rc;
4146*042d53a7SEvalZero     }
4147*042d53a7SEvalZero 
4148*042d53a7SEvalZero     rc = ble_hs_hci_cmd_tx_empty_ack(BLE_HCI_OP(BLE_HCI_OGF_LE,
4149*042d53a7SEvalZero                                                 BLE_HCI_OCF_LE_CONN_UPDATE),
4150*042d53a7SEvalZero                                      buf, sizeof(buf));
4151*042d53a7SEvalZero     if (rc != 0) {
4152*042d53a7SEvalZero         return rc;
4153*042d53a7SEvalZero     }
4154*042d53a7SEvalZero 
4155*042d53a7SEvalZero     return 0;
4156*042d53a7SEvalZero }
4157*042d53a7SEvalZero 
4158*042d53a7SEvalZero static bool
ble_gap_validate_conn_params(const struct ble_gap_upd_params * params)4159*042d53a7SEvalZero ble_gap_validate_conn_params(const struct ble_gap_upd_params *params)
4160*042d53a7SEvalZero {
4161*042d53a7SEvalZero 
4162*042d53a7SEvalZero     /* Requirements from Bluetooth spec. v4.2 [Vol 2, Part E], 7.8.18 */
4163*042d53a7SEvalZero     if (params->itvl_min > params->itvl_max) {
4164*042d53a7SEvalZero         return false;
4165*042d53a7SEvalZero     }
4166*042d53a7SEvalZero 
4167*042d53a7SEvalZero     if (params->itvl_min < 0x0006 || params->itvl_max > 0x0C80) {
4168*042d53a7SEvalZero         return false;
4169*042d53a7SEvalZero     }
4170*042d53a7SEvalZero 
4171*042d53a7SEvalZero     if (params->latency > 0x01F3) {
4172*042d53a7SEvalZero         return false;
4173*042d53a7SEvalZero     }
4174*042d53a7SEvalZero 
4175*042d53a7SEvalZero     /* According to specification mentioned above we should make sure that:
4176*042d53a7SEvalZero      * supervision_timeout_ms > (1 + latency) * 2 * max_interval_ms
4177*042d53a7SEvalZero      *    =>
4178*042d53a7SEvalZero      * supervision_timeout * 10 ms > (1 + latency) * 2 * itvl_max * 1.25ms
4179*042d53a7SEvalZero      */
4180*042d53a7SEvalZero     if (params->supervision_timeout <=
4181*042d53a7SEvalZero                    (((1 + params->latency) * params->itvl_max) / 4)) {
4182*042d53a7SEvalZero         return false;
4183*042d53a7SEvalZero     }
4184*042d53a7SEvalZero 
4185*042d53a7SEvalZero     return true;
4186*042d53a7SEvalZero }
4187*042d53a7SEvalZero 
4188*042d53a7SEvalZero int
ble_gap_update_params(uint16_t conn_handle,const struct ble_gap_upd_params * params)4189*042d53a7SEvalZero ble_gap_update_params(uint16_t conn_handle,
4190*042d53a7SEvalZero                       const struct ble_gap_upd_params *params)
4191*042d53a7SEvalZero {
4192*042d53a7SEvalZero #if !NIMBLE_BLE_CONNECT
4193*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
4194*042d53a7SEvalZero #endif
4195*042d53a7SEvalZero 
4196*042d53a7SEvalZero     struct ble_l2cap_sig_update_params l2cap_params;
4197*042d53a7SEvalZero     struct ble_gap_update_entry *entry;
4198*042d53a7SEvalZero     struct ble_gap_update_entry *dup;
4199*042d53a7SEvalZero     struct ble_hs_conn *conn;
4200*042d53a7SEvalZero     int l2cap_update;
4201*042d53a7SEvalZero     int rc;
4202*042d53a7SEvalZero 
4203*042d53a7SEvalZero     l2cap_update = 0;
4204*042d53a7SEvalZero 
4205*042d53a7SEvalZero     /* Validate parameters with a spec */
4206*042d53a7SEvalZero     if (!ble_gap_validate_conn_params(params)) {
4207*042d53a7SEvalZero         return BLE_HS_EINVAL;
4208*042d53a7SEvalZero     }
4209*042d53a7SEvalZero 
4210*042d53a7SEvalZero     STATS_INC(ble_gap_stats, update);
4211*042d53a7SEvalZero     memset(&l2cap_params, 0, sizeof l2cap_params);
4212*042d53a7SEvalZero     entry = NULL;
4213*042d53a7SEvalZero 
4214*042d53a7SEvalZero     ble_hs_lock();
4215*042d53a7SEvalZero 
4216*042d53a7SEvalZero     conn = ble_hs_conn_find(conn_handle);
4217*042d53a7SEvalZero     if (conn == NULL) {
4218*042d53a7SEvalZero         rc = BLE_HS_ENOTCONN;
4219*042d53a7SEvalZero         goto done;
4220*042d53a7SEvalZero     }
4221*042d53a7SEvalZero 
4222*042d53a7SEvalZero     /* Don't allow two concurrent updates to the same connection. */
4223*042d53a7SEvalZero     dup = ble_gap_update_entry_find(conn_handle, NULL);
4224*042d53a7SEvalZero     if (dup != NULL) {
4225*042d53a7SEvalZero         rc = BLE_HS_EALREADY;
4226*042d53a7SEvalZero         goto done;
4227*042d53a7SEvalZero     }
4228*042d53a7SEvalZero 
4229*042d53a7SEvalZero     entry = ble_gap_update_entry_alloc();
4230*042d53a7SEvalZero     if (entry == NULL) {
4231*042d53a7SEvalZero         rc = BLE_HS_ENOMEM;
4232*042d53a7SEvalZero         goto done;
4233*042d53a7SEvalZero     }
4234*042d53a7SEvalZero 
4235*042d53a7SEvalZero     entry->conn_handle = conn_handle;
4236*042d53a7SEvalZero     entry->params = *params;
4237*042d53a7SEvalZero 
4238*042d53a7SEvalZero     entry->exp_os_ticks = ble_npl_time_get() +
4239*042d53a7SEvalZero                           ble_npl_time_ms_to_ticks32(BLE_GAP_UPDATE_TIMEOUT_MS);
4240*042d53a7SEvalZero 
4241*042d53a7SEvalZero     BLE_HS_LOG(INFO, "GAP procedure initiated: ");
4242*042d53a7SEvalZero     ble_gap_log_update(conn_handle, params);
4243*042d53a7SEvalZero     BLE_HS_LOG(INFO, "\n");
4244*042d53a7SEvalZero 
4245*042d53a7SEvalZero     /*
4246*042d53a7SEvalZero      * If LL update procedure is not supported on this connection and we are
4247*042d53a7SEvalZero      * the slave, fail over to the L2CAP update procedure.
4248*042d53a7SEvalZero      */
4249*042d53a7SEvalZero     if ((conn->supported_feat & BLE_HS_HCI_LE_FEAT_CONN_PARAM_REQUEST) == 0 &&
4250*042d53a7SEvalZero             !(conn->bhc_flags & BLE_HS_CONN_F_MASTER)) {
4251*042d53a7SEvalZero         l2cap_update = 1;
4252*042d53a7SEvalZero         rc = 0;
4253*042d53a7SEvalZero     } else {
4254*042d53a7SEvalZero         rc = ble_gap_update_tx(conn_handle, params);
4255*042d53a7SEvalZero     }
4256*042d53a7SEvalZero 
4257*042d53a7SEvalZero done:
4258*042d53a7SEvalZero     ble_hs_unlock();
4259*042d53a7SEvalZero 
4260*042d53a7SEvalZero     if (!l2cap_update) {
4261*042d53a7SEvalZero         ble_hs_timer_resched();
4262*042d53a7SEvalZero     } else {
4263*042d53a7SEvalZero         ble_gap_update_to_l2cap(params, &l2cap_params);
4264*042d53a7SEvalZero 
4265*042d53a7SEvalZero         rc = ble_l2cap_sig_update(conn_handle, &l2cap_params,
4266*042d53a7SEvalZero                                               ble_gap_update_l2cap_cb, NULL);
4267*042d53a7SEvalZero     }
4268*042d53a7SEvalZero 
4269*042d53a7SEvalZero     ble_hs_lock();
4270*042d53a7SEvalZero     if (rc == 0) {
4271*042d53a7SEvalZero         SLIST_INSERT_HEAD(&ble_gap_update_entries, entry, next);
4272*042d53a7SEvalZero     } else {
4273*042d53a7SEvalZero         ble_gap_update_entry_free(entry);
4274*042d53a7SEvalZero         STATS_INC(ble_gap_stats, update_fail);
4275*042d53a7SEvalZero     }
4276*042d53a7SEvalZero     ble_hs_unlock();
4277*042d53a7SEvalZero 
4278*042d53a7SEvalZero     return rc;
4279*042d53a7SEvalZero }
4280*042d53a7SEvalZero 
4281*042d53a7SEvalZero /*****************************************************************************
4282*042d53a7SEvalZero  * $security                                                                 *
4283*042d53a7SEvalZero  *****************************************************************************/
4284*042d53a7SEvalZero int
ble_gap_security_initiate(uint16_t conn_handle)4285*042d53a7SEvalZero ble_gap_security_initiate(uint16_t conn_handle)
4286*042d53a7SEvalZero {
4287*042d53a7SEvalZero #if !NIMBLE_BLE_SM
4288*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
4289*042d53a7SEvalZero #endif
4290*042d53a7SEvalZero 
4291*042d53a7SEvalZero     struct ble_store_value_sec value_sec;
4292*042d53a7SEvalZero     struct ble_store_key_sec key_sec;
4293*042d53a7SEvalZero     struct ble_hs_conn_addrs addrs;
4294*042d53a7SEvalZero     ble_hs_conn_flags_t conn_flags;
4295*042d53a7SEvalZero     struct ble_hs_conn *conn;
4296*042d53a7SEvalZero     int rc;
4297*042d53a7SEvalZero 
4298*042d53a7SEvalZero     STATS_INC(ble_gap_stats, security_initiate);
4299*042d53a7SEvalZero 
4300*042d53a7SEvalZero     ble_hs_lock();
4301*042d53a7SEvalZero     conn = ble_hs_conn_find(conn_handle);
4302*042d53a7SEvalZero     if (conn != NULL) {
4303*042d53a7SEvalZero         conn_flags = conn->bhc_flags;
4304*042d53a7SEvalZero         ble_hs_conn_addrs(conn, &addrs);
4305*042d53a7SEvalZero 
4306*042d53a7SEvalZero         memset(&key_sec, 0, sizeof key_sec);
4307*042d53a7SEvalZero         key_sec.peer_addr = addrs.peer_id_addr;
4308*042d53a7SEvalZero     }
4309*042d53a7SEvalZero     ble_hs_unlock();
4310*042d53a7SEvalZero 
4311*042d53a7SEvalZero     if (conn == NULL) {
4312*042d53a7SEvalZero         rc = BLE_HS_ENOTCONN;
4313*042d53a7SEvalZero         goto done;
4314*042d53a7SEvalZero     }
4315*042d53a7SEvalZero 
4316*042d53a7SEvalZero     if (conn_flags & BLE_HS_CONN_F_MASTER) {
4317*042d53a7SEvalZero         /* Search the security database for an LTK for this peer.  If one
4318*042d53a7SEvalZero          * is found, perform the encryption procedure rather than the pairing
4319*042d53a7SEvalZero          * procedure.
4320*042d53a7SEvalZero          */
4321*042d53a7SEvalZero         rc = ble_store_read_peer_sec(&key_sec, &value_sec);
4322*042d53a7SEvalZero         if (rc == 0 && value_sec.ltk_present) {
4323*042d53a7SEvalZero             rc = ble_sm_enc_initiate(conn_handle, value_sec.ltk,
4324*042d53a7SEvalZero                                      value_sec.ediv, value_sec.rand_num,
4325*042d53a7SEvalZero                                      value_sec.authenticated);
4326*042d53a7SEvalZero             if (rc != 0) {
4327*042d53a7SEvalZero                 goto done;
4328*042d53a7SEvalZero             }
4329*042d53a7SEvalZero         } else {
4330*042d53a7SEvalZero             rc = ble_sm_pair_initiate(conn_handle);
4331*042d53a7SEvalZero             if (rc != 0) {
4332*042d53a7SEvalZero                 goto done;
4333*042d53a7SEvalZero             }
4334*042d53a7SEvalZero         }
4335*042d53a7SEvalZero     } else {
4336*042d53a7SEvalZero         rc = ble_sm_slave_initiate(conn_handle);
4337*042d53a7SEvalZero         if (rc != 0) {
4338*042d53a7SEvalZero             goto done;
4339*042d53a7SEvalZero         }
4340*042d53a7SEvalZero     }
4341*042d53a7SEvalZero 
4342*042d53a7SEvalZero     rc = 0;
4343*042d53a7SEvalZero 
4344*042d53a7SEvalZero done:
4345*042d53a7SEvalZero     if (rc != 0) {
4346*042d53a7SEvalZero         STATS_INC(ble_gap_stats, security_initiate_fail);
4347*042d53a7SEvalZero     }
4348*042d53a7SEvalZero 
4349*042d53a7SEvalZero     return rc;
4350*042d53a7SEvalZero }
4351*042d53a7SEvalZero 
4352*042d53a7SEvalZero int
ble_gap_pair_initiate(uint16_t conn_handle)4353*042d53a7SEvalZero ble_gap_pair_initiate(uint16_t conn_handle)
4354*042d53a7SEvalZero {
4355*042d53a7SEvalZero     int rc;
4356*042d53a7SEvalZero 
4357*042d53a7SEvalZero     rc = ble_sm_pair_initiate(conn_handle);
4358*042d53a7SEvalZero 
4359*042d53a7SEvalZero     return rc;
4360*042d53a7SEvalZero }
4361*042d53a7SEvalZero 
4362*042d53a7SEvalZero int
ble_gap_encryption_initiate(uint16_t conn_handle,const uint8_t * ltk,uint16_t ediv,uint64_t rand_val,int auth)4363*042d53a7SEvalZero ble_gap_encryption_initiate(uint16_t conn_handle,
4364*042d53a7SEvalZero                             const uint8_t *ltk,
4365*042d53a7SEvalZero                             uint16_t ediv,
4366*042d53a7SEvalZero                             uint64_t rand_val,
4367*042d53a7SEvalZero                             int auth)
4368*042d53a7SEvalZero {
4369*042d53a7SEvalZero #if !NIMBLE_BLE_SM
4370*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
4371*042d53a7SEvalZero #endif
4372*042d53a7SEvalZero 
4373*042d53a7SEvalZero     ble_hs_conn_flags_t conn_flags;
4374*042d53a7SEvalZero     int rc;
4375*042d53a7SEvalZero 
4376*042d53a7SEvalZero     rc = ble_hs_atomic_conn_flags(conn_handle, &conn_flags);
4377*042d53a7SEvalZero     if (rc != 0) {
4378*042d53a7SEvalZero         return rc;
4379*042d53a7SEvalZero     }
4380*042d53a7SEvalZero 
4381*042d53a7SEvalZero     if (!(conn_flags & BLE_HS_CONN_F_MASTER)) {
4382*042d53a7SEvalZero         return BLE_HS_EROLE;
4383*042d53a7SEvalZero     }
4384*042d53a7SEvalZero 
4385*042d53a7SEvalZero     rc = ble_sm_enc_initiate(conn_handle, ltk, ediv, rand_val, auth);
4386*042d53a7SEvalZero     return rc;
4387*042d53a7SEvalZero }
4388*042d53a7SEvalZero 
4389*042d53a7SEvalZero int
ble_gap_unpair(const ble_addr_t * peer_addr)4390*042d53a7SEvalZero ble_gap_unpair(const ble_addr_t *peer_addr)
4391*042d53a7SEvalZero {
4392*042d53a7SEvalZero     struct ble_hs_conn *conn;
4393*042d53a7SEvalZero     int rc;
4394*042d53a7SEvalZero 
4395*042d53a7SEvalZero     if (ble_addr_cmp(peer_addr, BLE_ADDR_ANY) == 0) {
4396*042d53a7SEvalZero         return BLE_HS_EINVAL;
4397*042d53a7SEvalZero     }
4398*042d53a7SEvalZero 
4399*042d53a7SEvalZero     conn = ble_hs_conn_find_by_addr(peer_addr);
4400*042d53a7SEvalZero     if (conn != NULL) {
4401*042d53a7SEvalZero         rc = ble_gap_terminate(conn->bhc_handle, BLE_ERR_REM_USER_CONN_TERM);
4402*042d53a7SEvalZero         if ((rc != BLE_HS_EALREADY) && (rc != BLE_HS_ENOTCONN)) {
4403*042d53a7SEvalZero             return rc;
4404*042d53a7SEvalZero         }
4405*042d53a7SEvalZero     }
4406*042d53a7SEvalZero 
4407*042d53a7SEvalZero     rc = ble_hs_pvcy_remove_entry(peer_addr->type,
4408*042d53a7SEvalZero                                   peer_addr->val);
4409*042d53a7SEvalZero     if (rc != 0) {
4410*042d53a7SEvalZero         return rc;
4411*042d53a7SEvalZero     }
4412*042d53a7SEvalZero 
4413*042d53a7SEvalZero     return ble_store_util_delete_peer(peer_addr);
4414*042d53a7SEvalZero }
4415*042d53a7SEvalZero 
4416*042d53a7SEvalZero int
ble_gap_unpair_oldest_peer(void)4417*042d53a7SEvalZero ble_gap_unpair_oldest_peer(void)
4418*042d53a7SEvalZero {
4419*042d53a7SEvalZero     ble_addr_t oldest_peer_id_addr;
4420*042d53a7SEvalZero     int num_peers;
4421*042d53a7SEvalZero     int rc;
4422*042d53a7SEvalZero 
4423*042d53a7SEvalZero     rc = ble_store_util_bonded_peers(
4424*042d53a7SEvalZero             &oldest_peer_id_addr, &num_peers, 1);
4425*042d53a7SEvalZero     if (rc != 0) {
4426*042d53a7SEvalZero         return rc;
4427*042d53a7SEvalZero     }
4428*042d53a7SEvalZero 
4429*042d53a7SEvalZero     if (num_peers == 0) {
4430*042d53a7SEvalZero         return 0;
4431*042d53a7SEvalZero     }
4432*042d53a7SEvalZero 
4433*042d53a7SEvalZero     rc = ble_gap_unpair(&oldest_peer_id_addr);
4434*042d53a7SEvalZero     if (rc != 0) {
4435*042d53a7SEvalZero         return rc;
4436*042d53a7SEvalZero     }
4437*042d53a7SEvalZero 
4438*042d53a7SEvalZero     return 0;
4439*042d53a7SEvalZero }
4440*042d53a7SEvalZero 
4441*042d53a7SEvalZero void
ble_gap_passkey_event(uint16_t conn_handle,struct ble_gap_passkey_params * passkey_params)4442*042d53a7SEvalZero ble_gap_passkey_event(uint16_t conn_handle,
4443*042d53a7SEvalZero                       struct ble_gap_passkey_params *passkey_params)
4444*042d53a7SEvalZero {
4445*042d53a7SEvalZero #if !NIMBLE_BLE_SM
4446*042d53a7SEvalZero     return;
4447*042d53a7SEvalZero #endif
4448*042d53a7SEvalZero 
4449*042d53a7SEvalZero     struct ble_gap_event event;
4450*042d53a7SEvalZero 
4451*042d53a7SEvalZero     BLE_HS_LOG(DEBUG, "send passkey action request %d\n",
4452*042d53a7SEvalZero                passkey_params->action);
4453*042d53a7SEvalZero 
4454*042d53a7SEvalZero     memset(&event, 0, sizeof event);
4455*042d53a7SEvalZero     event.type = BLE_GAP_EVENT_PASSKEY_ACTION;
4456*042d53a7SEvalZero     event.passkey.conn_handle = conn_handle;
4457*042d53a7SEvalZero     event.passkey.params = *passkey_params;
4458*042d53a7SEvalZero     ble_gap_call_conn_event_cb(&event, conn_handle);
4459*042d53a7SEvalZero }
4460*042d53a7SEvalZero 
4461*042d53a7SEvalZero void
ble_gap_enc_event(uint16_t conn_handle,int status,int security_restored)4462*042d53a7SEvalZero ble_gap_enc_event(uint16_t conn_handle, int status, int security_restored)
4463*042d53a7SEvalZero {
4464*042d53a7SEvalZero #if !NIMBLE_BLE_SM
4465*042d53a7SEvalZero     return;
4466*042d53a7SEvalZero #endif
4467*042d53a7SEvalZero 
4468*042d53a7SEvalZero     struct ble_gap_event event;
4469*042d53a7SEvalZero 
4470*042d53a7SEvalZero     memset(&event, 0, sizeof event);
4471*042d53a7SEvalZero     event.type = BLE_GAP_EVENT_ENC_CHANGE;
4472*042d53a7SEvalZero     event.enc_change.conn_handle = conn_handle;
4473*042d53a7SEvalZero     event.enc_change.status = status;
4474*042d53a7SEvalZero 
4475*042d53a7SEvalZero     ble_gap_event_listener_call(&event);
4476*042d53a7SEvalZero     ble_gap_call_conn_event_cb(&event, conn_handle);
4477*042d53a7SEvalZero 
4478*042d53a7SEvalZero     if (status == 0 && security_restored) {
4479*042d53a7SEvalZero         ble_gatts_bonding_restored(conn_handle);
4480*042d53a7SEvalZero     }
4481*042d53a7SEvalZero }
4482*042d53a7SEvalZero 
4483*042d53a7SEvalZero void
ble_gap_identity_event(uint16_t conn_handle)4484*042d53a7SEvalZero ble_gap_identity_event(uint16_t conn_handle)
4485*042d53a7SEvalZero {
4486*042d53a7SEvalZero #if !NIMBLE_BLE_SM
4487*042d53a7SEvalZero     return;
4488*042d53a7SEvalZero #endif
4489*042d53a7SEvalZero 
4490*042d53a7SEvalZero     struct ble_gap_event event;
4491*042d53a7SEvalZero 
4492*042d53a7SEvalZero     BLE_HS_LOG(DEBUG, "send identity changed");
4493*042d53a7SEvalZero 
4494*042d53a7SEvalZero     memset(&event, 0, sizeof event);
4495*042d53a7SEvalZero     event.type = BLE_GAP_EVENT_IDENTITY_RESOLVED;
4496*042d53a7SEvalZero     event.identity_resolved.conn_handle = conn_handle;
4497*042d53a7SEvalZero     ble_gap_call_conn_event_cb(&event, conn_handle);
4498*042d53a7SEvalZero }
4499*042d53a7SEvalZero 
4500*042d53a7SEvalZero int
ble_gap_repeat_pairing_event(const struct ble_gap_repeat_pairing * rp)4501*042d53a7SEvalZero ble_gap_repeat_pairing_event(const struct ble_gap_repeat_pairing *rp)
4502*042d53a7SEvalZero {
4503*042d53a7SEvalZero #if !NIMBLE_BLE_SM
4504*042d53a7SEvalZero     return 0;
4505*042d53a7SEvalZero #endif
4506*042d53a7SEvalZero 
4507*042d53a7SEvalZero     struct ble_gap_event event;
4508*042d53a7SEvalZero     int rc;
4509*042d53a7SEvalZero 
4510*042d53a7SEvalZero     memset(&event, 0, sizeof event);
4511*042d53a7SEvalZero     event.type = BLE_GAP_EVENT_REPEAT_PAIRING;
4512*042d53a7SEvalZero     event.repeat_pairing = *rp;
4513*042d53a7SEvalZero     rc = ble_gap_call_conn_event_cb(&event, rp->conn_handle);
4514*042d53a7SEvalZero     return rc;
4515*042d53a7SEvalZero }
4516*042d53a7SEvalZero 
4517*042d53a7SEvalZero /*****************************************************************************
4518*042d53a7SEvalZero  * $rssi                                                                     *
4519*042d53a7SEvalZero  *****************************************************************************/
4520*042d53a7SEvalZero 
4521*042d53a7SEvalZero int
ble_gap_conn_rssi(uint16_t conn_handle,int8_t * out_rssi)4522*042d53a7SEvalZero ble_gap_conn_rssi(uint16_t conn_handle, int8_t *out_rssi)
4523*042d53a7SEvalZero {
4524*042d53a7SEvalZero     int rc;
4525*042d53a7SEvalZero 
4526*042d53a7SEvalZero     rc = ble_hs_hci_util_read_rssi(conn_handle, out_rssi);
4527*042d53a7SEvalZero     return rc;
4528*042d53a7SEvalZero }
4529*042d53a7SEvalZero 
4530*042d53a7SEvalZero /*****************************************************************************
4531*042d53a7SEvalZero  * $notify                                                                   *
4532*042d53a7SEvalZero  *****************************************************************************/
4533*042d53a7SEvalZero 
4534*042d53a7SEvalZero void
ble_gap_notify_rx_event(uint16_t conn_handle,uint16_t attr_handle,struct os_mbuf * om,int is_indication)4535*042d53a7SEvalZero ble_gap_notify_rx_event(uint16_t conn_handle, uint16_t attr_handle,
4536*042d53a7SEvalZero                         struct os_mbuf *om, int is_indication)
4537*042d53a7SEvalZero {
4538*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_GATT_NOTIFY) && !MYNEWT_VAL(BLE_GATT_INDICATE)
4539*042d53a7SEvalZero     return;
4540*042d53a7SEvalZero #endif
4541*042d53a7SEvalZero 
4542*042d53a7SEvalZero     struct ble_gap_event event;
4543*042d53a7SEvalZero 
4544*042d53a7SEvalZero     memset(&event, 0, sizeof event);
4545*042d53a7SEvalZero     event.type = BLE_GAP_EVENT_NOTIFY_RX;
4546*042d53a7SEvalZero     event.notify_rx.conn_handle = conn_handle;
4547*042d53a7SEvalZero     event.notify_rx.attr_handle = attr_handle;
4548*042d53a7SEvalZero     event.notify_rx.om = om;
4549*042d53a7SEvalZero     event.notify_rx.indication = is_indication;
4550*042d53a7SEvalZero     ble_gap_call_conn_event_cb(&event, conn_handle);
4551*042d53a7SEvalZero 
4552*042d53a7SEvalZero     os_mbuf_free_chain(event.notify_rx.om);
4553*042d53a7SEvalZero }
4554*042d53a7SEvalZero 
4555*042d53a7SEvalZero void
ble_gap_notify_tx_event(int status,uint16_t conn_handle,uint16_t attr_handle,int is_indication)4556*042d53a7SEvalZero ble_gap_notify_tx_event(int status, uint16_t conn_handle, uint16_t attr_handle,
4557*042d53a7SEvalZero                         int is_indication)
4558*042d53a7SEvalZero {
4559*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_GATT_NOTIFY) && !MYNEWT_VAL(BLE_GATT_INDICATE)
4560*042d53a7SEvalZero     return;
4561*042d53a7SEvalZero #endif
4562*042d53a7SEvalZero 
4563*042d53a7SEvalZero     struct ble_gap_event event;
4564*042d53a7SEvalZero 
4565*042d53a7SEvalZero     memset(&event, 0, sizeof event);
4566*042d53a7SEvalZero     event.type = BLE_GAP_EVENT_NOTIFY_TX;
4567*042d53a7SEvalZero     event.notify_tx.conn_handle = conn_handle;
4568*042d53a7SEvalZero     event.notify_tx.status = status;
4569*042d53a7SEvalZero     event.notify_tx.attr_handle = attr_handle;
4570*042d53a7SEvalZero     event.notify_tx.indication = is_indication;
4571*042d53a7SEvalZero     ble_gap_call_conn_event_cb(&event, conn_handle);
4572*042d53a7SEvalZero }
4573*042d53a7SEvalZero 
4574*042d53a7SEvalZero /*****************************************************************************
4575*042d53a7SEvalZero  * $subscribe                                                                *
4576*042d53a7SEvalZero  *****************************************************************************/
4577*042d53a7SEvalZero 
4578*042d53a7SEvalZero void
ble_gap_subscribe_event(uint16_t conn_handle,uint16_t attr_handle,uint8_t reason,uint8_t prev_notify,uint8_t cur_notify,uint8_t prev_indicate,uint8_t cur_indicate)4579*042d53a7SEvalZero ble_gap_subscribe_event(uint16_t conn_handle, uint16_t attr_handle,
4580*042d53a7SEvalZero                         uint8_t reason,
4581*042d53a7SEvalZero                         uint8_t prev_notify, uint8_t cur_notify,
4582*042d53a7SEvalZero                         uint8_t prev_indicate, uint8_t cur_indicate)
4583*042d53a7SEvalZero {
4584*042d53a7SEvalZero     struct ble_gap_event event;
4585*042d53a7SEvalZero 
4586*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(prev_notify != cur_notify ||
4587*042d53a7SEvalZero                       prev_indicate != cur_indicate);
4588*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(reason == BLE_GAP_SUBSCRIBE_REASON_WRITE ||
4589*042d53a7SEvalZero                       reason == BLE_GAP_SUBSCRIBE_REASON_TERM  ||
4590*042d53a7SEvalZero                       reason == BLE_GAP_SUBSCRIBE_REASON_RESTORE);
4591*042d53a7SEvalZero 
4592*042d53a7SEvalZero     memset(&event, 0, sizeof event);
4593*042d53a7SEvalZero     event.type = BLE_GAP_EVENT_SUBSCRIBE;
4594*042d53a7SEvalZero     event.subscribe.conn_handle = conn_handle;
4595*042d53a7SEvalZero     event.subscribe.attr_handle = attr_handle;
4596*042d53a7SEvalZero     event.subscribe.reason = reason;
4597*042d53a7SEvalZero     event.subscribe.prev_notify = !!prev_notify;
4598*042d53a7SEvalZero     event.subscribe.cur_notify = !!cur_notify;
4599*042d53a7SEvalZero     event.subscribe.prev_indicate = !!prev_indicate;
4600*042d53a7SEvalZero     event.subscribe.cur_indicate = !!cur_indicate;
4601*042d53a7SEvalZero 
4602*042d53a7SEvalZero     ble_gap_event_listener_call(&event);
4603*042d53a7SEvalZero     ble_gap_call_conn_event_cb(&event, conn_handle);
4604*042d53a7SEvalZero 
4605*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MESH)
4606*042d53a7SEvalZero     if (ble_gap_mesh.cb) {
4607*042d53a7SEvalZero         ble_gap_mesh.cb(&event, ble_gap_mesh.cb_arg);
4608*042d53a7SEvalZero     }
4609*042d53a7SEvalZero #endif
4610*042d53a7SEvalZero }
4611*042d53a7SEvalZero 
4612*042d53a7SEvalZero /*****************************************************************************
4613*042d53a7SEvalZero  * $mtu                                                                      *
4614*042d53a7SEvalZero  *****************************************************************************/
4615*042d53a7SEvalZero 
4616*042d53a7SEvalZero void
ble_gap_mtu_event(uint16_t conn_handle,uint16_t cid,uint16_t mtu)4617*042d53a7SEvalZero ble_gap_mtu_event(uint16_t conn_handle, uint16_t cid, uint16_t mtu)
4618*042d53a7SEvalZero {
4619*042d53a7SEvalZero     struct ble_gap_event event;
4620*042d53a7SEvalZero 
4621*042d53a7SEvalZero     memset(&event, 0, sizeof event);
4622*042d53a7SEvalZero     event.type = BLE_GAP_EVENT_MTU;
4623*042d53a7SEvalZero     event.mtu.conn_handle = conn_handle;
4624*042d53a7SEvalZero     event.mtu.channel_id = cid;
4625*042d53a7SEvalZero     event.mtu.value = mtu;
4626*042d53a7SEvalZero 
4627*042d53a7SEvalZero     ble_gap_event_listener_call(&event);
4628*042d53a7SEvalZero     ble_gap_call_conn_event_cb(&event, conn_handle);
4629*042d53a7SEvalZero }
4630*042d53a7SEvalZero 
4631*042d53a7SEvalZero /*****************************************************************************
4632*042d53a7SEvalZero  * $preempt                                                                  *
4633*042d53a7SEvalZero  *****************************************************************************/
4634*042d53a7SEvalZero 
4635*042d53a7SEvalZero void
ble_gap_preempt_no_lock(void)4636*042d53a7SEvalZero ble_gap_preempt_no_lock(void)
4637*042d53a7SEvalZero {
4638*042d53a7SEvalZero     int rc;
4639*042d53a7SEvalZero     int i;
4640*042d53a7SEvalZero 
4641*042d53a7SEvalZero     (void)rc;
4642*042d53a7SEvalZero     (void)i;
4643*042d53a7SEvalZero 
4644*042d53a7SEvalZero #if NIMBLE_BLE_ADVERTISE
4645*042d53a7SEvalZero #if MYNEWT_VAL(BLE_EXT_ADV)
4646*042d53a7SEvalZero     for (i = 0; i < BLE_ADV_INSTANCES; i++) {
4647*042d53a7SEvalZero         rc = ble_gap_ext_adv_stop_no_lock(i);
4648*042d53a7SEvalZero         if (rc == 0) {
4649*042d53a7SEvalZero             ble_gap_slave[i].preempted = 1;
4650*042d53a7SEvalZero         }
4651*042d53a7SEvalZero     }
4652*042d53a7SEvalZero #else
4653*042d53a7SEvalZero     rc = ble_gap_adv_stop_no_lock();
4654*042d53a7SEvalZero     if (rc == 0) {
4655*042d53a7SEvalZero         ble_gap_slave[0].preempted = 1;
4656*042d53a7SEvalZero     }
4657*042d53a7SEvalZero #endif
4658*042d53a7SEvalZero #endif
4659*042d53a7SEvalZero 
4660*042d53a7SEvalZero #if NIMBLE_BLE_CONNECT
4661*042d53a7SEvalZero     rc = ble_gap_conn_cancel_no_lock();
4662*042d53a7SEvalZero     if (rc == 0) {
4663*042d53a7SEvalZero         ble_gap_master.preempted_op = BLE_GAP_OP_M_CONN;
4664*042d53a7SEvalZero     }
4665*042d53a7SEvalZero #endif
4666*042d53a7SEvalZero 
4667*042d53a7SEvalZero #if NIMBLE_BLE_SCAN
4668*042d53a7SEvalZero     rc = ble_gap_disc_cancel_no_lock();
4669*042d53a7SEvalZero     if (rc == 0) {
4670*042d53a7SEvalZero         ble_gap_master.preempted_op = BLE_GAP_OP_M_DISC;
4671*042d53a7SEvalZero     }
4672*042d53a7SEvalZero #endif
4673*042d53a7SEvalZero }
4674*042d53a7SEvalZero 
4675*042d53a7SEvalZero /**
4676*042d53a7SEvalZero  * @brief Preempts the GAP if it is not already preempted.
4677*042d53a7SEvalZero  *
4678*042d53a7SEvalZero  * Aborts all active GAP procedures and prevents new ones from being started.
4679*042d53a7SEvalZero  * This function is used to ensure an idle GAP so that the controller's
4680*042d53a7SEvalZero  * resolving list can be modified.  When done accessing the resolving list, the
4681*042d53a7SEvalZero  * caller must call `ble_gap_preempt_done()` to permit new GAP procedures.
4682*042d53a7SEvalZero  *
4683*042d53a7SEvalZero  * On preemption, all aborted GAP procedures are reported with a status or
4684*042d53a7SEvalZero  * reason code of BLE_HS_EPREEMPTED.  An attempt to initiate a new GAP
4685*042d53a7SEvalZero  * procedure during preemption fails with a return code of BLE_HS_EPREEMPTED.
4686*042d53a7SEvalZero  */
4687*042d53a7SEvalZero void
ble_gap_preempt(void)4688*042d53a7SEvalZero ble_gap_preempt(void)
4689*042d53a7SEvalZero {
4690*042d53a7SEvalZero     ble_hs_lock();
4691*042d53a7SEvalZero 
4692*042d53a7SEvalZero     if (!ble_gap_is_preempted()) {
4693*042d53a7SEvalZero         ble_gap_preempt_no_lock();
4694*042d53a7SEvalZero     }
4695*042d53a7SEvalZero 
4696*042d53a7SEvalZero     ble_hs_unlock();
4697*042d53a7SEvalZero }
4698*042d53a7SEvalZero 
4699*042d53a7SEvalZero /**
4700*042d53a7SEvalZero  * Takes GAP out of the preempted state, allowing new GAP procedures to be
4701*042d53a7SEvalZero  * initiated.  This function should only be called after a call to
4702*042d53a7SEvalZero  * `ble_gap_preempt()`.
4703*042d53a7SEvalZero  */
4704*042d53a7SEvalZero 
4705*042d53a7SEvalZero static struct ble_npl_mutex preempt_done_mutex;
4706*042d53a7SEvalZero 
4707*042d53a7SEvalZero void
ble_gap_preempt_done(void)4708*042d53a7SEvalZero ble_gap_preempt_done(void)
4709*042d53a7SEvalZero {
4710*042d53a7SEvalZero     struct ble_gap_event event;
4711*042d53a7SEvalZero     ble_gap_event_fn *master_cb;
4712*042d53a7SEvalZero     void *master_arg;
4713*042d53a7SEvalZero     int disc_preempted;
4714*042d53a7SEvalZero     int i;
4715*042d53a7SEvalZero     static struct {
4716*042d53a7SEvalZero         ble_gap_event_fn *cb;
4717*042d53a7SEvalZero         void *arg;
4718*042d53a7SEvalZero     } slaves[BLE_ADV_INSTANCES];
4719*042d53a7SEvalZero 
4720*042d53a7SEvalZero     disc_preempted = 0;
4721*042d53a7SEvalZero 
4722*042d53a7SEvalZero     /* protects slaves from accessing by multiple threads */
4723*042d53a7SEvalZero     ble_npl_mutex_pend(&preempt_done_mutex, 0xFFFFFFFF);
4724*042d53a7SEvalZero     memset(slaves, 0, sizeof(slaves));
4725*042d53a7SEvalZero 
4726*042d53a7SEvalZero     ble_hs_lock();
4727*042d53a7SEvalZero 
4728*042d53a7SEvalZero     for (i = 0; i < BLE_ADV_INSTANCES; i++) {
4729*042d53a7SEvalZero         if (ble_gap_slave[i].preempted) {
4730*042d53a7SEvalZero             ble_gap_slave[i].preempted = 0;
4731*042d53a7SEvalZero             slaves[i].cb = ble_gap_slave[i].cb;
4732*042d53a7SEvalZero             slaves[i].arg = ble_gap_slave[i].cb_arg;
4733*042d53a7SEvalZero         }
4734*042d53a7SEvalZero     }
4735*042d53a7SEvalZero 
4736*042d53a7SEvalZero     if (ble_gap_master.preempted_op == BLE_GAP_OP_M_DISC) {
4737*042d53a7SEvalZero         ble_gap_master.preempted_op = BLE_GAP_OP_NULL;
4738*042d53a7SEvalZero         disc_preempted = 1;
4739*042d53a7SEvalZero         master_cb = ble_gap_master.cb;
4740*042d53a7SEvalZero         master_arg = ble_gap_master.cb_arg;
4741*042d53a7SEvalZero     }
4742*042d53a7SEvalZero 
4743*042d53a7SEvalZero     ble_hs_unlock();
4744*042d53a7SEvalZero 
4745*042d53a7SEvalZero     event.type = BLE_GAP_EVENT_ADV_COMPLETE;
4746*042d53a7SEvalZero     event.adv_complete.reason = BLE_HS_EPREEMPTED;
4747*042d53a7SEvalZero 
4748*042d53a7SEvalZero     for (i = 0; i < BLE_ADV_INSTANCES; i++) {
4749*042d53a7SEvalZero         if (slaves[i].cb) {
4750*042d53a7SEvalZero #if MYNEWT_VAL(BLE_EXT_ADV)
4751*042d53a7SEvalZero             event.adv_complete.instance = i;
4752*042d53a7SEvalZero             event.adv_complete.conn_handle = i;
4753*042d53a7SEvalZero #endif
4754*042d53a7SEvalZero             ble_gap_call_event_cb(&event, slaves[i].cb, slaves[i].arg);
4755*042d53a7SEvalZero         }
4756*042d53a7SEvalZero     }
4757*042d53a7SEvalZero     ble_npl_mutex_release(&preempt_done_mutex);
4758*042d53a7SEvalZero 
4759*042d53a7SEvalZero     if (disc_preempted) {
4760*042d53a7SEvalZero         event.type = BLE_GAP_EVENT_DISC_COMPLETE;
4761*042d53a7SEvalZero         event.disc_complete.reason = BLE_HS_EPREEMPTED;
4762*042d53a7SEvalZero         ble_gap_call_event_cb(&event, master_cb, master_arg);
4763*042d53a7SEvalZero     }
4764*042d53a7SEvalZero }
4765*042d53a7SEvalZero 
4766*042d53a7SEvalZero int
ble_gap_event_listener_register(struct ble_gap_event_listener * listener,ble_gap_event_fn * fn,void * arg)4767*042d53a7SEvalZero ble_gap_event_listener_register(struct ble_gap_event_listener *listener,
4768*042d53a7SEvalZero                                 ble_gap_event_fn *fn, void *arg)
4769*042d53a7SEvalZero {
4770*042d53a7SEvalZero     struct ble_gap_event_listener *evl = NULL;
4771*042d53a7SEvalZero     int rc;
4772*042d53a7SEvalZero 
4773*042d53a7SEvalZero     SLIST_FOREACH(evl, &ble_gap_event_listener_list, link) {
4774*042d53a7SEvalZero         if (evl == listener) {
4775*042d53a7SEvalZero             break;
4776*042d53a7SEvalZero         }
4777*042d53a7SEvalZero     }
4778*042d53a7SEvalZero 
4779*042d53a7SEvalZero     if (!evl) {
4780*042d53a7SEvalZero         if (fn) {
4781*042d53a7SEvalZero             memset(listener, 0, sizeof(*listener));
4782*042d53a7SEvalZero             listener->fn = fn;
4783*042d53a7SEvalZero             listener->arg = arg;
4784*042d53a7SEvalZero             SLIST_INSERT_HEAD(&ble_gap_event_listener_list, listener, link);
4785*042d53a7SEvalZero             rc = 0;
4786*042d53a7SEvalZero         } else {
4787*042d53a7SEvalZero             rc = BLE_HS_EINVAL;
4788*042d53a7SEvalZero         }
4789*042d53a7SEvalZero     } else {
4790*042d53a7SEvalZero         rc = BLE_HS_EALREADY;
4791*042d53a7SEvalZero     }
4792*042d53a7SEvalZero 
4793*042d53a7SEvalZero     return rc;
4794*042d53a7SEvalZero }
4795*042d53a7SEvalZero 
4796*042d53a7SEvalZero int
ble_gap_event_listener_unregister(struct ble_gap_event_listener * listener)4797*042d53a7SEvalZero ble_gap_event_listener_unregister(struct ble_gap_event_listener *listener)
4798*042d53a7SEvalZero {
4799*042d53a7SEvalZero     struct ble_gap_event_listener *evl = NULL;
4800*042d53a7SEvalZero     int rc;
4801*042d53a7SEvalZero 
4802*042d53a7SEvalZero     /*
4803*042d53a7SEvalZero      * We check if element exists on the list only for sanity to let caller
4804*042d53a7SEvalZero      * know whether it registered its listener before.
4805*042d53a7SEvalZero      */
4806*042d53a7SEvalZero 
4807*042d53a7SEvalZero     SLIST_FOREACH(evl, &ble_gap_event_listener_list, link) {
4808*042d53a7SEvalZero         if (evl == listener) {
4809*042d53a7SEvalZero             break;
4810*042d53a7SEvalZero         }
4811*042d53a7SEvalZero     }
4812*042d53a7SEvalZero 
4813*042d53a7SEvalZero     if (!evl) {
4814*042d53a7SEvalZero         rc = BLE_HS_ENOENT;
4815*042d53a7SEvalZero     } else {
4816*042d53a7SEvalZero         SLIST_REMOVE(&ble_gap_event_listener_list, listener,
4817*042d53a7SEvalZero                      ble_gap_event_listener, link);
4818*042d53a7SEvalZero         rc = 0;
4819*042d53a7SEvalZero     }
4820*042d53a7SEvalZero 
4821*042d53a7SEvalZero     return rc;
4822*042d53a7SEvalZero }
4823*042d53a7SEvalZero 
4824*042d53a7SEvalZero static int
ble_gap_event_listener_call(struct ble_gap_event * event)4825*042d53a7SEvalZero ble_gap_event_listener_call(struct ble_gap_event *event)
4826*042d53a7SEvalZero {
4827*042d53a7SEvalZero     struct ble_gap_event_listener *evl = NULL;
4828*042d53a7SEvalZero 
4829*042d53a7SEvalZero     SLIST_FOREACH(evl, &ble_gap_event_listener_list, link) {
4830*042d53a7SEvalZero         evl->fn(event, evl->arg);
4831*042d53a7SEvalZero     }
4832*042d53a7SEvalZero 
4833*042d53a7SEvalZero     return 0;
4834*042d53a7SEvalZero }
4835*042d53a7SEvalZero 
4836*042d53a7SEvalZero /*****************************************************************************
4837*042d53a7SEvalZero  * $init                                                                     *
4838*042d53a7SEvalZero  *****************************************************************************/
4839*042d53a7SEvalZero 
4840*042d53a7SEvalZero int
ble_gap_init(void)4841*042d53a7SEvalZero ble_gap_init(void)
4842*042d53a7SEvalZero {
4843*042d53a7SEvalZero     int rc;
4844*042d53a7SEvalZero 
4845*042d53a7SEvalZero     memset(&ble_gap_master, 0, sizeof ble_gap_master);
4846*042d53a7SEvalZero     memset(ble_gap_slave, 0, sizeof ble_gap_slave);
4847*042d53a7SEvalZero 
4848*042d53a7SEvalZero     ble_npl_mutex_init(&preempt_done_mutex);
4849*042d53a7SEvalZero 
4850*042d53a7SEvalZero     SLIST_INIT(&ble_gap_update_entries);
4851*042d53a7SEvalZero     SLIST_INIT(&ble_gap_event_listener_list);
4852*042d53a7SEvalZero 
4853*042d53a7SEvalZero     rc = os_mempool_init(&ble_gap_update_entry_pool,
4854*042d53a7SEvalZero                          MYNEWT_VAL(BLE_GAP_MAX_PENDING_CONN_PARAM_UPDATE),
4855*042d53a7SEvalZero                          sizeof (struct ble_gap_update_entry),
4856*042d53a7SEvalZero                          ble_gap_update_entry_mem,
4857*042d53a7SEvalZero                          "ble_gap_update");
4858*042d53a7SEvalZero     switch (rc) {
4859*042d53a7SEvalZero     case 0:
4860*042d53a7SEvalZero         break;
4861*042d53a7SEvalZero     case OS_ENOMEM:
4862*042d53a7SEvalZero         rc = BLE_HS_ENOMEM;
4863*042d53a7SEvalZero         goto err;
4864*042d53a7SEvalZero     default:
4865*042d53a7SEvalZero         rc = BLE_HS_EOS;
4866*042d53a7SEvalZero         goto err;
4867*042d53a7SEvalZero     }
4868*042d53a7SEvalZero 
4869*042d53a7SEvalZero     rc = stats_init_and_reg(
4870*042d53a7SEvalZero         STATS_HDR(ble_gap_stats), STATS_SIZE_INIT_PARMS(ble_gap_stats,
4871*042d53a7SEvalZero         STATS_SIZE_32), STATS_NAME_INIT_PARMS(ble_gap_stats), "ble_gap");
4872*042d53a7SEvalZero     if (rc != 0) {
4873*042d53a7SEvalZero         goto err;
4874*042d53a7SEvalZero     }
4875*042d53a7SEvalZero 
4876*042d53a7SEvalZero     return 0;
4877*042d53a7SEvalZero 
4878*042d53a7SEvalZero err:
4879*042d53a7SEvalZero     return rc;
4880*042d53a7SEvalZero }
4881