xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/controller/src/ble_ll_conn_hci.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 <stdint.h>
21*042d53a7SEvalZero #include <string.h>
22*042d53a7SEvalZero #include <assert.h>
23*042d53a7SEvalZero #include "syscfg/syscfg.h"
24*042d53a7SEvalZero #include "os/os.h"
25*042d53a7SEvalZero #include "nimble/ble.h"
26*042d53a7SEvalZero #include "nimble/nimble_opt.h"
27*042d53a7SEvalZero #include "nimble/hci_common.h"
28*042d53a7SEvalZero #include "nimble/ble_hci_trans.h"
29*042d53a7SEvalZero #include "controller/ble_ll.h"
30*042d53a7SEvalZero #include "controller/ble_ll_hci.h"
31*042d53a7SEvalZero #include "controller/ble_ll_conn.h"
32*042d53a7SEvalZero #include "controller/ble_ll_ctrl.h"
33*042d53a7SEvalZero #include "controller/ble_ll_scan.h"
34*042d53a7SEvalZero #include "controller/ble_ll_adv.h"
35*042d53a7SEvalZero #include "ble_ll_conn_priv.h"
36*042d53a7SEvalZero 
37*042d53a7SEvalZero /*
38*042d53a7SEvalZero  * Used to limit the rate at which we send the number of completed packets
39*042d53a7SEvalZero  * event to the host. This is the os time at which we can send an event.
40*042d53a7SEvalZero  */
41*042d53a7SEvalZero static ble_npl_time_t g_ble_ll_last_num_comp_pkt_evt;
42*042d53a7SEvalZero extern uint8_t *g_ble_ll_conn_comp_ev;
43*042d53a7SEvalZero 
44*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
45*042d53a7SEvalZero static const uint8_t ble_ll_valid_conn_phy_mask = (BLE_HCI_LE_PHY_1M_PREF_MASK
46*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY)
47*042d53a7SEvalZero                                 | BLE_HCI_LE_PHY_2M_PREF_MASK
48*042d53a7SEvalZero #endif
49*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
50*042d53a7SEvalZero                                 | BLE_HCI_LE_PHY_CODED_PREF_MASK
51*042d53a7SEvalZero #endif
52*042d53a7SEvalZero                               );
53*042d53a7SEvalZero static const uint8_t ble_ll_conn_required_phy_mask = (BLE_HCI_LE_PHY_1M_PREF_MASK
54*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
55*042d53a7SEvalZero                             | BLE_HCI_LE_PHY_CODED_PREF_MASK
56*042d53a7SEvalZero #endif
57*042d53a7SEvalZero                             );
58*042d53a7SEvalZero #endif
59*042d53a7SEvalZero 
60*042d53a7SEvalZero /**
61*042d53a7SEvalZero  * Allocate an event to send a connection complete event when initiating
62*042d53a7SEvalZero  *
63*042d53a7SEvalZero  * @return int 0: success -1: failure
64*042d53a7SEvalZero  */
65*042d53a7SEvalZero static int
ble_ll_init_alloc_conn_comp_ev(void)66*042d53a7SEvalZero ble_ll_init_alloc_conn_comp_ev(void)
67*042d53a7SEvalZero {
68*042d53a7SEvalZero     int rc;
69*042d53a7SEvalZero     uint8_t *evbuf;
70*042d53a7SEvalZero 
71*042d53a7SEvalZero     rc = 0;
72*042d53a7SEvalZero     evbuf = g_ble_ll_conn_comp_ev;
73*042d53a7SEvalZero     if (evbuf == NULL) {
74*042d53a7SEvalZero         evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
75*042d53a7SEvalZero         if (!evbuf) {
76*042d53a7SEvalZero             rc = -1;
77*042d53a7SEvalZero         } else {
78*042d53a7SEvalZero             g_ble_ll_conn_comp_ev = evbuf;
79*042d53a7SEvalZero         }
80*042d53a7SEvalZero     }
81*042d53a7SEvalZero 
82*042d53a7SEvalZero     return rc;
83*042d53a7SEvalZero }
84*042d53a7SEvalZero 
85*042d53a7SEvalZero /**
86*042d53a7SEvalZero  * Called to check that the connection parameters are within range
87*042d53a7SEvalZero  *
88*042d53a7SEvalZero  * @param itvl_min
89*042d53a7SEvalZero  * @param itvl_max
90*042d53a7SEvalZero  * @param latency
91*042d53a7SEvalZero  * @param spvn_tmo
92*042d53a7SEvalZero  *
93*042d53a7SEvalZero  * @return int BLE_ERR_INV_HCI_CMD_PARMS if invalid parameters, 0 otherwise
94*042d53a7SEvalZero  */
95*042d53a7SEvalZero int
ble_ll_conn_hci_chk_conn_params(uint16_t itvl_min,uint16_t itvl_max,uint16_t latency,uint16_t spvn_tmo)96*042d53a7SEvalZero ble_ll_conn_hci_chk_conn_params(uint16_t itvl_min, uint16_t itvl_max,
97*042d53a7SEvalZero                                 uint16_t latency, uint16_t spvn_tmo)
98*042d53a7SEvalZero {
99*042d53a7SEvalZero     uint32_t spvn_tmo_usecs;
100*042d53a7SEvalZero     uint32_t min_spvn_tmo_usecs;
101*042d53a7SEvalZero 
102*042d53a7SEvalZero     if ((itvl_min > itvl_max) ||
103*042d53a7SEvalZero         (itvl_min < BLE_HCI_CONN_ITVL_MIN) ||
104*042d53a7SEvalZero         (itvl_max > BLE_HCI_CONN_ITVL_MAX) ||
105*042d53a7SEvalZero         (latency > BLE_HCI_CONN_LATENCY_MAX) ||
106*042d53a7SEvalZero         (spvn_tmo < BLE_HCI_CONN_SPVN_TIMEOUT_MIN) ||
107*042d53a7SEvalZero         (spvn_tmo > BLE_HCI_CONN_SPVN_TIMEOUT_MAX)) {
108*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
109*042d53a7SEvalZero     }
110*042d53a7SEvalZero 
111*042d53a7SEvalZero     /*
112*042d53a7SEvalZero     * Supervision timeout (in msecs) must be more than:
113*042d53a7SEvalZero     *  (1 + connLatency) * connIntervalMax * 1.25 msecs * 2.
114*042d53a7SEvalZero     */
115*042d53a7SEvalZero     spvn_tmo_usecs = spvn_tmo;
116*042d53a7SEvalZero     spvn_tmo_usecs *= (BLE_HCI_CONN_SPVN_TMO_UNITS * 1000);
117*042d53a7SEvalZero     min_spvn_tmo_usecs = (uint32_t)itvl_max * 2 * BLE_LL_CONN_ITVL_USECS;
118*042d53a7SEvalZero     min_spvn_tmo_usecs *= (1 + latency);
119*042d53a7SEvalZero     if (spvn_tmo_usecs <= min_spvn_tmo_usecs) {
120*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
121*042d53a7SEvalZero     }
122*042d53a7SEvalZero 
123*042d53a7SEvalZero     return BLE_ERR_SUCCESS;
124*042d53a7SEvalZero }
125*042d53a7SEvalZero 
126*042d53a7SEvalZero /**
127*042d53a7SEvalZero  * Send a connection complete event
128*042d53a7SEvalZero  *
129*042d53a7SEvalZero  * @param status The BLE error code associated with the event
130*042d53a7SEvalZero  */
131*042d53a7SEvalZero void
ble_ll_conn_comp_event_send(struct ble_ll_conn_sm * connsm,uint8_t status,uint8_t * evbuf,struct ble_ll_adv_sm * advsm)132*042d53a7SEvalZero ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status,
133*042d53a7SEvalZero                             uint8_t *evbuf, struct ble_ll_adv_sm *advsm)
134*042d53a7SEvalZero {
135*042d53a7SEvalZero     uint8_t peer_addr_type;
136*042d53a7SEvalZero     uint8_t enabled;
137*042d53a7SEvalZero     uint8_t enh_enabled;
138*042d53a7SEvalZero     uint8_t *evdata;
139*042d53a7SEvalZero     uint8_t *rpa;
140*042d53a7SEvalZero 
141*042d53a7SEvalZero     enabled = ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_CONN_COMPLETE);
142*042d53a7SEvalZero     enh_enabled = ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_ENH_CONN_COMPLETE);
143*042d53a7SEvalZero 
144*042d53a7SEvalZero     if (enabled || enh_enabled) {
145*042d53a7SEvalZero         /* Put common elements in event */
146*042d53a7SEvalZero         evbuf[0] = BLE_HCI_EVCODE_LE_META;
147*042d53a7SEvalZero         if (enh_enabled) {
148*042d53a7SEvalZero             evbuf[1] = BLE_HCI_LE_ENH_CONN_COMPLETE_LEN;
149*042d53a7SEvalZero             evbuf[2] = BLE_HCI_LE_SUBEV_ENH_CONN_COMPLETE;
150*042d53a7SEvalZero         } else {
151*042d53a7SEvalZero             evbuf[1] = BLE_HCI_LE_CONN_COMPLETE_LEN;
152*042d53a7SEvalZero             evbuf[2] = BLE_HCI_LE_SUBEV_CONN_COMPLETE;
153*042d53a7SEvalZero         }
154*042d53a7SEvalZero         evbuf[3] = status;
155*042d53a7SEvalZero 
156*042d53a7SEvalZero         if (connsm) {
157*042d53a7SEvalZero             put_le16(evbuf + 4, connsm->conn_handle);
158*042d53a7SEvalZero 
159*042d53a7SEvalZero             evbuf[6] = connsm->conn_role - 1;
160*042d53a7SEvalZero             peer_addr_type = connsm->peer_addr_type;
161*042d53a7SEvalZero 
162*042d53a7SEvalZero             evdata = evbuf + 14;
163*042d53a7SEvalZero             if (enh_enabled) {
164*042d53a7SEvalZero                 memset(evdata, 0, 2 * BLE_DEV_ADDR_LEN);
165*042d53a7SEvalZero                 if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
166*042d53a7SEvalZero                     if (connsm->inita_identity_used) {
167*042d53a7SEvalZero                         /* If it was direct advertising we were replying to and we used
168*042d53a7SEvalZero                          * identity address there (which might be just fine), we should
169*042d53a7SEvalZero                          * we should take it into account here in this event.
170*042d53a7SEvalZero                          */
171*042d53a7SEvalZero                         rpa = NULL;
172*042d53a7SEvalZero                     } else  if (connsm->own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) {
173*042d53a7SEvalZero                         rpa = ble_ll_scan_get_local_rpa();
174*042d53a7SEvalZero                     } else {
175*042d53a7SEvalZero                         rpa = NULL;
176*042d53a7SEvalZero                     }
177*042d53a7SEvalZero                 } else {
178*042d53a7SEvalZero                     rpa = ble_ll_adv_get_local_rpa(advsm);
179*042d53a7SEvalZero                 }
180*042d53a7SEvalZero                 if (rpa) {
181*042d53a7SEvalZero                     memcpy(evdata, rpa, BLE_DEV_ADDR_LEN);
182*042d53a7SEvalZero                 }
183*042d53a7SEvalZero 
184*042d53a7SEvalZero                 /* We need to adjust peer type if device connected using RPA
185*042d53a7SEvalZero                  * and was resolved since RPA needs to be added to HCI event.
186*042d53a7SEvalZero                  */
187*042d53a7SEvalZero                  if (connsm->peer_addr_type < BLE_HCI_CONN_PEER_ADDR_PUBLIC_IDENT
188*042d53a7SEvalZero                          && (connsm->rpa_index > -1)) {
189*042d53a7SEvalZero                      peer_addr_type += 2;
190*042d53a7SEvalZero                  }
191*042d53a7SEvalZero 
192*042d53a7SEvalZero                 if (peer_addr_type > BLE_HCI_CONN_PEER_ADDR_RANDOM) {
193*042d53a7SEvalZero                     if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
194*042d53a7SEvalZero                         rpa = ble_ll_scan_get_peer_rpa();
195*042d53a7SEvalZero                     } else {
196*042d53a7SEvalZero                         rpa = ble_ll_adv_get_peer_rpa(advsm);
197*042d53a7SEvalZero                     }
198*042d53a7SEvalZero                     memcpy(evdata + 6, rpa, BLE_DEV_ADDR_LEN);
199*042d53a7SEvalZero                 }
200*042d53a7SEvalZero                 evdata += 12;
201*042d53a7SEvalZero             } else {
202*042d53a7SEvalZero                 if (peer_addr_type > BLE_HCI_CONN_PEER_ADDR_RANDOM) {
203*042d53a7SEvalZero                     peer_addr_type -= 2;
204*042d53a7SEvalZero                 }
205*042d53a7SEvalZero             }
206*042d53a7SEvalZero 
207*042d53a7SEvalZero             evbuf[7] = peer_addr_type;
208*042d53a7SEvalZero             memcpy(evbuf + 8, connsm->peer_addr, BLE_DEV_ADDR_LEN);
209*042d53a7SEvalZero 
210*042d53a7SEvalZero             put_le16(evdata, connsm->conn_itvl);
211*042d53a7SEvalZero             put_le16(evdata + 2, connsm->slave_latency);
212*042d53a7SEvalZero             put_le16(evdata + 4, connsm->supervision_tmo);
213*042d53a7SEvalZero             evdata[6] = connsm->master_sca;
214*042d53a7SEvalZero         } else {
215*042d53a7SEvalZero             /* zero remaining bytes of event (2 bytes used for subevent opcode
216*042d53a7SEvalZero              * and status)
217*042d53a7SEvalZero              **/
218*042d53a7SEvalZero             memset(&evbuf[4], 0, evbuf[1] - 2);
219*042d53a7SEvalZero         }
220*042d53a7SEvalZero         ble_ll_hci_event_send(evbuf);
221*042d53a7SEvalZero     }
222*042d53a7SEvalZero }
223*042d53a7SEvalZero 
224*042d53a7SEvalZero 
225*042d53a7SEvalZero /**
226*042d53a7SEvalZero  * Called to create and send the number of completed packets event to the
227*042d53a7SEvalZero  * host.
228*042d53a7SEvalZero  */
229*042d53a7SEvalZero void
ble_ll_conn_num_comp_pkts_event_send(struct ble_ll_conn_sm * connsm)230*042d53a7SEvalZero ble_ll_conn_num_comp_pkts_event_send(struct ble_ll_conn_sm *connsm)
231*042d53a7SEvalZero {
232*042d53a7SEvalZero     /** The maximum number of handles that will fit in an event buffer. */
233*042d53a7SEvalZero     static const int max_handles =
234*042d53a7SEvalZero         (BLE_LL_MAX_EVT_LEN - BLE_HCI_EVENT_HDR_LEN - 1) / 4;
235*042d53a7SEvalZero 
236*042d53a7SEvalZero     int event_sent;
237*042d53a7SEvalZero     uint8_t *evbuf;
238*042d53a7SEvalZero     uint8_t *handle_ptr;
239*042d53a7SEvalZero     uint8_t handles;
240*042d53a7SEvalZero 
241*042d53a7SEvalZero     if (connsm == NULL) {
242*042d53a7SEvalZero         goto skip_conn;
243*042d53a7SEvalZero     }
244*042d53a7SEvalZero 
245*042d53a7SEvalZero     /*
246*042d53a7SEvalZero      * At some periodic rate, make sure we go through all active connections
247*042d53a7SEvalZero      * and send the number of completed packet events. We do this mainly
248*042d53a7SEvalZero      * because the spec says we must update the host even though no packets
249*042d53a7SEvalZero      * have completed but there are data packets in the controller buffers
250*042d53a7SEvalZero      * (i.e. enqueued in a connection state machine).
251*042d53a7SEvalZero      */
252*042d53a7SEvalZero     if ((ble_npl_stime_t)(ble_npl_time_get() - g_ble_ll_last_num_comp_pkt_evt) <
253*042d53a7SEvalZero                                             MYNEWT_VAL(BLE_NUM_COMP_PKT_RATE)) {
254*042d53a7SEvalZero         /*
255*042d53a7SEvalZero          * If this connection has completed packets, send an event right away.
256*042d53a7SEvalZero          * We do this to increase throughput but we dont want to search the
257*042d53a7SEvalZero          * entire active list every time.
258*042d53a7SEvalZero          */
259*042d53a7SEvalZero         if (connsm->completed_pkts) {
260*042d53a7SEvalZero             evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
261*042d53a7SEvalZero             if (evbuf) {
262*042d53a7SEvalZero                 evbuf[0] = BLE_HCI_EVCODE_NUM_COMP_PKTS;
263*042d53a7SEvalZero                 evbuf[1] = (2 * sizeof(uint16_t)) + 1;
264*042d53a7SEvalZero                 evbuf[2] = 1;
265*042d53a7SEvalZero                 put_le16(evbuf + 3, connsm->conn_handle);
266*042d53a7SEvalZero                 put_le16(evbuf + 5, connsm->completed_pkts);
267*042d53a7SEvalZero                 ble_ll_hci_event_send(evbuf);
268*042d53a7SEvalZero                 connsm->completed_pkts = 0;
269*042d53a7SEvalZero             }
270*042d53a7SEvalZero         }
271*042d53a7SEvalZero         return;
272*042d53a7SEvalZero     }
273*042d53a7SEvalZero 
274*042d53a7SEvalZero     /* Iterate through all the active, created connections */
275*042d53a7SEvalZero skip_conn:
276*042d53a7SEvalZero     evbuf = NULL;
277*042d53a7SEvalZero     handles = 0;
278*042d53a7SEvalZero     handle_ptr = NULL;
279*042d53a7SEvalZero     event_sent = 0;
280*042d53a7SEvalZero     SLIST_FOREACH(connsm, &g_ble_ll_conn_active_list, act_sle) {
281*042d53a7SEvalZero         /*
282*042d53a7SEvalZero          * Only look at connections that we have sent a connection complete
283*042d53a7SEvalZero          * event and that either has packets enqueued or has completed packets.
284*042d53a7SEvalZero          */
285*042d53a7SEvalZero         if ((connsm->conn_state != BLE_LL_CONN_STATE_IDLE) &&
286*042d53a7SEvalZero             (connsm->completed_pkts || !STAILQ_EMPTY(&connsm->conn_txq))) {
287*042d53a7SEvalZero             /* If no buffer, get one, If cant get one, leave. */
288*042d53a7SEvalZero             if (!evbuf) {
289*042d53a7SEvalZero                 evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
290*042d53a7SEvalZero                 if (!evbuf) {
291*042d53a7SEvalZero                     break;
292*042d53a7SEvalZero                 }
293*042d53a7SEvalZero                 handles = 0;
294*042d53a7SEvalZero                 handle_ptr = evbuf + 3;
295*042d53a7SEvalZero             }
296*042d53a7SEvalZero 
297*042d53a7SEvalZero             /* Add handle and complete packets */
298*042d53a7SEvalZero             put_le16(handle_ptr, connsm->conn_handle);
299*042d53a7SEvalZero             put_le16(handle_ptr + 2, connsm->completed_pkts);
300*042d53a7SEvalZero             connsm->completed_pkts = 0;
301*042d53a7SEvalZero             handle_ptr += (2 * sizeof(uint16_t));
302*042d53a7SEvalZero             ++handles;
303*042d53a7SEvalZero 
304*042d53a7SEvalZero             /* Send now if the buffer is full. */
305*042d53a7SEvalZero             if (handles == max_handles) {
306*042d53a7SEvalZero                 evbuf[0] = BLE_HCI_EVCODE_NUM_COMP_PKTS;
307*042d53a7SEvalZero                 evbuf[1] = (handles * 2 * sizeof(uint16_t)) + 1;
308*042d53a7SEvalZero                 evbuf[2] = handles;
309*042d53a7SEvalZero                 ble_ll_hci_event_send(evbuf);
310*042d53a7SEvalZero                 evbuf = NULL;
311*042d53a7SEvalZero                 handles = 0;
312*042d53a7SEvalZero                 event_sent = 1;
313*042d53a7SEvalZero             }
314*042d53a7SEvalZero         }
315*042d53a7SEvalZero     }
316*042d53a7SEvalZero 
317*042d53a7SEvalZero     /* Send event if there is an event to send */
318*042d53a7SEvalZero     if (evbuf) {
319*042d53a7SEvalZero         evbuf[0] = BLE_HCI_EVCODE_NUM_COMP_PKTS;
320*042d53a7SEvalZero         evbuf[1] = (handles * 2 * sizeof(uint16_t)) + 1;
321*042d53a7SEvalZero         evbuf[2] = handles;
322*042d53a7SEvalZero         ble_ll_hci_event_send(evbuf);
323*042d53a7SEvalZero         event_sent = 1;
324*042d53a7SEvalZero     }
325*042d53a7SEvalZero 
326*042d53a7SEvalZero     if (event_sent) {
327*042d53a7SEvalZero         g_ble_ll_last_num_comp_pkt_evt = ble_npl_time_get();
328*042d53a7SEvalZero     }
329*042d53a7SEvalZero }
330*042d53a7SEvalZero 
331*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) == 1)
332*042d53a7SEvalZero /**
333*042d53a7SEvalZero  * Send a authenticated payload timeout event
334*042d53a7SEvalZero  *
335*042d53a7SEvalZero  * NOTE: we currently only send this event when we have a reason to send it;
336*042d53a7SEvalZero  * not when it fails.
337*042d53a7SEvalZero  *
338*042d53a7SEvalZero  * @param reason The BLE error code to send as a disconnect reason
339*042d53a7SEvalZero  */
340*042d53a7SEvalZero void
ble_ll_auth_pyld_tmo_event_send(struct ble_ll_conn_sm * connsm)341*042d53a7SEvalZero ble_ll_auth_pyld_tmo_event_send(struct ble_ll_conn_sm *connsm)
342*042d53a7SEvalZero {
343*042d53a7SEvalZero     uint8_t *evbuf;
344*042d53a7SEvalZero 
345*042d53a7SEvalZero     if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_AUTH_PYLD_TMO)) {
346*042d53a7SEvalZero         evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
347*042d53a7SEvalZero         if (evbuf) {
348*042d53a7SEvalZero             evbuf[0] = BLE_HCI_EVCODE_AUTH_PYLD_TMO;
349*042d53a7SEvalZero             evbuf[1] = sizeof(uint16_t);
350*042d53a7SEvalZero             put_le16(evbuf + 2, connsm->conn_handle);
351*042d53a7SEvalZero             ble_ll_hci_event_send(evbuf);
352*042d53a7SEvalZero         }
353*042d53a7SEvalZero     }
354*042d53a7SEvalZero }
355*042d53a7SEvalZero #endif
356*042d53a7SEvalZero 
357*042d53a7SEvalZero /**
358*042d53a7SEvalZero  * Send a disconnection complete event.
359*042d53a7SEvalZero  *
360*042d53a7SEvalZero  * NOTE: we currently only send this event when we have a reason to send it;
361*042d53a7SEvalZero  * not when it fails.
362*042d53a7SEvalZero  *
363*042d53a7SEvalZero  * @param reason The BLE error code to send as a disconnect reason
364*042d53a7SEvalZero  */
365*042d53a7SEvalZero void
ble_ll_disconn_comp_event_send(struct ble_ll_conn_sm * connsm,uint8_t reason)366*042d53a7SEvalZero ble_ll_disconn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t reason)
367*042d53a7SEvalZero {
368*042d53a7SEvalZero     uint8_t *evbuf;
369*042d53a7SEvalZero 
370*042d53a7SEvalZero     if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_DISCONN_CMP)) {
371*042d53a7SEvalZero         evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
372*042d53a7SEvalZero         if (evbuf) {
373*042d53a7SEvalZero             evbuf[0] = BLE_HCI_EVCODE_DISCONN_CMP;
374*042d53a7SEvalZero             evbuf[1] = BLE_HCI_EVENT_DISCONN_COMPLETE_LEN;
375*042d53a7SEvalZero             evbuf[2] = BLE_ERR_SUCCESS;
376*042d53a7SEvalZero             put_le16(evbuf + 3, connsm->conn_handle);
377*042d53a7SEvalZero             evbuf[5] = reason;
378*042d53a7SEvalZero             ble_ll_hci_event_send(evbuf);
379*042d53a7SEvalZero         }
380*042d53a7SEvalZero     }
381*042d53a7SEvalZero }
382*042d53a7SEvalZero 
383*042d53a7SEvalZero static int
ble_ll_conn_hci_chk_scan_params(uint16_t itvl,uint16_t window)384*042d53a7SEvalZero ble_ll_conn_hci_chk_scan_params(uint16_t itvl, uint16_t window)
385*042d53a7SEvalZero {
386*042d53a7SEvalZero     /* Check interval and window */
387*042d53a7SEvalZero     if ((itvl < BLE_HCI_SCAN_ITVL_MIN) ||
388*042d53a7SEvalZero         (itvl > BLE_HCI_SCAN_ITVL_MAX) ||
389*042d53a7SEvalZero         (window < BLE_HCI_SCAN_WINDOW_MIN) ||
390*042d53a7SEvalZero         (window > BLE_HCI_SCAN_WINDOW_MAX) ||
391*042d53a7SEvalZero         (itvl < window)) {
392*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
393*042d53a7SEvalZero     }
394*042d53a7SEvalZero 
395*042d53a7SEvalZero     return 0;
396*042d53a7SEvalZero }
397*042d53a7SEvalZero 
398*042d53a7SEvalZero /**
399*042d53a7SEvalZero  * Process the HCI command to create a connection.
400*042d53a7SEvalZero  *
401*042d53a7SEvalZero  * Context: Link Layer task (HCI command processing)
402*042d53a7SEvalZero  *
403*042d53a7SEvalZero  * @param cmdbuf
404*042d53a7SEvalZero  *
405*042d53a7SEvalZero  * @return int
406*042d53a7SEvalZero  */
407*042d53a7SEvalZero int
ble_ll_conn_create(uint8_t * cmdbuf)408*042d53a7SEvalZero ble_ll_conn_create(uint8_t *cmdbuf)
409*042d53a7SEvalZero {
410*042d53a7SEvalZero     int rc;
411*042d53a7SEvalZero     struct hci_create_conn ccdata;
412*042d53a7SEvalZero     struct hci_create_conn *hcc;
413*042d53a7SEvalZero     struct ble_ll_conn_sm *connsm;
414*042d53a7SEvalZero 
415*042d53a7SEvalZero     /* If we are already creating a connection we should leave */
416*042d53a7SEvalZero     if (g_ble_ll_conn_create_sm) {
417*042d53a7SEvalZero         return BLE_ERR_CMD_DISALLOWED;
418*042d53a7SEvalZero     }
419*042d53a7SEvalZero 
420*042d53a7SEvalZero     /* If already enabled, we return an error */
421*042d53a7SEvalZero     if (ble_ll_scan_enabled()) {
422*042d53a7SEvalZero         return BLE_ERR_CMD_DISALLOWED;
423*042d53a7SEvalZero     }
424*042d53a7SEvalZero 
425*042d53a7SEvalZero     /* Retrieve command data */
426*042d53a7SEvalZero     hcc = &ccdata;
427*042d53a7SEvalZero     hcc->scan_itvl = get_le16(cmdbuf);
428*042d53a7SEvalZero     hcc->scan_window = get_le16(cmdbuf + 2);
429*042d53a7SEvalZero 
430*042d53a7SEvalZero     rc = ble_ll_conn_hci_chk_scan_params(hcc->scan_itvl, hcc->scan_window);
431*042d53a7SEvalZero     if (rc) {
432*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
433*042d53a7SEvalZero     }
434*042d53a7SEvalZero 
435*042d53a7SEvalZero     /* Check filter policy */
436*042d53a7SEvalZero     hcc->filter_policy = cmdbuf[4];
437*042d53a7SEvalZero     if (hcc->filter_policy > BLE_HCI_INITIATOR_FILT_POLICY_MAX) {
438*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
439*042d53a7SEvalZero     }
440*042d53a7SEvalZero 
441*042d53a7SEvalZero     /* Get peer address type and address only if no whitelist used */
442*042d53a7SEvalZero     if (hcc->filter_policy == 0) {
443*042d53a7SEvalZero         hcc->peer_addr_type = cmdbuf[5];
444*042d53a7SEvalZero         if (hcc->peer_addr_type > BLE_HCI_CONN_PEER_ADDR_MAX) {
445*042d53a7SEvalZero             return BLE_ERR_INV_HCI_CMD_PARMS;
446*042d53a7SEvalZero         }
447*042d53a7SEvalZero 
448*042d53a7SEvalZero         memcpy(&hcc->peer_addr, cmdbuf + 6, BLE_DEV_ADDR_LEN);
449*042d53a7SEvalZero     }
450*042d53a7SEvalZero 
451*042d53a7SEvalZero     /* Get own address type (used in connection request) */
452*042d53a7SEvalZero     hcc->own_addr_type = cmdbuf[12];
453*042d53a7SEvalZero     if (hcc->own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) {
454*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
455*042d53a7SEvalZero     }
456*042d53a7SEvalZero 
457*042d53a7SEvalZero     /* Check connection interval, latency and supervision timeoout */
458*042d53a7SEvalZero     hcc->conn_itvl_min = get_le16(cmdbuf + 13);
459*042d53a7SEvalZero     hcc->conn_itvl_max = get_le16(cmdbuf + 15);
460*042d53a7SEvalZero     hcc->conn_latency = get_le16(cmdbuf + 17);
461*042d53a7SEvalZero     hcc->supervision_timeout = get_le16(cmdbuf + 19);
462*042d53a7SEvalZero     rc = ble_ll_conn_hci_chk_conn_params(hcc->conn_itvl_min,
463*042d53a7SEvalZero                                          hcc->conn_itvl_max,
464*042d53a7SEvalZero                                          hcc->conn_latency,
465*042d53a7SEvalZero                                          hcc->supervision_timeout);
466*042d53a7SEvalZero     if (rc) {
467*042d53a7SEvalZero         return rc;
468*042d53a7SEvalZero     }
469*042d53a7SEvalZero 
470*042d53a7SEvalZero     /* Min/max connection event lengths */
471*042d53a7SEvalZero     hcc->min_ce_len = get_le16(cmdbuf + 21);
472*042d53a7SEvalZero     hcc->max_ce_len = get_le16(cmdbuf + 23);
473*042d53a7SEvalZero     if (hcc->min_ce_len > hcc->max_ce_len) {
474*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
475*042d53a7SEvalZero     }
476*042d53a7SEvalZero 
477*042d53a7SEvalZero     /* Make sure we can allocate an event to send the connection complete */
478*042d53a7SEvalZero     if (ble_ll_init_alloc_conn_comp_ev()) {
479*042d53a7SEvalZero         return BLE_ERR_MEM_CAPACITY;
480*042d53a7SEvalZero     }
481*042d53a7SEvalZero 
482*042d53a7SEvalZero     /* Make sure we can accept a connection! */
483*042d53a7SEvalZero     connsm = ble_ll_conn_sm_get();
484*042d53a7SEvalZero     if (connsm == NULL) {
485*042d53a7SEvalZero         return BLE_ERR_CONN_LIMIT;
486*042d53a7SEvalZero     }
487*042d53a7SEvalZero 
488*042d53a7SEvalZero     /* Initialize state machine in master role and start state machine */
489*042d53a7SEvalZero     ble_ll_conn_master_init(connsm, hcc);
490*042d53a7SEvalZero     ble_ll_conn_sm_new(connsm);
491*042d53a7SEvalZero     /* CSA will be selected when advertising is received */
492*042d53a7SEvalZero 
493*042d53a7SEvalZero     /* Start scanning */
494*042d53a7SEvalZero     rc = ble_ll_scan_initiator_start(hcc, &connsm->scansm);
495*042d53a7SEvalZero     if (rc) {
496*042d53a7SEvalZero         SLIST_REMOVE(&g_ble_ll_conn_active_list,connsm,ble_ll_conn_sm,act_sle);
497*042d53a7SEvalZero         STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe);
498*042d53a7SEvalZero     } else {
499*042d53a7SEvalZero         /* Set the connection state machine we are trying to create. */
500*042d53a7SEvalZero         g_ble_ll_conn_create_sm = connsm;
501*042d53a7SEvalZero     }
502*042d53a7SEvalZero 
503*042d53a7SEvalZero     return rc;
504*042d53a7SEvalZero }
505*042d53a7SEvalZero 
506*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
507*042d53a7SEvalZero static void
ble_ll_conn_init_hcc_params(struct hci_ext_create_conn * hcc,int valid_param_idx)508*042d53a7SEvalZero ble_ll_conn_init_hcc_params(struct hci_ext_create_conn *hcc,
509*042d53a7SEvalZero                             int valid_param_idx)
510*042d53a7SEvalZero {
511*042d53a7SEvalZero     struct hci_ext_conn_params *hcc_params = &hcc->params[valid_param_idx];
512*042d53a7SEvalZero 
513*042d53a7SEvalZero     if (valid_param_idx != 0 && !(hcc->init_phy_mask & BLE_PHY_MASK_1M)) {
514*042d53a7SEvalZero         hcc->params[0] = *hcc_params;
515*042d53a7SEvalZero     }
516*042d53a7SEvalZero 
517*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY)
518*042d53a7SEvalZero     if (valid_param_idx != 1 && !(hcc->init_phy_mask & BLE_PHY_MASK_2M)) {
519*042d53a7SEvalZero         hcc->params[1] = *hcc_params;
520*042d53a7SEvalZero     }
521*042d53a7SEvalZero #endif
522*042d53a7SEvalZero 
523*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
524*042d53a7SEvalZero     if (valid_param_idx != 2 && !(hcc->init_phy_mask & BLE_PHY_MASK_CODED)) {
525*042d53a7SEvalZero         hcc->params[2] = *hcc_params;
526*042d53a7SEvalZero     }
527*042d53a7SEvalZero #endif
528*042d53a7SEvalZero }
529*042d53a7SEvalZero 
530*042d53a7SEvalZero int
ble_ll_ext_conn_create(uint8_t * cmdbuf,uint8_t cmdlen)531*042d53a7SEvalZero ble_ll_ext_conn_create(uint8_t *cmdbuf, uint8_t cmdlen)
532*042d53a7SEvalZero {
533*042d53a7SEvalZero     int rc;
534*042d53a7SEvalZero     struct hci_ext_create_conn ccdata;
535*042d53a7SEvalZero     struct hci_ext_create_conn *hcc;
536*042d53a7SEvalZero     struct hci_ext_conn_params *hcc_params;
537*042d53a7SEvalZero     struct ble_ll_conn_sm *connsm;
538*042d53a7SEvalZero     int valid_param_idx = -1;
539*042d53a7SEvalZero     int iter;
540*042d53a7SEvalZero 
541*042d53a7SEvalZero     /* validate length */
542*042d53a7SEvalZero     if (cmdlen < 10) {
543*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
544*042d53a7SEvalZero     }
545*042d53a7SEvalZero 
546*042d53a7SEvalZero     /* If we are already creating a connection we should leave */
547*042d53a7SEvalZero     if (g_ble_ll_conn_create_sm) {
548*042d53a7SEvalZero         return BLE_ERR_CMD_DISALLOWED;
549*042d53a7SEvalZero     }
550*042d53a7SEvalZero 
551*042d53a7SEvalZero     /* If already enabled, we return an error */
552*042d53a7SEvalZero     if (ble_ll_scan_enabled()) {
553*042d53a7SEvalZero         return BLE_ERR_CMD_DISALLOWED;
554*042d53a7SEvalZero     }
555*042d53a7SEvalZero 
556*042d53a7SEvalZero     /* Retrieve command data */
557*042d53a7SEvalZero     hcc = &ccdata;
558*042d53a7SEvalZero     memset (hcc, 0, sizeof(*hcc));
559*042d53a7SEvalZero 
560*042d53a7SEvalZero     /* Check filter policy */
561*042d53a7SEvalZero     hcc->filter_policy = cmdbuf[0];
562*042d53a7SEvalZero     if (hcc->filter_policy > BLE_HCI_INITIATOR_FILT_POLICY_MAX) {
563*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
564*042d53a7SEvalZero     }
565*042d53a7SEvalZero 
566*042d53a7SEvalZero     /* Get own address type (used in connection request) */
567*042d53a7SEvalZero     hcc->own_addr_type = cmdbuf[1];
568*042d53a7SEvalZero     if (hcc->own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) {
569*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
570*042d53a7SEvalZero     }
571*042d53a7SEvalZero 
572*042d53a7SEvalZero     /* Get peer address type and address only if no whitelist used */
573*042d53a7SEvalZero     if (hcc->filter_policy == 0) {
574*042d53a7SEvalZero         hcc->peer_addr_type = cmdbuf[2];
575*042d53a7SEvalZero         if (hcc->peer_addr_type > BLE_HCI_CONN_PEER_ADDR_MAX) {
576*042d53a7SEvalZero             return BLE_ERR_INV_HCI_CMD_PARMS;
577*042d53a7SEvalZero         }
578*042d53a7SEvalZero 
579*042d53a7SEvalZero         memcpy(&hcc->peer_addr, cmdbuf + 3, BLE_DEV_ADDR_LEN);
580*042d53a7SEvalZero     }
581*042d53a7SEvalZero 
582*042d53a7SEvalZero     hcc->init_phy_mask = cmdbuf[9];
583*042d53a7SEvalZero     if (hcc->init_phy_mask & ~ble_ll_valid_conn_phy_mask) {
584*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
585*042d53a7SEvalZero     }
586*042d53a7SEvalZero 
587*042d53a7SEvalZero     if (!(hcc->init_phy_mask & ble_ll_conn_required_phy_mask)) {
588*042d53a7SEvalZero         /* At least one of those need to be set */
589*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
590*042d53a7SEvalZero     }
591*042d53a7SEvalZero 
592*042d53a7SEvalZero     iter = 10;
593*042d53a7SEvalZero     if (hcc->init_phy_mask & BLE_PHY_MASK_1M) {
594*042d53a7SEvalZero         /* validate length */
595*042d53a7SEvalZero         if (cmdlen < iter + 16) {
596*042d53a7SEvalZero             return BLE_ERR_INV_HCI_CMD_PARMS;
597*042d53a7SEvalZero         }
598*042d53a7SEvalZero 
599*042d53a7SEvalZero         hcc_params = &hcc->params[0];
600*042d53a7SEvalZero         hcc_params->scan_itvl = get_le16(cmdbuf + iter);
601*042d53a7SEvalZero         hcc_params->scan_window = get_le16(cmdbuf + iter + 2);
602*042d53a7SEvalZero         iter += 4;
603*042d53a7SEvalZero 
604*042d53a7SEvalZero         rc = ble_ll_conn_hci_chk_scan_params(hcc_params->scan_itvl,
605*042d53a7SEvalZero                                              hcc_params->scan_window);
606*042d53a7SEvalZero         if (rc) {
607*042d53a7SEvalZero             return rc;
608*042d53a7SEvalZero         }
609*042d53a7SEvalZero 
610*042d53a7SEvalZero         hcc_params->conn_itvl_min = get_le16(cmdbuf + iter);
611*042d53a7SEvalZero         hcc_params->conn_itvl_max = get_le16(cmdbuf + iter + 2);
612*042d53a7SEvalZero         hcc_params->conn_latency = get_le16(cmdbuf + iter + 4);
613*042d53a7SEvalZero         hcc_params->supervision_timeout = get_le16(cmdbuf + iter + 6);
614*042d53a7SEvalZero         rc = ble_ll_conn_hci_chk_conn_params(hcc_params->conn_itvl_min,
615*042d53a7SEvalZero                                              hcc_params->conn_itvl_max,
616*042d53a7SEvalZero                                              hcc_params->conn_latency,
617*042d53a7SEvalZero                                              hcc_params->supervision_timeout);
618*042d53a7SEvalZero         if (rc) {
619*042d53a7SEvalZero             return rc;
620*042d53a7SEvalZero         }
621*042d53a7SEvalZero         iter += 8;
622*042d53a7SEvalZero 
623*042d53a7SEvalZero         /* Min/max connection event lengths */
624*042d53a7SEvalZero         hcc_params->min_ce_len = get_le16(cmdbuf + iter);
625*042d53a7SEvalZero         hcc_params->max_ce_len = get_le16(cmdbuf + iter + 2);
626*042d53a7SEvalZero         if (hcc_params->min_ce_len > hcc_params->max_ce_len) {
627*042d53a7SEvalZero             return BLE_ERR_INV_HCI_CMD_PARMS;
628*042d53a7SEvalZero         }
629*042d53a7SEvalZero 
630*042d53a7SEvalZero         iter += 4;
631*042d53a7SEvalZero         valid_param_idx = 0;
632*042d53a7SEvalZero     }
633*042d53a7SEvalZero 
634*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY)
635*042d53a7SEvalZero     if (hcc->init_phy_mask & BLE_PHY_MASK_2M) {
636*042d53a7SEvalZero         /* validate length */
637*042d53a7SEvalZero         if (cmdlen < iter + 16) {
638*042d53a7SEvalZero             return BLE_ERR_INV_HCI_CMD_PARMS;
639*042d53a7SEvalZero         }
640*042d53a7SEvalZero 
641*042d53a7SEvalZero         /* Move to connection parameters */
642*042d53a7SEvalZero         hcc_params = &hcc->params[1];
643*042d53a7SEvalZero         iter += 4;
644*042d53a7SEvalZero 
645*042d53a7SEvalZero         hcc_params->conn_itvl_min = get_le16(cmdbuf + iter);
646*042d53a7SEvalZero         hcc_params->conn_itvl_max = get_le16(cmdbuf + iter + 2);
647*042d53a7SEvalZero         hcc_params->conn_latency = get_le16(cmdbuf + iter + 4);
648*042d53a7SEvalZero         hcc_params->supervision_timeout = get_le16(cmdbuf + iter + 6);
649*042d53a7SEvalZero         rc = ble_ll_conn_hci_chk_conn_params(hcc_params->conn_itvl_min,
650*042d53a7SEvalZero                                              hcc_params->conn_itvl_max,
651*042d53a7SEvalZero                                              hcc_params->conn_latency,
652*042d53a7SEvalZero                                              hcc_params->supervision_timeout);
653*042d53a7SEvalZero         if (rc) {
654*042d53a7SEvalZero             return rc;
655*042d53a7SEvalZero         }
656*042d53a7SEvalZero         iter += 8;
657*042d53a7SEvalZero 
658*042d53a7SEvalZero         /* Min/max connection event lengths */
659*042d53a7SEvalZero         hcc_params->min_ce_len = get_le16(cmdbuf + iter);
660*042d53a7SEvalZero         hcc_params->max_ce_len = get_le16(cmdbuf + iter + 2);
661*042d53a7SEvalZero         if (hcc_params->min_ce_len > hcc_params->max_ce_len) {
662*042d53a7SEvalZero             return BLE_ERR_INV_HCI_CMD_PARMS;
663*042d53a7SEvalZero         }
664*042d53a7SEvalZero 
665*042d53a7SEvalZero         iter += 4;
666*042d53a7SEvalZero     }
667*042d53a7SEvalZero #endif
668*042d53a7SEvalZero 
669*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
670*042d53a7SEvalZero     if (hcc->init_phy_mask & BLE_PHY_MASK_CODED) {
671*042d53a7SEvalZero         /* validate length */
672*042d53a7SEvalZero         if (cmdlen < iter + 16) {
673*042d53a7SEvalZero             return BLE_ERR_INV_HCI_CMD_PARMS;
674*042d53a7SEvalZero         }
675*042d53a7SEvalZero 
676*042d53a7SEvalZero         hcc_params = &hcc->params[2];
677*042d53a7SEvalZero         hcc_params->scan_itvl = get_le16(cmdbuf + iter);
678*042d53a7SEvalZero         hcc_params->scan_window = get_le16(cmdbuf + iter + 2);
679*042d53a7SEvalZero         iter += 4;
680*042d53a7SEvalZero 
681*042d53a7SEvalZero         rc = ble_ll_conn_hci_chk_scan_params(hcc_params->scan_itvl,
682*042d53a7SEvalZero                                              hcc_params->scan_window);
683*042d53a7SEvalZero         if (rc) {
684*042d53a7SEvalZero             return rc;
685*042d53a7SEvalZero         }
686*042d53a7SEvalZero 
687*042d53a7SEvalZero         hcc_params->conn_itvl_min = get_le16(cmdbuf + iter);
688*042d53a7SEvalZero         hcc_params->conn_itvl_max = get_le16(cmdbuf + iter + 2);
689*042d53a7SEvalZero         hcc_params->conn_latency = get_le16(cmdbuf + iter + 4);
690*042d53a7SEvalZero         hcc_params->supervision_timeout = get_le16(cmdbuf + iter + 6);
691*042d53a7SEvalZero         rc = ble_ll_conn_hci_chk_conn_params(hcc_params->conn_itvl_min,
692*042d53a7SEvalZero                                              hcc_params->conn_itvl_max,
693*042d53a7SEvalZero                                              hcc_params->conn_latency,
694*042d53a7SEvalZero                                              hcc_params->supervision_timeout);
695*042d53a7SEvalZero         if (rc) {
696*042d53a7SEvalZero             return rc;
697*042d53a7SEvalZero         }
698*042d53a7SEvalZero         iter += 8;
699*042d53a7SEvalZero 
700*042d53a7SEvalZero         /* Min/max connection event lengths */
701*042d53a7SEvalZero         hcc_params->min_ce_len = get_le16(cmdbuf + iter);
702*042d53a7SEvalZero         hcc_params->max_ce_len = get_le16(cmdbuf + iter + 2);
703*042d53a7SEvalZero         if (hcc_params->min_ce_len > hcc_params->max_ce_len) {
704*042d53a7SEvalZero             return BLE_ERR_INV_HCI_CMD_PARMS;
705*042d53a7SEvalZero         }
706*042d53a7SEvalZero 
707*042d53a7SEvalZero         iter += 4;
708*042d53a7SEvalZero         if (valid_param_idx < 0) {
709*042d53a7SEvalZero             valid_param_idx = 2;
710*042d53a7SEvalZero         }
711*042d53a7SEvalZero     }
712*042d53a7SEvalZero #endif
713*042d53a7SEvalZero 
714*042d53a7SEvalZero     /* Make sure we can allocate an event to send the connection complete */
715*042d53a7SEvalZero     if (ble_ll_init_alloc_conn_comp_ev()) {
716*042d53a7SEvalZero         return BLE_ERR_MEM_CAPACITY;
717*042d53a7SEvalZero     }
718*042d53a7SEvalZero 
719*042d53a7SEvalZero     /* Make sure we can accept a connection! */
720*042d53a7SEvalZero     connsm = ble_ll_conn_sm_get();
721*042d53a7SEvalZero     if (connsm == NULL) {
722*042d53a7SEvalZero         return BLE_ERR_CONN_LIMIT;
723*042d53a7SEvalZero     }
724*042d53a7SEvalZero 
725*042d53a7SEvalZero     ble_ll_conn_init_hcc_params(hcc, valid_param_idx);
726*042d53a7SEvalZero 
727*042d53a7SEvalZero     /* Initialize state machine in master role and start state machine */
728*042d53a7SEvalZero     ble_ll_conn_ext_master_init(connsm, hcc);
729*042d53a7SEvalZero     ble_ll_conn_sm_new(connsm);
730*042d53a7SEvalZero 
731*042d53a7SEvalZero     /* CSA will be selected when advertising is received */
732*042d53a7SEvalZero 
733*042d53a7SEvalZero     /* Start scanning */
734*042d53a7SEvalZero     rc = ble_ll_scan_ext_initiator_start(hcc, &connsm->scansm);
735*042d53a7SEvalZero     if (rc) {
736*042d53a7SEvalZero         SLIST_REMOVE(&g_ble_ll_conn_active_list,connsm,ble_ll_conn_sm,act_sle);
737*042d53a7SEvalZero         STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe);
738*042d53a7SEvalZero     } else {
739*042d53a7SEvalZero         /* Set the connection state machine we are trying to create. */
740*042d53a7SEvalZero         g_ble_ll_conn_create_sm = connsm;
741*042d53a7SEvalZero     }
742*042d53a7SEvalZero 
743*042d53a7SEvalZero     return rc;
744*042d53a7SEvalZero }
745*042d53a7SEvalZero #endif
746*042d53a7SEvalZero 
747*042d53a7SEvalZero static int
ble_ll_conn_process_conn_params(uint8_t * cmdbuf,struct ble_ll_conn_sm * connsm)748*042d53a7SEvalZero ble_ll_conn_process_conn_params(uint8_t *cmdbuf, struct ble_ll_conn_sm *connsm)
749*042d53a7SEvalZero {
750*042d53a7SEvalZero     int rc;
751*042d53a7SEvalZero     struct hci_conn_update *hcu;
752*042d53a7SEvalZero 
753*042d53a7SEvalZero     /* Retrieve command data */
754*042d53a7SEvalZero     hcu = &connsm->conn_param_req;
755*042d53a7SEvalZero     hcu->handle = connsm->conn_handle;
756*042d53a7SEvalZero     hcu->conn_itvl_min = get_le16(cmdbuf + 2);
757*042d53a7SEvalZero     hcu->conn_itvl_max = get_le16(cmdbuf + 4);
758*042d53a7SEvalZero     hcu->conn_latency = get_le16(cmdbuf + 6);
759*042d53a7SEvalZero     hcu->supervision_timeout = get_le16(cmdbuf + 8);
760*042d53a7SEvalZero     hcu->min_ce_len = get_le16(cmdbuf + 10);
761*042d53a7SEvalZero     hcu->max_ce_len = get_le16(cmdbuf + 12);
762*042d53a7SEvalZero 
763*042d53a7SEvalZero     /* Check that parameter values are in range */
764*042d53a7SEvalZero     rc = ble_ll_conn_hci_chk_conn_params(hcu->conn_itvl_min,
765*042d53a7SEvalZero                                          hcu->conn_itvl_max,
766*042d53a7SEvalZero                                          hcu->conn_latency,
767*042d53a7SEvalZero                                          hcu->supervision_timeout);
768*042d53a7SEvalZero 
769*042d53a7SEvalZero     /* Check valid min/max ce length */
770*042d53a7SEvalZero     if (rc || (hcu->min_ce_len > hcu->max_ce_len)) {
771*042d53a7SEvalZero         hcu->handle = 0;
772*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
773*042d53a7SEvalZero     }
774*042d53a7SEvalZero     return rc;
775*042d53a7SEvalZero }
776*042d53a7SEvalZero 
777*042d53a7SEvalZero /**
778*042d53a7SEvalZero  * Called when the host issues the read remote features command
779*042d53a7SEvalZero  *
780*042d53a7SEvalZero  * @param cmdbuf
781*042d53a7SEvalZero  *
782*042d53a7SEvalZero  * @return int
783*042d53a7SEvalZero  */
784*042d53a7SEvalZero int
ble_ll_conn_hci_read_rem_features(uint8_t * cmdbuf)785*042d53a7SEvalZero ble_ll_conn_hci_read_rem_features(uint8_t *cmdbuf)
786*042d53a7SEvalZero {
787*042d53a7SEvalZero     uint16_t handle;
788*042d53a7SEvalZero     struct ble_ll_conn_sm *connsm;
789*042d53a7SEvalZero 
790*042d53a7SEvalZero     /* If no connection handle exit with error */
791*042d53a7SEvalZero     handle = get_le16(cmdbuf);
792*042d53a7SEvalZero     connsm = ble_ll_conn_find_active_conn(handle);
793*042d53a7SEvalZero     if (!connsm) {
794*042d53a7SEvalZero         return BLE_ERR_UNK_CONN_ID;
795*042d53a7SEvalZero     }
796*042d53a7SEvalZero 
797*042d53a7SEvalZero     /* If already pending exit with error */
798*042d53a7SEvalZero     if (connsm->csmflags.cfbit.pending_hci_rd_features) {
799*042d53a7SEvalZero         return BLE_ERR_CMD_DISALLOWED;
800*042d53a7SEvalZero     }
801*042d53a7SEvalZero 
802*042d53a7SEvalZero     /*
803*042d53a7SEvalZero      * Start control procedure if we did not receive peer's features and did not
804*042d53a7SEvalZero      * start procedure already.
805*042d53a7SEvalZero      */
806*042d53a7SEvalZero     if (!connsm->csmflags.cfbit.rxd_features &&
807*042d53a7SEvalZero                 !IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG)) {
808*042d53a7SEvalZero         if ((connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) &&
809*042d53a7SEvalZero             !(ble_ll_read_supp_features() & BLE_LL_FEAT_SLAVE_INIT)) {
810*042d53a7SEvalZero                 return BLE_ERR_CMD_DISALLOWED;
811*042d53a7SEvalZero         }
812*042d53a7SEvalZero 
813*042d53a7SEvalZero         ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG);
814*042d53a7SEvalZero     }
815*042d53a7SEvalZero 
816*042d53a7SEvalZero     connsm->csmflags.cfbit.pending_hci_rd_features = 1;
817*042d53a7SEvalZero 
818*042d53a7SEvalZero     return BLE_ERR_SUCCESS;
819*042d53a7SEvalZero }
820*042d53a7SEvalZero 
821*042d53a7SEvalZero /**
822*042d53a7SEvalZero  * Called to process a connection update command.
823*042d53a7SEvalZero  *
824*042d53a7SEvalZero  * @param cmdbuf
825*042d53a7SEvalZero  *
826*042d53a7SEvalZero  * @return int
827*042d53a7SEvalZero  */
828*042d53a7SEvalZero int
ble_ll_conn_hci_update(uint8_t * cmdbuf)829*042d53a7SEvalZero ble_ll_conn_hci_update(uint8_t *cmdbuf)
830*042d53a7SEvalZero {
831*042d53a7SEvalZero     int rc;
832*042d53a7SEvalZero     uint8_t ctrl_proc;
833*042d53a7SEvalZero     uint16_t handle;
834*042d53a7SEvalZero     struct ble_ll_conn_sm *connsm;
835*042d53a7SEvalZero     struct hci_conn_update *hcu;
836*042d53a7SEvalZero 
837*042d53a7SEvalZero     /*
838*042d53a7SEvalZero      * XXX: must deal with slave not supporting this feature and using
839*042d53a7SEvalZero      * conn update! Right now, we only check if WE support the connection
840*042d53a7SEvalZero      * parameters request procedure. We dont check if the remote does.
841*042d53a7SEvalZero      * We should also be able to deal with sending the parameter request,
842*042d53a7SEvalZero      * getting an UNKOWN_RSP ctrl pdu and resorting to use normal
843*042d53a7SEvalZero      * connection update procedure.
844*042d53a7SEvalZero      */
845*042d53a7SEvalZero 
846*042d53a7SEvalZero     /* If no connection handle exit with error */
847*042d53a7SEvalZero     handle = get_le16(cmdbuf);
848*042d53a7SEvalZero     connsm = ble_ll_conn_find_active_conn(handle);
849*042d53a7SEvalZero     if (!connsm) {
850*042d53a7SEvalZero         return BLE_ERR_UNK_CONN_ID;
851*042d53a7SEvalZero     }
852*042d53a7SEvalZero 
853*042d53a7SEvalZero     /* Better not have this procedure ongoing! */
854*042d53a7SEvalZero     if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ) ||
855*042d53a7SEvalZero         IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_UPDATE)) {
856*042d53a7SEvalZero         return BLE_ERR_CMD_DISALLOWED;
857*042d53a7SEvalZero     }
858*042d53a7SEvalZero 
859*042d53a7SEvalZero     /* See if this feature is supported on both sides */
860*042d53a7SEvalZero     if ((connsm->conn_features & BLE_LL_FEAT_CONN_PARM_REQ) == 0) {
861*042d53a7SEvalZero         if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
862*042d53a7SEvalZero             return BLE_ERR_UNSUPP_REM_FEATURE;
863*042d53a7SEvalZero         }
864*042d53a7SEvalZero         ctrl_proc = BLE_LL_CTRL_PROC_CONN_UPDATE;
865*042d53a7SEvalZero     } else {
866*042d53a7SEvalZero         ctrl_proc = BLE_LL_CTRL_PROC_CONN_PARAM_REQ;
867*042d53a7SEvalZero     }
868*042d53a7SEvalZero 
869*042d53a7SEvalZero     /*
870*042d53a7SEvalZero      * If we are a slave and the master has initiated the procedure already
871*042d53a7SEvalZero      * we should deny the slave request for now. If we are a master and the
872*042d53a7SEvalZero      * slave has initiated the procedure, we need to send a reject to the
873*042d53a7SEvalZero      * slave.
874*042d53a7SEvalZero      */
875*042d53a7SEvalZero     if (connsm->csmflags.cfbit.awaiting_host_reply) {
876*042d53a7SEvalZero         if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
877*042d53a7SEvalZero             return BLE_ERR_LMP_COLLISION;
878*042d53a7SEvalZero         } else {
879*042d53a7SEvalZero             connsm->csmflags.cfbit.awaiting_host_reply = 0;
880*042d53a7SEvalZero 
881*042d53a7SEvalZero             /* XXX: If this fails no reject ind will be sent! */
882*042d53a7SEvalZero             ble_ll_ctrl_reject_ind_send(connsm, connsm->host_reply_opcode,
883*042d53a7SEvalZero                                         BLE_ERR_LMP_COLLISION);
884*042d53a7SEvalZero         }
885*042d53a7SEvalZero     }
886*042d53a7SEvalZero 
887*042d53a7SEvalZero     /*
888*042d53a7SEvalZero      * If we are a slave and the master has initiated the channel map
889*042d53a7SEvalZero      * update procedure we should deny the slave request for now.
890*042d53a7SEvalZero      */
891*042d53a7SEvalZero     if (connsm->csmflags.cfbit.chanmap_update_scheduled) {
892*042d53a7SEvalZero         if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
893*042d53a7SEvalZero             return BLE_ERR_DIFF_TRANS_COLL;
894*042d53a7SEvalZero         }
895*042d53a7SEvalZero     }
896*042d53a7SEvalZero 
897*042d53a7SEvalZero     /* Retrieve command data */
898*042d53a7SEvalZero     hcu = &connsm->conn_param_req;
899*042d53a7SEvalZero     hcu->handle = handle;
900*042d53a7SEvalZero     hcu->conn_itvl_min = get_le16(cmdbuf + 2);
901*042d53a7SEvalZero     hcu->conn_itvl_max = get_le16(cmdbuf + 4);
902*042d53a7SEvalZero     hcu->conn_latency = get_le16(cmdbuf + 6);
903*042d53a7SEvalZero     hcu->supervision_timeout = get_le16(cmdbuf + 8);
904*042d53a7SEvalZero     hcu->min_ce_len = get_le16(cmdbuf + 10);
905*042d53a7SEvalZero     hcu->max_ce_len = get_le16(cmdbuf + 12);
906*042d53a7SEvalZero     if (hcu->min_ce_len > hcu->max_ce_len) {
907*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
908*042d53a7SEvalZero     }
909*042d53a7SEvalZero 
910*042d53a7SEvalZero     /* Check that parameter values are in range */
911*042d53a7SEvalZero     rc = ble_ll_conn_hci_chk_conn_params(hcu->conn_itvl_min,
912*042d53a7SEvalZero                                          hcu->conn_itvl_max,
913*042d53a7SEvalZero                                          hcu->conn_latency,
914*042d53a7SEvalZero                                          hcu->supervision_timeout);
915*042d53a7SEvalZero     if (!rc) {
916*042d53a7SEvalZero         /* Start the control procedure */
917*042d53a7SEvalZero         ble_ll_ctrl_proc_start(connsm, ctrl_proc);
918*042d53a7SEvalZero     }
919*042d53a7SEvalZero 
920*042d53a7SEvalZero     return rc;
921*042d53a7SEvalZero }
922*042d53a7SEvalZero 
923*042d53a7SEvalZero int
ble_ll_conn_hci_param_reply(uint8_t * cmdbuf,int positive_reply,uint8_t * rspbuf,uint8_t * rsplen)924*042d53a7SEvalZero ble_ll_conn_hci_param_reply(uint8_t *cmdbuf, int positive_reply,
925*042d53a7SEvalZero                             uint8_t *rspbuf, uint8_t *rsplen)
926*042d53a7SEvalZero {
927*042d53a7SEvalZero     int rc;
928*042d53a7SEvalZero     uint8_t ble_err;
929*042d53a7SEvalZero     uint8_t *dptr;
930*042d53a7SEvalZero     uint8_t rsp_opcode;
931*042d53a7SEvalZero     uint8_t len;
932*042d53a7SEvalZero     uint16_t handle;
933*042d53a7SEvalZero     struct os_mbuf *om;
934*042d53a7SEvalZero     struct ble_ll_conn_sm *connsm;
935*042d53a7SEvalZero 
936*042d53a7SEvalZero     handle = get_le16(cmdbuf);
937*042d53a7SEvalZero 
938*042d53a7SEvalZero     /* See if we support this feature */
939*042d53a7SEvalZero     if ((ble_ll_read_supp_features() & BLE_LL_FEAT_CONN_PARM_REQ) == 0) {
940*042d53a7SEvalZero         rc = BLE_ERR_UNKNOWN_HCI_CMD;
941*042d53a7SEvalZero         goto done;
942*042d53a7SEvalZero     }
943*042d53a7SEvalZero 
944*042d53a7SEvalZero     /* If we dont have a handle we cant do anything */
945*042d53a7SEvalZero     connsm = ble_ll_conn_find_active_conn(handle);
946*042d53a7SEvalZero     if (!connsm) {
947*042d53a7SEvalZero         rc = BLE_ERR_UNK_CONN_ID;
948*042d53a7SEvalZero         goto done;
949*042d53a7SEvalZero     }
950*042d53a7SEvalZero 
951*042d53a7SEvalZero     /* Make sure connection parameters are valid if this is a positive reply */
952*042d53a7SEvalZero     rc = BLE_ERR_SUCCESS;
953*042d53a7SEvalZero     ble_err = cmdbuf[2];
954*042d53a7SEvalZero     if (positive_reply) {
955*042d53a7SEvalZero         rc = ble_ll_conn_process_conn_params(cmdbuf, connsm);
956*042d53a7SEvalZero         if (rc) {
957*042d53a7SEvalZero             ble_err = BLE_ERR_CONN_PARMS;
958*042d53a7SEvalZero         }
959*042d53a7SEvalZero     }
960*042d53a7SEvalZero 
961*042d53a7SEvalZero     /* The connection should be awaiting a reply. If not, just discard */
962*042d53a7SEvalZero     if (connsm->csmflags.cfbit.awaiting_host_reply) {
963*042d53a7SEvalZero         /* Get a control packet buffer */
964*042d53a7SEvalZero         if (positive_reply && (rc == BLE_ERR_SUCCESS)) {
965*042d53a7SEvalZero             om = os_msys_get_pkthdr(BLE_LL_CTRL_MAX_PAYLOAD + 1,
966*042d53a7SEvalZero                                     sizeof(struct ble_mbuf_hdr));
967*042d53a7SEvalZero             if (om) {
968*042d53a7SEvalZero                 dptr = om->om_data;
969*042d53a7SEvalZero                 rsp_opcode = ble_ll_ctrl_conn_param_reply(connsm, dptr,
970*042d53a7SEvalZero                                                           &connsm->conn_cp);
971*042d53a7SEvalZero                 dptr[0] = rsp_opcode;
972*042d53a7SEvalZero                 len = g_ble_ll_ctrl_pkt_lengths[rsp_opcode] + 1;
973*042d53a7SEvalZero                 ble_ll_conn_enqueue_pkt(connsm, om, BLE_LL_LLID_CTRL, len);
974*042d53a7SEvalZero             }
975*042d53a7SEvalZero         } else {
976*042d53a7SEvalZero             /* XXX: check return code and deal */
977*042d53a7SEvalZero             ble_ll_ctrl_reject_ind_send(connsm, connsm->host_reply_opcode,
978*042d53a7SEvalZero                                         ble_err);
979*042d53a7SEvalZero         }
980*042d53a7SEvalZero         connsm->csmflags.cfbit.awaiting_host_reply = 0;
981*042d53a7SEvalZero 
982*042d53a7SEvalZero         /* XXX: if we cant get a buffer, what do we do? We need to remember
983*042d53a7SEvalZero          * reason if it was a negative reply. We also would need to have
984*042d53a7SEvalZero            some state to tell us this happened */
985*042d53a7SEvalZero     }
986*042d53a7SEvalZero 
987*042d53a7SEvalZero done:
988*042d53a7SEvalZero     put_le16(rspbuf, handle);
989*042d53a7SEvalZero     *rsplen = sizeof(uint16_t);
990*042d53a7SEvalZero     return rc;
991*042d53a7SEvalZero }
992*042d53a7SEvalZero 
993*042d53a7SEvalZero /* this is called from same context after cmd complete is send so it is
994*042d53a7SEvalZero  * safe to use g_ble_ll_conn_comp_ev
995*042d53a7SEvalZero  */
996*042d53a7SEvalZero static void
ble_ll_conn_hci_cancel_conn_complete_event(void)997*042d53a7SEvalZero ble_ll_conn_hci_cancel_conn_complete_event(void)
998*042d53a7SEvalZero {
999*042d53a7SEvalZero     BLE_LL_ASSERT(g_ble_ll_conn_comp_ev);
1000*042d53a7SEvalZero 
1001*042d53a7SEvalZero     ble_ll_conn_comp_event_send(NULL, BLE_ERR_UNK_CONN_ID,
1002*042d53a7SEvalZero                                 g_ble_ll_conn_comp_ev, NULL);
1003*042d53a7SEvalZero     g_ble_ll_conn_comp_ev = NULL;
1004*042d53a7SEvalZero }
1005*042d53a7SEvalZero 
1006*042d53a7SEvalZero /**
1007*042d53a7SEvalZero  * Called when HCI command to cancel a create connection command has been
1008*042d53a7SEvalZero  * received.
1009*042d53a7SEvalZero  *
1010*042d53a7SEvalZero  * Context: Link Layer (HCI command parser)
1011*042d53a7SEvalZero  *
1012*042d53a7SEvalZero  * @return int
1013*042d53a7SEvalZero  */
1014*042d53a7SEvalZero int
ble_ll_conn_create_cancel(ble_ll_hci_post_cmd_complete_cb * post_cmd_cb)1015*042d53a7SEvalZero ble_ll_conn_create_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb)
1016*042d53a7SEvalZero {
1017*042d53a7SEvalZero     int rc;
1018*042d53a7SEvalZero     struct ble_ll_conn_sm *connsm;
1019*042d53a7SEvalZero 
1020*042d53a7SEvalZero     /*
1021*042d53a7SEvalZero      * If we receive this command and we have not got a connection
1022*042d53a7SEvalZero      * create command, we have to return disallowed. The spec does not say
1023*042d53a7SEvalZero      * what happens if the connection has already been established. We
1024*042d53a7SEvalZero      * return disallowed as well
1025*042d53a7SEvalZero      */
1026*042d53a7SEvalZero     connsm = g_ble_ll_conn_create_sm;
1027*042d53a7SEvalZero     if (connsm && (connsm->conn_state == BLE_LL_CONN_STATE_IDLE)) {
1028*042d53a7SEvalZero         /* stop scanning and end the connection event */
1029*042d53a7SEvalZero         g_ble_ll_conn_create_sm = NULL;
1030*042d53a7SEvalZero         ble_ll_scan_sm_stop(1);
1031*042d53a7SEvalZero         ble_ll_conn_end(connsm, BLE_ERR_UNK_CONN_ID);
1032*042d53a7SEvalZero 
1033*042d53a7SEvalZero         *post_cmd_cb = ble_ll_conn_hci_cancel_conn_complete_event;
1034*042d53a7SEvalZero 
1035*042d53a7SEvalZero         rc = BLE_ERR_SUCCESS;
1036*042d53a7SEvalZero     } else {
1037*042d53a7SEvalZero         /* If we are not attempting to create a connection*/
1038*042d53a7SEvalZero         rc = BLE_ERR_CMD_DISALLOWED;
1039*042d53a7SEvalZero     }
1040*042d53a7SEvalZero 
1041*042d53a7SEvalZero     return rc;
1042*042d53a7SEvalZero }
1043*042d53a7SEvalZero 
1044*042d53a7SEvalZero /**
1045*042d53a7SEvalZero  * Called to process a HCI disconnect command
1046*042d53a7SEvalZero  *
1047*042d53a7SEvalZero  * Context: Link Layer task (HCI command parser).
1048*042d53a7SEvalZero  *
1049*042d53a7SEvalZero  * @param cmdbuf
1050*042d53a7SEvalZero  *
1051*042d53a7SEvalZero  * @return int
1052*042d53a7SEvalZero  */
1053*042d53a7SEvalZero int
ble_ll_conn_hci_disconnect_cmd(uint8_t * cmdbuf)1054*042d53a7SEvalZero ble_ll_conn_hci_disconnect_cmd(uint8_t *cmdbuf)
1055*042d53a7SEvalZero {
1056*042d53a7SEvalZero     int rc;
1057*042d53a7SEvalZero     uint8_t reason;
1058*042d53a7SEvalZero     uint16_t handle;
1059*042d53a7SEvalZero     struct ble_ll_conn_sm *connsm;
1060*042d53a7SEvalZero 
1061*042d53a7SEvalZero     /* Check for valid parameters */
1062*042d53a7SEvalZero     handle = get_le16(cmdbuf);
1063*042d53a7SEvalZero     reason = cmdbuf[2];
1064*042d53a7SEvalZero 
1065*042d53a7SEvalZero     rc = BLE_ERR_INV_HCI_CMD_PARMS;
1066*042d53a7SEvalZero     if (handle <= BLE_LL_CONN_MAX_CONN_HANDLE) {
1067*042d53a7SEvalZero         /* Make sure reason is valid */
1068*042d53a7SEvalZero         switch (reason) {
1069*042d53a7SEvalZero         case BLE_ERR_AUTH_FAIL:
1070*042d53a7SEvalZero         case BLE_ERR_REM_USER_CONN_TERM:
1071*042d53a7SEvalZero         case BLE_ERR_RD_CONN_TERM_RESRCS:
1072*042d53a7SEvalZero         case BLE_ERR_RD_CONN_TERM_PWROFF:
1073*042d53a7SEvalZero         case BLE_ERR_UNSUPP_REM_FEATURE:
1074*042d53a7SEvalZero         case BLE_ERR_UNIT_KEY_PAIRING:
1075*042d53a7SEvalZero         case BLE_ERR_CONN_PARMS:
1076*042d53a7SEvalZero             connsm = ble_ll_conn_find_active_conn(handle);
1077*042d53a7SEvalZero             if (connsm) {
1078*042d53a7SEvalZero                 /* Do not allow command if we are in process of disconnecting */
1079*042d53a7SEvalZero                 if (connsm->disconnect_reason) {
1080*042d53a7SEvalZero                     rc = BLE_ERR_CMD_DISALLOWED;
1081*042d53a7SEvalZero                 } else {
1082*042d53a7SEvalZero                     /* This control procedure better not be pending! */
1083*042d53a7SEvalZero                     BLE_LL_ASSERT(CONN_F_TERMINATE_STARTED(connsm) == 0);
1084*042d53a7SEvalZero 
1085*042d53a7SEvalZero                     /* Record the disconnect reason */
1086*042d53a7SEvalZero                     connsm->disconnect_reason = reason;
1087*042d53a7SEvalZero 
1088*042d53a7SEvalZero                     /* Start this control procedure */
1089*042d53a7SEvalZero                     ble_ll_ctrl_terminate_start(connsm);
1090*042d53a7SEvalZero 
1091*042d53a7SEvalZero                     rc = BLE_ERR_SUCCESS;
1092*042d53a7SEvalZero                 }
1093*042d53a7SEvalZero             } else {
1094*042d53a7SEvalZero                 rc = BLE_ERR_UNK_CONN_ID;
1095*042d53a7SEvalZero             }
1096*042d53a7SEvalZero             break;
1097*042d53a7SEvalZero         default:
1098*042d53a7SEvalZero             break;
1099*042d53a7SEvalZero         }
1100*042d53a7SEvalZero     }
1101*042d53a7SEvalZero 
1102*042d53a7SEvalZero     return rc;
1103*042d53a7SEvalZero }
1104*042d53a7SEvalZero 
1105*042d53a7SEvalZero /**
1106*042d53a7SEvalZero  * Called to process a HCI disconnect command
1107*042d53a7SEvalZero  *
1108*042d53a7SEvalZero  * Context: Link Layer task (HCI command parser).
1109*042d53a7SEvalZero  *
1110*042d53a7SEvalZero  * @param cmdbuf
1111*042d53a7SEvalZero  *
1112*042d53a7SEvalZero  * @return int
1113*042d53a7SEvalZero  */
1114*042d53a7SEvalZero int
ble_ll_conn_hci_rd_rem_ver_cmd(uint8_t * cmdbuf)1115*042d53a7SEvalZero ble_ll_conn_hci_rd_rem_ver_cmd(uint8_t *cmdbuf)
1116*042d53a7SEvalZero {
1117*042d53a7SEvalZero     uint16_t handle;
1118*042d53a7SEvalZero     struct ble_ll_conn_sm *connsm;
1119*042d53a7SEvalZero 
1120*042d53a7SEvalZero     /* Check for valid parameters */
1121*042d53a7SEvalZero     handle = get_le16(cmdbuf);
1122*042d53a7SEvalZero     connsm = ble_ll_conn_find_active_conn(handle);
1123*042d53a7SEvalZero     if (!connsm) {
1124*042d53a7SEvalZero         return BLE_ERR_UNK_CONN_ID;
1125*042d53a7SEvalZero     }
1126*042d53a7SEvalZero 
1127*042d53a7SEvalZero     /* Return error if in progress */
1128*042d53a7SEvalZero     if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_VERSION_XCHG)) {
1129*042d53a7SEvalZero         return BLE_ERR_CMD_DISALLOWED;
1130*042d53a7SEvalZero     }
1131*042d53a7SEvalZero 
1132*042d53a7SEvalZero     /*
1133*042d53a7SEvalZero      * Start this control procedure. If we have already done this control
1134*042d53a7SEvalZero      * procedure we set the pending bit so that the host gets an event because
1135*042d53a7SEvalZero      * it is obviously expecting one (or would not have sent the command).
1136*042d53a7SEvalZero      * NOTE: we cant just send the event here. That would cause the event to
1137*042d53a7SEvalZero      * be queued before the command status.
1138*042d53a7SEvalZero      */
1139*042d53a7SEvalZero     if (!connsm->csmflags.cfbit.version_ind_sent) {
1140*042d53a7SEvalZero         ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_VERSION_XCHG);
1141*042d53a7SEvalZero     } else {
1142*042d53a7SEvalZero         connsm->pending_ctrl_procs |= (1 << BLE_LL_CTRL_PROC_VERSION_XCHG);
1143*042d53a7SEvalZero     }
1144*042d53a7SEvalZero 
1145*042d53a7SEvalZero     return BLE_ERR_SUCCESS;
1146*042d53a7SEvalZero }
1147*042d53a7SEvalZero 
1148*042d53a7SEvalZero /**
1149*042d53a7SEvalZero  * Called to read the RSSI for a given connection handle
1150*042d53a7SEvalZero  *
1151*042d53a7SEvalZero  * @param cmdbuf
1152*042d53a7SEvalZero  * @param rspbuf
1153*042d53a7SEvalZero  * @param rsplen
1154*042d53a7SEvalZero  *
1155*042d53a7SEvalZero  * @return int
1156*042d53a7SEvalZero  */
1157*042d53a7SEvalZero int
ble_ll_conn_hci_rd_rssi(uint8_t * cmdbuf,uint8_t * rspbuf,uint8_t * rsplen)1158*042d53a7SEvalZero ble_ll_conn_hci_rd_rssi(uint8_t *cmdbuf, uint8_t *rspbuf, uint8_t *rsplen)
1159*042d53a7SEvalZero {
1160*042d53a7SEvalZero     int rc;
1161*042d53a7SEvalZero     int8_t rssi;
1162*042d53a7SEvalZero     uint16_t handle;
1163*042d53a7SEvalZero     struct ble_ll_conn_sm *connsm;
1164*042d53a7SEvalZero 
1165*042d53a7SEvalZero     handle = get_le16(cmdbuf);
1166*042d53a7SEvalZero     connsm = ble_ll_conn_find_active_conn(handle);
1167*042d53a7SEvalZero     if (!connsm) {
1168*042d53a7SEvalZero         rssi = 127;
1169*042d53a7SEvalZero         rc = BLE_ERR_UNK_CONN_ID;
1170*042d53a7SEvalZero     } else {
1171*042d53a7SEvalZero         rssi = connsm->conn_rssi;
1172*042d53a7SEvalZero         rc = BLE_ERR_SUCCESS;
1173*042d53a7SEvalZero     }
1174*042d53a7SEvalZero 
1175*042d53a7SEvalZero     put_le16(rspbuf, handle);
1176*042d53a7SEvalZero     rspbuf[2] = (uint8_t)rssi;
1177*042d53a7SEvalZero     *rsplen = 3;
1178*042d53a7SEvalZero 
1179*042d53a7SEvalZero     /* Place the RSSI of the connection into the response buffer */
1180*042d53a7SEvalZero     return rc;
1181*042d53a7SEvalZero }
1182*042d53a7SEvalZero 
1183*042d53a7SEvalZero /**
1184*042d53a7SEvalZero  * Called to read the current channel map of a connection
1185*042d53a7SEvalZero  *
1186*042d53a7SEvalZero  * @param cmdbuf
1187*042d53a7SEvalZero  * @param rspbuf
1188*042d53a7SEvalZero  * @param rsplen
1189*042d53a7SEvalZero  *
1190*042d53a7SEvalZero  * @return int
1191*042d53a7SEvalZero  */
1192*042d53a7SEvalZero int
ble_ll_conn_hci_rd_chan_map(uint8_t * cmdbuf,uint8_t * rspbuf,uint8_t * rsplen)1193*042d53a7SEvalZero ble_ll_conn_hci_rd_chan_map(uint8_t *cmdbuf, uint8_t *rspbuf, uint8_t *rsplen)
1194*042d53a7SEvalZero {
1195*042d53a7SEvalZero     int rc;
1196*042d53a7SEvalZero     uint16_t handle;
1197*042d53a7SEvalZero     struct ble_ll_conn_sm *connsm;
1198*042d53a7SEvalZero 
1199*042d53a7SEvalZero     handle = get_le16(cmdbuf);
1200*042d53a7SEvalZero     connsm = ble_ll_conn_find_active_conn(handle);
1201*042d53a7SEvalZero     if (!connsm) {
1202*042d53a7SEvalZero         rc = BLE_ERR_UNK_CONN_ID;
1203*042d53a7SEvalZero     } else {
1204*042d53a7SEvalZero         if (connsm->csmflags.cfbit.chanmap_update_scheduled) {
1205*042d53a7SEvalZero             memcpy(rspbuf + 2, &connsm->req_chanmap[0], BLE_LL_CONN_CHMAP_LEN);
1206*042d53a7SEvalZero         } else {
1207*042d53a7SEvalZero             memcpy(rspbuf + 2, &connsm->chanmap[0], BLE_LL_CONN_CHMAP_LEN);
1208*042d53a7SEvalZero         }
1209*042d53a7SEvalZero         rc = BLE_ERR_SUCCESS;
1210*042d53a7SEvalZero     }
1211*042d53a7SEvalZero 
1212*042d53a7SEvalZero     put_le16(rspbuf, handle);
1213*042d53a7SEvalZero     *rsplen = sizeof(uint16_t) + BLE_LL_CONN_CHMAP_LEN;
1214*042d53a7SEvalZero     return rc;
1215*042d53a7SEvalZero }
1216*042d53a7SEvalZero 
1217*042d53a7SEvalZero /**
1218*042d53a7SEvalZero  * Called when the host issues the LE command "set host channel classification"
1219*042d53a7SEvalZero  *
1220*042d53a7SEvalZero  * @param cmdbuf
1221*042d53a7SEvalZero  *
1222*042d53a7SEvalZero  * @return int
1223*042d53a7SEvalZero  */
1224*042d53a7SEvalZero int
ble_ll_conn_hci_set_chan_class(uint8_t * cmdbuf)1225*042d53a7SEvalZero ble_ll_conn_hci_set_chan_class(uint8_t *cmdbuf)
1226*042d53a7SEvalZero {
1227*042d53a7SEvalZero     int rc;
1228*042d53a7SEvalZero     uint8_t num_used_chans;
1229*042d53a7SEvalZero 
1230*042d53a7SEvalZero     /*
1231*042d53a7SEvalZero      * The HCI command states that the host is allowed to mask in just one
1232*042d53a7SEvalZero      * channel but the Link Layer needs minimum two channels to operate. So
1233*042d53a7SEvalZero      * I will not allow this command if there are less than 2 channels masked.
1234*042d53a7SEvalZero      */
1235*042d53a7SEvalZero     rc = BLE_ERR_SUCCESS;
1236*042d53a7SEvalZero     num_used_chans = ble_ll_conn_calc_used_chans(cmdbuf);
1237*042d53a7SEvalZero     if ((num_used_chans < 2) || ((cmdbuf[4] & 0xe0) != 0)) {
1238*042d53a7SEvalZero         rc = BLE_ERR_INV_HCI_CMD_PARMS;
1239*042d53a7SEvalZero     }
1240*042d53a7SEvalZero 
1241*042d53a7SEvalZero     /* Set the host channel mask */
1242*042d53a7SEvalZero     ble_ll_conn_set_global_chanmap(num_used_chans, cmdbuf);
1243*042d53a7SEvalZero     return rc;
1244*042d53a7SEvalZero }
1245*042d53a7SEvalZero 
1246*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) == 1)
1247*042d53a7SEvalZero int
ble_ll_conn_hci_set_data_len(uint8_t * cmdbuf,uint8_t * rspbuf,uint8_t * rsplen)1248*042d53a7SEvalZero ble_ll_conn_hci_set_data_len(uint8_t *cmdbuf, uint8_t *rspbuf, uint8_t *rsplen)
1249*042d53a7SEvalZero {
1250*042d53a7SEvalZero     int rc;
1251*042d53a7SEvalZero     uint16_t handle;
1252*042d53a7SEvalZero     uint16_t txoctets;
1253*042d53a7SEvalZero     uint16_t txtime;
1254*042d53a7SEvalZero     struct ble_ll_conn_sm *connsm;
1255*042d53a7SEvalZero 
1256*042d53a7SEvalZero     /* Find connection */
1257*042d53a7SEvalZero     handle = get_le16(cmdbuf);
1258*042d53a7SEvalZero     connsm = ble_ll_conn_find_active_conn(handle);
1259*042d53a7SEvalZero     if (!connsm) {
1260*042d53a7SEvalZero         rc = BLE_ERR_UNK_CONN_ID;
1261*042d53a7SEvalZero         goto done;
1262*042d53a7SEvalZero     }
1263*042d53a7SEvalZero 
1264*042d53a7SEvalZero     txoctets = get_le16(cmdbuf + 2);
1265*042d53a7SEvalZero     txtime = get_le16(cmdbuf + 4);
1266*042d53a7SEvalZero 
1267*042d53a7SEvalZero     /* Make sure it is valid */
1268*042d53a7SEvalZero     if (!ble_ll_chk_txrx_octets(txoctets) ||
1269*042d53a7SEvalZero         !ble_ll_chk_txrx_time(txtime)) {
1270*042d53a7SEvalZero         rc = BLE_ERR_INV_HCI_CMD_PARMS;
1271*042d53a7SEvalZero         goto done;
1272*042d53a7SEvalZero     }
1273*042d53a7SEvalZero 
1274*042d53a7SEvalZero     rc = BLE_ERR_SUCCESS;
1275*042d53a7SEvalZero     if (connsm->max_tx_time != txtime ||
1276*042d53a7SEvalZero         connsm->max_tx_octets != txoctets) {
1277*042d53a7SEvalZero 
1278*042d53a7SEvalZero         connsm->max_tx_time = txtime;
1279*042d53a7SEvalZero         connsm->max_tx_octets = txoctets;
1280*042d53a7SEvalZero 
1281*042d53a7SEvalZero         ble_ll_ctrl_initiate_dle(connsm);
1282*042d53a7SEvalZero     }
1283*042d53a7SEvalZero 
1284*042d53a7SEvalZero done:
1285*042d53a7SEvalZero     put_le16(rspbuf, handle);
1286*042d53a7SEvalZero     *rsplen = sizeof(uint16_t);
1287*042d53a7SEvalZero     return rc;
1288*042d53a7SEvalZero }
1289*042d53a7SEvalZero #endif
1290*042d53a7SEvalZero 
1291*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
1292*042d53a7SEvalZero /**
1293*042d53a7SEvalZero  * LE start encrypt command
1294*042d53a7SEvalZero  *
1295*042d53a7SEvalZero  * @param cmdbuf
1296*042d53a7SEvalZero  *
1297*042d53a7SEvalZero  * @return int
1298*042d53a7SEvalZero  */
1299*042d53a7SEvalZero int
ble_ll_conn_hci_le_start_encrypt(uint8_t * cmdbuf)1300*042d53a7SEvalZero ble_ll_conn_hci_le_start_encrypt(uint8_t *cmdbuf)
1301*042d53a7SEvalZero {
1302*042d53a7SEvalZero     int rc;
1303*042d53a7SEvalZero     uint16_t handle;
1304*042d53a7SEvalZero     struct ble_ll_conn_sm *connsm;
1305*042d53a7SEvalZero 
1306*042d53a7SEvalZero     handle = get_le16(cmdbuf);
1307*042d53a7SEvalZero     connsm = ble_ll_conn_find_active_conn(handle);
1308*042d53a7SEvalZero     if (!connsm) {
1309*042d53a7SEvalZero         rc = BLE_ERR_UNK_CONN_ID;
1310*042d53a7SEvalZero     } else if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
1311*042d53a7SEvalZero         rc = BLE_ERR_UNSPECIFIED;
1312*042d53a7SEvalZero     } else if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_ENCRYPT) {
1313*042d53a7SEvalZero         /*
1314*042d53a7SEvalZero          * The specification does not say what to do here but the host should
1315*042d53a7SEvalZero          * not be telling us to start encryption while we are in the process
1316*042d53a7SEvalZero          * of honoring a previous start encrypt.
1317*042d53a7SEvalZero          */
1318*042d53a7SEvalZero         rc = BLE_ERR_CMD_DISALLOWED;
1319*042d53a7SEvalZero     } else {
1320*042d53a7SEvalZero         /* Start the control procedure */
1321*042d53a7SEvalZero         connsm->enc_data.host_rand_num = get_le64(cmdbuf + 2);
1322*042d53a7SEvalZero         connsm->enc_data.enc_div = get_le16(cmdbuf + 10);
1323*042d53a7SEvalZero         swap_buf(connsm->enc_data.enc_block.key, cmdbuf + 12, 16);
1324*042d53a7SEvalZero         ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_ENCRYPT);
1325*042d53a7SEvalZero         rc = BLE_ERR_SUCCESS;
1326*042d53a7SEvalZero     }
1327*042d53a7SEvalZero 
1328*042d53a7SEvalZero     return rc;
1329*042d53a7SEvalZero }
1330*042d53a7SEvalZero 
1331*042d53a7SEvalZero /**
1332*042d53a7SEvalZero  * Called to process the LE long term key reply.
1333*042d53a7SEvalZero  *
1334*042d53a7SEvalZero  * Context: Link Layer Task.
1335*042d53a7SEvalZero  *
1336*042d53a7SEvalZero  * @param cmdbuf
1337*042d53a7SEvalZero  * @param rspbuf
1338*042d53a7SEvalZero  * @param ocf
1339*042d53a7SEvalZero  *
1340*042d53a7SEvalZero  * @return int
1341*042d53a7SEvalZero  */
1342*042d53a7SEvalZero int
ble_ll_conn_hci_le_ltk_reply(uint8_t * cmdbuf,uint8_t * rspbuf,uint8_t * rsplen)1343*042d53a7SEvalZero ble_ll_conn_hci_le_ltk_reply(uint8_t *cmdbuf, uint8_t *rspbuf, uint8_t *rsplen)
1344*042d53a7SEvalZero {
1345*042d53a7SEvalZero     int rc;
1346*042d53a7SEvalZero     uint16_t handle;
1347*042d53a7SEvalZero     struct ble_ll_conn_sm *connsm;
1348*042d53a7SEvalZero 
1349*042d53a7SEvalZero     /* Find connection handle */
1350*042d53a7SEvalZero     handle = get_le16(cmdbuf);
1351*042d53a7SEvalZero     connsm = ble_ll_conn_find_active_conn(handle);
1352*042d53a7SEvalZero     if (!connsm) {
1353*042d53a7SEvalZero         rc = BLE_ERR_UNK_CONN_ID;
1354*042d53a7SEvalZero         goto ltk_key_cmd_complete;
1355*042d53a7SEvalZero     }
1356*042d53a7SEvalZero 
1357*042d53a7SEvalZero     /* Should never get this if we are a master! */
1358*042d53a7SEvalZero     if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
1359*042d53a7SEvalZero         rc = BLE_ERR_UNSPECIFIED;
1360*042d53a7SEvalZero         goto ltk_key_cmd_complete;
1361*042d53a7SEvalZero     }
1362*042d53a7SEvalZero 
1363*042d53a7SEvalZero     /* The connection should be awaiting a reply. If not, just discard */
1364*042d53a7SEvalZero     if (connsm->enc_data.enc_state != CONN_ENC_S_LTK_REQ_WAIT) {
1365*042d53a7SEvalZero         rc = BLE_ERR_CMD_DISALLOWED;
1366*042d53a7SEvalZero         goto ltk_key_cmd_complete;
1367*042d53a7SEvalZero     }
1368*042d53a7SEvalZero 
1369*042d53a7SEvalZero     swap_buf(connsm->enc_data.enc_block.key, cmdbuf + 2, 16);
1370*042d53a7SEvalZero     ble_ll_calc_session_key(connsm);
1371*042d53a7SEvalZero     ble_ll_ctrl_start_enc_send(connsm);
1372*042d53a7SEvalZero     rc = BLE_ERR_SUCCESS;
1373*042d53a7SEvalZero 
1374*042d53a7SEvalZero ltk_key_cmd_complete:
1375*042d53a7SEvalZero     put_le16(rspbuf, handle);
1376*042d53a7SEvalZero     *rsplen = sizeof(uint16_t);
1377*042d53a7SEvalZero     return rc;
1378*042d53a7SEvalZero }
1379*042d53a7SEvalZero 
1380*042d53a7SEvalZero /**
1381*042d53a7SEvalZero  * Called to process the LE long term key negative reply.
1382*042d53a7SEvalZero  *
1383*042d53a7SEvalZero  * Context: Link Layer Task.
1384*042d53a7SEvalZero  *
1385*042d53a7SEvalZero  * @param cmdbuf
1386*042d53a7SEvalZero  * @param rspbuf
1387*042d53a7SEvalZero  * @param ocf
1388*042d53a7SEvalZero  *
1389*042d53a7SEvalZero  * @return int
1390*042d53a7SEvalZero  */
1391*042d53a7SEvalZero int
ble_ll_conn_hci_le_ltk_neg_reply(uint8_t * cmdbuf,uint8_t * rspbuf,uint8_t * rsplen)1392*042d53a7SEvalZero ble_ll_conn_hci_le_ltk_neg_reply(uint8_t *cmdbuf, uint8_t *rspbuf,
1393*042d53a7SEvalZero                                  uint8_t *rsplen)
1394*042d53a7SEvalZero {
1395*042d53a7SEvalZero     int rc;
1396*042d53a7SEvalZero     uint16_t handle;
1397*042d53a7SEvalZero     struct ble_ll_conn_sm *connsm;
1398*042d53a7SEvalZero 
1399*042d53a7SEvalZero     /* Find connection handle */
1400*042d53a7SEvalZero     handle = get_le16(cmdbuf);
1401*042d53a7SEvalZero     connsm = ble_ll_conn_find_active_conn(handle);
1402*042d53a7SEvalZero     if (!connsm) {
1403*042d53a7SEvalZero         rc = BLE_ERR_UNK_CONN_ID;
1404*042d53a7SEvalZero         goto ltk_key_cmd_complete;
1405*042d53a7SEvalZero     }
1406*042d53a7SEvalZero 
1407*042d53a7SEvalZero     /* Should never get this if we are a master! */
1408*042d53a7SEvalZero     if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
1409*042d53a7SEvalZero         rc = BLE_ERR_UNSPECIFIED;
1410*042d53a7SEvalZero         goto ltk_key_cmd_complete;
1411*042d53a7SEvalZero     }
1412*042d53a7SEvalZero 
1413*042d53a7SEvalZero     /* The connection should be awaiting a reply. If not, just discard */
1414*042d53a7SEvalZero     if (connsm->enc_data.enc_state != CONN_ENC_S_LTK_REQ_WAIT) {
1415*042d53a7SEvalZero         rc = BLE_ERR_CMD_DISALLOWED;
1416*042d53a7SEvalZero         goto ltk_key_cmd_complete;
1417*042d53a7SEvalZero     }
1418*042d53a7SEvalZero 
1419*042d53a7SEvalZero     /* We received a negative reply! Send REJECT_IND */
1420*042d53a7SEvalZero     ble_ll_ctrl_reject_ind_send(connsm, BLE_LL_CTRL_ENC_REQ,
1421*042d53a7SEvalZero                                 BLE_ERR_PINKEY_MISSING);
1422*042d53a7SEvalZero     connsm->enc_data.enc_state = CONN_ENC_S_LTK_NEG_REPLY;
1423*042d53a7SEvalZero 
1424*042d53a7SEvalZero     rc = BLE_ERR_SUCCESS;
1425*042d53a7SEvalZero 
1426*042d53a7SEvalZero ltk_key_cmd_complete:
1427*042d53a7SEvalZero     put_le16(rspbuf, handle);
1428*042d53a7SEvalZero     *rsplen = sizeof(uint16_t);
1429*042d53a7SEvalZero     return rc;
1430*042d53a7SEvalZero }
1431*042d53a7SEvalZero #endif
1432*042d53a7SEvalZero 
1433*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) == 1)
1434*042d53a7SEvalZero /**
1435*042d53a7SEvalZero  * Read authenticated payload timeout (OGF=3, OCF==0x007B)
1436*042d53a7SEvalZero  *
1437*042d53a7SEvalZero  * @param cmdbuf
1438*042d53a7SEvalZero  * @param rsplen
1439*042d53a7SEvalZero  *
1440*042d53a7SEvalZero  * @return int
1441*042d53a7SEvalZero  */
1442*042d53a7SEvalZero int
ble_ll_conn_hci_rd_auth_pyld_tmo(uint8_t * cmdbuf,uint8_t * rsp,uint8_t * rsplen)1443*042d53a7SEvalZero ble_ll_conn_hci_rd_auth_pyld_tmo(uint8_t *cmdbuf, uint8_t *rsp, uint8_t *rsplen)
1444*042d53a7SEvalZero {
1445*042d53a7SEvalZero     int rc;
1446*042d53a7SEvalZero     uint16_t handle;
1447*042d53a7SEvalZero     struct ble_ll_conn_sm *connsm;
1448*042d53a7SEvalZero 
1449*042d53a7SEvalZero     handle = get_le16(cmdbuf);
1450*042d53a7SEvalZero     connsm = ble_ll_conn_find_active_conn(handle);
1451*042d53a7SEvalZero     if (!connsm) {
1452*042d53a7SEvalZero         rc = BLE_ERR_UNK_CONN_ID;
1453*042d53a7SEvalZero     } else {
1454*042d53a7SEvalZero         put_le16(rsp + 2, connsm->auth_pyld_tmo);
1455*042d53a7SEvalZero         rc = BLE_ERR_SUCCESS;
1456*042d53a7SEvalZero     }
1457*042d53a7SEvalZero 
1458*042d53a7SEvalZero     put_le16(rsp, handle);
1459*042d53a7SEvalZero     *rsplen = BLE_HCI_RD_AUTH_PYLD_TMO_LEN;
1460*042d53a7SEvalZero     return rc;
1461*042d53a7SEvalZero }
1462*042d53a7SEvalZero 
1463*042d53a7SEvalZero /**
1464*042d53a7SEvalZero  * Write authenticated payload timeout (OGF=3, OCF=00x7C)
1465*042d53a7SEvalZero  *
1466*042d53a7SEvalZero  * @param cmdbuf
1467*042d53a7SEvalZero  * @param rsplen
1468*042d53a7SEvalZero  *
1469*042d53a7SEvalZero  * @return int
1470*042d53a7SEvalZero  */
1471*042d53a7SEvalZero int
ble_ll_conn_hci_wr_auth_pyld_tmo(uint8_t * cmdbuf,uint8_t * rsp,uint8_t * rsplen)1472*042d53a7SEvalZero ble_ll_conn_hci_wr_auth_pyld_tmo(uint8_t *cmdbuf, uint8_t *rsp, uint8_t *rsplen)
1473*042d53a7SEvalZero {
1474*042d53a7SEvalZero     int rc;
1475*042d53a7SEvalZero     uint16_t handle;
1476*042d53a7SEvalZero     uint16_t tmo;
1477*042d53a7SEvalZero     uint32_t min_tmo;
1478*042d53a7SEvalZero     struct ble_ll_conn_sm *connsm;
1479*042d53a7SEvalZero 
1480*042d53a7SEvalZero     rc = BLE_ERR_SUCCESS;
1481*042d53a7SEvalZero 
1482*042d53a7SEvalZero     handle = get_le16(cmdbuf);
1483*042d53a7SEvalZero     connsm = ble_ll_conn_find_active_conn(handle);
1484*042d53a7SEvalZero     if (!connsm) {
1485*042d53a7SEvalZero         rc = BLE_ERR_UNK_CONN_ID;
1486*042d53a7SEvalZero         goto wr_auth_exit;
1487*042d53a7SEvalZero     }
1488*042d53a7SEvalZero 
1489*042d53a7SEvalZero     /*
1490*042d53a7SEvalZero      * The timeout is in units of 10 msecs. We need to make sure that the
1491*042d53a7SEvalZero      * timeout is greater than or equal to connItvl * (1 + slaveLatency)
1492*042d53a7SEvalZero      */
1493*042d53a7SEvalZero     tmo = get_le16(cmdbuf + 2);
1494*042d53a7SEvalZero     min_tmo = (uint32_t)connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS;
1495*042d53a7SEvalZero     min_tmo *= (connsm->slave_latency + 1);
1496*042d53a7SEvalZero     min_tmo /= 10000;
1497*042d53a7SEvalZero 
1498*042d53a7SEvalZero     if (tmo < min_tmo) {
1499*042d53a7SEvalZero         rc = BLE_ERR_INV_HCI_CMD_PARMS;
1500*042d53a7SEvalZero     } else {
1501*042d53a7SEvalZero         connsm->auth_pyld_tmo = tmo;
1502*042d53a7SEvalZero         if (ble_npl_callout_is_active(&connsm->auth_pyld_timer)) {
1503*042d53a7SEvalZero             ble_ll_conn_auth_pyld_timer_start(connsm);
1504*042d53a7SEvalZero         }
1505*042d53a7SEvalZero     }
1506*042d53a7SEvalZero 
1507*042d53a7SEvalZero wr_auth_exit:
1508*042d53a7SEvalZero     put_le16(rsp, handle);
1509*042d53a7SEvalZero     *rsplen = BLE_HCI_WR_AUTH_PYLD_TMO_LEN;
1510*042d53a7SEvalZero     return rc;
1511*042d53a7SEvalZero }
1512*042d53a7SEvalZero #endif
1513*042d53a7SEvalZero 
1514*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
1515*042d53a7SEvalZero /**
1516*042d53a7SEvalZero  * Read current phy for connection (OGF=8, OCF==0x0030)
1517*042d53a7SEvalZero  *
1518*042d53a7SEvalZero  * @param cmdbuf
1519*042d53a7SEvalZero  * @param rsplen
1520*042d53a7SEvalZero  *
1521*042d53a7SEvalZero  * @return int
1522*042d53a7SEvalZero  */
1523*042d53a7SEvalZero int
ble_ll_conn_hci_le_rd_phy(uint8_t * cmdbuf,uint8_t * rsp,uint8_t * rsplen)1524*042d53a7SEvalZero ble_ll_conn_hci_le_rd_phy(uint8_t *cmdbuf, uint8_t *rsp, uint8_t *rsplen)
1525*042d53a7SEvalZero {
1526*042d53a7SEvalZero     int rc;
1527*042d53a7SEvalZero     uint16_t handle;
1528*042d53a7SEvalZero     struct ble_ll_conn_sm *connsm;
1529*042d53a7SEvalZero 
1530*042d53a7SEvalZero     handle = get_le16(cmdbuf);
1531*042d53a7SEvalZero     connsm = ble_ll_conn_find_active_conn(handle);
1532*042d53a7SEvalZero     if (!connsm) {
1533*042d53a7SEvalZero         rc = BLE_ERR_UNK_CONN_ID;
1534*042d53a7SEvalZero     } else {
1535*042d53a7SEvalZero         rsp[2] = connsm->phy_data.cur_tx_phy;
1536*042d53a7SEvalZero         rsp[3] = connsm->phy_data.cur_rx_phy;
1537*042d53a7SEvalZero         rc = BLE_ERR_SUCCESS;
1538*042d53a7SEvalZero     }
1539*042d53a7SEvalZero 
1540*042d53a7SEvalZero     put_le16(rsp, handle);
1541*042d53a7SEvalZero     *rsplen = BLE_HCI_LE_RD_PHY_RSPLEN;
1542*042d53a7SEvalZero     return rc;
1543*042d53a7SEvalZero }
1544*042d53a7SEvalZero 
1545*042d53a7SEvalZero /**
1546*042d53a7SEvalZero  * Set PHY preferences for connection
1547*042d53a7SEvalZero  *
1548*042d53a7SEvalZero  * @param cmdbuf
1549*042d53a7SEvalZero  *
1550*042d53a7SEvalZero  * @return int
1551*042d53a7SEvalZero  */
1552*042d53a7SEvalZero int
ble_ll_conn_hci_le_set_phy(uint8_t * cmdbuf)1553*042d53a7SEvalZero ble_ll_conn_hci_le_set_phy(uint8_t *cmdbuf)
1554*042d53a7SEvalZero {
1555*042d53a7SEvalZero     int rc;
1556*042d53a7SEvalZero     uint16_t phy_options;
1557*042d53a7SEvalZero     uint8_t tx_phys;
1558*042d53a7SEvalZero     uint8_t rx_phys;
1559*042d53a7SEvalZero     uint16_t handle;
1560*042d53a7SEvalZero     struct ble_ll_conn_sm *connsm;
1561*042d53a7SEvalZero 
1562*042d53a7SEvalZero     handle = get_le16(cmdbuf);
1563*042d53a7SEvalZero     connsm = ble_ll_conn_find_active_conn(handle);
1564*042d53a7SEvalZero     if (!connsm) {
1565*042d53a7SEvalZero         return BLE_ERR_UNK_CONN_ID;
1566*042d53a7SEvalZero     }
1567*042d53a7SEvalZero 
1568*042d53a7SEvalZero     /*
1569*042d53a7SEvalZero      * If host has requested a PHY update and we are not finished do
1570*042d53a7SEvalZero      * not allow another one
1571*042d53a7SEvalZero      */
1572*042d53a7SEvalZero     if (CONN_F_HOST_PHY_UPDATE(connsm)) {
1573*042d53a7SEvalZero         return BLE_ERR_CMD_DISALLOWED;
1574*042d53a7SEvalZero     }
1575*042d53a7SEvalZero 
1576*042d53a7SEvalZero     phy_options = get_le16(cmdbuf + 5);
1577*042d53a7SEvalZero     if (phy_options > BLE_HCI_LE_PHY_CODED_S8_PREF) {
1578*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
1579*042d53a7SEvalZero     }
1580*042d53a7SEvalZero 
1581*042d53a7SEvalZero     /* Check valid parameters */
1582*042d53a7SEvalZero     rc = ble_ll_hci_chk_phy_masks(cmdbuf + 2, &tx_phys, &rx_phys);
1583*042d53a7SEvalZero     if (rc) {
1584*042d53a7SEvalZero         goto phy_cmd_param_err;
1585*042d53a7SEvalZero     }
1586*042d53a7SEvalZero 
1587*042d53a7SEvalZero     connsm->phy_data.phy_options = phy_options & 0x03;
1588*042d53a7SEvalZero     connsm->phy_data.host_pref_tx_phys_mask = tx_phys,
1589*042d53a7SEvalZero     connsm->phy_data.host_pref_rx_phys_mask = rx_phys;
1590*042d53a7SEvalZero 
1591*042d53a7SEvalZero     /*
1592*042d53a7SEvalZero      * The host preferences override the default phy preferences. Currently,
1593*042d53a7SEvalZero      * the only reason the controller will initiate a procedure on its own
1594*042d53a7SEvalZero      * is due to the fact that the host set default preferences. So if there
1595*042d53a7SEvalZero      * is a pending control procedure and it has not yet started, we do not
1596*042d53a7SEvalZero      * need to perform the default controller procedure.
1597*042d53a7SEvalZero      */
1598*042d53a7SEvalZero     if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE)) {
1599*042d53a7SEvalZero         if (connsm->cur_ctrl_proc != BLE_LL_CTRL_PROC_PHY_UPDATE) {
1600*042d53a7SEvalZero             CONN_F_CTRLR_PHY_UPDATE(connsm) = 0;
1601*042d53a7SEvalZero         }
1602*042d53a7SEvalZero         CONN_F_HOST_PHY_UPDATE(connsm) = 1;
1603*042d53a7SEvalZero     } else {
1604*042d53a7SEvalZero         /*
1605*042d53a7SEvalZero          * We could be doing a peer-initiated PHY update procedure. If this
1606*042d53a7SEvalZero          * is the case the requested phy preferences will not both be 0. If
1607*042d53a7SEvalZero          * we are not done with a peer-initiated procedure we just set the
1608*042d53a7SEvalZero          * pending bit but do not start the control procedure.
1609*042d53a7SEvalZero          */
1610*042d53a7SEvalZero         if (CONN_F_PEER_PHY_UPDATE(connsm)) {
1611*042d53a7SEvalZero             connsm->pending_ctrl_procs |= BLE_LL_CTRL_PROC_PHY_UPDATE;
1612*042d53a7SEvalZero             CONN_F_HOST_PHY_UPDATE(connsm) = 1;
1613*042d53a7SEvalZero         } else {
1614*042d53a7SEvalZero             /* Check if we should start phy update procedure */
1615*042d53a7SEvalZero             if (!ble_ll_conn_chk_phy_upd_start(connsm)) {
1616*042d53a7SEvalZero                 CONN_F_HOST_PHY_UPDATE(connsm) = 1;
1617*042d53a7SEvalZero             } else {
1618*042d53a7SEvalZero                 /*
1619*042d53a7SEvalZero                  * Set flag to send a PHY update complete event. We set flag
1620*042d53a7SEvalZero                  * even if we do not do an update procedure since we have to
1621*042d53a7SEvalZero                  * inform the host even if we decide not to change anything.
1622*042d53a7SEvalZero                  */
1623*042d53a7SEvalZero                 CONN_F_PHY_UPDATE_EVENT(connsm) = 1;
1624*042d53a7SEvalZero             }
1625*042d53a7SEvalZero         }
1626*042d53a7SEvalZero     }
1627*042d53a7SEvalZero 
1628*042d53a7SEvalZero phy_cmd_param_err:
1629*042d53a7SEvalZero     return rc;
1630*042d53a7SEvalZero }
1631*042d53a7SEvalZero #endif
1632