xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/host/src/ble_hs_conn.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 <string.h>
21*042d53a7SEvalZero #include <errno.h>
22*042d53a7SEvalZero #include "syscfg/syscfg.h"
23*042d53a7SEvalZero #include "os/os.h"
24*042d53a7SEvalZero #include "host/ble_hs_id.h"
25*042d53a7SEvalZero #include "ble_hs_priv.h"
26*042d53a7SEvalZero 
27*042d53a7SEvalZero /** At least three channels required per connection (sig, att, sm). */
28*042d53a7SEvalZero #define BLE_HS_CONN_MIN_CHANS       3
29*042d53a7SEvalZero 
30*042d53a7SEvalZero static SLIST_HEAD(, ble_hs_conn) ble_hs_conns;
31*042d53a7SEvalZero static struct os_mempool ble_hs_conn_pool;
32*042d53a7SEvalZero 
33*042d53a7SEvalZero static os_membuf_t ble_hs_conn_elem_mem[
34*042d53a7SEvalZero     OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_MAX_CONNECTIONS),
35*042d53a7SEvalZero                     sizeof (struct ble_hs_conn))
36*042d53a7SEvalZero ];
37*042d53a7SEvalZero 
38*042d53a7SEvalZero static const uint8_t ble_hs_conn_null_addr[6];
39*042d53a7SEvalZero 
40*042d53a7SEvalZero int
ble_hs_conn_can_alloc(void)41*042d53a7SEvalZero ble_hs_conn_can_alloc(void)
42*042d53a7SEvalZero {
43*042d53a7SEvalZero #if !NIMBLE_BLE_CONNECT
44*042d53a7SEvalZero     return 0;
45*042d53a7SEvalZero #endif
46*042d53a7SEvalZero 
47*042d53a7SEvalZero     return ble_hs_conn_pool.mp_num_free >= 1 &&
48*042d53a7SEvalZero            ble_l2cap_chan_pool.mp_num_free >= BLE_HS_CONN_MIN_CHANS &&
49*042d53a7SEvalZero            ble_gatts_conn_can_alloc();
50*042d53a7SEvalZero }
51*042d53a7SEvalZero 
52*042d53a7SEvalZero struct ble_l2cap_chan *
ble_hs_conn_chan_find_by_scid(struct ble_hs_conn * conn,uint16_t cid)53*042d53a7SEvalZero ble_hs_conn_chan_find_by_scid(struct ble_hs_conn *conn, uint16_t cid)
54*042d53a7SEvalZero {
55*042d53a7SEvalZero #if !NIMBLE_BLE_CONNECT
56*042d53a7SEvalZero     return NULL;
57*042d53a7SEvalZero #endif
58*042d53a7SEvalZero 
59*042d53a7SEvalZero     struct ble_l2cap_chan *chan;
60*042d53a7SEvalZero 
61*042d53a7SEvalZero     SLIST_FOREACH(chan, &conn->bhc_channels, next) {
62*042d53a7SEvalZero         if (chan->scid == cid) {
63*042d53a7SEvalZero             return chan;
64*042d53a7SEvalZero         }
65*042d53a7SEvalZero         if (chan->scid > cid) {
66*042d53a7SEvalZero             return NULL;
67*042d53a7SEvalZero         }
68*042d53a7SEvalZero     }
69*042d53a7SEvalZero 
70*042d53a7SEvalZero     return NULL;
71*042d53a7SEvalZero }
72*042d53a7SEvalZero 
73*042d53a7SEvalZero struct ble_l2cap_chan *
ble_hs_conn_chan_find_by_dcid(struct ble_hs_conn * conn,uint16_t cid)74*042d53a7SEvalZero ble_hs_conn_chan_find_by_dcid(struct ble_hs_conn *conn, uint16_t cid)
75*042d53a7SEvalZero {
76*042d53a7SEvalZero #if !NIMBLE_BLE_CONNECT
77*042d53a7SEvalZero     return NULL;
78*042d53a7SEvalZero #endif
79*042d53a7SEvalZero 
80*042d53a7SEvalZero     struct ble_l2cap_chan *chan;
81*042d53a7SEvalZero 
82*042d53a7SEvalZero     SLIST_FOREACH(chan, &conn->bhc_channels, next) {
83*042d53a7SEvalZero         if (chan->dcid == cid) {
84*042d53a7SEvalZero             return chan;
85*042d53a7SEvalZero         }
86*042d53a7SEvalZero         if (chan->dcid > cid) {
87*042d53a7SEvalZero             return NULL;
88*042d53a7SEvalZero         }
89*042d53a7SEvalZero     }
90*042d53a7SEvalZero 
91*042d53a7SEvalZero     return NULL;
92*042d53a7SEvalZero }
93*042d53a7SEvalZero 
94*042d53a7SEvalZero int
ble_hs_conn_chan_insert(struct ble_hs_conn * conn,struct ble_l2cap_chan * chan)95*042d53a7SEvalZero ble_hs_conn_chan_insert(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan)
96*042d53a7SEvalZero {
97*042d53a7SEvalZero #if !NIMBLE_BLE_CONNECT
98*042d53a7SEvalZero     return BLE_HS_ENOTSUP;
99*042d53a7SEvalZero #endif
100*042d53a7SEvalZero 
101*042d53a7SEvalZero     struct ble_l2cap_chan *prev;
102*042d53a7SEvalZero     struct ble_l2cap_chan *cur;
103*042d53a7SEvalZero 
104*042d53a7SEvalZero     prev = NULL;
105*042d53a7SEvalZero     SLIST_FOREACH(cur, &conn->bhc_channels, next) {
106*042d53a7SEvalZero         if (cur->scid == chan->scid) {
107*042d53a7SEvalZero             return BLE_HS_EALREADY;
108*042d53a7SEvalZero         }
109*042d53a7SEvalZero         if (cur->scid > chan->scid) {
110*042d53a7SEvalZero             break;
111*042d53a7SEvalZero         }
112*042d53a7SEvalZero 
113*042d53a7SEvalZero         prev = cur;
114*042d53a7SEvalZero     }
115*042d53a7SEvalZero 
116*042d53a7SEvalZero     if (prev == NULL) {
117*042d53a7SEvalZero         SLIST_INSERT_HEAD(&conn->bhc_channels, chan, next);
118*042d53a7SEvalZero     } else {
119*042d53a7SEvalZero         SLIST_INSERT_AFTER(prev, chan, next);
120*042d53a7SEvalZero     }
121*042d53a7SEvalZero 
122*042d53a7SEvalZero     return 0;
123*042d53a7SEvalZero }
124*042d53a7SEvalZero 
125*042d53a7SEvalZero struct ble_hs_conn *
ble_hs_conn_alloc(uint16_t conn_handle)126*042d53a7SEvalZero ble_hs_conn_alloc(uint16_t conn_handle)
127*042d53a7SEvalZero {
128*042d53a7SEvalZero #if !NIMBLE_BLE_CONNECT
129*042d53a7SEvalZero     return NULL;
130*042d53a7SEvalZero #endif
131*042d53a7SEvalZero 
132*042d53a7SEvalZero     struct ble_l2cap_chan *chan;
133*042d53a7SEvalZero     struct ble_hs_conn *conn;
134*042d53a7SEvalZero     int rc;
135*042d53a7SEvalZero 
136*042d53a7SEvalZero     conn = os_memblock_get(&ble_hs_conn_pool);
137*042d53a7SEvalZero     if (conn == NULL) {
138*042d53a7SEvalZero         goto err;
139*042d53a7SEvalZero     }
140*042d53a7SEvalZero     memset(conn, 0, sizeof *conn);
141*042d53a7SEvalZero     conn->bhc_handle = conn_handle;
142*042d53a7SEvalZero 
143*042d53a7SEvalZero     SLIST_INIT(&conn->bhc_channels);
144*042d53a7SEvalZero 
145*042d53a7SEvalZero     chan = ble_att_create_chan(conn_handle);
146*042d53a7SEvalZero     if (chan == NULL) {
147*042d53a7SEvalZero         goto err;
148*042d53a7SEvalZero     }
149*042d53a7SEvalZero     rc = ble_hs_conn_chan_insert(conn, chan);
150*042d53a7SEvalZero     if (rc != 0) {
151*042d53a7SEvalZero         goto err;
152*042d53a7SEvalZero     }
153*042d53a7SEvalZero 
154*042d53a7SEvalZero     chan = ble_l2cap_sig_create_chan(conn_handle);
155*042d53a7SEvalZero     if (chan == NULL) {
156*042d53a7SEvalZero         goto err;
157*042d53a7SEvalZero     }
158*042d53a7SEvalZero     rc = ble_hs_conn_chan_insert(conn, chan);
159*042d53a7SEvalZero     if (rc != 0) {
160*042d53a7SEvalZero         goto err;
161*042d53a7SEvalZero     }
162*042d53a7SEvalZero 
163*042d53a7SEvalZero     /* Create the SM channel even if not configured. We need it to reject SM
164*042d53a7SEvalZero      * messages.
165*042d53a7SEvalZero      */
166*042d53a7SEvalZero     chan = ble_sm_create_chan(conn_handle);
167*042d53a7SEvalZero     if (chan == NULL) {
168*042d53a7SEvalZero         goto err;
169*042d53a7SEvalZero     }
170*042d53a7SEvalZero     rc = ble_hs_conn_chan_insert(conn, chan);
171*042d53a7SEvalZero     if (rc != 0) {
172*042d53a7SEvalZero         goto err;
173*042d53a7SEvalZero     }
174*042d53a7SEvalZero 
175*042d53a7SEvalZero     rc = ble_gatts_conn_init(&conn->bhc_gatt_svr);
176*042d53a7SEvalZero     if (rc != 0) {
177*042d53a7SEvalZero         goto err;
178*042d53a7SEvalZero     }
179*042d53a7SEvalZero 
180*042d53a7SEvalZero     STAILQ_INIT(&conn->bhc_tx_q);
181*042d53a7SEvalZero 
182*042d53a7SEvalZero     STATS_INC(ble_hs_stats, conn_create);
183*042d53a7SEvalZero 
184*042d53a7SEvalZero     return conn;
185*042d53a7SEvalZero 
186*042d53a7SEvalZero err:
187*042d53a7SEvalZero     ble_hs_conn_free(conn);
188*042d53a7SEvalZero     return NULL;
189*042d53a7SEvalZero }
190*042d53a7SEvalZero 
191*042d53a7SEvalZero void
ble_hs_conn_delete_chan(struct ble_hs_conn * conn,struct ble_l2cap_chan * chan)192*042d53a7SEvalZero ble_hs_conn_delete_chan(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan)
193*042d53a7SEvalZero {
194*042d53a7SEvalZero     if (conn->bhc_rx_chan == chan) {
195*042d53a7SEvalZero         conn->bhc_rx_chan = NULL;
196*042d53a7SEvalZero     }
197*042d53a7SEvalZero 
198*042d53a7SEvalZero     SLIST_REMOVE(&conn->bhc_channels, chan, ble_l2cap_chan, next);
199*042d53a7SEvalZero     ble_l2cap_chan_free(chan);
200*042d53a7SEvalZero }
201*042d53a7SEvalZero 
202*042d53a7SEvalZero void
ble_hs_conn_free(struct ble_hs_conn * conn)203*042d53a7SEvalZero ble_hs_conn_free(struct ble_hs_conn *conn)
204*042d53a7SEvalZero {
205*042d53a7SEvalZero #if !NIMBLE_BLE_CONNECT
206*042d53a7SEvalZero     return;
207*042d53a7SEvalZero #endif
208*042d53a7SEvalZero 
209*042d53a7SEvalZero     struct ble_l2cap_chan *chan;
210*042d53a7SEvalZero     int rc;
211*042d53a7SEvalZero 
212*042d53a7SEvalZero     if (conn == NULL) {
213*042d53a7SEvalZero         return;
214*042d53a7SEvalZero     }
215*042d53a7SEvalZero 
216*042d53a7SEvalZero     ble_att_svr_prep_clear(&conn->bhc_att_svr.basc_prep_list);
217*042d53a7SEvalZero 
218*042d53a7SEvalZero     while ((chan = SLIST_FIRST(&conn->bhc_channels)) != NULL) {
219*042d53a7SEvalZero         ble_hs_conn_delete_chan(conn, chan);
220*042d53a7SEvalZero     }
221*042d53a7SEvalZero 
222*042d53a7SEvalZero #if MYNEWT_VAL(BLE_HS_DEBUG)
223*042d53a7SEvalZero     memset(conn, 0xff, sizeof *conn);
224*042d53a7SEvalZero #endif
225*042d53a7SEvalZero     rc = os_memblock_put(&ble_hs_conn_pool, conn);
226*042d53a7SEvalZero     BLE_HS_DBG_ASSERT_EVAL(rc == 0);
227*042d53a7SEvalZero 
228*042d53a7SEvalZero     STATS_INC(ble_hs_stats, conn_delete);
229*042d53a7SEvalZero }
230*042d53a7SEvalZero 
231*042d53a7SEvalZero void
ble_hs_conn_insert(struct ble_hs_conn * conn)232*042d53a7SEvalZero ble_hs_conn_insert(struct ble_hs_conn *conn)
233*042d53a7SEvalZero {
234*042d53a7SEvalZero #if !NIMBLE_BLE_CONNECT
235*042d53a7SEvalZero     return;
236*042d53a7SEvalZero #endif
237*042d53a7SEvalZero 
238*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task());
239*042d53a7SEvalZero 
240*042d53a7SEvalZero     BLE_HS_DBG_ASSERT_EVAL(ble_hs_conn_find(conn->bhc_handle) == NULL);
241*042d53a7SEvalZero     SLIST_INSERT_HEAD(&ble_hs_conns, conn, bhc_next);
242*042d53a7SEvalZero }
243*042d53a7SEvalZero 
244*042d53a7SEvalZero void
ble_hs_conn_remove(struct ble_hs_conn * conn)245*042d53a7SEvalZero ble_hs_conn_remove(struct ble_hs_conn *conn)
246*042d53a7SEvalZero {
247*042d53a7SEvalZero #if !NIMBLE_BLE_CONNECT
248*042d53a7SEvalZero     return;
249*042d53a7SEvalZero #endif
250*042d53a7SEvalZero 
251*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task());
252*042d53a7SEvalZero 
253*042d53a7SEvalZero     SLIST_REMOVE(&ble_hs_conns, conn, ble_hs_conn, bhc_next);
254*042d53a7SEvalZero }
255*042d53a7SEvalZero 
256*042d53a7SEvalZero struct ble_hs_conn *
ble_hs_conn_find(uint16_t conn_handle)257*042d53a7SEvalZero ble_hs_conn_find(uint16_t conn_handle)
258*042d53a7SEvalZero {
259*042d53a7SEvalZero #if !NIMBLE_BLE_CONNECT
260*042d53a7SEvalZero     return NULL;
261*042d53a7SEvalZero #endif
262*042d53a7SEvalZero 
263*042d53a7SEvalZero     struct ble_hs_conn *conn;
264*042d53a7SEvalZero 
265*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task());
266*042d53a7SEvalZero 
267*042d53a7SEvalZero     SLIST_FOREACH(conn, &ble_hs_conns, bhc_next) {
268*042d53a7SEvalZero         if (conn->bhc_handle == conn_handle) {
269*042d53a7SEvalZero             return conn;
270*042d53a7SEvalZero         }
271*042d53a7SEvalZero     }
272*042d53a7SEvalZero 
273*042d53a7SEvalZero     return NULL;
274*042d53a7SEvalZero }
275*042d53a7SEvalZero 
276*042d53a7SEvalZero struct ble_hs_conn *
ble_hs_conn_find_assert(uint16_t conn_handle)277*042d53a7SEvalZero ble_hs_conn_find_assert(uint16_t conn_handle)
278*042d53a7SEvalZero {
279*042d53a7SEvalZero     struct ble_hs_conn *conn;
280*042d53a7SEvalZero 
281*042d53a7SEvalZero     conn = ble_hs_conn_find(conn_handle);
282*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(conn != NULL);
283*042d53a7SEvalZero 
284*042d53a7SEvalZero     return conn;
285*042d53a7SEvalZero }
286*042d53a7SEvalZero 
287*042d53a7SEvalZero struct ble_hs_conn *
ble_hs_conn_find_by_addr(const ble_addr_t * addr)288*042d53a7SEvalZero ble_hs_conn_find_by_addr(const ble_addr_t *addr)
289*042d53a7SEvalZero {
290*042d53a7SEvalZero #if !NIMBLE_BLE_CONNECT
291*042d53a7SEvalZero     return NULL;
292*042d53a7SEvalZero #endif
293*042d53a7SEvalZero 
294*042d53a7SEvalZero     struct ble_hs_conn *conn;
295*042d53a7SEvalZero 
296*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task());
297*042d53a7SEvalZero 
298*042d53a7SEvalZero     if (!addr) {
299*042d53a7SEvalZero         return NULL;
300*042d53a7SEvalZero     }
301*042d53a7SEvalZero 
302*042d53a7SEvalZero     SLIST_FOREACH(conn, &ble_hs_conns, bhc_next) {
303*042d53a7SEvalZero         if (ble_addr_cmp(&conn->bhc_peer_addr, addr) == 0) {
304*042d53a7SEvalZero             return conn;
305*042d53a7SEvalZero         }
306*042d53a7SEvalZero     }
307*042d53a7SEvalZero 
308*042d53a7SEvalZero     return NULL;
309*042d53a7SEvalZero }
310*042d53a7SEvalZero 
311*042d53a7SEvalZero struct ble_hs_conn *
ble_hs_conn_find_by_idx(int idx)312*042d53a7SEvalZero ble_hs_conn_find_by_idx(int idx)
313*042d53a7SEvalZero {
314*042d53a7SEvalZero #if !NIMBLE_BLE_CONNECT
315*042d53a7SEvalZero     return NULL;
316*042d53a7SEvalZero #endif
317*042d53a7SEvalZero 
318*042d53a7SEvalZero     struct ble_hs_conn *conn;
319*042d53a7SEvalZero     int i;
320*042d53a7SEvalZero 
321*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task());
322*042d53a7SEvalZero 
323*042d53a7SEvalZero     i = 0;
324*042d53a7SEvalZero     SLIST_FOREACH(conn, &ble_hs_conns, bhc_next) {
325*042d53a7SEvalZero         if (i == idx) {
326*042d53a7SEvalZero             return conn;
327*042d53a7SEvalZero         }
328*042d53a7SEvalZero 
329*042d53a7SEvalZero         i++;
330*042d53a7SEvalZero     }
331*042d53a7SEvalZero 
332*042d53a7SEvalZero     return NULL;
333*042d53a7SEvalZero }
334*042d53a7SEvalZero 
335*042d53a7SEvalZero int
ble_hs_conn_exists(uint16_t conn_handle)336*042d53a7SEvalZero ble_hs_conn_exists(uint16_t conn_handle)
337*042d53a7SEvalZero {
338*042d53a7SEvalZero #if !NIMBLE_BLE_CONNECT
339*042d53a7SEvalZero     return 0;
340*042d53a7SEvalZero #endif
341*042d53a7SEvalZero     return ble_hs_conn_find(conn_handle) != NULL;
342*042d53a7SEvalZero }
343*042d53a7SEvalZero 
344*042d53a7SEvalZero /**
345*042d53a7SEvalZero  * Retrieves the first connection in the list.
346*042d53a7SEvalZero  */
347*042d53a7SEvalZero struct ble_hs_conn *
ble_hs_conn_first(void)348*042d53a7SEvalZero ble_hs_conn_first(void)
349*042d53a7SEvalZero {
350*042d53a7SEvalZero #if !NIMBLE_BLE_CONNECT
351*042d53a7SEvalZero     return NULL;
352*042d53a7SEvalZero #endif
353*042d53a7SEvalZero 
354*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task());
355*042d53a7SEvalZero     return SLIST_FIRST(&ble_hs_conns);
356*042d53a7SEvalZero }
357*042d53a7SEvalZero 
358*042d53a7SEvalZero void
ble_hs_conn_addrs(const struct ble_hs_conn * conn,struct ble_hs_conn_addrs * addrs)359*042d53a7SEvalZero ble_hs_conn_addrs(const struct ble_hs_conn *conn,
360*042d53a7SEvalZero                   struct ble_hs_conn_addrs *addrs)
361*042d53a7SEvalZero {
362*042d53a7SEvalZero     const uint8_t *our_id_addr_val;
363*042d53a7SEvalZero     int rc;
364*042d53a7SEvalZero 
365*042d53a7SEvalZero     /* Determine our address information. */
366*042d53a7SEvalZero     addrs->our_id_addr.type =
367*042d53a7SEvalZero         ble_hs_misc_addr_type_to_id(conn->bhc_our_addr_type);
368*042d53a7SEvalZero 
369*042d53a7SEvalZero #if MYNEWT_VAL(BLE_EXT_ADV)
370*042d53a7SEvalZero     /* With EA enabled random address for slave connection is per advertising
371*042d53a7SEvalZero      * instance and requires special handling here.
372*042d53a7SEvalZero      */
373*042d53a7SEvalZero 
374*042d53a7SEvalZero     if (!(conn->bhc_flags & BLE_HS_CONN_F_MASTER) &&
375*042d53a7SEvalZero             addrs->our_id_addr.type == BLE_ADDR_RANDOM) {
376*042d53a7SEvalZero         our_id_addr_val = conn->bhc_our_rnd_addr;
377*042d53a7SEvalZero     } else {
378*042d53a7SEvalZero         rc = ble_hs_id_addr(addrs->our_id_addr.type, &our_id_addr_val, NULL);
379*042d53a7SEvalZero         assert(rc == 0);
380*042d53a7SEvalZero     }
381*042d53a7SEvalZero #else
382*042d53a7SEvalZero     rc = ble_hs_id_addr(addrs->our_id_addr.type, &our_id_addr_val, NULL);
383*042d53a7SEvalZero     assert(rc == 0);
384*042d53a7SEvalZero #endif
385*042d53a7SEvalZero 
386*042d53a7SEvalZero     memcpy(addrs->our_id_addr.val, our_id_addr_val, 6);
387*042d53a7SEvalZero 
388*042d53a7SEvalZero     if (memcmp(conn->bhc_our_rpa_addr.val, ble_hs_conn_null_addr, 6) == 0) {
389*042d53a7SEvalZero         addrs->our_ota_addr = addrs->our_id_addr;
390*042d53a7SEvalZero     } else {
391*042d53a7SEvalZero         addrs->our_ota_addr = conn->bhc_our_rpa_addr;
392*042d53a7SEvalZero     }
393*042d53a7SEvalZero 
394*042d53a7SEvalZero     /* Determine peer address information. */
395*042d53a7SEvalZero     addrs->peer_id_addr = conn->bhc_peer_addr;
396*042d53a7SEvalZero     addrs->peer_ota_addr = conn->bhc_peer_addr;
397*042d53a7SEvalZero     switch (conn->bhc_peer_addr.type) {
398*042d53a7SEvalZero     case BLE_ADDR_PUBLIC:
399*042d53a7SEvalZero     case BLE_ADDR_RANDOM:
400*042d53a7SEvalZero         break;
401*042d53a7SEvalZero 
402*042d53a7SEvalZero     case BLE_ADDR_PUBLIC_ID:
403*042d53a7SEvalZero         addrs->peer_id_addr.type = BLE_ADDR_PUBLIC;
404*042d53a7SEvalZero         addrs->peer_ota_addr = conn->bhc_peer_rpa_addr;
405*042d53a7SEvalZero         break;
406*042d53a7SEvalZero 
407*042d53a7SEvalZero     case BLE_ADDR_RANDOM_ID:
408*042d53a7SEvalZero         addrs->peer_id_addr.type = BLE_ADDR_RANDOM;
409*042d53a7SEvalZero         addrs->peer_ota_addr = conn->bhc_peer_rpa_addr;
410*042d53a7SEvalZero         break;
411*042d53a7SEvalZero 
412*042d53a7SEvalZero     default:
413*042d53a7SEvalZero         BLE_HS_DBG_ASSERT(0);
414*042d53a7SEvalZero         break;
415*042d53a7SEvalZero     }
416*042d53a7SEvalZero }
417*042d53a7SEvalZero 
418*042d53a7SEvalZero int32_t
ble_hs_conn_timer(void)419*042d53a7SEvalZero ble_hs_conn_timer(void)
420*042d53a7SEvalZero {
421*042d53a7SEvalZero     /* If there are no timeouts configured, then there is nothing to check. */
422*042d53a7SEvalZero #if MYNEWT_VAL(BLE_L2CAP_RX_FRAG_TIMEOUT) == 0 && \
423*042d53a7SEvalZero     BLE_HS_ATT_SVR_QUEUED_WRITE_TMO == 0
424*042d53a7SEvalZero 
425*042d53a7SEvalZero     return BLE_HS_FOREVER;
426*042d53a7SEvalZero #endif
427*042d53a7SEvalZero 
428*042d53a7SEvalZero     struct ble_hs_conn *conn;
429*042d53a7SEvalZero     ble_npl_time_t now;
430*042d53a7SEvalZero     int32_t next_exp_in;
431*042d53a7SEvalZero     int32_t time_diff;
432*042d53a7SEvalZero     uint16_t conn_handle;
433*042d53a7SEvalZero 
434*042d53a7SEvalZero     conn_handle = BLE_HS_CONN_HANDLE_NONE;
435*042d53a7SEvalZero     next_exp_in = BLE_HS_FOREVER;
436*042d53a7SEvalZero     now = ble_npl_time_get();
437*042d53a7SEvalZero 
438*042d53a7SEvalZero     ble_hs_lock();
439*042d53a7SEvalZero 
440*042d53a7SEvalZero     /* This loop performs one of two tasks:
441*042d53a7SEvalZero      * 1. Determine if any connections need to be terminated due to timeout.
442*042d53a7SEvalZero      *    If so, break out of the loop and terminate the connection.  This
443*042d53a7SEvalZero      *    function will need to be executed again.
444*042d53a7SEvalZero      * 2. Otherwise, determine when the next timeout will occur.
445*042d53a7SEvalZero      */
446*042d53a7SEvalZero     SLIST_FOREACH(conn, &ble_hs_conns, bhc_next) {
447*042d53a7SEvalZero         if (!(conn->bhc_flags & BLE_HS_CONN_F_TERMINATING)) {
448*042d53a7SEvalZero 
449*042d53a7SEvalZero #if MYNEWT_VAL(BLE_L2CAP_RX_FRAG_TIMEOUT) != 0
450*042d53a7SEvalZero             /* Check each connection's rx fragment timer.  If too much time
451*042d53a7SEvalZero              * passes after a partial packet is received, the connection is
452*042d53a7SEvalZero              * terminated.
453*042d53a7SEvalZero              */
454*042d53a7SEvalZero             if (conn->bhc_rx_chan != NULL) {
455*042d53a7SEvalZero                 time_diff = conn->bhc_rx_timeout - now;
456*042d53a7SEvalZero 
457*042d53a7SEvalZero                 if (time_diff <= 0) {
458*042d53a7SEvalZero                     /* ACL reassembly has timed out.  Remember the connection
459*042d53a7SEvalZero                      * handle so it can be terminated after the mutex is
460*042d53a7SEvalZero                      * unlocked.
461*042d53a7SEvalZero                      */
462*042d53a7SEvalZero                     conn_handle = conn->bhc_handle;
463*042d53a7SEvalZero                     break;
464*042d53a7SEvalZero                 }
465*042d53a7SEvalZero 
466*042d53a7SEvalZero                 /* Determine if this connection is the soonest to time out. */
467*042d53a7SEvalZero                 if (time_diff < next_exp_in) {
468*042d53a7SEvalZero                     next_exp_in = time_diff;
469*042d53a7SEvalZero                 }
470*042d53a7SEvalZero             }
471*042d53a7SEvalZero #endif
472*042d53a7SEvalZero 
473*042d53a7SEvalZero #if BLE_HS_ATT_SVR_QUEUED_WRITE_TMO
474*042d53a7SEvalZero             /* Check each connection's rx queued write timer.  If too much
475*042d53a7SEvalZero              * time passes after a prep write is received, the queue is
476*042d53a7SEvalZero              * cleared.
477*042d53a7SEvalZero              */
478*042d53a7SEvalZero             time_diff = ble_att_svr_ticks_until_tmo(&conn->bhc_att_svr, now);
479*042d53a7SEvalZero             if (time_diff <= 0) {
480*042d53a7SEvalZero                 /* ACL reassembly has timed out.  Remember the connection
481*042d53a7SEvalZero                  * handle so it can be terminated after the mutex is
482*042d53a7SEvalZero                  * unlocked.
483*042d53a7SEvalZero                  */
484*042d53a7SEvalZero                 conn_handle = conn->bhc_handle;
485*042d53a7SEvalZero                 break;
486*042d53a7SEvalZero             }
487*042d53a7SEvalZero 
488*042d53a7SEvalZero             /* Determine if this connection is the soonest to time out. */
489*042d53a7SEvalZero             if (time_diff < next_exp_in) {
490*042d53a7SEvalZero                 next_exp_in = time_diff;
491*042d53a7SEvalZero             }
492*042d53a7SEvalZero #endif
493*042d53a7SEvalZero         }
494*042d53a7SEvalZero     }
495*042d53a7SEvalZero 
496*042d53a7SEvalZero     ble_hs_unlock();
497*042d53a7SEvalZero 
498*042d53a7SEvalZero     /* If a connection has timed out, terminate it.  We need to recursively
499*042d53a7SEvalZero      * call this function again to determine when the next timeout is.  This
500*042d53a7SEvalZero      * is a tail-recursive call, so it should be optimized to execute in the
501*042d53a7SEvalZero      * same stack frame.
502*042d53a7SEvalZero      */
503*042d53a7SEvalZero     if (conn_handle != BLE_HS_CONN_HANDLE_NONE) {
504*042d53a7SEvalZero         ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM);
505*042d53a7SEvalZero         return ble_hs_conn_timer();
506*042d53a7SEvalZero     }
507*042d53a7SEvalZero 
508*042d53a7SEvalZero     return next_exp_in;
509*042d53a7SEvalZero }
510*042d53a7SEvalZero 
511*042d53a7SEvalZero int
ble_hs_conn_init(void)512*042d53a7SEvalZero ble_hs_conn_init(void)
513*042d53a7SEvalZero {
514*042d53a7SEvalZero     int rc;
515*042d53a7SEvalZero 
516*042d53a7SEvalZero     rc = os_mempool_init(&ble_hs_conn_pool, MYNEWT_VAL(BLE_MAX_CONNECTIONS),
517*042d53a7SEvalZero                          sizeof (struct ble_hs_conn),
518*042d53a7SEvalZero                          ble_hs_conn_elem_mem, "ble_hs_conn_pool");
519*042d53a7SEvalZero     if (rc != 0) {
520*042d53a7SEvalZero         return BLE_HS_EOS;
521*042d53a7SEvalZero     }
522*042d53a7SEvalZero 
523*042d53a7SEvalZero     SLIST_INIT(&ble_hs_conns);
524*042d53a7SEvalZero 
525*042d53a7SEvalZero     return 0;
526*042d53a7SEvalZero }
527