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