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 #include <stdint.h>
20*042d53a7SEvalZero #include <assert.h>
21*042d53a7SEvalZero #include <string.h>
22*042d53a7SEvalZero #include "syscfg/syscfg.h"
23*042d53a7SEvalZero #include "nimble/ble.h"
24*042d53a7SEvalZero #include "nimble/nimble_opt.h"
25*042d53a7SEvalZero #include "nimble/hci_common.h"
26*042d53a7SEvalZero #include "controller/ble_ll.h"
27*042d53a7SEvalZero #include "controller/ble_ll_hci.h"
28*042d53a7SEvalZero #include "controller/ble_ll_ctrl.h"
29*042d53a7SEvalZero #include "controller/ble_ll_trace.h"
30*042d53a7SEvalZero #include "controller/ble_hw.h"
31*042d53a7SEvalZero #include "ble_ll_conn_priv.h"
32*042d53a7SEvalZero
33*042d53a7SEvalZero /* To use spec sample data for testing */
34*042d53a7SEvalZero #undef BLE_LL_ENCRYPT_USE_TEST_DATA
35*042d53a7SEvalZero
36*042d53a7SEvalZero /*
37*042d53a7SEvalZero * For console debug to show session key calculation. NOTE: if you define
38*042d53a7SEvalZero * this the stack requirements for the LL task go up considerably. The
39*042d53a7SEvalZero * default stack will not be enough and must be increased.
40*042d53a7SEvalZero */
41*042d53a7SEvalZero #undef BLE_LL_ENCRYPT_DEBUG
42*042d53a7SEvalZero #ifdef BLE_LL_ENCRYPT_DEBUG
43*042d53a7SEvalZero #include "console/console.h"
44*042d53a7SEvalZero #endif
45*042d53a7SEvalZero
46*042d53a7SEvalZero /*
47*042d53a7SEvalZero * XXX:
48*042d53a7SEvalZero * 1) Do I need to keep track of which procedures have already been done?
49*042d53a7SEvalZero * Do I need to worry about repeating procedures?
50*042d53a7SEvalZero * 2) Should we create pool of control pdu's?. Dont need more
51*042d53a7SEvalZero * than the # of connections and can probably deal with quite a few less
52*042d53a7SEvalZero * if we have lots of connections.
53*042d53a7SEvalZero * 3) What about procedures that have been completed but try to restart?
54*042d53a7SEvalZero * 4) NOTE: there is a supported features procedure. However, in the case
55*042d53a7SEvalZero * of data length extension, if the receiving device does not understand
56*042d53a7SEvalZero * the pdu or it does not support data length extension, the LL_UNKNOWN_RSP
57*042d53a7SEvalZero * pdu is sent. That needs to be processed...
58*042d53a7SEvalZero * 5) We are supposed to remember when we do the data length update proc if
59*042d53a7SEvalZero * the device sent us an unknown rsp. We should not send it another len req.
60*042d53a7SEvalZero * Implement this how? Through remote supported features?
61*042d53a7SEvalZero * 8) How to count control pdus sent. DO we count enqueued + sent, or only
62*042d53a7SEvalZero * sent (actually attempted to tx). Do we count failures? How?
63*042d53a7SEvalZero */
64*042d53a7SEvalZero
65*042d53a7SEvalZero /*
66*042d53a7SEvalZero * XXX: I definitely have an issue with control procedures and connection
67*042d53a7SEvalZero * param request procedure and connection update procedure. This was
68*042d53a7SEvalZero * noted when receiving an unknown response. Right now, I am getting confused
69*042d53a7SEvalZero * with connection parameter request and updates regarding which procedures
70*042d53a7SEvalZero * are running. So I need to go look through all the code and see where I
71*042d53a7SEvalZero * used the request procedure and the update procedure and make sure I am doing
72*042d53a7SEvalZero * the correct thing.
73*042d53a7SEvalZero */
74*042d53a7SEvalZero
75*042d53a7SEvalZero /*
76*042d53a7SEvalZero * This array contains the length of the CtrData field in LL control PDU's.
77*042d53a7SEvalZero * Note that there is a one byte opcode which precedes this field in the LL
78*042d53a7SEvalZero * control PDU, so total data channel payload length for the control pdu is
79*042d53a7SEvalZero * one greater.
80*042d53a7SEvalZero */
81*042d53a7SEvalZero const uint8_t g_ble_ll_ctrl_pkt_lengths[BLE_LL_CTRL_OPCODES] =
82*042d53a7SEvalZero {
83*042d53a7SEvalZero BLE_LL_CTRL_CONN_UPD_REQ_LEN,
84*042d53a7SEvalZero BLE_LL_CTRL_CHAN_MAP_LEN,
85*042d53a7SEvalZero BLE_LL_CTRL_TERMINATE_IND_LEN,
86*042d53a7SEvalZero BLE_LL_CTRL_ENC_REQ_LEN,
87*042d53a7SEvalZero BLE_LL_CTRL_ENC_RSP_LEN,
88*042d53a7SEvalZero BLE_LL_CTRL_START_ENC_REQ_LEN,
89*042d53a7SEvalZero BLE_LL_CTRL_START_ENC_RSP_LEN,
90*042d53a7SEvalZero BLE_LL_CTRL_UNK_RSP_LEN,
91*042d53a7SEvalZero BLE_LL_CTRL_FEATURE_LEN,
92*042d53a7SEvalZero BLE_LL_CTRL_FEATURE_LEN,
93*042d53a7SEvalZero BLE_LL_CTRL_PAUSE_ENC_REQ_LEN,
94*042d53a7SEvalZero BLE_LL_CTRL_PAUSE_ENC_RSP_LEN,
95*042d53a7SEvalZero BLE_LL_CTRL_VERSION_IND_LEN,
96*042d53a7SEvalZero BLE_LL_CTRL_REJ_IND_LEN,
97*042d53a7SEvalZero BLE_LL_CTRL_SLAVE_FEATURE_REQ_LEN,
98*042d53a7SEvalZero BLE_LL_CTRL_CONN_PARAMS_LEN,
99*042d53a7SEvalZero BLE_LL_CTRL_CONN_PARAMS_LEN,
100*042d53a7SEvalZero BLE_LL_CTRL_REJECT_IND_EXT_LEN,
101*042d53a7SEvalZero BLE_LL_CTRL_PING_LEN,
102*042d53a7SEvalZero BLE_LL_CTRL_PING_LEN,
103*042d53a7SEvalZero BLE_LL_CTRL_LENGTH_REQ_LEN,
104*042d53a7SEvalZero BLE_LL_CTRL_LENGTH_REQ_LEN,
105*042d53a7SEvalZero BLE_LL_CTRL_PHY_REQ_LEN,
106*042d53a7SEvalZero BLE_LL_CTRL_PHY_RSP_LEN,
107*042d53a7SEvalZero BLE_LL_CTRL_PHY_UPD_IND_LEN,
108*042d53a7SEvalZero BLE_LL_CTRL_MIN_USED_CHAN_LEN
109*042d53a7SEvalZero };
110*042d53a7SEvalZero
111*042d53a7SEvalZero /**
112*042d53a7SEvalZero * Called to determine if a LL control procedure with an instant has
113*042d53a7SEvalZero * been initiated.
114*042d53a7SEvalZero *
115*042d53a7SEvalZero * If the function returns a 0 it means no conflicting procedure has
116*042d53a7SEvalZero * been initiated. Otherwise it returns the appropriate BLE error code to
117*042d53a7SEvalZero * send.
118*042d53a7SEvalZero *
119*042d53a7SEvalZero * @param connsm Pointer to connection state machine.
120*042d53a7SEvalZero * @param req_ctrl_proc The procedure that the peer is trying to initiate
121*042d53a7SEvalZero *
122*042d53a7SEvalZero * @return uint8_t
123*042d53a7SEvalZero */
124*042d53a7SEvalZero uint8_t
ble_ll_ctrl_proc_with_instant_initiated(struct ble_ll_conn_sm * connsm,uint8_t req_ctrl_proc)125*042d53a7SEvalZero ble_ll_ctrl_proc_with_instant_initiated(struct ble_ll_conn_sm *connsm,
126*042d53a7SEvalZero uint8_t req_ctrl_proc)
127*042d53a7SEvalZero {
128*042d53a7SEvalZero uint8_t err;
129*042d53a7SEvalZero
130*042d53a7SEvalZero switch (connsm->cur_ctrl_proc) {
131*042d53a7SEvalZero case BLE_LL_CTRL_PROC_PHY_UPDATE:
132*042d53a7SEvalZero case BLE_LL_CTRL_PROC_CONN_UPDATE:
133*042d53a7SEvalZero case BLE_LL_CTRL_PROC_CONN_PARAM_REQ:
134*042d53a7SEvalZero case BLE_LL_CTRL_PROC_CHAN_MAP_UPD:
135*042d53a7SEvalZero if (req_ctrl_proc == connsm->cur_ctrl_proc) {
136*042d53a7SEvalZero err = BLE_ERR_LMP_COLLISION;
137*042d53a7SEvalZero } else if ((connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_CONN_UPDATE) &&
138*042d53a7SEvalZero (req_ctrl_proc == BLE_LL_CTRL_PROC_CONN_PARAM_REQ)) {
139*042d53a7SEvalZero err = BLE_ERR_LMP_COLLISION;
140*042d53a7SEvalZero } else {
141*042d53a7SEvalZero err = BLE_ERR_DIFF_TRANS_COLL;
142*042d53a7SEvalZero }
143*042d53a7SEvalZero break;
144*042d53a7SEvalZero default:
145*042d53a7SEvalZero err = 0;
146*042d53a7SEvalZero }
147*042d53a7SEvalZero
148*042d53a7SEvalZero return err;
149*042d53a7SEvalZero }
150*042d53a7SEvalZero
151*042d53a7SEvalZero /**
152*042d53a7SEvalZero * Create a LL_REJECT_EXT_IND pdu.
153*042d53a7SEvalZero *
154*042d53a7SEvalZero * @param rej_opcode Opcode to be rejected.
155*042d53a7SEvalZero * @param err: error response
156*042d53a7SEvalZero * @param ctrdata: Pointer to where CtrData starts in pdu
157*042d53a7SEvalZero */
158*042d53a7SEvalZero void
ble_ll_ctrl_rej_ext_ind_make(uint8_t rej_opcode,uint8_t err,uint8_t * ctrdata)159*042d53a7SEvalZero ble_ll_ctrl_rej_ext_ind_make(uint8_t rej_opcode, uint8_t err, uint8_t *ctrdata)
160*042d53a7SEvalZero {
161*042d53a7SEvalZero ctrdata[0] = rej_opcode;
162*042d53a7SEvalZero ctrdata[1] = err;
163*042d53a7SEvalZero }
164*042d53a7SEvalZero
165*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
166*042d53a7SEvalZero /**
167*042d53a7SEvalZero * Called to cancel a phy update procedure.
168*042d53a7SEvalZero *
169*042d53a7SEvalZero * @param connsm
170*042d53a7SEvalZero * @param ble_err
171*042d53a7SEvalZero */
172*042d53a7SEvalZero void
ble_ll_ctrl_phy_update_cancel(struct ble_ll_conn_sm * connsm,uint8_t ble_err)173*042d53a7SEvalZero ble_ll_ctrl_phy_update_cancel(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
174*042d53a7SEvalZero {
175*042d53a7SEvalZero /* cancel any pending phy update procedures */
176*042d53a7SEvalZero CLR_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE);
177*042d53a7SEvalZero
178*042d53a7SEvalZero /* Check if the host wants an event */
179*042d53a7SEvalZero if (CONN_F_HOST_PHY_UPDATE(connsm)) {
180*042d53a7SEvalZero ble_ll_hci_ev_phy_update(connsm, ble_err);
181*042d53a7SEvalZero CONN_F_HOST_PHY_UPDATE(connsm) = 0;
182*042d53a7SEvalZero }
183*042d53a7SEvalZero
184*042d53a7SEvalZero /* Clear any bits for phy updates that might be in progress */
185*042d53a7SEvalZero CONN_F_CTRLR_PHY_UPDATE(connsm) = 0;
186*042d53a7SEvalZero }
187*042d53a7SEvalZero #endif
188*042d53a7SEvalZero
189*042d53a7SEvalZero static int
ble_ll_ctrl_len_proc(struct ble_ll_conn_sm * connsm,uint8_t * dptr)190*042d53a7SEvalZero ble_ll_ctrl_len_proc(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
191*042d53a7SEvalZero {
192*042d53a7SEvalZero int rc;
193*042d53a7SEvalZero struct ble_ll_len_req ctrl_req;
194*042d53a7SEvalZero
195*042d53a7SEvalZero /* Extract parameters and check if valid */
196*042d53a7SEvalZero ctrl_req.max_rx_bytes = get_le16(dptr);
197*042d53a7SEvalZero ctrl_req.max_rx_time = get_le16(dptr + 2);
198*042d53a7SEvalZero ctrl_req.max_tx_bytes = get_le16(dptr + 4);
199*042d53a7SEvalZero ctrl_req.max_tx_time = get_le16(dptr + 6);
200*042d53a7SEvalZero
201*042d53a7SEvalZero if ((ctrl_req.max_rx_bytes < BLE_LL_CONN_SUPP_BYTES_MIN) ||
202*042d53a7SEvalZero (ctrl_req.max_rx_time < BLE_LL_CONN_SUPP_TIME_MIN) ||
203*042d53a7SEvalZero (ctrl_req.max_tx_bytes < BLE_LL_CONN_SUPP_BYTES_MIN) ||
204*042d53a7SEvalZero (ctrl_req.max_tx_time < BLE_LL_CONN_SUPP_TIME_MIN)) {
205*042d53a7SEvalZero rc = 1;
206*042d53a7SEvalZero } else {
207*042d53a7SEvalZero /* Update the connection with the new parameters */
208*042d53a7SEvalZero ble_ll_conn_datalen_update(connsm, &ctrl_req);
209*042d53a7SEvalZero rc = 0;
210*042d53a7SEvalZero }
211*042d53a7SEvalZero
212*042d53a7SEvalZero return rc;
213*042d53a7SEvalZero }
214*042d53a7SEvalZero
215*042d53a7SEvalZero /**
216*042d53a7SEvalZero * Process a received LL_PING_RSP control pdu.
217*042d53a7SEvalZero *
218*042d53a7SEvalZero * NOTE: we dont have to reset the callout since this packet will have had a
219*042d53a7SEvalZero * valid MIC and that will restart the authenticated payload timer
220*042d53a7SEvalZero *
221*042d53a7SEvalZero * @param connsm
222*042d53a7SEvalZero */
223*042d53a7SEvalZero static void
ble_ll_ctrl_rx_ping_rsp(struct ble_ll_conn_sm * connsm)224*042d53a7SEvalZero ble_ll_ctrl_rx_ping_rsp(struct ble_ll_conn_sm *connsm)
225*042d53a7SEvalZero {
226*042d53a7SEvalZero /* Stop the control procedure */
227*042d53a7SEvalZero ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_LE_PING);
228*042d53a7SEvalZero }
229*042d53a7SEvalZero
230*042d53a7SEvalZero /**
231*042d53a7SEvalZero * Called when we receive either a connection parameter request or response.
232*042d53a7SEvalZero *
233*042d53a7SEvalZero * @param connsm
234*042d53a7SEvalZero * @param dptr
235*042d53a7SEvalZero * @param rspbuf
236*042d53a7SEvalZero * @param opcode
237*042d53a7SEvalZero *
238*042d53a7SEvalZero * @return int
239*042d53a7SEvalZero */
240*042d53a7SEvalZero static int
ble_ll_ctrl_conn_param_pdu_proc(struct ble_ll_conn_sm * connsm,uint8_t * dptr,uint8_t * rspbuf,uint8_t opcode)241*042d53a7SEvalZero ble_ll_ctrl_conn_param_pdu_proc(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
242*042d53a7SEvalZero uint8_t *rspbuf, uint8_t opcode)
243*042d53a7SEvalZero {
244*042d53a7SEvalZero int rc;
245*042d53a7SEvalZero int indicate;
246*042d53a7SEvalZero uint8_t rsp_opcode;
247*042d53a7SEvalZero uint8_t ble_err;
248*042d53a7SEvalZero struct ble_ll_conn_params *req;
249*042d53a7SEvalZero struct hci_conn_update *hcu;
250*042d53a7SEvalZero
251*042d53a7SEvalZero /* Extract parameters and check if valid */
252*042d53a7SEvalZero req = &connsm->conn_cp;
253*042d53a7SEvalZero req->interval_min = get_le16(dptr);
254*042d53a7SEvalZero req->interval_max = get_le16(dptr + 2);
255*042d53a7SEvalZero req->latency = get_le16(dptr + 4);
256*042d53a7SEvalZero req->timeout = get_le16(dptr + 6);
257*042d53a7SEvalZero req->pref_periodicity = dptr[8];
258*042d53a7SEvalZero req->ref_conn_event_cnt = get_le16(dptr + 9);
259*042d53a7SEvalZero req->offset0 = get_le16(dptr + 11);
260*042d53a7SEvalZero req->offset1 = get_le16(dptr + 13);
261*042d53a7SEvalZero req->offset2 = get_le16(dptr + 15);
262*042d53a7SEvalZero req->offset3 = get_le16(dptr + 17);
263*042d53a7SEvalZero req->offset4 = get_le16(dptr + 19);
264*042d53a7SEvalZero req->offset5 = get_le16(dptr + 21);
265*042d53a7SEvalZero
266*042d53a7SEvalZero /* Check if parameters are valid */
267*042d53a7SEvalZero ble_err = BLE_ERR_SUCCESS;
268*042d53a7SEvalZero rc = ble_ll_conn_hci_chk_conn_params(req->interval_min,
269*042d53a7SEvalZero req->interval_max,
270*042d53a7SEvalZero req->latency,
271*042d53a7SEvalZero req->timeout);
272*042d53a7SEvalZero if (rc) {
273*042d53a7SEvalZero ble_err = BLE_ERR_INV_LMP_LL_PARM;
274*042d53a7SEvalZero goto conn_param_pdu_exit;
275*042d53a7SEvalZero }
276*042d53a7SEvalZero
277*042d53a7SEvalZero /*
278*042d53a7SEvalZero * Check if there is a requested change to either the interval, timeout
279*042d53a7SEvalZero * or latency. If not, this may just be an anchor point change and we do
280*042d53a7SEvalZero * not have to notify the host.
281*042d53a7SEvalZero * XXX: what if we dont like the parameters? When do we check that out?
282*042d53a7SEvalZero */
283*042d53a7SEvalZero indicate = 1;
284*042d53a7SEvalZero if (opcode == BLE_LL_CTRL_CONN_PARM_REQ) {
285*042d53a7SEvalZero if ((connsm->conn_itvl >= req->interval_min) &&
286*042d53a7SEvalZero (connsm->conn_itvl <= req->interval_max) &&
287*042d53a7SEvalZero (connsm->supervision_tmo == req->timeout) &&
288*042d53a7SEvalZero (connsm->slave_latency == req->latency)) {
289*042d53a7SEvalZero indicate = 0;
290*042d53a7SEvalZero goto conn_parm_req_do_indicate;
291*042d53a7SEvalZero }
292*042d53a7SEvalZero }
293*042d53a7SEvalZero
294*042d53a7SEvalZero /*
295*042d53a7SEvalZero * A change has been requested. Is it within the values specified by
296*042d53a7SEvalZero * the host? Note that for a master we will not be processing a
297*042d53a7SEvalZero * connect param request from a slave if we are currently trying to
298*042d53a7SEvalZero * update the connection parameters. This means that the previous
299*042d53a7SEvalZero * check is all we need for a master (when receiving a request).
300*042d53a7SEvalZero */
301*042d53a7SEvalZero if ((connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) ||
302*042d53a7SEvalZero (opcode == BLE_LL_CTRL_CONN_PARM_RSP)) {
303*042d53a7SEvalZero /*
304*042d53a7SEvalZero * Not sure what to do about the slave. It is possible that the
305*042d53a7SEvalZero * current connection parameters are not the same ones as the local host
306*042d53a7SEvalZero * has provided? Not sure what to do here. Do we need to remember what
307*042d53a7SEvalZero * host sent us? For now, I will assume that we need to remember what
308*042d53a7SEvalZero * the host sent us and check it out.
309*042d53a7SEvalZero */
310*042d53a7SEvalZero hcu = &connsm->conn_param_req;
311*042d53a7SEvalZero if (hcu->handle != 0) {
312*042d53a7SEvalZero if (!((req->interval_min < hcu->conn_itvl_min) ||
313*042d53a7SEvalZero (req->interval_min > hcu->conn_itvl_max) ||
314*042d53a7SEvalZero (req->interval_max < hcu->conn_itvl_min) ||
315*042d53a7SEvalZero (req->interval_max > hcu->conn_itvl_max) ||
316*042d53a7SEvalZero (req->latency != hcu->conn_latency) ||
317*042d53a7SEvalZero (req->timeout != hcu->supervision_timeout))) {
318*042d53a7SEvalZero indicate = 0;
319*042d53a7SEvalZero }
320*042d53a7SEvalZero }
321*042d53a7SEvalZero }
322*042d53a7SEvalZero
323*042d53a7SEvalZero conn_parm_req_do_indicate:
324*042d53a7SEvalZero /*
325*042d53a7SEvalZero * XXX: are the connection update parameters acceptable? If not, we will
326*042d53a7SEvalZero * need to know before we indicate to the host that they are acceptable.
327*042d53a7SEvalZero */
328*042d53a7SEvalZero if (indicate) {
329*042d53a7SEvalZero /* If Host masked out Remote Connection Parameter Request Event, we need to
330*042d53a7SEvalZero * send Reject back to the remote device
331*042d53a7SEvalZero */
332*042d53a7SEvalZero if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_REM_CONN_PARM_REQ)){
333*042d53a7SEvalZero ble_err = BLE_ERR_UNSUPP_REM_FEATURE;
334*042d53a7SEvalZero goto conn_param_pdu_exit;
335*042d53a7SEvalZero }
336*042d53a7SEvalZero
337*042d53a7SEvalZero /*
338*042d53a7SEvalZero * Send event to host. At this point we leave and wait to get
339*042d53a7SEvalZero * an answer.
340*042d53a7SEvalZero */
341*042d53a7SEvalZero ble_ll_hci_ev_rem_conn_parm_req(connsm, req);
342*042d53a7SEvalZero connsm->host_reply_opcode = opcode;
343*042d53a7SEvalZero connsm->csmflags.cfbit.awaiting_host_reply = 1;
344*042d53a7SEvalZero rsp_opcode = 255;
345*042d53a7SEvalZero } else {
346*042d53a7SEvalZero /* Create reply to connection request */
347*042d53a7SEvalZero rsp_opcode = ble_ll_ctrl_conn_param_reply(connsm, rspbuf, req);
348*042d53a7SEvalZero }
349*042d53a7SEvalZero
350*042d53a7SEvalZero conn_param_pdu_exit:
351*042d53a7SEvalZero if (ble_err) {
352*042d53a7SEvalZero rsp_opcode = BLE_LL_CTRL_REJECT_IND_EXT;
353*042d53a7SEvalZero rspbuf[1] = opcode;
354*042d53a7SEvalZero rspbuf[2] = ble_err;
355*042d53a7SEvalZero }
356*042d53a7SEvalZero return rsp_opcode;
357*042d53a7SEvalZero }
358*042d53a7SEvalZero
359*042d53a7SEvalZero /**
360*042d53a7SEvalZero * Called to make a connection update request LL control PDU
361*042d53a7SEvalZero *
362*042d53a7SEvalZero * Context: Link Layer
363*042d53a7SEvalZero *
364*042d53a7SEvalZero * @param connsm
365*042d53a7SEvalZero * @param rsp
366*042d53a7SEvalZero */
367*042d53a7SEvalZero static void
ble_ll_ctrl_conn_upd_make(struct ble_ll_conn_sm * connsm,uint8_t * pyld,struct ble_ll_conn_params * cp)368*042d53a7SEvalZero ble_ll_ctrl_conn_upd_make(struct ble_ll_conn_sm *connsm, uint8_t *pyld,
369*042d53a7SEvalZero struct ble_ll_conn_params *cp)
370*042d53a7SEvalZero {
371*042d53a7SEvalZero uint16_t instant;
372*042d53a7SEvalZero uint32_t dt;
373*042d53a7SEvalZero uint32_t num_old_ce;
374*042d53a7SEvalZero uint32_t new_itvl_usecs;
375*042d53a7SEvalZero uint32_t old_itvl_usecs;
376*042d53a7SEvalZero struct hci_conn_update *hcu;
377*042d53a7SEvalZero struct ble_ll_conn_upd_req *req;
378*042d53a7SEvalZero
379*042d53a7SEvalZero /*
380*042d53a7SEvalZero * Set instant. We set the instant to the current event counter plus
381*042d53a7SEvalZero * the amount of slave latency as the slave may not be listening
382*042d53a7SEvalZero * at every connection interval and we are not sure when the connect
383*042d53a7SEvalZero * request will actually get sent. We add one more event plus the
384*042d53a7SEvalZero * minimum as per the spec of 6 connection events.
385*042d53a7SEvalZero */
386*042d53a7SEvalZero instant = connsm->event_cntr + connsm->slave_latency + 6 + 1;
387*042d53a7SEvalZero
388*042d53a7SEvalZero /*
389*042d53a7SEvalZero * XXX: This should change in the future, but for now we will just
390*042d53a7SEvalZero * start the new instant at the same anchor using win offset 0.
391*042d53a7SEvalZero */
392*042d53a7SEvalZero /* Copy parameters in connection update structure */
393*042d53a7SEvalZero hcu = &connsm->conn_param_req;
394*042d53a7SEvalZero req = &connsm->conn_update_req;
395*042d53a7SEvalZero if (cp) {
396*042d53a7SEvalZero /* XXX: so we need to make the new anchor point some time away
397*042d53a7SEvalZero * from txwinoffset by some amount of msecs. Not sure how to do
398*042d53a7SEvalZero that here. We dont need to, but we should. */
399*042d53a7SEvalZero /* Calculate offset from requested offsets (if any) */
400*042d53a7SEvalZero if (cp->offset0 != 0xFFFF) {
401*042d53a7SEvalZero new_itvl_usecs = cp->interval_max * BLE_LL_CONN_ITVL_USECS;
402*042d53a7SEvalZero old_itvl_usecs = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS;
403*042d53a7SEvalZero if ((int16_t)(cp->ref_conn_event_cnt - instant) >= 0) {
404*042d53a7SEvalZero num_old_ce = cp->ref_conn_event_cnt - instant;
405*042d53a7SEvalZero dt = old_itvl_usecs * num_old_ce;
406*042d53a7SEvalZero dt += (cp->offset0 * BLE_LL_CONN_ITVL_USECS);
407*042d53a7SEvalZero dt = dt % new_itvl_usecs;
408*042d53a7SEvalZero } else {
409*042d53a7SEvalZero num_old_ce = instant - cp->ref_conn_event_cnt;
410*042d53a7SEvalZero dt = old_itvl_usecs * num_old_ce;
411*042d53a7SEvalZero dt -= (cp->offset0 * BLE_LL_CONN_ITVL_USECS);
412*042d53a7SEvalZero dt = dt % new_itvl_usecs;
413*042d53a7SEvalZero dt = new_itvl_usecs - dt;
414*042d53a7SEvalZero }
415*042d53a7SEvalZero req->winoffset = dt / BLE_LL_CONN_TX_WIN_USECS;
416*042d53a7SEvalZero } else {
417*042d53a7SEvalZero req->winoffset = 0;
418*042d53a7SEvalZero }
419*042d53a7SEvalZero req->interval = cp->interval_max;
420*042d53a7SEvalZero req->timeout = cp->timeout;
421*042d53a7SEvalZero req->latency = cp->latency;
422*042d53a7SEvalZero req->winsize = 1;
423*042d53a7SEvalZero } else {
424*042d53a7SEvalZero req->interval = hcu->conn_itvl_max;
425*042d53a7SEvalZero req->timeout = hcu->supervision_timeout;
426*042d53a7SEvalZero req->latency = hcu->conn_latency;
427*042d53a7SEvalZero req->winoffset = 0;
428*042d53a7SEvalZero req->winsize = connsm->tx_win_size;
429*042d53a7SEvalZero }
430*042d53a7SEvalZero req->instant = instant;
431*042d53a7SEvalZero
432*042d53a7SEvalZero /* XXX: make sure this works for the connection parameter request proc. */
433*042d53a7SEvalZero pyld[0] = req->winsize;
434*042d53a7SEvalZero put_le16(pyld + 1, req->winoffset);
435*042d53a7SEvalZero put_le16(pyld + 3, req->interval);
436*042d53a7SEvalZero put_le16(pyld + 5, req->latency);
437*042d53a7SEvalZero put_le16(pyld + 7, req->timeout);
438*042d53a7SEvalZero put_le16(pyld + 9, instant);
439*042d53a7SEvalZero
440*042d53a7SEvalZero /* Set flag in state machine to denote we have scheduled an update */
441*042d53a7SEvalZero connsm->csmflags.cfbit.conn_update_sched = 1;
442*042d53a7SEvalZero }
443*042d53a7SEvalZero
444*042d53a7SEvalZero /**
445*042d53a7SEvalZero * Called to process and UNKNOWN_RSP LL control packet.
446*042d53a7SEvalZero *
447*042d53a7SEvalZero * Context: Link Layer Task
448*042d53a7SEvalZero *
449*042d53a7SEvalZero * @param dptr
450*042d53a7SEvalZero */
451*042d53a7SEvalZero static int
ble_ll_ctrl_proc_unk_rsp(struct ble_ll_conn_sm * connsm,uint8_t * dptr,uint8_t * rspdata)452*042d53a7SEvalZero ble_ll_ctrl_proc_unk_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr, uint8_t *rspdata)
453*042d53a7SEvalZero {
454*042d53a7SEvalZero uint8_t ctrl_proc;
455*042d53a7SEvalZero uint8_t opcode;
456*042d53a7SEvalZero
457*042d53a7SEvalZero /* Get opcode of unknown LL control frame */
458*042d53a7SEvalZero opcode = dptr[0];
459*042d53a7SEvalZero
460*042d53a7SEvalZero /* Convert opcode to control procedure id */
461*042d53a7SEvalZero switch (opcode) {
462*042d53a7SEvalZero case BLE_LL_CTRL_LENGTH_REQ:
463*042d53a7SEvalZero ctrl_proc = BLE_LL_CTRL_PROC_DATA_LEN_UPD;
464*042d53a7SEvalZero BLE_LL_CONN_CLEAR_FEATURE(connsm, BLE_LL_FEAT_DATA_LEN_EXT);
465*042d53a7SEvalZero break;
466*042d53a7SEvalZero case BLE_LL_CTRL_CONN_UPDATE_IND:
467*042d53a7SEvalZero ctrl_proc = BLE_LL_CTRL_PROC_CONN_UPDATE;
468*042d53a7SEvalZero break;
469*042d53a7SEvalZero case BLE_LL_CTRL_SLAVE_FEATURE_REQ:
470*042d53a7SEvalZero ctrl_proc = BLE_LL_CTRL_PROC_FEATURE_XCHG;
471*042d53a7SEvalZero BLE_LL_CONN_CLEAR_FEATURE(connsm, BLE_LL_FEAT_SLAVE_INIT);
472*042d53a7SEvalZero break;
473*042d53a7SEvalZero case BLE_LL_CTRL_CONN_PARM_REQ:
474*042d53a7SEvalZero BLE_LL_CONN_CLEAR_FEATURE(connsm, BLE_LL_FEAT_CONN_PARM_REQ);
475*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
476*042d53a7SEvalZero ble_ll_ctrl_conn_upd_make(connsm, rspdata, NULL);
477*042d53a7SEvalZero connsm->reject_reason = BLE_ERR_SUCCESS;
478*042d53a7SEvalZero return BLE_LL_CTRL_CONN_UPDATE_IND;
479*042d53a7SEvalZero }
480*042d53a7SEvalZero /* note: fall-through intentional */
481*042d53a7SEvalZero case BLE_LL_CTRL_CONN_PARM_RSP:
482*042d53a7SEvalZero ctrl_proc = BLE_LL_CTRL_PROC_CONN_PARAM_REQ;
483*042d53a7SEvalZero break;
484*042d53a7SEvalZero case BLE_LL_CTRL_PING_REQ:
485*042d53a7SEvalZero /* LL can authenticate remote device even if remote device does not
486*042d53a7SEvalZero * support LE Ping feature.
487*042d53a7SEvalZero */
488*042d53a7SEvalZero ctrl_proc = BLE_LL_CTRL_PROC_LE_PING;
489*042d53a7SEvalZero BLE_LL_CONN_CLEAR_FEATURE(connsm, BLE_LL_FEAT_LE_PING);
490*042d53a7SEvalZero break;
491*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED ==1)
492*042d53a7SEvalZero case BLE_LL_CTRL_PHY_REQ:
493*042d53a7SEvalZero ble_ll_ctrl_phy_update_cancel(connsm, BLE_ERR_UNSUPP_REM_FEATURE);
494*042d53a7SEvalZero ctrl_proc = BLE_LL_CTRL_PROC_PHY_UPDATE;
495*042d53a7SEvalZero break;
496*042d53a7SEvalZero #endif
497*042d53a7SEvalZero default:
498*042d53a7SEvalZero ctrl_proc = BLE_LL_CTRL_PROC_NUM;
499*042d53a7SEvalZero break;
500*042d53a7SEvalZero }
501*042d53a7SEvalZero
502*042d53a7SEvalZero /* If we are running this one currently, stop it */
503*042d53a7SEvalZero if (connsm->cur_ctrl_proc == ctrl_proc) {
504*042d53a7SEvalZero /* Stop the control procedure */
505*042d53a7SEvalZero ble_ll_ctrl_proc_stop(connsm, ctrl_proc);
506*042d53a7SEvalZero if (ctrl_proc == BLE_LL_CTRL_PROC_CONN_PARAM_REQ) {
507*042d53a7SEvalZero ble_ll_hci_ev_conn_update(connsm, BLE_ERR_UNSUPP_REM_FEATURE);
508*042d53a7SEvalZero } else if (ctrl_proc == BLE_LL_CTRL_PROC_FEATURE_XCHG) {
509*042d53a7SEvalZero if (connsm->csmflags.cfbit.pending_hci_rd_features) {
510*042d53a7SEvalZero ble_ll_hci_ev_rd_rem_used_feat(connsm,
511*042d53a7SEvalZero BLE_ERR_UNSUPP_REM_FEATURE);
512*042d53a7SEvalZero }
513*042d53a7SEvalZero connsm->csmflags.cfbit.pending_hci_rd_features = 0;
514*042d53a7SEvalZero }
515*042d53a7SEvalZero }
516*042d53a7SEvalZero
517*042d53a7SEvalZero return BLE_ERR_MAX;
518*042d53a7SEvalZero }
519*042d53a7SEvalZero
520*042d53a7SEvalZero /**
521*042d53a7SEvalZero * Callback when LL control procedure times out (for a given connection). If
522*042d53a7SEvalZero * this is called, it means that we need to end the connection because it
523*042d53a7SEvalZero * has not responded to a LL control request.
524*042d53a7SEvalZero *
525*042d53a7SEvalZero * Context: Link Layer
526*042d53a7SEvalZero *
527*042d53a7SEvalZero * @param arg Pointer to connection state machine.
528*042d53a7SEvalZero */
529*042d53a7SEvalZero static void
ble_ll_ctrl_proc_rsp_timer_cb(struct ble_npl_event * ev)530*042d53a7SEvalZero ble_ll_ctrl_proc_rsp_timer_cb(struct ble_npl_event *ev)
531*042d53a7SEvalZero {
532*042d53a7SEvalZero /* Control procedure has timed out. Kill the connection */
533*042d53a7SEvalZero ble_ll_conn_timeout((struct ble_ll_conn_sm *)ble_npl_event_get_arg(ev),
534*042d53a7SEvalZero BLE_ERR_LMP_LL_RSP_TMO);
535*042d53a7SEvalZero }
536*042d53a7SEvalZero
537*042d53a7SEvalZero static void
ble_ll_ctrl_start_rsp_timer(struct ble_ll_conn_sm * connsm)538*042d53a7SEvalZero ble_ll_ctrl_start_rsp_timer(struct ble_ll_conn_sm *connsm)
539*042d53a7SEvalZero {
540*042d53a7SEvalZero ble_npl_callout_init(&connsm->ctrl_proc_rsp_timer,
541*042d53a7SEvalZero &g_ble_ll_data.ll_evq,
542*042d53a7SEvalZero ble_ll_ctrl_proc_rsp_timer_cb,
543*042d53a7SEvalZero connsm);
544*042d53a7SEvalZero
545*042d53a7SEvalZero /* Re-start timer. Control procedure timeout is 40 seconds */
546*042d53a7SEvalZero ble_npl_callout_reset(&connsm->ctrl_proc_rsp_timer,
547*042d53a7SEvalZero ble_npl_time_ms_to_ticks32(BLE_LL_CTRL_PROC_TIMEOUT_MS));
548*042d53a7SEvalZero }
549*042d53a7SEvalZero
550*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
551*042d53a7SEvalZero void
ble_ll_ctrl_phy_update_proc_complete(struct ble_ll_conn_sm * connsm)552*042d53a7SEvalZero ble_ll_ctrl_phy_update_proc_complete(struct ble_ll_conn_sm *connsm)
553*042d53a7SEvalZero {
554*042d53a7SEvalZero int chk_proc_stop;
555*042d53a7SEvalZero int chk_host_phy;
556*042d53a7SEvalZero
557*042d53a7SEvalZero chk_proc_stop = 1;
558*042d53a7SEvalZero chk_host_phy = 1;
559*042d53a7SEvalZero
560*042d53a7SEvalZero connsm->phy_tx_transition = BLE_PHY_TRANSITION_INVALID;
561*042d53a7SEvalZero
562*042d53a7SEvalZero if (CONN_F_PEER_PHY_UPDATE(connsm)) {
563*042d53a7SEvalZero CONN_F_PEER_PHY_UPDATE(connsm) = 0;
564*042d53a7SEvalZero } else if (CONN_F_CTRLR_PHY_UPDATE(connsm)) {
565*042d53a7SEvalZero CONN_F_CTRLR_PHY_UPDATE(connsm) = 0;
566*042d53a7SEvalZero } else {
567*042d53a7SEvalZero /* Must be a host-initiated update */
568*042d53a7SEvalZero CONN_F_HOST_PHY_UPDATE(connsm) = 0;
569*042d53a7SEvalZero chk_host_phy = 0;
570*042d53a7SEvalZero if (CONN_F_PHY_UPDATE_EVENT(connsm) == 0) {
571*042d53a7SEvalZero ble_ll_hci_ev_phy_update(connsm, BLE_ERR_SUCCESS);
572*042d53a7SEvalZero }
573*042d53a7SEvalZero }
574*042d53a7SEvalZero
575*042d53a7SEvalZero /* Must check if we need to start host procedure */
576*042d53a7SEvalZero if (chk_host_phy) {
577*042d53a7SEvalZero if (CONN_F_HOST_PHY_UPDATE(connsm)) {
578*042d53a7SEvalZero if (ble_ll_conn_chk_phy_upd_start(connsm)) {
579*042d53a7SEvalZero CONN_F_HOST_PHY_UPDATE(connsm) = 0;
580*042d53a7SEvalZero } else {
581*042d53a7SEvalZero chk_proc_stop = 0;
582*042d53a7SEvalZero }
583*042d53a7SEvalZero }
584*042d53a7SEvalZero }
585*042d53a7SEvalZero
586*042d53a7SEvalZero if (chk_proc_stop) {
587*042d53a7SEvalZero ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE);
588*042d53a7SEvalZero }
589*042d53a7SEvalZero }
590*042d53a7SEvalZero
591*042d53a7SEvalZero /**
592*042d53a7SEvalZero * Convert a phy mask to a numeric phy value.
593*042d53a7SEvalZero *
594*042d53a7SEvalZero * NOTE: only one bit should be set here and there should be at least one.
595*042d53a7SEvalZero * If this function returns a 0 it is an error!
596*042d53a7SEvalZero *
597*042d53a7SEvalZero * @param phy_mask Bitmask of phy
598*042d53a7SEvalZero *
599*042d53a7SEvalZero * @return uint8_t The numeric value associated with the phy mask
600*042d53a7SEvalZero *
601*042d53a7SEvalZero * BLE_HCI_LE_PHY_1M (1)
602*042d53a7SEvalZero * BLE_HCI_LE_PHY_2M (2)
603*042d53a7SEvalZero * BLE_HCI_LE_PHY_CODED (3)
604*042d53a7SEvalZero */
605*042d53a7SEvalZero static uint8_t
ble_ll_ctrl_phy_from_phy_mask(uint8_t phy_mask)606*042d53a7SEvalZero ble_ll_ctrl_phy_from_phy_mask(uint8_t phy_mask)
607*042d53a7SEvalZero {
608*042d53a7SEvalZero uint8_t phy;
609*042d53a7SEvalZero
610*042d53a7SEvalZero /*
611*042d53a7SEvalZero * NOTE: wipe out unsupported PHYs. There should not be an unsupported
612*042d53a7SEvalZero * in this mask if the other side is working correctly.
613*042d53a7SEvalZero */
614*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY)
615*042d53a7SEvalZero phy_mask &= ~BLE_HCI_LE_PHY_2M_PREF_MASK;
616*042d53a7SEvalZero #endif
617*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
618*042d53a7SEvalZero phy_mask &= ~BLE_HCI_LE_PHY_CODED_PREF_MASK;
619*042d53a7SEvalZero #endif
620*042d53a7SEvalZero
621*042d53a7SEvalZero if (phy_mask & BLE_PHY_MASK_1M) {
622*042d53a7SEvalZero phy = BLE_PHY_1M;
623*042d53a7SEvalZero phy_mask &= ~BLE_PHY_MASK_1M;
624*042d53a7SEvalZero } else if (phy_mask & BLE_PHY_MASK_2M) {
625*042d53a7SEvalZero phy = BLE_PHY_2M;
626*042d53a7SEvalZero phy_mask &= ~BLE_PHY_MASK_2M;
627*042d53a7SEvalZero } else if (phy_mask & BLE_PHY_MASK_CODED) {
628*042d53a7SEvalZero phy = BLE_PHY_CODED;
629*042d53a7SEvalZero phy_mask &= ~BLE_PHY_MASK_CODED;
630*042d53a7SEvalZero } else {
631*042d53a7SEvalZero phy = 0;
632*042d53a7SEvalZero }
633*042d53a7SEvalZero
634*042d53a7SEvalZero if (phy_mask != 0) {
635*042d53a7SEvalZero phy = 0;
636*042d53a7SEvalZero }
637*042d53a7SEvalZero
638*042d53a7SEvalZero return phy;
639*042d53a7SEvalZero }
640*042d53a7SEvalZero
641*042d53a7SEvalZero /**
642*042d53a7SEvalZero *
643*042d53a7SEvalZero * There is probably a better way for the controller to choose which PHY use.
644*042d53a7SEvalZero * There are no BER metrics and RSSI does not give you S/N so for now we will
645*042d53a7SEvalZero * choose this heirarchy:
646*042d53a7SEvalZero * -> if 2Mbps available, use it.
647*042d53a7SEvalZero * -> If 1Mbps available, use it.
648*042d53a7SEvalZero * -> otherwise use coded phy.
649*042d53a7SEvalZero *
650*042d53a7SEvalZero * @param prefs The mask of preferred phys
651*042d53a7SEvalZero * @return uint8_t The phy to use (not a mask)
652*042d53a7SEvalZero */
653*042d53a7SEvalZero static uint8_t
ble_ll_ctrl_find_new_phy(uint8_t phy_mask_prefs)654*042d53a7SEvalZero ble_ll_ctrl_find_new_phy(uint8_t phy_mask_prefs)
655*042d53a7SEvalZero {
656*042d53a7SEvalZero uint8_t new_phy;
657*042d53a7SEvalZero
658*042d53a7SEvalZero new_phy = phy_mask_prefs;
659*042d53a7SEvalZero if (new_phy) {
660*042d53a7SEvalZero if (new_phy & BLE_PHY_MASK_2M) {
661*042d53a7SEvalZero new_phy = BLE_PHY_2M;
662*042d53a7SEvalZero } else if (new_phy & BLE_PHY_MASK_1M) {
663*042d53a7SEvalZero new_phy = BLE_PHY_1M;
664*042d53a7SEvalZero } else {
665*042d53a7SEvalZero new_phy = BLE_PHY_CODED;
666*042d53a7SEvalZero }
667*042d53a7SEvalZero }
668*042d53a7SEvalZero
669*042d53a7SEvalZero return new_phy;
670*042d53a7SEvalZero }
671*042d53a7SEvalZero
672*042d53a7SEvalZero /**
673*042d53a7SEvalZero * Create a LL_PHY_UPDATE_IND pdu
674*042d53a7SEvalZero *
675*042d53a7SEvalZero * @param connsm Pointer to connection state machine
676*042d53a7SEvalZero * @param dptr Pointer to PHY_REQ or PHY_RSP data.
677*042d53a7SEvalZero * @param ctrdata: Pointer to where CtrData of UPDATE_IND pdu starts
678*042d53a7SEvalZero * @param slave_req flag denoting if slave requested this. 0: no 1:yes
679*042d53a7SEvalZero */
680*042d53a7SEvalZero static void
ble_ll_ctrl_phy_update_ind_make(struct ble_ll_conn_sm * connsm,uint8_t * dptr,uint8_t * ctrdata,int slave_req)681*042d53a7SEvalZero ble_ll_ctrl_phy_update_ind_make(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
682*042d53a7SEvalZero uint8_t *ctrdata, int slave_req)
683*042d53a7SEvalZero {
684*042d53a7SEvalZero uint8_t m_to_s;
685*042d53a7SEvalZero uint8_t s_to_m;
686*042d53a7SEvalZero uint8_t tx_phys;
687*042d53a7SEvalZero uint8_t rx_phys;
688*042d53a7SEvalZero uint16_t instant;
689*042d53a7SEvalZero
690*042d53a7SEvalZero /* Get preferences from PDU */
691*042d53a7SEvalZero tx_phys = dptr[0];
692*042d53a7SEvalZero rx_phys = dptr[1];
693*042d53a7SEvalZero
694*042d53a7SEvalZero /* Get m_to_s and s_to_m masks */
695*042d53a7SEvalZero if (slave_req) {
696*042d53a7SEvalZero m_to_s = connsm->phy_data.host_pref_tx_phys_mask & rx_phys;
697*042d53a7SEvalZero s_to_m = connsm->phy_data.host_pref_rx_phys_mask & tx_phys;
698*042d53a7SEvalZero } else {
699*042d53a7SEvalZero m_to_s = connsm->phy_data.req_pref_tx_phys_mask & rx_phys;
700*042d53a7SEvalZero s_to_m = connsm->phy_data.req_pref_rx_phys_mask & tx_phys;
701*042d53a7SEvalZero }
702*042d53a7SEvalZero
703*042d53a7SEvalZero /* Find new phys. If not different than current, set to 0 */
704*042d53a7SEvalZero m_to_s = ble_ll_ctrl_find_new_phy(m_to_s);
705*042d53a7SEvalZero if (m_to_s == connsm->phy_data.cur_tx_phy) {
706*042d53a7SEvalZero m_to_s = 0;
707*042d53a7SEvalZero }
708*042d53a7SEvalZero
709*042d53a7SEvalZero s_to_m = ble_ll_ctrl_find_new_phy(s_to_m);
710*042d53a7SEvalZero if (s_to_m == connsm->phy_data.cur_rx_phy) {
711*042d53a7SEvalZero s_to_m = 0;
712*042d53a7SEvalZero }
713*042d53a7SEvalZero
714*042d53a7SEvalZero /* At this point, m_to_s and s_to_m are not masks; they are numeric */
715*042d53a7SEvalZero
716*042d53a7SEvalZero /*
717*042d53a7SEvalZero * If not changing we still send update ind. Check if hosts expects
718*042d53a7SEvalZero * the event and if so send it. Stop control procedure if it is the
719*042d53a7SEvalZero * one running.
720*042d53a7SEvalZero */
721*042d53a7SEvalZero if ((m_to_s == 0) && (s_to_m == 0)) {
722*042d53a7SEvalZero if (CONN_F_PEER_PHY_UPDATE(connsm)) {
723*042d53a7SEvalZero CONN_F_PEER_PHY_UPDATE(connsm) = 0;
724*042d53a7SEvalZero } else if (CONN_F_CTRLR_PHY_UPDATE(connsm)) {
725*042d53a7SEvalZero CONN_F_CTRLR_PHY_UPDATE(connsm) = 0;
726*042d53a7SEvalZero ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE);
727*042d53a7SEvalZero } else {
728*042d53a7SEvalZero ble_ll_hci_ev_phy_update(connsm, BLE_ERR_SUCCESS);
729*042d53a7SEvalZero CONN_F_HOST_PHY_UPDATE(connsm) = 0;
730*042d53a7SEvalZero ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE);
731*042d53a7SEvalZero }
732*042d53a7SEvalZero instant = 0;
733*042d53a7SEvalZero } else {
734*042d53a7SEvalZero /* Determine instant we will use. 6 more is minimum */
735*042d53a7SEvalZero instant = connsm->event_cntr + connsm->slave_latency + 6 + 1;
736*042d53a7SEvalZero connsm->phy_instant = instant;
737*042d53a7SEvalZero CONN_F_PHY_UPDATE_SCHED(connsm) = 1;
738*042d53a7SEvalZero
739*042d53a7SEvalZero /* Set new phys to use when instant occurs */
740*042d53a7SEvalZero connsm->phy_data.new_tx_phy = m_to_s;
741*042d53a7SEvalZero connsm->phy_data.new_rx_phy = s_to_m;
742*042d53a7SEvalZero
743*042d53a7SEvalZero /* Convert m_to_s and s_to_m to masks */
744*042d53a7SEvalZero if (m_to_s) {
745*042d53a7SEvalZero m_to_s = 1 << (m_to_s - 1);
746*042d53a7SEvalZero }
747*042d53a7SEvalZero
748*042d53a7SEvalZero if (s_to_m) {
749*042d53a7SEvalZero s_to_m = 1 << (s_to_m - 1);
750*042d53a7SEvalZero }
751*042d53a7SEvalZero }
752*042d53a7SEvalZero
753*042d53a7SEvalZero ctrdata[0] = m_to_s;
754*042d53a7SEvalZero ctrdata[1] = s_to_m;
755*042d53a7SEvalZero put_le16(ctrdata + 2, instant);
756*042d53a7SEvalZero }
757*042d53a7SEvalZero
758*042d53a7SEvalZero /**
759*042d53a7SEvalZero * Create a LL_PHY_REQ or LL_PHY_RSP pdu
760*042d53a7SEvalZero *
761*042d53a7SEvalZero * @param connsm Pointer to connection state machine
762*042d53a7SEvalZero * @param ctrdata: Pointer to where CtrData starts in pdu
763*042d53a7SEvalZero */
764*042d53a7SEvalZero static void
ble_ll_ctrl_phy_req_rsp_make(struct ble_ll_conn_sm * connsm,uint8_t * ctrdata)765*042d53a7SEvalZero ble_ll_ctrl_phy_req_rsp_make(struct ble_ll_conn_sm *connsm, uint8_t *ctrdata)
766*042d53a7SEvalZero {
767*042d53a7SEvalZero /* If no preference we use current phy */
768*042d53a7SEvalZero if (connsm->phy_data.host_pref_tx_phys_mask == 0) {
769*042d53a7SEvalZero ctrdata[0] = CONN_CUR_TX_PHY_MASK(connsm);
770*042d53a7SEvalZero } else {
771*042d53a7SEvalZero ctrdata[0] = connsm->phy_data.host_pref_tx_phys_mask;
772*042d53a7SEvalZero }
773*042d53a7SEvalZero if (connsm->phy_data.host_pref_rx_phys_mask == 0) {
774*042d53a7SEvalZero ctrdata[1] = CONN_CUR_RX_PHY_MASK(connsm);
775*042d53a7SEvalZero } else {
776*042d53a7SEvalZero ctrdata[1] = connsm->phy_data.host_pref_rx_phys_mask;
777*042d53a7SEvalZero }
778*042d53a7SEvalZero }
779*042d53a7SEvalZero
780*042d53a7SEvalZero static uint8_t
ble_ll_ctrl_rx_phy_req(struct ble_ll_conn_sm * connsm,uint8_t * req,uint8_t * rsp)781*042d53a7SEvalZero ble_ll_ctrl_rx_phy_req(struct ble_ll_conn_sm *connsm, uint8_t *req,
782*042d53a7SEvalZero uint8_t *rsp)
783*042d53a7SEvalZero {
784*042d53a7SEvalZero uint8_t rsp_opcode;
785*042d53a7SEvalZero uint8_t err;
786*042d53a7SEvalZero
787*042d53a7SEvalZero /*
788*042d53a7SEvalZero * XXX: TODO if we have an instant in progress we should end connection.
789*042d53a7SEvalZero * At least it seems that is the case. Need to figure out more from
790*042d53a7SEvalZero * the spec here.
791*042d53a7SEvalZero */
792*042d53a7SEvalZero
793*042d53a7SEvalZero /* Check if we have already initiated a procedure with an instant */
794*042d53a7SEvalZero err = ble_ll_ctrl_proc_with_instant_initiated(connsm,
795*042d53a7SEvalZero BLE_LL_CTRL_PROC_PHY_UPDATE);
796*042d53a7SEvalZero
797*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
798*042d53a7SEvalZero if (err) {
799*042d53a7SEvalZero ble_ll_ctrl_rej_ext_ind_make(BLE_LL_CTRL_PHY_REQ, err, rsp);
800*042d53a7SEvalZero rsp_opcode = BLE_LL_CTRL_REJECT_IND_EXT;
801*042d53a7SEvalZero } else {
802*042d53a7SEvalZero /*
803*042d53a7SEvalZero * NOTE: do not change order of these two lines as the call to
804*042d53a7SEvalZero * make the LL_PHY_UPDATE_IND pdu might clear the flag.
805*042d53a7SEvalZero */
806*042d53a7SEvalZero CONN_F_PEER_PHY_UPDATE(connsm) = 1;
807*042d53a7SEvalZero ble_ll_ctrl_phy_update_ind_make(connsm, req, rsp, 1);
808*042d53a7SEvalZero rsp_opcode = BLE_LL_CTRL_PHY_UPDATE_IND;
809*042d53a7SEvalZero }
810*042d53a7SEvalZero } else {
811*042d53a7SEvalZero /* XXX: deal with other control procedures that we need to stop */
812*042d53a7SEvalZero if (err) {
813*042d53a7SEvalZero if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_PHY_UPDATE) {
814*042d53a7SEvalZero ble_npl_callout_stop(&connsm->ctrl_proc_rsp_timer);
815*042d53a7SEvalZero connsm->cur_ctrl_proc = BLE_LL_CTRL_PROC_IDLE;
816*042d53a7SEvalZero }
817*042d53a7SEvalZero
818*042d53a7SEvalZero /* If there is a PHY update procedure pending cancel it */
819*042d53a7SEvalZero ble_ll_ctrl_phy_update_cancel(connsm, err);
820*042d53a7SEvalZero
821*042d53a7SEvalZero /* XXX: ? Should not be any phy update events */
822*042d53a7SEvalZero CONN_F_PHY_UPDATE_EVENT(connsm) = 0;
823*042d53a7SEvalZero }
824*042d53a7SEvalZero
825*042d53a7SEvalZero /* XXX: TODO: if we started another procedure with an instant
826*042d53a7SEvalZero * why are we doing this? Need to look into this.*/
827*042d53a7SEvalZero
828*042d53a7SEvalZero /* Respond to master's phy update procedure */
829*042d53a7SEvalZero CONN_F_PEER_PHY_UPDATE(connsm) = 1;
830*042d53a7SEvalZero ble_ll_ctrl_phy_req_rsp_make(connsm, rsp);
831*042d53a7SEvalZero rsp_opcode = BLE_LL_CTRL_PHY_RSP;
832*042d53a7SEvalZero
833*042d53a7SEvalZero if (rsp[0] & BLE_PHY_MASK_1M) {
834*042d53a7SEvalZero connsm->phy_tx_transition = BLE_PHY_1M;
835*042d53a7SEvalZero } else if (rsp[0] & BLE_PHY_MASK_2M) {
836*042d53a7SEvalZero connsm->phy_tx_transition = BLE_PHY_2M;
837*042d53a7SEvalZero } else if (rsp[0] & BLE_PHY_MASK_CODED) {
838*042d53a7SEvalZero connsm->phy_tx_transition = BLE_PHY_CODED;
839*042d53a7SEvalZero }
840*042d53a7SEvalZero
841*042d53a7SEvalZero /* Start response timer */
842*042d53a7SEvalZero connsm->cur_ctrl_proc = BLE_LL_CTRL_PROC_PHY_UPDATE;
843*042d53a7SEvalZero ble_ll_ctrl_start_rsp_timer(connsm);
844*042d53a7SEvalZero }
845*042d53a7SEvalZero return rsp_opcode;
846*042d53a7SEvalZero }
847*042d53a7SEvalZero
848*042d53a7SEvalZero /**
849*042d53a7SEvalZero * Process a received LL_PHY_RSP pdu
850*042d53a7SEvalZero *
851*042d53a7SEvalZero * @param connsm
852*042d53a7SEvalZero * @param dptr Pointer to LL_PHY_RSP ctrdata
853*042d53a7SEvalZero * @param rsp Pointer to CtrData of PHY_UPDATE_IND.
854*042d53a7SEvalZero *
855*042d53a7SEvalZero * @return uint8_t
856*042d53a7SEvalZero */
857*042d53a7SEvalZero static uint8_t
ble_ll_ctrl_rx_phy_rsp(struct ble_ll_conn_sm * connsm,uint8_t * dptr,uint8_t * rsp)858*042d53a7SEvalZero ble_ll_ctrl_rx_phy_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
859*042d53a7SEvalZero uint8_t *rsp)
860*042d53a7SEvalZero {
861*042d53a7SEvalZero uint8_t rsp_opcode;
862*042d53a7SEvalZero
863*042d53a7SEvalZero rsp_opcode = BLE_ERR_MAX;
864*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
865*042d53a7SEvalZero if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_PHY_UPDATE) {
866*042d53a7SEvalZero ble_ll_ctrl_phy_update_ind_make(connsm, dptr, rsp, 0);
867*042d53a7SEvalZero ble_npl_callout_stop(&connsm->ctrl_proc_rsp_timer);
868*042d53a7SEvalZero rsp_opcode = BLE_LL_CTRL_PHY_UPDATE_IND;
869*042d53a7SEvalZero }
870*042d53a7SEvalZero
871*042d53a7SEvalZero /*
872*042d53a7SEvalZero * If not in the process of doing this control procedure something
873*042d53a7SEvalZero * is wrong. End connection? Assert?
874*042d53a7SEvalZero *
875*042d53a7SEvalZero * XXX: TODO count some stat?
876*042d53a7SEvalZero */
877*042d53a7SEvalZero } else {
878*042d53a7SEvalZero rsp_opcode = BLE_LL_CTRL_UNKNOWN_RSP;
879*042d53a7SEvalZero }
880*042d53a7SEvalZero
881*042d53a7SEvalZero /* NOTE: slave should never receive one of these */
882*042d53a7SEvalZero
883*042d53a7SEvalZero return rsp_opcode;
884*042d53a7SEvalZero }
885*042d53a7SEvalZero
886*042d53a7SEvalZero /**
887*042d53a7SEvalZero * Called when a LL_PHY_UPDATE_IND pdu is received
888*042d53a7SEvalZero *
889*042d53a7SEvalZero * NOTE: slave is the only device that should receive this.
890*042d53a7SEvalZero *
891*042d53a7SEvalZero * @param connsm
892*042d53a7SEvalZero * @param dptr
893*042d53a7SEvalZero *
894*042d53a7SEvalZero * @return uint8_t
895*042d53a7SEvalZero */
896*042d53a7SEvalZero static uint8_t
ble_ll_ctrl_rx_phy_update_ind(struct ble_ll_conn_sm * connsm,uint8_t * dptr)897*042d53a7SEvalZero ble_ll_ctrl_rx_phy_update_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
898*042d53a7SEvalZero {
899*042d53a7SEvalZero int no_change;
900*042d53a7SEvalZero uint8_t new_m_to_s_mask;
901*042d53a7SEvalZero uint8_t new_s_to_m_mask;
902*042d53a7SEvalZero uint8_t new_tx_phy;
903*042d53a7SEvalZero uint8_t new_rx_phy;
904*042d53a7SEvalZero uint16_t instant;
905*042d53a7SEvalZero uint16_t delta;
906*042d53a7SEvalZero
907*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
908*042d53a7SEvalZero return BLE_LL_CTRL_UNKNOWN_RSP;
909*042d53a7SEvalZero }
910*042d53a7SEvalZero
911*042d53a7SEvalZero /*
912*042d53a7SEvalZero * Reception stops the procedure response timer but does not
913*042d53a7SEvalZero * complete the procedure
914*042d53a7SEvalZero */
915*042d53a7SEvalZero if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_PHY_UPDATE) {
916*042d53a7SEvalZero ble_npl_callout_stop(&connsm->ctrl_proc_rsp_timer);
917*042d53a7SEvalZero }
918*042d53a7SEvalZero
919*042d53a7SEvalZero /*
920*042d53a7SEvalZero * XXX: Should we check to see if we are expecting to receive one
921*042d53a7SEvalZero * of these, and if not, kill connection? Meaning we better be
922*042d53a7SEvalZero * doing either a PEER, CTRLR, or HOST phy update.
923*042d53a7SEvalZero */
924*042d53a7SEvalZero /* get the new phy masks and see if we need to change */
925*042d53a7SEvalZero new_m_to_s_mask = dptr[0];
926*042d53a7SEvalZero new_s_to_m_mask = dptr[1];
927*042d53a7SEvalZero instant = get_le16(dptr + 2);
928*042d53a7SEvalZero
929*042d53a7SEvalZero if ((new_m_to_s_mask == 0) && (new_s_to_m_mask == 0)) {
930*042d53a7SEvalZero /* No change in phy */
931*042d53a7SEvalZero no_change = 1;
932*042d53a7SEvalZero } else {
933*042d53a7SEvalZero no_change = 0;
934*042d53a7SEvalZero /*
935*042d53a7SEvalZero * NOTE: from the slaves perspective, the m to s phy is the one
936*042d53a7SEvalZero * that the slave will receive on; s to m is the one it will
937*042d53a7SEvalZero * transmit on
938*042d53a7SEvalZero */
939*042d53a7SEvalZero new_rx_phy = ble_ll_ctrl_phy_from_phy_mask(new_m_to_s_mask);
940*042d53a7SEvalZero new_tx_phy = ble_ll_ctrl_phy_from_phy_mask(new_s_to_m_mask);
941*042d53a7SEvalZero
942*042d53a7SEvalZero if ((new_tx_phy == 0) && (new_rx_phy == 0)) {
943*042d53a7SEvalZero /* XXX: this is an error! What to do??? */
944*042d53a7SEvalZero no_change = 1;
945*042d53a7SEvalZero }
946*042d53a7SEvalZero
947*042d53a7SEvalZero if ((new_tx_phy == connsm->phy_data.cur_tx_phy) &&
948*042d53a7SEvalZero (new_rx_phy == connsm->phy_data.cur_rx_phy)) {
949*042d53a7SEvalZero no_change = 1;
950*042d53a7SEvalZero }
951*042d53a7SEvalZero }
952*042d53a7SEvalZero
953*042d53a7SEvalZero if (!no_change) {
954*042d53a7SEvalZero /* If instant is in the past, we have to end the connection */
955*042d53a7SEvalZero delta = (instant - connsm->event_cntr) & 0xFFFF;
956*042d53a7SEvalZero if (delta >= 32767) {
957*042d53a7SEvalZero ble_ll_conn_timeout(connsm, BLE_ERR_INSTANT_PASSED);
958*042d53a7SEvalZero } else {
959*042d53a7SEvalZero connsm->phy_data.new_tx_phy = new_tx_phy;
960*042d53a7SEvalZero connsm->phy_data.new_rx_phy = new_rx_phy;
961*042d53a7SEvalZero connsm->phy_instant = instant;
962*042d53a7SEvalZero CONN_F_PHY_UPDATE_SCHED(connsm) = 1;
963*042d53a7SEvalZero }
964*042d53a7SEvalZero return BLE_ERR_MAX;
965*042d53a7SEvalZero }
966*042d53a7SEvalZero
967*042d53a7SEvalZero ble_ll_ctrl_phy_update_proc_complete(connsm);
968*042d53a7SEvalZero
969*042d53a7SEvalZero return BLE_ERR_MAX;
970*042d53a7SEvalZero }
971*042d53a7SEvalZero #endif
972*042d53a7SEvalZero
973*042d53a7SEvalZero /**
974*042d53a7SEvalZero * Create a link layer length request or length response PDU.
975*042d53a7SEvalZero *
976*042d53a7SEvalZero * NOTE: this function does not set the LL data pdu header nor does it
977*042d53a7SEvalZero * set the opcode in the buffer.
978*042d53a7SEvalZero *
979*042d53a7SEvalZero * @param connsm
980*042d53a7SEvalZero * @param dptr: Pointer to where control pdu payload starts
981*042d53a7SEvalZero */
982*042d53a7SEvalZero static void
ble_ll_ctrl_datalen_upd_make(struct ble_ll_conn_sm * connsm,uint8_t * dptr)983*042d53a7SEvalZero ble_ll_ctrl_datalen_upd_make(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
984*042d53a7SEvalZero {
985*042d53a7SEvalZero put_le16(dptr + 1, connsm->max_rx_octets);
986*042d53a7SEvalZero put_le16(dptr + 3, connsm->max_rx_time);
987*042d53a7SEvalZero put_le16(dptr + 5, connsm->max_tx_octets);
988*042d53a7SEvalZero put_le16(dptr + 7, connsm->max_tx_time);
989*042d53a7SEvalZero }
990*042d53a7SEvalZero
991*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
992*042d53a7SEvalZero void
ble_ll_calc_session_key(struct ble_ll_conn_sm * connsm)993*042d53a7SEvalZero ble_ll_calc_session_key(struct ble_ll_conn_sm *connsm)
994*042d53a7SEvalZero {
995*042d53a7SEvalZero #ifdef BLE_LL_ENCRYPT_DEBUG
996*042d53a7SEvalZero int cnt;
997*042d53a7SEvalZero #endif
998*042d53a7SEvalZero
999*042d53a7SEvalZero /* XXX: possibly have some way out of this if this locks up */
1000*042d53a7SEvalZero while (1) {
1001*042d53a7SEvalZero if (!ble_hw_encrypt_block(&connsm->enc_data.enc_block)) {
1002*042d53a7SEvalZero break;
1003*042d53a7SEvalZero }
1004*042d53a7SEvalZero }
1005*042d53a7SEvalZero
1006*042d53a7SEvalZero #ifdef BLE_LL_ENCRYPT_DEBUG
1007*042d53a7SEvalZero console_printf("Calculating Session Key for handle=%u",
1008*042d53a7SEvalZero connsm->conn_handle);
1009*042d53a7SEvalZero
1010*042d53a7SEvalZero console_printf("\nLTK:");
1011*042d53a7SEvalZero for (cnt = 0; cnt < 16; ++cnt) {
1012*042d53a7SEvalZero console_printf("%02x", connsm->enc_data.enc_block.key[cnt]);
1013*042d53a7SEvalZero }
1014*042d53a7SEvalZero console_printf("\nSKD:");
1015*042d53a7SEvalZero for (cnt = 0; cnt < 16; ++cnt) {
1016*042d53a7SEvalZero console_printf("%02x", connsm->enc_data.enc_block.plain_text[cnt]);
1017*042d53a7SEvalZero }
1018*042d53a7SEvalZero console_printf("\nSession Key:");
1019*042d53a7SEvalZero for (cnt = 0; cnt < 16; ++cnt) {
1020*042d53a7SEvalZero console_printf("%02x", connsm->enc_data.enc_block.cipher_text[cnt]);
1021*042d53a7SEvalZero }
1022*042d53a7SEvalZero console_printf("\nIV:");
1023*042d53a7SEvalZero for (cnt = 0; cnt < 8; ++ cnt) {
1024*042d53a7SEvalZero console_printf("%02x", connsm->enc_data.iv[cnt]);
1025*042d53a7SEvalZero }
1026*042d53a7SEvalZero console_printf("\n");
1027*042d53a7SEvalZero #endif
1028*042d53a7SEvalZero }
1029*042d53a7SEvalZero
1030*042d53a7SEvalZero /**
1031*042d53a7SEvalZero * Called to determine if this is a control PDU we are allowed to send. This
1032*042d53a7SEvalZero * is called when a link is being encrypted, as only certain control PDU's
1033*042d53a7SEvalZero * area lowed to be sent.
1034*042d53a7SEvalZero *
1035*042d53a7SEvalZero * XXX: the current code may actually allow some control pdu's to be sent
1036*042d53a7SEvalZero * in states where they shouldnt. I dont expect those states to occur so I
1037*042d53a7SEvalZero * dont try to check for them but we could do more... for example there are
1038*042d53a7SEvalZero * different PDUs allowed for master/slave and TX/RX
1039*042d53a7SEvalZero *
1040*042d53a7SEvalZero * @param llid
1041*042d53a7SEvalZero * @param opcode
1042*042d53a7SEvalZero * @param len
1043*042d53a7SEvalZero *
1044*042d53a7SEvalZero * @return int
1045*042d53a7SEvalZero */
1046*042d53a7SEvalZero static int
ble_ll_ctrl_enc_allowed_pdu(uint8_t llid,uint8_t len,uint8_t opcode)1047*042d53a7SEvalZero ble_ll_ctrl_enc_allowed_pdu(uint8_t llid, uint8_t len, uint8_t opcode)
1048*042d53a7SEvalZero {
1049*042d53a7SEvalZero int allowed;
1050*042d53a7SEvalZero
1051*042d53a7SEvalZero allowed = 0;
1052*042d53a7SEvalZero
1053*042d53a7SEvalZero switch (llid) {
1054*042d53a7SEvalZero case BLE_LL_LLID_CTRL:
1055*042d53a7SEvalZero switch (opcode) {
1056*042d53a7SEvalZero case BLE_LL_CTRL_REJECT_IND:
1057*042d53a7SEvalZero case BLE_LL_CTRL_REJECT_IND_EXT:
1058*042d53a7SEvalZero case BLE_LL_CTRL_START_ENC_RSP:
1059*042d53a7SEvalZero case BLE_LL_CTRL_START_ENC_REQ:
1060*042d53a7SEvalZero case BLE_LL_CTRL_ENC_REQ:
1061*042d53a7SEvalZero case BLE_LL_CTRL_ENC_RSP:
1062*042d53a7SEvalZero case BLE_LL_CTRL_PAUSE_ENC_REQ:
1063*042d53a7SEvalZero case BLE_LL_CTRL_PAUSE_ENC_RSP:
1064*042d53a7SEvalZero case BLE_LL_CTRL_TERMINATE_IND:
1065*042d53a7SEvalZero allowed = 1;
1066*042d53a7SEvalZero break;
1067*042d53a7SEvalZero }
1068*042d53a7SEvalZero break;
1069*042d53a7SEvalZero case BLE_LL_LLID_DATA_FRAG:
1070*042d53a7SEvalZero if (len == 0) {
1071*042d53a7SEvalZero /* Empty PDUs are allowed */
1072*042d53a7SEvalZero allowed = 1;
1073*042d53a7SEvalZero }
1074*042d53a7SEvalZero break;
1075*042d53a7SEvalZero }
1076*042d53a7SEvalZero
1077*042d53a7SEvalZero return allowed;
1078*042d53a7SEvalZero }
1079*042d53a7SEvalZero
1080*042d53a7SEvalZero int
ble_ll_ctrl_enc_allowed_pdu_rx(struct os_mbuf * rxpdu)1081*042d53a7SEvalZero ble_ll_ctrl_enc_allowed_pdu_rx(struct os_mbuf *rxpdu)
1082*042d53a7SEvalZero {
1083*042d53a7SEvalZero uint8_t llid;
1084*042d53a7SEvalZero uint8_t len;
1085*042d53a7SEvalZero uint8_t opcode;
1086*042d53a7SEvalZero
1087*042d53a7SEvalZero llid = rxpdu->om_data[0] & BLE_LL_DATA_HDR_LLID_MASK;
1088*042d53a7SEvalZero len = rxpdu->om_data[1];
1089*042d53a7SEvalZero if (llid == BLE_LL_LLID_CTRL) {
1090*042d53a7SEvalZero opcode = rxpdu->om_data[2];
1091*042d53a7SEvalZero } else {
1092*042d53a7SEvalZero opcode = 0;
1093*042d53a7SEvalZero }
1094*042d53a7SEvalZero
1095*042d53a7SEvalZero return ble_ll_ctrl_enc_allowed_pdu(llid, len, opcode);
1096*042d53a7SEvalZero }
1097*042d53a7SEvalZero
1098*042d53a7SEvalZero int
ble_ll_ctrl_enc_allowed_pdu_tx(struct os_mbuf_pkthdr * pkthdr)1099*042d53a7SEvalZero ble_ll_ctrl_enc_allowed_pdu_tx(struct os_mbuf_pkthdr *pkthdr)
1100*042d53a7SEvalZero {
1101*042d53a7SEvalZero struct os_mbuf *m;
1102*042d53a7SEvalZero struct ble_mbuf_hdr *ble_hdr;
1103*042d53a7SEvalZero uint8_t llid;
1104*042d53a7SEvalZero uint8_t len;
1105*042d53a7SEvalZero uint8_t opcode;
1106*042d53a7SEvalZero
1107*042d53a7SEvalZero m = OS_MBUF_PKTHDR_TO_MBUF(pkthdr);
1108*042d53a7SEvalZero ble_hdr = BLE_MBUF_HDR_PTR(m);
1109*042d53a7SEvalZero
1110*042d53a7SEvalZero llid = ble_hdr->txinfo.hdr_byte & BLE_LL_DATA_HDR_LLID_MASK;
1111*042d53a7SEvalZero len = ble_hdr->txinfo.pyld_len;
1112*042d53a7SEvalZero if (llid == BLE_LL_LLID_CTRL) {
1113*042d53a7SEvalZero opcode = m->om_data[0];
1114*042d53a7SEvalZero } else {
1115*042d53a7SEvalZero opcode = 0;
1116*042d53a7SEvalZero }
1117*042d53a7SEvalZero
1118*042d53a7SEvalZero return ble_ll_ctrl_enc_allowed_pdu(llid, len, opcode);
1119*042d53a7SEvalZero }
1120*042d53a7SEvalZero
1121*042d53a7SEvalZero int
ble_ll_ctrl_is_start_enc_rsp(struct os_mbuf * txpdu)1122*042d53a7SEvalZero ble_ll_ctrl_is_start_enc_rsp(struct os_mbuf *txpdu)
1123*042d53a7SEvalZero {
1124*042d53a7SEvalZero int is_start_enc_rsp;
1125*042d53a7SEvalZero uint8_t opcode;
1126*042d53a7SEvalZero uint8_t llid;
1127*042d53a7SEvalZero struct ble_mbuf_hdr *ble_hdr;
1128*042d53a7SEvalZero
1129*042d53a7SEvalZero is_start_enc_rsp = 0;
1130*042d53a7SEvalZero ble_hdr = BLE_MBUF_HDR_PTR(txpdu);
1131*042d53a7SEvalZero
1132*042d53a7SEvalZero llid = ble_hdr->txinfo.hdr_byte & BLE_LL_DATA_HDR_LLID_MASK;
1133*042d53a7SEvalZero if (llid == BLE_LL_LLID_CTRL) {
1134*042d53a7SEvalZero opcode = txpdu->om_data[0];
1135*042d53a7SEvalZero if (opcode == BLE_LL_CTRL_START_ENC_RSP) {
1136*042d53a7SEvalZero is_start_enc_rsp = 1;
1137*042d53a7SEvalZero }
1138*042d53a7SEvalZero }
1139*042d53a7SEvalZero
1140*042d53a7SEvalZero return is_start_enc_rsp;
1141*042d53a7SEvalZero }
1142*042d53a7SEvalZero
1143*042d53a7SEvalZero /**
1144*042d53a7SEvalZero * Called to create and send a LL_START_ENC_REQ
1145*042d53a7SEvalZero *
1146*042d53a7SEvalZero * @param connsm
1147*042d53a7SEvalZero * @param err
1148*042d53a7SEvalZero *
1149*042d53a7SEvalZero * @return int
1150*042d53a7SEvalZero */
1151*042d53a7SEvalZero int
ble_ll_ctrl_start_enc_send(struct ble_ll_conn_sm * connsm)1152*042d53a7SEvalZero ble_ll_ctrl_start_enc_send(struct ble_ll_conn_sm *connsm)
1153*042d53a7SEvalZero {
1154*042d53a7SEvalZero int rc;
1155*042d53a7SEvalZero struct os_mbuf *om;
1156*042d53a7SEvalZero
1157*042d53a7SEvalZero om = os_msys_get_pkthdr(BLE_LL_CTRL_MAX_PDU_LEN,
1158*042d53a7SEvalZero sizeof(struct ble_mbuf_hdr));
1159*042d53a7SEvalZero if (om) {
1160*042d53a7SEvalZero om->om_data[0] = BLE_LL_CTRL_START_ENC_REQ;
1161*042d53a7SEvalZero ble_ll_conn_enqueue_pkt(connsm, om, BLE_LL_LLID_CTRL, 1);
1162*042d53a7SEvalZero
1163*042d53a7SEvalZero /* Wait for LL_START_ENC_RSP */
1164*042d53a7SEvalZero connsm->cur_ctrl_proc = BLE_LL_CTRL_PROC_ENCRYPT;
1165*042d53a7SEvalZero ble_ll_ctrl_start_rsp_timer(connsm);
1166*042d53a7SEvalZero
1167*042d53a7SEvalZero rc = 0;
1168*042d53a7SEvalZero } else {
1169*042d53a7SEvalZero rc = -1;
1170*042d53a7SEvalZero }
1171*042d53a7SEvalZero return rc;
1172*042d53a7SEvalZero }
1173*042d53a7SEvalZero
1174*042d53a7SEvalZero /**
1175*042d53a7SEvalZero * Create a link layer control "encrypt request" PDU.
1176*042d53a7SEvalZero *
1177*042d53a7SEvalZero * The LL_ENC_REQ PDU format is:
1178*042d53a7SEvalZero * Rand (8)
1179*042d53a7SEvalZero * EDIV (2)
1180*042d53a7SEvalZero * SKDm (8)
1181*042d53a7SEvalZero * IVm (4)
1182*042d53a7SEvalZero *
1183*042d53a7SEvalZero * The random number and encrypted diversifier come from the host command.
1184*042d53a7SEvalZero * Controller generates master portion of SDK and IV.
1185*042d53a7SEvalZero *
1186*042d53a7SEvalZero * NOTE: this function does not set the LL data pdu header nor does it
1187*042d53a7SEvalZero * set the opcode in the buffer.
1188*042d53a7SEvalZero *
1189*042d53a7SEvalZero * @param connsm
1190*042d53a7SEvalZero * @param dptr: Pointer to where control pdu payload starts
1191*042d53a7SEvalZero */
1192*042d53a7SEvalZero static void
ble_ll_ctrl_enc_req_make(struct ble_ll_conn_sm * connsm,uint8_t * dptr)1193*042d53a7SEvalZero ble_ll_ctrl_enc_req_make(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
1194*042d53a7SEvalZero {
1195*042d53a7SEvalZero put_le64(dptr, connsm->enc_data.host_rand_num);
1196*042d53a7SEvalZero put_le16(dptr + 8, connsm->enc_data.enc_div);
1197*042d53a7SEvalZero
1198*042d53a7SEvalZero #ifdef BLE_LL_ENCRYPT_USE_TEST_DATA
1199*042d53a7SEvalZero /* IV stored LSB to MSB, IVm is LSB, IVs is MSB */
1200*042d53a7SEvalZero put_le64(dptr + 10, g_bletest_SKDm);
1201*042d53a7SEvalZero swap_buf(connsm->enc_data.enc_block.plain_text + 8, dptr + 10, 8);
1202*042d53a7SEvalZero put_le32(dptr + 18, g_bletest_IVm);
1203*042d53a7SEvalZero memcpy(connsm->enc_data.iv, dptr + 18, 4);
1204*042d53a7SEvalZero return;
1205*042d53a7SEvalZero #endif
1206*042d53a7SEvalZero
1207*042d53a7SEvalZero ble_ll_rand_data_get(connsm->enc_data.enc_block.plain_text + 8, 8);
1208*042d53a7SEvalZero swap_buf(dptr + 10, connsm->enc_data.enc_block.plain_text + 8, 8);
1209*042d53a7SEvalZero ble_ll_rand_data_get(connsm->enc_data.iv, 4);
1210*042d53a7SEvalZero memcpy(dptr + 18, connsm->enc_data.iv, 4);
1211*042d53a7SEvalZero }
1212*042d53a7SEvalZero
1213*042d53a7SEvalZero /**
1214*042d53a7SEvalZero * Called when LL_ENC_RSP is received by the master.
1215*042d53a7SEvalZero *
1216*042d53a7SEvalZero * Context: Link Layer Task.
1217*042d53a7SEvalZero *
1218*042d53a7SEvalZero * Format of the LL_ENC_RSP is:
1219*042d53a7SEvalZero * SKDs (8)
1220*042d53a7SEvalZero * IVs (4)
1221*042d53a7SEvalZero *
1222*042d53a7SEvalZero * The master now has the long term key (from the start encrypt command)
1223*042d53a7SEvalZero * and the SKD (stored in the plain text encryption block). From this the
1224*042d53a7SEvalZero * sessionKey is generated.
1225*042d53a7SEvalZero *
1226*042d53a7SEvalZero * @param connsm
1227*042d53a7SEvalZero * @param dptr
1228*042d53a7SEvalZero */
1229*042d53a7SEvalZero static void
ble_ll_ctrl_rx_enc_rsp(struct ble_ll_conn_sm * connsm,uint8_t * dptr)1230*042d53a7SEvalZero ble_ll_ctrl_rx_enc_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
1231*042d53a7SEvalZero {
1232*042d53a7SEvalZero /* Calculate session key now that we have received the ENC_RSP */
1233*042d53a7SEvalZero if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_ENCRYPT) {
1234*042d53a7SEvalZero /* In case we were already encrypted we need to reset packet counters */
1235*042d53a7SEvalZero connsm->enc_data.rx_pkt_cntr = 0;
1236*042d53a7SEvalZero connsm->enc_data.tx_pkt_cntr = 0;
1237*042d53a7SEvalZero connsm->enc_data.tx_encrypted = 0;
1238*042d53a7SEvalZero
1239*042d53a7SEvalZero swap_buf(connsm->enc_data.enc_block.plain_text, dptr, 8);
1240*042d53a7SEvalZero memcpy(connsm->enc_data.iv + 4, dptr + 8, 4);
1241*042d53a7SEvalZero ble_ll_calc_session_key(connsm);
1242*042d53a7SEvalZero connsm->enc_data.enc_state = CONN_ENC_S_START_ENC_REQ_WAIT;
1243*042d53a7SEvalZero }
1244*042d53a7SEvalZero }
1245*042d53a7SEvalZero
1246*042d53a7SEvalZero /**
1247*042d53a7SEvalZero * Called when we have received a LL control encryption request PDU. This
1248*042d53a7SEvalZero * should only be received by a slave.
1249*042d53a7SEvalZero *
1250*042d53a7SEvalZero * The LL_ENC_REQ PDU format is:
1251*042d53a7SEvalZero * Rand (8)
1252*042d53a7SEvalZero * EDIV (2)
1253*042d53a7SEvalZero * SKDm (8)
1254*042d53a7SEvalZero * IVm (4)
1255*042d53a7SEvalZero *
1256*042d53a7SEvalZero * This function returns the response opcode. Typically this will be ENC_RSP
1257*042d53a7SEvalZero * but it could be a reject ind. Note that the caller of this function
1258*042d53a7SEvalZero * will send the REJECT_IND_EXT if supported by remote.
1259*042d53a7SEvalZero *
1260*042d53a7SEvalZero * NOTE: if this is received by a master we will silently discard the PDU
1261*042d53a7SEvalZero * (denoted by return BLE_ERR_MAX).
1262*042d53a7SEvalZero *
1263*042d53a7SEvalZero * @param connsm
1264*042d53a7SEvalZero * @param dptr Pointer to start of encrypt request data.
1265*042d53a7SEvalZero * @param rspbuf
1266*042d53a7SEvalZero */
1267*042d53a7SEvalZero static uint8_t
ble_ll_ctrl_rx_enc_req(struct ble_ll_conn_sm * connsm,uint8_t * dptr,uint8_t * rspdata)1268*042d53a7SEvalZero ble_ll_ctrl_rx_enc_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
1269*042d53a7SEvalZero uint8_t *rspdata)
1270*042d53a7SEvalZero {
1271*042d53a7SEvalZero if (connsm->conn_role != BLE_LL_CONN_ROLE_SLAVE) {
1272*042d53a7SEvalZero return BLE_LL_CTRL_UNKNOWN_RSP;
1273*042d53a7SEvalZero }
1274*042d53a7SEvalZero
1275*042d53a7SEvalZero /* In case we were already encrypted we need to reset packet counters */
1276*042d53a7SEvalZero connsm->enc_data.rx_pkt_cntr = 0;
1277*042d53a7SEvalZero connsm->enc_data.tx_pkt_cntr = 0;
1278*042d53a7SEvalZero connsm->enc_data.tx_encrypted = 0;
1279*042d53a7SEvalZero
1280*042d53a7SEvalZero /* Extract information from request */
1281*042d53a7SEvalZero connsm->enc_data.host_rand_num = get_le64(dptr);
1282*042d53a7SEvalZero connsm->enc_data.enc_div = get_le16(dptr + 8);
1283*042d53a7SEvalZero
1284*042d53a7SEvalZero #if BLE_LL_ENCRYPT_USE_TEST_DATA
1285*042d53a7SEvalZero swap_buf(connsm->enc_data.enc_block.plain_text + 8, dptr + 10, 8);
1286*042d53a7SEvalZero memcpy(connsm->enc_data.iv, dptr + 18, 4);
1287*042d53a7SEvalZero
1288*042d53a7SEvalZero put_le64(rspdata, g_bletest_SKDs);
1289*042d53a7SEvalZero swap_buf(connsm->enc_data.enc_block.plain_text, rspdata, 8);
1290*042d53a7SEvalZero put_le32(rspdata + 8, g_bletest_IVs);
1291*042d53a7SEvalZero memcpy(connsm->enc_data.iv + 4, rspdata + 8, 4);
1292*042d53a7SEvalZero return BLE_LL_CTRL_ENC_RSP;
1293*042d53a7SEvalZero #endif
1294*042d53a7SEvalZero
1295*042d53a7SEvalZero swap_buf(connsm->enc_data.enc_block.plain_text + 8, dptr + 10, 8);
1296*042d53a7SEvalZero memcpy(connsm->enc_data.iv, dptr + 18, 4);
1297*042d53a7SEvalZero
1298*042d53a7SEvalZero /* Create the ENC_RSP. Concatenate our SKD and IV */
1299*042d53a7SEvalZero ble_ll_rand_data_get(connsm->enc_data.enc_block.plain_text, 8);
1300*042d53a7SEvalZero swap_buf(rspdata, connsm->enc_data.enc_block.plain_text, 8);
1301*042d53a7SEvalZero ble_ll_rand_data_get(connsm->enc_data.iv + 4, 4);
1302*042d53a7SEvalZero memcpy(rspdata + 8, connsm->enc_data.iv + 4, 4);
1303*042d53a7SEvalZero
1304*042d53a7SEvalZero return BLE_LL_CTRL_ENC_RSP;
1305*042d53a7SEvalZero }
1306*042d53a7SEvalZero
1307*042d53a7SEvalZero static uint8_t
ble_ll_ctrl_rx_start_enc_req(struct ble_ll_conn_sm * connsm)1308*042d53a7SEvalZero ble_ll_ctrl_rx_start_enc_req(struct ble_ll_conn_sm *connsm)
1309*042d53a7SEvalZero {
1310*042d53a7SEvalZero int rc;
1311*042d53a7SEvalZero
1312*042d53a7SEvalZero /* Only master should receive start enc request */
1313*042d53a7SEvalZero rc = BLE_ERR_MAX;
1314*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
1315*042d53a7SEvalZero /* We only want to send a START_ENC_RSP if we havent yet */
1316*042d53a7SEvalZero if (connsm->enc_data.enc_state == CONN_ENC_S_START_ENC_REQ_WAIT) {
1317*042d53a7SEvalZero connsm->enc_data.enc_state = CONN_ENC_S_START_ENC_RSP_WAIT;
1318*042d53a7SEvalZero rc = BLE_LL_CTRL_START_ENC_RSP;
1319*042d53a7SEvalZero }
1320*042d53a7SEvalZero } else {
1321*042d53a7SEvalZero rc = BLE_LL_CTRL_UNKNOWN_RSP;
1322*042d53a7SEvalZero }
1323*042d53a7SEvalZero return rc;
1324*042d53a7SEvalZero }
1325*042d53a7SEvalZero
1326*042d53a7SEvalZero static uint8_t
ble_ll_ctrl_rx_pause_enc_req(struct ble_ll_conn_sm * connsm)1327*042d53a7SEvalZero ble_ll_ctrl_rx_pause_enc_req(struct ble_ll_conn_sm *connsm)
1328*042d53a7SEvalZero {
1329*042d53a7SEvalZero int rc;
1330*042d53a7SEvalZero
1331*042d53a7SEvalZero /*
1332*042d53a7SEvalZero * The spec does not say what to do here, but if we receive a pause
1333*042d53a7SEvalZero * encryption request and we are not encrypted, what do we do? We
1334*042d53a7SEvalZero * ignore it...
1335*042d53a7SEvalZero */
1336*042d53a7SEvalZero rc = BLE_ERR_MAX;
1337*042d53a7SEvalZero if ((connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) &&
1338*042d53a7SEvalZero (connsm->enc_data.enc_state == CONN_ENC_S_ENCRYPTED)) {
1339*042d53a7SEvalZero rc = BLE_LL_CTRL_PAUSE_ENC_RSP;
1340*042d53a7SEvalZero } else {
1341*042d53a7SEvalZero rc = BLE_LL_CTRL_UNKNOWN_RSP;
1342*042d53a7SEvalZero }
1343*042d53a7SEvalZero
1344*042d53a7SEvalZero return rc;
1345*042d53a7SEvalZero }
1346*042d53a7SEvalZero
1347*042d53a7SEvalZero /**
1348*042d53a7SEvalZero * Called when a LL control pdu with opcode PAUSE_ENC_RSP is received.
1349*042d53a7SEvalZero *
1350*042d53a7SEvalZero *
1351*042d53a7SEvalZero * @param connsm
1352*042d53a7SEvalZero *
1353*042d53a7SEvalZero * @return uint8_t
1354*042d53a7SEvalZero */
1355*042d53a7SEvalZero static uint8_t
ble_ll_ctrl_rx_pause_enc_rsp(struct ble_ll_conn_sm * connsm)1356*042d53a7SEvalZero ble_ll_ctrl_rx_pause_enc_rsp(struct ble_ll_conn_sm *connsm)
1357*042d53a7SEvalZero {
1358*042d53a7SEvalZero int rc;
1359*042d53a7SEvalZero
1360*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
1361*042d53a7SEvalZero rc = BLE_LL_CTRL_PAUSE_ENC_RSP;
1362*042d53a7SEvalZero } else {
1363*042d53a7SEvalZero rc = BLE_LL_CTRL_UNKNOWN_RSP;
1364*042d53a7SEvalZero }
1365*042d53a7SEvalZero
1366*042d53a7SEvalZero return rc;
1367*042d53a7SEvalZero }
1368*042d53a7SEvalZero
1369*042d53a7SEvalZero /**
1370*042d53a7SEvalZero * Called when we have received a LL_CTRL_START_ENC_RSP.
1371*042d53a7SEvalZero *
1372*042d53a7SEvalZero * Context: Link-layer task
1373*042d53a7SEvalZero *
1374*042d53a7SEvalZero * @param connsm
1375*042d53a7SEvalZero *
1376*042d53a7SEvalZero * @return uint8_t
1377*042d53a7SEvalZero */
1378*042d53a7SEvalZero static uint8_t
ble_ll_ctrl_rx_start_enc_rsp(struct ble_ll_conn_sm * connsm)1379*042d53a7SEvalZero ble_ll_ctrl_rx_start_enc_rsp(struct ble_ll_conn_sm *connsm)
1380*042d53a7SEvalZero {
1381*042d53a7SEvalZero int rc;
1382*042d53a7SEvalZero
1383*042d53a7SEvalZero /* Not in proper state. Discard */
1384*042d53a7SEvalZero if (connsm->enc_data.enc_state != CONN_ENC_S_START_ENC_RSP_WAIT) {
1385*042d53a7SEvalZero return BLE_ERR_MAX;
1386*042d53a7SEvalZero }
1387*042d53a7SEvalZero
1388*042d53a7SEvalZero ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_ENCRYPT);
1389*042d53a7SEvalZero
1390*042d53a7SEvalZero /* If master, we are done. Stop control procedure and sent event to host */
1391*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
1392*042d53a7SEvalZero /* We are encrypted */
1393*042d53a7SEvalZero connsm->enc_data.enc_state = CONN_ENC_S_ENCRYPTED;
1394*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) == 1)
1395*042d53a7SEvalZero ble_ll_conn_auth_pyld_timer_start(connsm);
1396*042d53a7SEvalZero #endif
1397*042d53a7SEvalZero rc = BLE_ERR_MAX;
1398*042d53a7SEvalZero } else {
1399*042d53a7SEvalZero /* Procedure has completed but slave needs to send START_ENC_RSP */
1400*042d53a7SEvalZero rc = BLE_LL_CTRL_START_ENC_RSP;
1401*042d53a7SEvalZero }
1402*042d53a7SEvalZero
1403*042d53a7SEvalZero /*
1404*042d53a7SEvalZero * XXX: for now, a Slave sends this event when it receivest the
1405*042d53a7SEvalZero * START_ENC_RSP from the master. It might be technically incorrect
1406*042d53a7SEvalZero * to send it before we transmit our own START_ENC_RSP.
1407*042d53a7SEvalZero */
1408*042d53a7SEvalZero ble_ll_hci_ev_encrypt_chg(connsm, BLE_ERR_SUCCESS);
1409*042d53a7SEvalZero
1410*042d53a7SEvalZero return rc;
1411*042d53a7SEvalZero }
1412*042d53a7SEvalZero
1413*042d53a7SEvalZero #endif
1414*042d53a7SEvalZero
1415*042d53a7SEvalZero /**
1416*042d53a7SEvalZero * Called to make a connection parameter request or response control pdu.
1417*042d53a7SEvalZero *
1418*042d53a7SEvalZero * @param connsm
1419*042d53a7SEvalZero * @param dptr Pointer to start of data. NOTE: the opcode is not part
1420*042d53a7SEvalZero * of the data.
1421*042d53a7SEvalZero */
1422*042d53a7SEvalZero static void
ble_ll_ctrl_conn_param_pdu_make(struct ble_ll_conn_sm * connsm,uint8_t * dptr,struct ble_ll_conn_params * req)1423*042d53a7SEvalZero ble_ll_ctrl_conn_param_pdu_make(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
1424*042d53a7SEvalZero struct ble_ll_conn_params *req)
1425*042d53a7SEvalZero {
1426*042d53a7SEvalZero uint16_t offset;
1427*042d53a7SEvalZero struct hci_conn_update *hcu;
1428*042d53a7SEvalZero
1429*042d53a7SEvalZero /* If we were passed in a request, we use the parameters from the request */
1430*042d53a7SEvalZero if (req) {
1431*042d53a7SEvalZero put_le16(dptr, req->interval_min);
1432*042d53a7SEvalZero put_le16(dptr + 2, req->interval_max);
1433*042d53a7SEvalZero put_le16(dptr + 4, req->latency);
1434*042d53a7SEvalZero put_le16(dptr + 6, req->timeout);
1435*042d53a7SEvalZero } else {
1436*042d53a7SEvalZero hcu = &connsm->conn_param_req;
1437*042d53a7SEvalZero /* The host should have provided the parameters! */
1438*042d53a7SEvalZero BLE_LL_ASSERT(hcu->handle != 0);
1439*042d53a7SEvalZero put_le16(dptr, hcu->conn_itvl_min);
1440*042d53a7SEvalZero put_le16(dptr + 2, hcu->conn_itvl_max);
1441*042d53a7SEvalZero put_le16(dptr + 4, hcu->conn_latency);
1442*042d53a7SEvalZero put_le16(dptr + 6, hcu->supervision_timeout);
1443*042d53a7SEvalZero }
1444*042d53a7SEvalZero
1445*042d53a7SEvalZero /* XXX: NOTE: if interval min and interval max are != to each
1446*042d53a7SEvalZero * other this value should be set to non-zero. I think this
1447*042d53a7SEvalZero * applies only when an offset field is set. See section 5.1.7.1 pg 103
1448*042d53a7SEvalZero * Vol 6 Part B.
1449*042d53a7SEvalZero */
1450*042d53a7SEvalZero /* XXX: for now, set periodicity to 0 */
1451*042d53a7SEvalZero dptr[8] = 0;
1452*042d53a7SEvalZero
1453*042d53a7SEvalZero /* XXX: deal with reference event count. what to put here? */
1454*042d53a7SEvalZero put_le16(dptr + 9, connsm->event_cntr);
1455*042d53a7SEvalZero
1456*042d53a7SEvalZero /* XXX: For now, dont use offsets */
1457*042d53a7SEvalZero offset = 0xFFFF;
1458*042d53a7SEvalZero put_le16(dptr + 11, offset);
1459*042d53a7SEvalZero put_le16(dptr + 13, offset);
1460*042d53a7SEvalZero put_le16(dptr + 15, offset);
1461*042d53a7SEvalZero put_le16(dptr + 17, offset);
1462*042d53a7SEvalZero put_le16(dptr + 19, offset);
1463*042d53a7SEvalZero put_le16(dptr + 21, offset);
1464*042d53a7SEvalZero }
1465*042d53a7SEvalZero
1466*042d53a7SEvalZero static void
ble_ll_ctrl_version_ind_make(struct ble_ll_conn_sm * connsm,uint8_t * pyld)1467*042d53a7SEvalZero ble_ll_ctrl_version_ind_make(struct ble_ll_conn_sm *connsm, uint8_t *pyld)
1468*042d53a7SEvalZero {
1469*042d53a7SEvalZero /* Set flag to denote we have sent/received this */
1470*042d53a7SEvalZero connsm->csmflags.cfbit.version_ind_sent = 1;
1471*042d53a7SEvalZero
1472*042d53a7SEvalZero /* Fill out response */
1473*042d53a7SEvalZero pyld[0] = BLE_HCI_VER_BCS_5_0;
1474*042d53a7SEvalZero put_le16(pyld + 1, MYNEWT_VAL(BLE_LL_MFRG_ID));
1475*042d53a7SEvalZero put_le16(pyld + 3, BLE_LL_SUB_VERS_NR);
1476*042d53a7SEvalZero }
1477*042d53a7SEvalZero
1478*042d53a7SEvalZero /**
1479*042d53a7SEvalZero * Called to make a LL control channel map request PDU.
1480*042d53a7SEvalZero *
1481*042d53a7SEvalZero * @param connsm Pointer to connection state machine
1482*042d53a7SEvalZero * @param pyld Pointer to payload of LL control PDU
1483*042d53a7SEvalZero */
1484*042d53a7SEvalZero static void
ble_ll_ctrl_chanmap_req_make(struct ble_ll_conn_sm * connsm,uint8_t * pyld)1485*042d53a7SEvalZero ble_ll_ctrl_chanmap_req_make(struct ble_ll_conn_sm *connsm, uint8_t *pyld)
1486*042d53a7SEvalZero {
1487*042d53a7SEvalZero /* Copy channel map that host desires into request */
1488*042d53a7SEvalZero memcpy(pyld, g_ble_ll_conn_params.master_chan_map, BLE_LL_CONN_CHMAP_LEN);
1489*042d53a7SEvalZero memcpy(connsm->req_chanmap, pyld, BLE_LL_CONN_CHMAP_LEN);
1490*042d53a7SEvalZero
1491*042d53a7SEvalZero /* Place instant into request */
1492*042d53a7SEvalZero connsm->chanmap_instant = connsm->event_cntr + connsm->slave_latency + 6 + 1;
1493*042d53a7SEvalZero put_le16(pyld + BLE_LL_CONN_CHMAP_LEN, connsm->chanmap_instant);
1494*042d53a7SEvalZero
1495*042d53a7SEvalZero /* Set scheduled flag */
1496*042d53a7SEvalZero connsm->csmflags.cfbit.chanmap_update_scheduled = 1;
1497*042d53a7SEvalZero }
1498*042d53a7SEvalZero
1499*042d53a7SEvalZero /**
1500*042d53a7SEvalZero * Called to respond to a LL control PDU connection parameter request or
1501*042d53a7SEvalZero * response.
1502*042d53a7SEvalZero *
1503*042d53a7SEvalZero * @param connsm
1504*042d53a7SEvalZero * @param rsp
1505*042d53a7SEvalZero * @param req
1506*042d53a7SEvalZero *
1507*042d53a7SEvalZero * @return uint8_t
1508*042d53a7SEvalZero */
1509*042d53a7SEvalZero uint8_t
ble_ll_ctrl_conn_param_reply(struct ble_ll_conn_sm * connsm,uint8_t * rsp,struct ble_ll_conn_params * req)1510*042d53a7SEvalZero ble_ll_ctrl_conn_param_reply(struct ble_ll_conn_sm *connsm, uint8_t *rsp,
1511*042d53a7SEvalZero struct ble_ll_conn_params *req)
1512*042d53a7SEvalZero {
1513*042d53a7SEvalZero uint8_t rsp_opcode;
1514*042d53a7SEvalZero
1515*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
1516*042d53a7SEvalZero /* Create a connection parameter response */
1517*042d53a7SEvalZero ble_ll_ctrl_conn_param_pdu_make(connsm, rsp + 1, req);
1518*042d53a7SEvalZero rsp_opcode = BLE_LL_CTRL_CONN_PARM_RSP;
1519*042d53a7SEvalZero } else {
1520*042d53a7SEvalZero /* Create a connection update pdu */
1521*042d53a7SEvalZero ble_ll_ctrl_conn_upd_make(connsm, rsp + 1, req);
1522*042d53a7SEvalZero rsp_opcode = BLE_LL_CTRL_CONN_UPDATE_IND;
1523*042d53a7SEvalZero }
1524*042d53a7SEvalZero
1525*042d53a7SEvalZero return rsp_opcode;
1526*042d53a7SEvalZero }
1527*042d53a7SEvalZero
1528*042d53a7SEvalZero /**
1529*042d53a7SEvalZero * Called when we have received a LL_REJECT_IND or LL_REJECT_IND_EXT link
1530*042d53a7SEvalZero * layer control Data Channel pdu.
1531*042d53a7SEvalZero *
1532*042d53a7SEvalZero * @param connsm
1533*042d53a7SEvalZero * @param dptr
1534*042d53a7SEvalZero * @param opcode
1535*042d53a7SEvalZero */
1536*042d53a7SEvalZero static int
ble_ll_ctrl_rx_reject_ind(struct ble_ll_conn_sm * connsm,uint8_t * dptr,uint8_t opcode,uint8_t * rspdata)1537*042d53a7SEvalZero ble_ll_ctrl_rx_reject_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
1538*042d53a7SEvalZero uint8_t opcode, uint8_t *rspdata)
1539*042d53a7SEvalZero {
1540*042d53a7SEvalZero uint8_t ble_error;
1541*042d53a7SEvalZero uint8_t rsp_opcode = BLE_ERR_MAX;
1542*042d53a7SEvalZero
1543*042d53a7SEvalZero /* Get error out of received PDU */
1544*042d53a7SEvalZero if (opcode == BLE_LL_CTRL_REJECT_IND) {
1545*042d53a7SEvalZero ble_error = dptr[0];
1546*042d53a7SEvalZero } else {
1547*042d53a7SEvalZero ble_error = dptr[1];
1548*042d53a7SEvalZero }
1549*042d53a7SEvalZero
1550*042d53a7SEvalZero /* XXX: should I check to make sure the rejected opcode is sane
1551*042d53a7SEvalZero if we receive ind ext? */
1552*042d53a7SEvalZero switch (connsm->cur_ctrl_proc) {
1553*042d53a7SEvalZero case BLE_LL_CTRL_PROC_CONN_PARAM_REQ:
1554*042d53a7SEvalZero if (opcode == BLE_LL_CTRL_REJECT_IND_EXT) {
1555*042d53a7SEvalZero /* As a master we should send connection update indication in this point */
1556*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
1557*042d53a7SEvalZero rsp_opcode = BLE_LL_CTRL_CONN_UPDATE_IND;
1558*042d53a7SEvalZero ble_ll_ctrl_conn_upd_make(connsm, rspdata, NULL);
1559*042d53a7SEvalZero connsm->reject_reason = BLE_ERR_SUCCESS;
1560*042d53a7SEvalZero } else {
1561*042d53a7SEvalZero ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ);
1562*042d53a7SEvalZero ble_ll_hci_ev_conn_update(connsm, ble_error);
1563*042d53a7SEvalZero }
1564*042d53a7SEvalZero }
1565*042d53a7SEvalZero break;
1566*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
1567*042d53a7SEvalZero case BLE_LL_CTRL_PROC_ENCRYPT:
1568*042d53a7SEvalZero ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_ENCRYPT);
1569*042d53a7SEvalZero ble_ll_hci_ev_encrypt_chg(connsm, ble_error);
1570*042d53a7SEvalZero connsm->enc_data.enc_state = CONN_ENC_S_UNENCRYPTED;
1571*042d53a7SEvalZero break;
1572*042d53a7SEvalZero #endif
1573*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
1574*042d53a7SEvalZero case BLE_LL_CTRL_PROC_PHY_UPDATE:
1575*042d53a7SEvalZero ble_ll_ctrl_phy_update_cancel(connsm, ble_error);
1576*042d53a7SEvalZero ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE);
1577*042d53a7SEvalZero break;
1578*042d53a7SEvalZero #endif
1579*042d53a7SEvalZero case BLE_LL_CTRL_PROC_DATA_LEN_UPD:
1580*042d53a7SEvalZero /* That should not happen according to Bluetooth 5.0 Vol6 Part B, 5.1.9
1581*042d53a7SEvalZero * However we need this workaround as there are devices on the market
1582*042d53a7SEvalZero * which do send LL_REJECT on LL_LENGTH_REQ when collision happens
1583*042d53a7SEvalZero */
1584*042d53a7SEvalZero ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD);
1585*042d53a7SEvalZero break;
1586*042d53a7SEvalZero default:
1587*042d53a7SEvalZero break;
1588*042d53a7SEvalZero }
1589*042d53a7SEvalZero
1590*042d53a7SEvalZero return rsp_opcode;
1591*042d53a7SEvalZero }
1592*042d53a7SEvalZero
1593*042d53a7SEvalZero /**
1594*042d53a7SEvalZero * Called when we receive a connection update event
1595*042d53a7SEvalZero *
1596*042d53a7SEvalZero * @param connsm
1597*042d53a7SEvalZero * @param dptr
1598*042d53a7SEvalZero *
1599*042d53a7SEvalZero * @return int
1600*042d53a7SEvalZero */
1601*042d53a7SEvalZero static int
ble_ll_ctrl_rx_conn_update(struct ble_ll_conn_sm * connsm,uint8_t * dptr)1602*042d53a7SEvalZero ble_ll_ctrl_rx_conn_update(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
1603*042d53a7SEvalZero {
1604*042d53a7SEvalZero uint8_t rsp_opcode;
1605*042d53a7SEvalZero uint16_t conn_events;
1606*042d53a7SEvalZero struct ble_ll_conn_upd_req *reqdata;
1607*042d53a7SEvalZero
1608*042d53a7SEvalZero /* Only a slave should receive this */
1609*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
1610*042d53a7SEvalZero return BLE_LL_CTRL_UNKNOWN_RSP;
1611*042d53a7SEvalZero }
1612*042d53a7SEvalZero
1613*042d53a7SEvalZero /* Retrieve parameters */
1614*042d53a7SEvalZero reqdata = &connsm->conn_update_req;
1615*042d53a7SEvalZero reqdata->winsize = dptr[0];
1616*042d53a7SEvalZero reqdata->winoffset = get_le16(dptr + 1);
1617*042d53a7SEvalZero reqdata->interval = get_le16(dptr + 3);
1618*042d53a7SEvalZero reqdata->latency = get_le16(dptr + 5);
1619*042d53a7SEvalZero reqdata->timeout = get_le16(dptr + 7);
1620*042d53a7SEvalZero reqdata->instant = get_le16(dptr + 9);
1621*042d53a7SEvalZero
1622*042d53a7SEvalZero /* XXX: validate them at some point. If they dont check out, we
1623*042d53a7SEvalZero return the unknown response */
1624*042d53a7SEvalZero rsp_opcode = BLE_ERR_MAX;
1625*042d53a7SEvalZero
1626*042d53a7SEvalZero /* If instant is in the past, we have to end the connection */
1627*042d53a7SEvalZero conn_events = (reqdata->instant - connsm->event_cntr) & 0xFFFF;
1628*042d53a7SEvalZero if (conn_events >= 32767) {
1629*042d53a7SEvalZero ble_ll_conn_timeout(connsm, BLE_ERR_INSTANT_PASSED);
1630*042d53a7SEvalZero } else {
1631*042d53a7SEvalZero connsm->csmflags.cfbit.conn_update_sched = 1;
1632*042d53a7SEvalZero
1633*042d53a7SEvalZero /*
1634*042d53a7SEvalZero * Errata says that receiving a connection update when the event
1635*042d53a7SEvalZero * counter is equal to the instant means wesimply ignore the window
1636*042d53a7SEvalZero * offset and window size. Anchor point has already been set based on
1637*042d53a7SEvalZero * first packet received in connection event. Given that we increment
1638*042d53a7SEvalZero * the event counter BEFORE checking to see if the instant is equal to
1639*042d53a7SEvalZero * the event counter what we do here is increment the instant and set
1640*042d53a7SEvalZero * the window offset and size to 0.
1641*042d53a7SEvalZero */
1642*042d53a7SEvalZero if (conn_events == 0) {
1643*042d53a7SEvalZero reqdata->winoffset = 0;
1644*042d53a7SEvalZero reqdata->winsize = 0;
1645*042d53a7SEvalZero reqdata->instant += 1;
1646*042d53a7SEvalZero }
1647*042d53a7SEvalZero }
1648*042d53a7SEvalZero
1649*042d53a7SEvalZero return rsp_opcode;
1650*042d53a7SEvalZero }
1651*042d53a7SEvalZero
1652*042d53a7SEvalZero void
ble_ll_ctrl_initiate_dle(struct ble_ll_conn_sm * connsm)1653*042d53a7SEvalZero ble_ll_ctrl_initiate_dle(struct ble_ll_conn_sm *connsm)
1654*042d53a7SEvalZero {
1655*042d53a7SEvalZero if (!(connsm->conn_features & BLE_LL_FEAT_DATA_LEN_EXT)) {
1656*042d53a7SEvalZero return;
1657*042d53a7SEvalZero }
1658*042d53a7SEvalZero
1659*042d53a7SEvalZero /*
1660*042d53a7SEvalZero * Section 4.5.10 Vol 6 PART B. If the max tx/rx time or octets
1661*042d53a7SEvalZero * exceeds the minimum, data length procedure needs to occur
1662*042d53a7SEvalZero */
1663*042d53a7SEvalZero if ((connsm->max_tx_octets <= BLE_LL_CONN_SUPP_BYTES_MIN) &&
1664*042d53a7SEvalZero (connsm->max_rx_octets <= BLE_LL_CONN_SUPP_BYTES_MIN) &&
1665*042d53a7SEvalZero (connsm->max_tx_time <= BLE_LL_CONN_SUPP_TIME_MIN) &&
1666*042d53a7SEvalZero (connsm->max_rx_time <= BLE_LL_CONN_SUPP_TIME_MIN)) {
1667*042d53a7SEvalZero return;
1668*042d53a7SEvalZero }
1669*042d53a7SEvalZero
1670*042d53a7SEvalZero ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD);
1671*042d53a7SEvalZero }
1672*042d53a7SEvalZero
1673*042d53a7SEvalZero /**
1674*042d53a7SEvalZero * Called when we receive a feature request or a slave initiated feature
1675*042d53a7SEvalZero * request.
1676*042d53a7SEvalZero *
1677*042d53a7SEvalZero *
1678*042d53a7SEvalZero * @param connsm
1679*042d53a7SEvalZero * @param dptr
1680*042d53a7SEvalZero * @param rspbuf
1681*042d53a7SEvalZero * @param opcode
1682*042d53a7SEvalZero *
1683*042d53a7SEvalZero * @return int
1684*042d53a7SEvalZero */
1685*042d53a7SEvalZero static int
ble_ll_ctrl_rx_feature_req(struct ble_ll_conn_sm * connsm,uint8_t * dptr,uint8_t * rspbuf,uint8_t opcode)1686*042d53a7SEvalZero ble_ll_ctrl_rx_feature_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
1687*042d53a7SEvalZero uint8_t *rspbuf, uint8_t opcode)
1688*042d53a7SEvalZero {
1689*042d53a7SEvalZero uint8_t rsp_opcode;
1690*042d53a7SEvalZero uint32_t our_feat;
1691*042d53a7SEvalZero
1692*042d53a7SEvalZero /*
1693*042d53a7SEvalZero * Only accept slave feature requests if we are a master and feature
1694*042d53a7SEvalZero * requests if we are a slave.
1695*042d53a7SEvalZero */
1696*042d53a7SEvalZero if (opcode == BLE_LL_CTRL_SLAVE_FEATURE_REQ) {
1697*042d53a7SEvalZero if (connsm->conn_role != BLE_LL_CONN_ROLE_MASTER) {
1698*042d53a7SEvalZero return BLE_LL_CTRL_UNKNOWN_RSP;
1699*042d53a7SEvalZero }
1700*042d53a7SEvalZero } else {
1701*042d53a7SEvalZero /* XXX: not sure this is correct but do it anyway */
1702*042d53a7SEvalZero if (connsm->conn_role != BLE_LL_CONN_ROLE_SLAVE) {
1703*042d53a7SEvalZero return BLE_LL_CTRL_UNKNOWN_RSP;
1704*042d53a7SEvalZero }
1705*042d53a7SEvalZero }
1706*042d53a7SEvalZero
1707*042d53a7SEvalZero our_feat = ble_ll_read_supp_features();
1708*042d53a7SEvalZero
1709*042d53a7SEvalZero rsp_opcode = BLE_LL_CTRL_FEATURE_RSP;
1710*042d53a7SEvalZero
1711*042d53a7SEvalZero /*
1712*042d53a7SEvalZero * 1st octet of features should be common features of local and remote
1713*042d53a7SEvalZero * controller - we call this 'connection features'
1714*042d53a7SEvalZero * remaining octets are features of controller which sends PDU, in this case
1715*042d53a7SEvalZero * it's our controller
1716*042d53a7SEvalZero *
1717*042d53a7SEvalZero * See: Vol 6, Part B, section 2.4.2.10
1718*042d53a7SEvalZero */
1719*042d53a7SEvalZero
1720*042d53a7SEvalZero connsm->conn_features = dptr[0] & our_feat;
1721*042d53a7SEvalZero memset(rspbuf + 1, 0, 8);
1722*042d53a7SEvalZero put_le32(rspbuf + 1, our_feat);
1723*042d53a7SEvalZero rspbuf[1] = connsm->conn_features;
1724*042d53a7SEvalZero
1725*042d53a7SEvalZero /* If this is the first time we received remote features, try to start DLE */
1726*042d53a7SEvalZero if (!connsm->csmflags.cfbit.rxd_features) {
1727*042d53a7SEvalZero ble_ll_ctrl_initiate_dle(connsm);
1728*042d53a7SEvalZero connsm->csmflags.cfbit.rxd_features = 1;
1729*042d53a7SEvalZero }
1730*042d53a7SEvalZero
1731*042d53a7SEvalZero return rsp_opcode;
1732*042d53a7SEvalZero }
1733*042d53a7SEvalZero
1734*042d53a7SEvalZero /**
1735*042d53a7SEvalZero *
1736*042d53a7SEvalZero *
1737*042d53a7SEvalZero * Context: Link Layer task
1738*042d53a7SEvalZero *
1739*042d53a7SEvalZero * @param connsm
1740*042d53a7SEvalZero * @param dptr
1741*042d53a7SEvalZero * @param rspbuf
1742*042d53a7SEvalZero *
1743*042d53a7SEvalZero * @return int
1744*042d53a7SEvalZero */
1745*042d53a7SEvalZero static int
ble_ll_ctrl_rx_conn_param_req(struct ble_ll_conn_sm * connsm,uint8_t * dptr,uint8_t * rspbuf)1746*042d53a7SEvalZero ble_ll_ctrl_rx_conn_param_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
1747*042d53a7SEvalZero uint8_t *rspbuf)
1748*042d53a7SEvalZero {
1749*042d53a7SEvalZero uint8_t rsp_opcode;
1750*042d53a7SEvalZero
1751*042d53a7SEvalZero /*
1752*042d53a7SEvalZero * This is not in the specification per se but it simplifies the
1753*042d53a7SEvalZero * implementation. If we get a connection parameter request and we
1754*042d53a7SEvalZero * are awaiting a reply from the host, simply ignore the request. This
1755*042d53a7SEvalZero * might not be a good idea if the parameters are different, but oh
1756*042d53a7SEvalZero * well. This is not expected to happen anyway. A return of BLE_ERR_MAX
1757*042d53a7SEvalZero * means that we will simply discard the connection parameter request
1758*042d53a7SEvalZero */
1759*042d53a7SEvalZero if (connsm->csmflags.cfbit.awaiting_host_reply) {
1760*042d53a7SEvalZero return BLE_ERR_MAX;
1761*042d53a7SEvalZero }
1762*042d53a7SEvalZero
1763*042d53a7SEvalZero /* XXX: remember to deal with this on the master: if the slave has
1764*042d53a7SEvalZero * initiated a procedure we may have received its connection parameter
1765*042d53a7SEvalZero * update request and have signaled the host with an event. If that
1766*042d53a7SEvalZero * is the case, we will need to drop the host command when we get it
1767*042d53a7SEvalZero and also clear any applicable states. */
1768*042d53a7SEvalZero
1769*042d53a7SEvalZero /* XXX: Read 5.3 again. There are multiple control procedures that might
1770*042d53a7SEvalZero * be pending (a connection update) that will cause collisions and the
1771*042d53a7SEvalZero behavior below. */
1772*042d53a7SEvalZero /*
1773*042d53a7SEvalZero * Check for procedure collision (Vol 6 PartB 5.3). If we are a slave
1774*042d53a7SEvalZero * and we receive a request we "consider the slave initiated
1775*042d53a7SEvalZero * procedure as complete". This means send a connection update complete
1776*042d53a7SEvalZero * event (with error).
1777*042d53a7SEvalZero *
1778*042d53a7SEvalZero * If a master, we send reject with a
1779*042d53a7SEvalZero * transaction collision error code.
1780*042d53a7SEvalZero */
1781*042d53a7SEvalZero if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ)) {
1782*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
1783*042d53a7SEvalZero ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ);
1784*042d53a7SEvalZero ble_ll_hci_ev_conn_update(connsm, BLE_ERR_LMP_COLLISION);
1785*042d53a7SEvalZero } else {
1786*042d53a7SEvalZero /* The master sends reject ind ext w/error code 0x23 */
1787*042d53a7SEvalZero rsp_opcode = BLE_LL_CTRL_REJECT_IND_EXT;
1788*042d53a7SEvalZero rspbuf[1] = BLE_LL_CTRL_CONN_PARM_REQ;
1789*042d53a7SEvalZero rspbuf[2] = BLE_ERR_LMP_COLLISION;
1790*042d53a7SEvalZero return rsp_opcode;
1791*042d53a7SEvalZero }
1792*042d53a7SEvalZero }
1793*042d53a7SEvalZero
1794*042d53a7SEvalZero /*
1795*042d53a7SEvalZero * If we are a master and we currently performing a channel map
1796*042d53a7SEvalZero * update procedure we need to return an error
1797*042d53a7SEvalZero */
1798*042d53a7SEvalZero if ((connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) &&
1799*042d53a7SEvalZero (connsm->csmflags.cfbit.chanmap_update_scheduled)) {
1800*042d53a7SEvalZero rsp_opcode = BLE_LL_CTRL_REJECT_IND_EXT;
1801*042d53a7SEvalZero rspbuf[1] = BLE_LL_CTRL_CONN_PARM_REQ;
1802*042d53a7SEvalZero rspbuf[2] = BLE_ERR_DIFF_TRANS_COLL;
1803*042d53a7SEvalZero return rsp_opcode;
1804*042d53a7SEvalZero }
1805*042d53a7SEvalZero
1806*042d53a7SEvalZero /* Process the received connection parameter request */
1807*042d53a7SEvalZero rsp_opcode = ble_ll_ctrl_conn_param_pdu_proc(connsm, dptr, rspbuf,
1808*042d53a7SEvalZero BLE_LL_CTRL_CONN_PARM_REQ);
1809*042d53a7SEvalZero return rsp_opcode;
1810*042d53a7SEvalZero }
1811*042d53a7SEvalZero
1812*042d53a7SEvalZero static int
ble_ll_ctrl_rx_conn_param_rsp(struct ble_ll_conn_sm * connsm,uint8_t * dptr,uint8_t * rspbuf)1813*042d53a7SEvalZero ble_ll_ctrl_rx_conn_param_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
1814*042d53a7SEvalZero uint8_t *rspbuf)
1815*042d53a7SEvalZero {
1816*042d53a7SEvalZero uint8_t rsp_opcode;
1817*042d53a7SEvalZero
1818*042d53a7SEvalZero /* A slave should never receive this response */
1819*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
1820*042d53a7SEvalZero return BLE_LL_CTRL_UNKNOWN_RSP;
1821*042d53a7SEvalZero }
1822*042d53a7SEvalZero
1823*042d53a7SEvalZero /*
1824*042d53a7SEvalZero * This case should never happen! It means that the slave initiated a
1825*042d53a7SEvalZero * procedure and the master initiated one as well. If we do get in this
1826*042d53a7SEvalZero * state just clear the awaiting reply. The slave will hopefully stop its
1827*042d53a7SEvalZero * procedure when we reply.
1828*042d53a7SEvalZero */
1829*042d53a7SEvalZero if (connsm->csmflags.cfbit.awaiting_host_reply) {
1830*042d53a7SEvalZero connsm->csmflags.cfbit.awaiting_host_reply = 0;
1831*042d53a7SEvalZero }
1832*042d53a7SEvalZero
1833*042d53a7SEvalZero /* If we receive a response and no procedure is pending, just leave */
1834*042d53a7SEvalZero if (!IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ)) {
1835*042d53a7SEvalZero return BLE_ERR_MAX;
1836*042d53a7SEvalZero }
1837*042d53a7SEvalZero
1838*042d53a7SEvalZero /* Process the received connection parameter response */
1839*042d53a7SEvalZero rsp_opcode = ble_ll_ctrl_conn_param_pdu_proc(connsm, dptr, rspbuf,
1840*042d53a7SEvalZero BLE_LL_CTRL_CONN_PARM_RSP);
1841*042d53a7SEvalZero return rsp_opcode;
1842*042d53a7SEvalZero }
1843*042d53a7SEvalZero
1844*042d53a7SEvalZero /**
1845*042d53a7SEvalZero * Called to process the LL control PDU VERSION_IND
1846*042d53a7SEvalZero *
1847*042d53a7SEvalZero * Context: Link Layer task
1848*042d53a7SEvalZero *
1849*042d53a7SEvalZero * @param connsm
1850*042d53a7SEvalZero * @param dptr
1851*042d53a7SEvalZero * @param rspbuf
1852*042d53a7SEvalZero *
1853*042d53a7SEvalZero * @return int
1854*042d53a7SEvalZero */
1855*042d53a7SEvalZero static int
ble_ll_ctrl_rx_version_ind(struct ble_ll_conn_sm * connsm,uint8_t * dptr,uint8_t * rspbuf)1856*042d53a7SEvalZero ble_ll_ctrl_rx_version_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
1857*042d53a7SEvalZero uint8_t *rspbuf)
1858*042d53a7SEvalZero {
1859*042d53a7SEvalZero uint8_t rsp_opcode;
1860*042d53a7SEvalZero
1861*042d53a7SEvalZero /* Process the packet */
1862*042d53a7SEvalZero connsm->vers_nr = dptr[0];
1863*042d53a7SEvalZero connsm->comp_id = get_le16(dptr + 1);
1864*042d53a7SEvalZero connsm->sub_vers_nr = get_le16(dptr + 3);
1865*042d53a7SEvalZero connsm->csmflags.cfbit.rxd_version_ind = 1;
1866*042d53a7SEvalZero
1867*042d53a7SEvalZero rsp_opcode = BLE_ERR_MAX;
1868*042d53a7SEvalZero if (!connsm->csmflags.cfbit.version_ind_sent) {
1869*042d53a7SEvalZero rsp_opcode = BLE_LL_CTRL_VERSION_IND;
1870*042d53a7SEvalZero ble_ll_ctrl_version_ind_make(connsm, rspbuf);
1871*042d53a7SEvalZero }
1872*042d53a7SEvalZero
1873*042d53a7SEvalZero /* Stop the control procedure */
1874*042d53a7SEvalZero if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_VERSION_XCHG)) {
1875*042d53a7SEvalZero ble_ll_hci_ev_rd_rem_ver(connsm, BLE_ERR_SUCCESS);
1876*042d53a7SEvalZero ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_VERSION_XCHG);
1877*042d53a7SEvalZero }
1878*042d53a7SEvalZero return rsp_opcode;
1879*042d53a7SEvalZero }
1880*042d53a7SEvalZero
1881*042d53a7SEvalZero /**
1882*042d53a7SEvalZero * Called to process a received channel map request control pdu.
1883*042d53a7SEvalZero *
1884*042d53a7SEvalZero * Context: Link Layer task
1885*042d53a7SEvalZero *
1886*042d53a7SEvalZero * @param connsm
1887*042d53a7SEvalZero * @param dptr
1888*042d53a7SEvalZero */
1889*042d53a7SEvalZero static int
ble_ll_ctrl_rx_chanmap_req(struct ble_ll_conn_sm * connsm,uint8_t * dptr)1890*042d53a7SEvalZero ble_ll_ctrl_rx_chanmap_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
1891*042d53a7SEvalZero {
1892*042d53a7SEvalZero uint16_t instant;
1893*042d53a7SEvalZero uint16_t conn_events;
1894*042d53a7SEvalZero
1895*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
1896*042d53a7SEvalZero return BLE_LL_CTRL_UNKNOWN_RSP;
1897*042d53a7SEvalZero }
1898*042d53a7SEvalZero
1899*042d53a7SEvalZero /* If instant is in the past, we have to end the connection */
1900*042d53a7SEvalZero instant = get_le16(dptr + BLE_LL_CONN_CHMAP_LEN);
1901*042d53a7SEvalZero conn_events = (instant - connsm->event_cntr) & 0xFFFF;
1902*042d53a7SEvalZero if (conn_events >= 32767) {
1903*042d53a7SEvalZero ble_ll_conn_timeout(connsm, BLE_ERR_INSTANT_PASSED);
1904*042d53a7SEvalZero } else {
1905*042d53a7SEvalZero connsm->chanmap_instant = instant;
1906*042d53a7SEvalZero memcpy(connsm->req_chanmap, dptr, BLE_LL_CONN_CHMAP_LEN);
1907*042d53a7SEvalZero connsm->csmflags.cfbit.chanmap_update_scheduled = 1;
1908*042d53a7SEvalZero }
1909*042d53a7SEvalZero
1910*042d53a7SEvalZero return BLE_ERR_MAX;
1911*042d53a7SEvalZero }
1912*042d53a7SEvalZero
1913*042d53a7SEvalZero /**
1914*042d53a7SEvalZero * Initiate LL control procedure.
1915*042d53a7SEvalZero *
1916*042d53a7SEvalZero * This function is called to obtain a mbuf to send a LL control PDU. The data
1917*042d53a7SEvalZero * channel PDU header is not part of the mbuf data; it is part of the BLE
1918*042d53a7SEvalZero * header (which is part of the mbuf).
1919*042d53a7SEvalZero *
1920*042d53a7SEvalZero * Context: LL task.
1921*042d53a7SEvalZero *
1922*042d53a7SEvalZero * @param connsm
1923*042d53a7SEvalZero * @param ctrl_proc
1924*042d53a7SEvalZero */
1925*042d53a7SEvalZero static struct os_mbuf *
ble_ll_ctrl_proc_init(struct ble_ll_conn_sm * connsm,int ctrl_proc)1926*042d53a7SEvalZero ble_ll_ctrl_proc_init(struct ble_ll_conn_sm *connsm, int ctrl_proc)
1927*042d53a7SEvalZero {
1928*042d53a7SEvalZero uint8_t len;
1929*042d53a7SEvalZero uint8_t opcode;
1930*042d53a7SEvalZero uint8_t *dptr;
1931*042d53a7SEvalZero uint8_t *ctrdata;
1932*042d53a7SEvalZero struct os_mbuf *om;
1933*042d53a7SEvalZero
1934*042d53a7SEvalZero /* Get an mbuf for the control pdu */
1935*042d53a7SEvalZero om = os_msys_get_pkthdr(BLE_LL_CTRL_MAX_PDU_LEN, sizeof(struct ble_mbuf_hdr));
1936*042d53a7SEvalZero
1937*042d53a7SEvalZero if (om) {
1938*042d53a7SEvalZero /* The control data starts after the opcode (1 byte) */
1939*042d53a7SEvalZero dptr = om->om_data;
1940*042d53a7SEvalZero ctrdata = dptr + 1;
1941*042d53a7SEvalZero
1942*042d53a7SEvalZero switch (ctrl_proc) {
1943*042d53a7SEvalZero case BLE_LL_CTRL_PROC_CONN_UPDATE:
1944*042d53a7SEvalZero opcode = BLE_LL_CTRL_CONN_UPDATE_IND;
1945*042d53a7SEvalZero ble_ll_ctrl_conn_upd_make(connsm, ctrdata, NULL);
1946*042d53a7SEvalZero break;
1947*042d53a7SEvalZero case BLE_LL_CTRL_PROC_CHAN_MAP_UPD:
1948*042d53a7SEvalZero opcode = BLE_LL_CTRL_CHANNEL_MAP_REQ;
1949*042d53a7SEvalZero ble_ll_ctrl_chanmap_req_make(connsm, ctrdata);
1950*042d53a7SEvalZero break;
1951*042d53a7SEvalZero case BLE_LL_CTRL_PROC_FEATURE_XCHG:
1952*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
1953*042d53a7SEvalZero opcode = BLE_LL_CTRL_FEATURE_REQ;
1954*042d53a7SEvalZero } else {
1955*042d53a7SEvalZero opcode = BLE_LL_CTRL_SLAVE_FEATURE_REQ;
1956*042d53a7SEvalZero }
1957*042d53a7SEvalZero memset(ctrdata, 0, BLE_LL_CTRL_FEATURE_LEN);
1958*042d53a7SEvalZero put_le32(ctrdata, ble_ll_read_supp_features());
1959*042d53a7SEvalZero break;
1960*042d53a7SEvalZero case BLE_LL_CTRL_PROC_VERSION_XCHG:
1961*042d53a7SEvalZero opcode = BLE_LL_CTRL_VERSION_IND;
1962*042d53a7SEvalZero ble_ll_ctrl_version_ind_make(connsm, ctrdata);
1963*042d53a7SEvalZero break;
1964*042d53a7SEvalZero case BLE_LL_CTRL_PROC_TERMINATE:
1965*042d53a7SEvalZero opcode = BLE_LL_CTRL_TERMINATE_IND;
1966*042d53a7SEvalZero ctrdata[0] = connsm->disconnect_reason;
1967*042d53a7SEvalZero break;
1968*042d53a7SEvalZero case BLE_LL_CTRL_PROC_CONN_PARAM_REQ:
1969*042d53a7SEvalZero opcode = BLE_LL_CTRL_CONN_PARM_REQ;
1970*042d53a7SEvalZero ble_ll_ctrl_conn_param_pdu_make(connsm, ctrdata, NULL);
1971*042d53a7SEvalZero break;
1972*042d53a7SEvalZero case BLE_LL_CTRL_PROC_LE_PING:
1973*042d53a7SEvalZero opcode = BLE_LL_CTRL_PING_REQ;
1974*042d53a7SEvalZero break;
1975*042d53a7SEvalZero case BLE_LL_CTRL_PROC_DATA_LEN_UPD:
1976*042d53a7SEvalZero opcode = BLE_LL_CTRL_LENGTH_REQ;
1977*042d53a7SEvalZero ble_ll_ctrl_datalen_upd_make(connsm, dptr);
1978*042d53a7SEvalZero break;
1979*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
1980*042d53a7SEvalZero /* XXX: deal with already encrypted connection.*/
1981*042d53a7SEvalZero case BLE_LL_CTRL_PROC_ENCRYPT:
1982*042d53a7SEvalZero /* If we are already encrypted we do pause procedure */
1983*042d53a7SEvalZero if (connsm->enc_data.enc_state == CONN_ENC_S_ENCRYPTED) {
1984*042d53a7SEvalZero opcode = BLE_LL_CTRL_PAUSE_ENC_REQ;
1985*042d53a7SEvalZero } else {
1986*042d53a7SEvalZero opcode = BLE_LL_CTRL_ENC_REQ;
1987*042d53a7SEvalZero ble_ll_ctrl_enc_req_make(connsm, ctrdata);
1988*042d53a7SEvalZero }
1989*042d53a7SEvalZero break;
1990*042d53a7SEvalZero #endif
1991*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
1992*042d53a7SEvalZero case BLE_LL_CTRL_PROC_PHY_UPDATE:
1993*042d53a7SEvalZero opcode = BLE_LL_CTRL_PHY_REQ;
1994*042d53a7SEvalZero ble_ll_ctrl_phy_req_rsp_make(connsm, ctrdata);
1995*042d53a7SEvalZero break;
1996*042d53a7SEvalZero #endif
1997*042d53a7SEvalZero default:
1998*042d53a7SEvalZero BLE_LL_ASSERT(0);
1999*042d53a7SEvalZero break;
2000*042d53a7SEvalZero }
2001*042d53a7SEvalZero
2002*042d53a7SEvalZero /* Set llid, length and opcode */
2003*042d53a7SEvalZero dptr[0] = opcode;
2004*042d53a7SEvalZero len = g_ble_ll_ctrl_pkt_lengths[opcode] + 1;
2005*042d53a7SEvalZero
2006*042d53a7SEvalZero /* Add packet to transmit queue of connection */
2007*042d53a7SEvalZero ble_ll_conn_enqueue_pkt(connsm, om, BLE_LL_LLID_CTRL, len);
2008*042d53a7SEvalZero }
2009*042d53a7SEvalZero
2010*042d53a7SEvalZero return om;
2011*042d53a7SEvalZero }
2012*042d53a7SEvalZero
2013*042d53a7SEvalZero /**
2014*042d53a7SEvalZero * Called to determine if the pdu is a TERMINATE_IND
2015*042d53a7SEvalZero *
2016*042d53a7SEvalZero * @param hdr
2017*042d53a7SEvalZero * @param opcode
2018*042d53a7SEvalZero *
2019*042d53a7SEvalZero * @return int
2020*042d53a7SEvalZero */
2021*042d53a7SEvalZero int
ble_ll_ctrl_is_terminate_ind(uint8_t hdr,uint8_t opcode)2022*042d53a7SEvalZero ble_ll_ctrl_is_terminate_ind(uint8_t hdr, uint8_t opcode)
2023*042d53a7SEvalZero {
2024*042d53a7SEvalZero int rc;
2025*042d53a7SEvalZero
2026*042d53a7SEvalZero rc = 0;
2027*042d53a7SEvalZero if ((hdr & BLE_LL_DATA_HDR_LLID_MASK) == BLE_LL_LLID_CTRL) {
2028*042d53a7SEvalZero if (opcode == BLE_LL_CTRL_TERMINATE_IND) {
2029*042d53a7SEvalZero rc = 1;
2030*042d53a7SEvalZero }
2031*042d53a7SEvalZero }
2032*042d53a7SEvalZero return rc;
2033*042d53a7SEvalZero }
2034*042d53a7SEvalZero
2035*042d53a7SEvalZero /**
2036*042d53a7SEvalZero * Stops the LL control procedure indicated by 'ctrl_proc'.
2037*042d53a7SEvalZero *
2038*042d53a7SEvalZero * Context: Link Layer task
2039*042d53a7SEvalZero *
2040*042d53a7SEvalZero * @param connsm
2041*042d53a7SEvalZero * @param ctrl_proc
2042*042d53a7SEvalZero */
2043*042d53a7SEvalZero void
ble_ll_ctrl_proc_stop(struct ble_ll_conn_sm * connsm,int ctrl_proc)2044*042d53a7SEvalZero ble_ll_ctrl_proc_stop(struct ble_ll_conn_sm *connsm, int ctrl_proc)
2045*042d53a7SEvalZero {
2046*042d53a7SEvalZero if (connsm->cur_ctrl_proc == ctrl_proc) {
2047*042d53a7SEvalZero ble_npl_callout_stop(&connsm->ctrl_proc_rsp_timer);
2048*042d53a7SEvalZero connsm->cur_ctrl_proc = BLE_LL_CTRL_PROC_IDLE;
2049*042d53a7SEvalZero }
2050*042d53a7SEvalZero CLR_PENDING_CTRL_PROC(connsm, ctrl_proc);
2051*042d53a7SEvalZero
2052*042d53a7SEvalZero /* If there are others, start them */
2053*042d53a7SEvalZero ble_ll_ctrl_chk_proc_start(connsm);
2054*042d53a7SEvalZero }
2055*042d53a7SEvalZero
2056*042d53a7SEvalZero /**
2057*042d53a7SEvalZero * Called to start the terminate procedure.
2058*042d53a7SEvalZero *
2059*042d53a7SEvalZero * Context: Link Layer task.
2060*042d53a7SEvalZero *
2061*042d53a7SEvalZero * @param connsm
2062*042d53a7SEvalZero */
2063*042d53a7SEvalZero void
ble_ll_ctrl_terminate_start(struct ble_ll_conn_sm * connsm)2064*042d53a7SEvalZero ble_ll_ctrl_terminate_start(struct ble_ll_conn_sm *connsm)
2065*042d53a7SEvalZero {
2066*042d53a7SEvalZero int ctrl_proc;
2067*042d53a7SEvalZero uint32_t usecs;
2068*042d53a7SEvalZero struct os_mbuf *om;
2069*042d53a7SEvalZero
2070*042d53a7SEvalZero BLE_LL_ASSERT(connsm->disconnect_reason != 0);
2071*042d53a7SEvalZero
2072*042d53a7SEvalZero ctrl_proc = BLE_LL_CTRL_PROC_TERMINATE;
2073*042d53a7SEvalZero om = ble_ll_ctrl_proc_init(connsm, ctrl_proc);
2074*042d53a7SEvalZero if (om) {
2075*042d53a7SEvalZero CONN_F_TERMINATE_STARTED(connsm) = 1;
2076*042d53a7SEvalZero
2077*042d53a7SEvalZero /* Set terminate "timeout" */
2078*042d53a7SEvalZero usecs = connsm->supervision_tmo * BLE_HCI_CONN_SPVN_TMO_UNITS * 1000;
2079*042d53a7SEvalZero connsm->terminate_timeout = os_cputime_get32() +
2080*042d53a7SEvalZero os_cputime_usecs_to_ticks(usecs);
2081*042d53a7SEvalZero }
2082*042d53a7SEvalZero }
2083*042d53a7SEvalZero
2084*042d53a7SEvalZero /**
2085*042d53a7SEvalZero * Called to start a LL control procedure except for the terminate procedure. We
2086*042d53a7SEvalZero * always set the control procedure pending bit even if the control procedure
2087*042d53a7SEvalZero * has been initiated.
2088*042d53a7SEvalZero *
2089*042d53a7SEvalZero * Context: Link Layer task.
2090*042d53a7SEvalZero *
2091*042d53a7SEvalZero * @param connsm Pointer to connection state machine.
2092*042d53a7SEvalZero */
2093*042d53a7SEvalZero void
ble_ll_ctrl_proc_start(struct ble_ll_conn_sm * connsm,int ctrl_proc)2094*042d53a7SEvalZero ble_ll_ctrl_proc_start(struct ble_ll_conn_sm *connsm, int ctrl_proc)
2095*042d53a7SEvalZero {
2096*042d53a7SEvalZero struct os_mbuf *om;
2097*042d53a7SEvalZero
2098*042d53a7SEvalZero BLE_LL_ASSERT(ctrl_proc != BLE_LL_CTRL_PROC_TERMINATE);
2099*042d53a7SEvalZero
2100*042d53a7SEvalZero om = NULL;
2101*042d53a7SEvalZero if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_IDLE) {
2102*042d53a7SEvalZero /* Initiate the control procedure. */
2103*042d53a7SEvalZero om = ble_ll_ctrl_proc_init(connsm, ctrl_proc);
2104*042d53a7SEvalZero if (om) {
2105*042d53a7SEvalZero /* Set the current control procedure */
2106*042d53a7SEvalZero connsm->cur_ctrl_proc = ctrl_proc;
2107*042d53a7SEvalZero
2108*042d53a7SEvalZero /* Initialize the procedure response timeout */
2109*042d53a7SEvalZero if (ctrl_proc != BLE_LL_CTRL_PROC_CHAN_MAP_UPD) {
2110*042d53a7SEvalZero ble_ll_ctrl_start_rsp_timer(connsm);
2111*042d53a7SEvalZero }
2112*042d53a7SEvalZero }
2113*042d53a7SEvalZero }
2114*042d53a7SEvalZero
2115*042d53a7SEvalZero /* Set bitmask denoting control procedure is pending */
2116*042d53a7SEvalZero connsm->pending_ctrl_procs |= (1 << ctrl_proc);
2117*042d53a7SEvalZero }
2118*042d53a7SEvalZero
2119*042d53a7SEvalZero /**
2120*042d53a7SEvalZero * Called to determine if we need to start a LL control procedure for the given
2121*042d53a7SEvalZero * connection.
2122*042d53a7SEvalZero *
2123*042d53a7SEvalZero * Context: Link Layer
2124*042d53a7SEvalZero *
2125*042d53a7SEvalZero * @param connsm Pointer to connection state machine.
2126*042d53a7SEvalZero */
2127*042d53a7SEvalZero void
ble_ll_ctrl_chk_proc_start(struct ble_ll_conn_sm * connsm)2128*042d53a7SEvalZero ble_ll_ctrl_chk_proc_start(struct ble_ll_conn_sm *connsm)
2129*042d53a7SEvalZero {
2130*042d53a7SEvalZero int i;
2131*042d53a7SEvalZero
2132*042d53a7SEvalZero /* XXX: TODO new rules! Cannot start certain control procedures if other
2133*042d53a7SEvalZero * ones are peer initiated. We need to wait. Deal with this.
2134*042d53a7SEvalZero */
2135*042d53a7SEvalZero
2136*042d53a7SEvalZero /*
2137*042d53a7SEvalZero * If we are terminating, dont start any new procedures but start
2138*042d53a7SEvalZero * terminate if needed
2139*042d53a7SEvalZero */
2140*042d53a7SEvalZero if (connsm->disconnect_reason) {
2141*042d53a7SEvalZero if (!CONN_F_TERMINATE_STARTED(connsm)) {
2142*042d53a7SEvalZero /*
2143*042d53a7SEvalZero * If the terminate procedure has not started it means we were not
2144*042d53a7SEvalZero * able to start it right away (no control pdu was available).
2145*042d53a7SEvalZero * Start it now. No need to start any other procedures.
2146*042d53a7SEvalZero */
2147*042d53a7SEvalZero ble_ll_ctrl_terminate_start(connsm);
2148*042d53a7SEvalZero }
2149*042d53a7SEvalZero return;
2150*042d53a7SEvalZero }
2151*042d53a7SEvalZero
2152*042d53a7SEvalZero /* If there is a running procedure or no pending, do nothing */
2153*042d53a7SEvalZero if ((connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_IDLE) &&
2154*042d53a7SEvalZero (connsm->pending_ctrl_procs != 0)) {
2155*042d53a7SEvalZero /*
2156*042d53a7SEvalZero * The specification says there is no priority to control procedures
2157*042d53a7SEvalZero * so just start from the first one for now.
2158*042d53a7SEvalZero */
2159*042d53a7SEvalZero for (i = 0; i < BLE_LL_CTRL_PROC_NUM; ++i) {
2160*042d53a7SEvalZero if (IS_PENDING_CTRL_PROC(connsm, i)) {
2161*042d53a7SEvalZero /*
2162*042d53a7SEvalZero * The version exchange is a special case. If we have already
2163*042d53a7SEvalZero * received the information dont start it.
2164*042d53a7SEvalZero */
2165*042d53a7SEvalZero if ((i == BLE_LL_CTRL_PROC_VERSION_XCHG) &&
2166*042d53a7SEvalZero (connsm->csmflags.cfbit.rxd_version_ind)) {
2167*042d53a7SEvalZero ble_ll_hci_ev_rd_rem_ver(connsm, BLE_ERR_SUCCESS);
2168*042d53a7SEvalZero CLR_PENDING_CTRL_PROC(connsm, i);
2169*042d53a7SEvalZero } else {
2170*042d53a7SEvalZero ble_ll_ctrl_proc_start(connsm, i);
2171*042d53a7SEvalZero break;
2172*042d53a7SEvalZero }
2173*042d53a7SEvalZero }
2174*042d53a7SEvalZero }
2175*042d53a7SEvalZero }
2176*042d53a7SEvalZero }
2177*042d53a7SEvalZero
2178*042d53a7SEvalZero /**
2179*042d53a7SEvalZero * Called when the Link Layer receives a LL control PDU.
2180*042d53a7SEvalZero *
2181*042d53a7SEvalZero * NOTE: this function uses the received PDU for the response in some cases. If
2182*042d53a7SEvalZero * the received PDU is not used it needs to be freed here.
2183*042d53a7SEvalZero *
2184*042d53a7SEvalZero * XXX: may want to check, for both master and slave, whether the control
2185*042d53a7SEvalZero * pdu should be received by that role. Might make for less code...
2186*042d53a7SEvalZero * Context: Link Layer
2187*042d53a7SEvalZero *
2188*042d53a7SEvalZero * @param om
2189*042d53a7SEvalZero * @param connsm
2190*042d53a7SEvalZero */
2191*042d53a7SEvalZero int
ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm * connsm,struct os_mbuf * om)2192*042d53a7SEvalZero ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om)
2193*042d53a7SEvalZero {
2194*042d53a7SEvalZero uint32_t features;
2195*042d53a7SEvalZero uint32_t feature;
2196*042d53a7SEvalZero uint8_t len;
2197*042d53a7SEvalZero uint8_t opcode;
2198*042d53a7SEvalZero uint8_t rsp_opcode;
2199*042d53a7SEvalZero uint8_t *dptr;
2200*042d53a7SEvalZero uint8_t *rspbuf;
2201*042d53a7SEvalZero uint8_t *rspdata;
2202*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
2203*042d53a7SEvalZero int restart_encryption;
2204*042d53a7SEvalZero #endif
2205*042d53a7SEvalZero int rc = 0;
2206*042d53a7SEvalZero
2207*042d53a7SEvalZero /* XXX: where do we validate length received and packet header length?
2208*042d53a7SEvalZero * do this in LL task when received. Someplace!!! What I mean
2209*042d53a7SEvalZero * is we should validate the over the air length with the mbuf length.
2210*042d53a7SEvalZero Should the PHY do that???? */
2211*042d53a7SEvalZero
2212*042d53a7SEvalZero /*
2213*042d53a7SEvalZero * dptr points to om_data pointer. The first byte of om_data is the
2214*042d53a7SEvalZero * first byte of the Data Channel PDU header. Get length from header and
2215*042d53a7SEvalZero * opcode from LL control PDU.
2216*042d53a7SEvalZero */
2217*042d53a7SEvalZero dptr = om->om_data;
2218*042d53a7SEvalZero len = dptr[1];
2219*042d53a7SEvalZero opcode = dptr[2];
2220*042d53a7SEvalZero
2221*042d53a7SEvalZero /*
2222*042d53a7SEvalZero * rspbuf points to first byte of response. The response buffer does not
2223*042d53a7SEvalZero * contain the Data Channel PDU. Thus, the first byte of rspbuf is the
2224*042d53a7SEvalZero * LL control PDU payload (the opcode of the control PDU). rspdata
2225*042d53a7SEvalZero * points to CtrData in the control PDU.
2226*042d53a7SEvalZero */
2227*042d53a7SEvalZero rspbuf = dptr;
2228*042d53a7SEvalZero rspdata = rspbuf + 1;
2229*042d53a7SEvalZero
2230*042d53a7SEvalZero /* Move data pointer to start of control data (2 byte PDU hdr + opcode) */
2231*042d53a7SEvalZero dptr += (BLE_LL_PDU_HDR_LEN + 1);
2232*042d53a7SEvalZero
2233*042d53a7SEvalZero /*
2234*042d53a7SEvalZero * Subtract the opcode from the length. Note that if the length was zero,
2235*042d53a7SEvalZero * which would be an error, we will fail the check against the length
2236*042d53a7SEvalZero * of the control packet.
2237*042d53a7SEvalZero */
2238*042d53a7SEvalZero --len;
2239*042d53a7SEvalZero
2240*042d53a7SEvalZero ble_ll_trace_u32x2(BLE_LL_TRACE_ID_CTRL_RX, opcode, len);
2241*042d53a7SEvalZero
2242*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
2243*042d53a7SEvalZero restart_encryption = 0;
2244*042d53a7SEvalZero #endif
2245*042d53a7SEvalZero
2246*042d53a7SEvalZero /* If opcode comes from reserved value or CtrlData fields is invalid
2247*042d53a7SEvalZero * we shall respond with LL_UNKNOWN_RSP
2248*042d53a7SEvalZero */
2249*042d53a7SEvalZero if ((opcode >= BLE_LL_CTRL_OPCODES) ||
2250*042d53a7SEvalZero (len != g_ble_ll_ctrl_pkt_lengths[opcode])) {
2251*042d53a7SEvalZero rc = -1;
2252*042d53a7SEvalZero rsp_opcode = BLE_LL_CTRL_UNKNOWN_RSP;
2253*042d53a7SEvalZero goto ll_ctrl_send_rsp;
2254*042d53a7SEvalZero }
2255*042d53a7SEvalZero
2256*042d53a7SEvalZero /* Check if the feature is supported. */
2257*042d53a7SEvalZero switch (opcode) {
2258*042d53a7SEvalZero case BLE_LL_CTRL_LENGTH_REQ:
2259*042d53a7SEvalZero feature = BLE_LL_FEAT_DATA_LEN_EXT;
2260*042d53a7SEvalZero break;
2261*042d53a7SEvalZero case BLE_LL_CTRL_SLAVE_FEATURE_REQ:
2262*042d53a7SEvalZero feature = BLE_LL_FEAT_SLAVE_INIT;
2263*042d53a7SEvalZero break;
2264*042d53a7SEvalZero case BLE_LL_CTRL_CONN_PARM_REQ:
2265*042d53a7SEvalZero case BLE_LL_CTRL_CONN_PARM_RSP:
2266*042d53a7SEvalZero feature = BLE_LL_FEAT_CONN_PARM_REQ;
2267*042d53a7SEvalZero break;
2268*042d53a7SEvalZero case BLE_LL_CTRL_ENC_REQ:
2269*042d53a7SEvalZero case BLE_LL_CTRL_START_ENC_REQ:
2270*042d53a7SEvalZero case BLE_LL_CTRL_PAUSE_ENC_REQ:
2271*042d53a7SEvalZero feature = BLE_LL_FEAT_LE_ENCRYPTION;
2272*042d53a7SEvalZero break;
2273*042d53a7SEvalZero case BLE_LL_CTRL_PING_REQ:
2274*042d53a7SEvalZero feature = BLE_LL_FEAT_LE_PING;
2275*042d53a7SEvalZero break;
2276*042d53a7SEvalZero case BLE_LL_CTRL_PHY_REQ:
2277*042d53a7SEvalZero feature = BLE_LL_FEAT_LE_2M_PHY | BLE_LL_FEAT_LE_CODED_PHY;
2278*042d53a7SEvalZero break;
2279*042d53a7SEvalZero case BLE_LL_CTRL_MIN_USED_CHAN_IND:
2280*042d53a7SEvalZero feature = BLE_LL_FEAT_MIN_USED_CHAN;
2281*042d53a7SEvalZero break;
2282*042d53a7SEvalZero default:
2283*042d53a7SEvalZero feature = 0;
2284*042d53a7SEvalZero break;
2285*042d53a7SEvalZero }
2286*042d53a7SEvalZero
2287*042d53a7SEvalZero if (feature) {
2288*042d53a7SEvalZero features = ble_ll_read_supp_features();
2289*042d53a7SEvalZero if ((features & feature) == 0) {
2290*042d53a7SEvalZero if (opcode == BLE_LL_CTRL_ENC_REQ) {
2291*042d53a7SEvalZero if (connsm->conn_features & BLE_LL_FEAT_EXTENDED_REJ) {
2292*042d53a7SEvalZero rsp_opcode = BLE_LL_CTRL_REJECT_IND_EXT;
2293*042d53a7SEvalZero rspbuf[1] = opcode;
2294*042d53a7SEvalZero rspbuf[2] = BLE_ERR_UNSUPP_REM_FEATURE;
2295*042d53a7SEvalZero
2296*042d53a7SEvalZero } else {
2297*042d53a7SEvalZero rsp_opcode = BLE_LL_CTRL_REJECT_IND;
2298*042d53a7SEvalZero rspbuf[1] = BLE_ERR_UNSUPP_REM_FEATURE;
2299*042d53a7SEvalZero }
2300*042d53a7SEvalZero } else {
2301*042d53a7SEvalZero /* Construct unknown rsp pdu */
2302*042d53a7SEvalZero rsp_opcode = BLE_LL_CTRL_UNKNOWN_RSP;
2303*042d53a7SEvalZero }
2304*042d53a7SEvalZero goto ll_ctrl_send_rsp;
2305*042d53a7SEvalZero }
2306*042d53a7SEvalZero }
2307*042d53a7SEvalZero
2308*042d53a7SEvalZero /* Process opcode */
2309*042d53a7SEvalZero rsp_opcode = BLE_ERR_MAX;
2310*042d53a7SEvalZero switch (opcode) {
2311*042d53a7SEvalZero case BLE_LL_CTRL_CONN_UPDATE_IND:
2312*042d53a7SEvalZero rsp_opcode = ble_ll_ctrl_rx_conn_update(connsm, dptr);
2313*042d53a7SEvalZero break;
2314*042d53a7SEvalZero case BLE_LL_CTRL_CHANNEL_MAP_REQ:
2315*042d53a7SEvalZero rsp_opcode = ble_ll_ctrl_rx_chanmap_req(connsm, dptr);
2316*042d53a7SEvalZero break;
2317*042d53a7SEvalZero case BLE_LL_CTRL_LENGTH_REQ:
2318*042d53a7SEvalZero /* Extract parameters and check if valid */
2319*042d53a7SEvalZero if (ble_ll_ctrl_len_proc(connsm, dptr)) {
2320*042d53a7SEvalZero rc = -1;
2321*042d53a7SEvalZero rsp_opcode = BLE_LL_CTRL_UNKNOWN_RSP;
2322*042d53a7SEvalZero goto ll_ctrl_send_rsp;
2323*042d53a7SEvalZero }
2324*042d53a7SEvalZero
2325*042d53a7SEvalZero /*
2326*042d53a7SEvalZero * If we have not started this procedure ourselves and it is
2327*042d53a7SEvalZero * pending, no need to perform it.
2328*042d53a7SEvalZero */
2329*042d53a7SEvalZero if ((connsm->cur_ctrl_proc != BLE_LL_CTRL_PROC_DATA_LEN_UPD) &&
2330*042d53a7SEvalZero IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD)) {
2331*042d53a7SEvalZero CLR_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD);
2332*042d53a7SEvalZero }
2333*042d53a7SEvalZero
2334*042d53a7SEvalZero /* Send a response */
2335*042d53a7SEvalZero rsp_opcode = BLE_LL_CTRL_LENGTH_RSP;
2336*042d53a7SEvalZero ble_ll_ctrl_datalen_upd_make(connsm, rspbuf);
2337*042d53a7SEvalZero break;
2338*042d53a7SEvalZero case BLE_LL_CTRL_LENGTH_RSP:
2339*042d53a7SEvalZero /* According to specification, process this only if we asked for it. */
2340*042d53a7SEvalZero if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_DATA_LEN_UPD) {
2341*042d53a7SEvalZero /*
2342*042d53a7SEvalZero * Process the received data. If received data is invalid, we'll
2343*042d53a7SEvalZero * reply with LL_UNKNOWN_RSP as per spec, but we still need to stop
2344*042d53a7SEvalZero * control procedure to avoid timeout.
2345*042d53a7SEvalZero */
2346*042d53a7SEvalZero if (ble_ll_ctrl_len_proc(connsm, dptr)) {
2347*042d53a7SEvalZero rc = -1;
2348*042d53a7SEvalZero rsp_opcode = BLE_LL_CTRL_UNKNOWN_RSP;
2349*042d53a7SEvalZero }
2350*042d53a7SEvalZero
2351*042d53a7SEvalZero /* Stop the control procedure */
2352*042d53a7SEvalZero ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD);
2353*042d53a7SEvalZero }
2354*042d53a7SEvalZero break;
2355*042d53a7SEvalZero case BLE_LL_CTRL_UNKNOWN_RSP:
2356*042d53a7SEvalZero rsp_opcode = ble_ll_ctrl_proc_unk_rsp(connsm, dptr, rspdata);
2357*042d53a7SEvalZero break;
2358*042d53a7SEvalZero case BLE_LL_CTRL_FEATURE_REQ:
2359*042d53a7SEvalZero rsp_opcode = ble_ll_ctrl_rx_feature_req(connsm, dptr, rspbuf, opcode);
2360*042d53a7SEvalZero break;
2361*042d53a7SEvalZero /* XXX: check to see if ctrl procedure was running? Do we care? */
2362*042d53a7SEvalZero case BLE_LL_CTRL_FEATURE_RSP:
2363*042d53a7SEvalZero connsm->conn_features = dptr[0];
2364*042d53a7SEvalZero memcpy(connsm->remote_features, dptr + 1, 7);
2365*042d53a7SEvalZero /* If this is the first time we received remote features, try to start DLE */
2366*042d53a7SEvalZero if (!connsm->csmflags.cfbit.rxd_features) {
2367*042d53a7SEvalZero ble_ll_ctrl_initiate_dle(connsm);
2368*042d53a7SEvalZero connsm->csmflags.cfbit.rxd_features = 1;
2369*042d53a7SEvalZero }
2370*042d53a7SEvalZero /* Stop the control procedure */
2371*042d53a7SEvalZero if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG)) {
2372*042d53a7SEvalZero ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG);
2373*042d53a7SEvalZero }
2374*042d53a7SEvalZero /* Send event to host if pending features read */
2375*042d53a7SEvalZero if (connsm->csmflags.cfbit.pending_hci_rd_features) {
2376*042d53a7SEvalZero ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_SUCCESS);
2377*042d53a7SEvalZero connsm->csmflags.cfbit.pending_hci_rd_features = 0;
2378*042d53a7SEvalZero }
2379*042d53a7SEvalZero break;
2380*042d53a7SEvalZero case BLE_LL_CTRL_VERSION_IND:
2381*042d53a7SEvalZero rsp_opcode = ble_ll_ctrl_rx_version_ind(connsm, dptr, rspdata);
2382*042d53a7SEvalZero break;
2383*042d53a7SEvalZero case BLE_LL_CTRL_SLAVE_FEATURE_REQ:
2384*042d53a7SEvalZero rsp_opcode = ble_ll_ctrl_rx_feature_req(connsm, dptr, rspbuf, opcode);
2385*042d53a7SEvalZero break;
2386*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
2387*042d53a7SEvalZero case BLE_LL_CTRL_ENC_REQ:
2388*042d53a7SEvalZero rsp_opcode = ble_ll_ctrl_rx_enc_req(connsm, dptr, rspdata);
2389*042d53a7SEvalZero break;
2390*042d53a7SEvalZero case BLE_LL_CTRL_ENC_RSP:
2391*042d53a7SEvalZero ble_ll_ctrl_rx_enc_rsp(connsm, dptr);
2392*042d53a7SEvalZero break;
2393*042d53a7SEvalZero case BLE_LL_CTRL_START_ENC_REQ:
2394*042d53a7SEvalZero rsp_opcode = ble_ll_ctrl_rx_start_enc_req(connsm);
2395*042d53a7SEvalZero break;
2396*042d53a7SEvalZero case BLE_LL_CTRL_START_ENC_RSP:
2397*042d53a7SEvalZero rsp_opcode = ble_ll_ctrl_rx_start_enc_rsp(connsm);
2398*042d53a7SEvalZero break;
2399*042d53a7SEvalZero case BLE_LL_CTRL_PAUSE_ENC_REQ:
2400*042d53a7SEvalZero rsp_opcode = ble_ll_ctrl_rx_pause_enc_req(connsm);
2401*042d53a7SEvalZero break;
2402*042d53a7SEvalZero case BLE_LL_CTRL_PAUSE_ENC_RSP:
2403*042d53a7SEvalZero rsp_opcode = ble_ll_ctrl_rx_pause_enc_rsp(connsm);
2404*042d53a7SEvalZero if (rsp_opcode == BLE_LL_CTRL_PAUSE_ENC_RSP) {
2405*042d53a7SEvalZero restart_encryption = 1;
2406*042d53a7SEvalZero }
2407*042d53a7SEvalZero break;
2408*042d53a7SEvalZero #endif
2409*042d53a7SEvalZero case BLE_LL_CTRL_PING_REQ:
2410*042d53a7SEvalZero rsp_opcode = BLE_LL_CTRL_PING_RSP;
2411*042d53a7SEvalZero break;
2412*042d53a7SEvalZero case BLE_LL_CTRL_PING_RSP:
2413*042d53a7SEvalZero ble_ll_ctrl_rx_ping_rsp(connsm);
2414*042d53a7SEvalZero break;
2415*042d53a7SEvalZero case BLE_LL_CTRL_CONN_PARM_REQ:
2416*042d53a7SEvalZero rsp_opcode = ble_ll_ctrl_rx_conn_param_req(connsm, dptr, rspbuf);
2417*042d53a7SEvalZero break;
2418*042d53a7SEvalZero case BLE_LL_CTRL_CONN_PARM_RSP:
2419*042d53a7SEvalZero rsp_opcode = ble_ll_ctrl_rx_conn_param_rsp(connsm, dptr, rspbuf);
2420*042d53a7SEvalZero break;
2421*042d53a7SEvalZero /* Fall-through intentional... */
2422*042d53a7SEvalZero case BLE_LL_CTRL_REJECT_IND:
2423*042d53a7SEvalZero case BLE_LL_CTRL_REJECT_IND_EXT:
2424*042d53a7SEvalZero /* Sometimes reject triggers sending other LL CTRL msg */
2425*042d53a7SEvalZero rsp_opcode = ble_ll_ctrl_rx_reject_ind(connsm, dptr, opcode, rspdata);
2426*042d53a7SEvalZero break;
2427*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
2428*042d53a7SEvalZero case BLE_LL_CTRL_PHY_REQ:
2429*042d53a7SEvalZero rsp_opcode = ble_ll_ctrl_rx_phy_req(connsm, dptr, rspdata);
2430*042d53a7SEvalZero break;
2431*042d53a7SEvalZero case BLE_LL_CTRL_PHY_RSP:
2432*042d53a7SEvalZero rsp_opcode = ble_ll_ctrl_rx_phy_rsp(connsm, dptr, rspdata);
2433*042d53a7SEvalZero break;
2434*042d53a7SEvalZero case BLE_LL_CTRL_PHY_UPDATE_IND:
2435*042d53a7SEvalZero rsp_opcode = ble_ll_ctrl_rx_phy_update_ind(connsm, dptr);
2436*042d53a7SEvalZero break;
2437*042d53a7SEvalZero #endif
2438*042d53a7SEvalZero default:
2439*042d53a7SEvalZero /* Nothing to do here */
2440*042d53a7SEvalZero break;
2441*042d53a7SEvalZero }
2442*042d53a7SEvalZero
2443*042d53a7SEvalZero /* Free mbuf or send response */
2444*042d53a7SEvalZero ll_ctrl_send_rsp:
2445*042d53a7SEvalZero if (rsp_opcode == BLE_ERR_MAX) {
2446*042d53a7SEvalZero os_mbuf_free_chain(om);
2447*042d53a7SEvalZero } else {
2448*042d53a7SEvalZero /*
2449*042d53a7SEvalZero * Write the response opcode into the buffer. If this is an unknown
2450*042d53a7SEvalZero * response, put opcode of unknown pdu into buffer.
2451*042d53a7SEvalZero */
2452*042d53a7SEvalZero rspbuf[0] = rsp_opcode;
2453*042d53a7SEvalZero if (rsp_opcode == BLE_LL_CTRL_UNKNOWN_RSP) {
2454*042d53a7SEvalZero rspbuf[1] = opcode;
2455*042d53a7SEvalZero }
2456*042d53a7SEvalZero len = g_ble_ll_ctrl_pkt_lengths[rsp_opcode] + 1;
2457*042d53a7SEvalZero ble_ll_conn_enqueue_pkt(connsm, om, BLE_LL_LLID_CTRL, len);
2458*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
2459*042d53a7SEvalZero if (restart_encryption) {
2460*042d53a7SEvalZero /* XXX: what happens if this fails? Meaning we cant allocate
2461*042d53a7SEvalZero mbuf? */
2462*042d53a7SEvalZero ble_ll_ctrl_proc_init(connsm, BLE_LL_CTRL_PROC_ENCRYPT);
2463*042d53a7SEvalZero }
2464*042d53a7SEvalZero #endif
2465*042d53a7SEvalZero }
2466*042d53a7SEvalZero return rc;
2467*042d53a7SEvalZero }
2468*042d53a7SEvalZero
2469*042d53a7SEvalZero /**
2470*042d53a7SEvalZero * Called to create and send a REJECT_IND_EXT control PDU or a REJECT_IND
2471*042d53a7SEvalZero *
2472*042d53a7SEvalZero * @param connsm
2473*042d53a7SEvalZero * @param rej_opcode
2474*042d53a7SEvalZero * @param err
2475*042d53a7SEvalZero *
2476*042d53a7SEvalZero * @return int
2477*042d53a7SEvalZero */
2478*042d53a7SEvalZero int
ble_ll_ctrl_reject_ind_send(struct ble_ll_conn_sm * connsm,uint8_t rej_opcode,uint8_t err)2479*042d53a7SEvalZero ble_ll_ctrl_reject_ind_send(struct ble_ll_conn_sm *connsm, uint8_t rej_opcode,
2480*042d53a7SEvalZero uint8_t err)
2481*042d53a7SEvalZero {
2482*042d53a7SEvalZero int rc;
2483*042d53a7SEvalZero uint8_t len;
2484*042d53a7SEvalZero uint8_t opcode;
2485*042d53a7SEvalZero uint8_t *rspbuf;
2486*042d53a7SEvalZero struct os_mbuf *om;
2487*042d53a7SEvalZero
2488*042d53a7SEvalZero om = os_msys_get_pkthdr(BLE_LL_CTRL_MAX_PDU_LEN,
2489*042d53a7SEvalZero sizeof(struct ble_mbuf_hdr));
2490*042d53a7SEvalZero if (om) {
2491*042d53a7SEvalZero rspbuf = om->om_data;
2492*042d53a7SEvalZero opcode = BLE_LL_CTRL_REJECT_IND_EXT;
2493*042d53a7SEvalZero if (rej_opcode == BLE_LL_CTRL_ENC_REQ) {
2494*042d53a7SEvalZero if ((connsm->conn_features & BLE_LL_FEAT_EXTENDED_REJ) == 0) {
2495*042d53a7SEvalZero opcode = BLE_LL_CTRL_REJECT_IND;
2496*042d53a7SEvalZero }
2497*042d53a7SEvalZero }
2498*042d53a7SEvalZero rspbuf[0] = opcode;
2499*042d53a7SEvalZero if (opcode == BLE_LL_CTRL_REJECT_IND) {
2500*042d53a7SEvalZero rspbuf[1] = err;
2501*042d53a7SEvalZero len = BLE_LL_CTRL_REJ_IND_LEN + 1;
2502*042d53a7SEvalZero } else {
2503*042d53a7SEvalZero rspbuf[1] = rej_opcode;
2504*042d53a7SEvalZero rspbuf[2] = err;
2505*042d53a7SEvalZero len = BLE_LL_CTRL_REJECT_IND_EXT_LEN + 1;
2506*042d53a7SEvalZero }
2507*042d53a7SEvalZero ble_ll_conn_enqueue_pkt(connsm, om, BLE_LL_LLID_CTRL, len);
2508*042d53a7SEvalZero rc = 0;
2509*042d53a7SEvalZero } else {
2510*042d53a7SEvalZero rc = 1;
2511*042d53a7SEvalZero }
2512*042d53a7SEvalZero return rc;
2513*042d53a7SEvalZero }
2514*042d53a7SEvalZero
2515*042d53a7SEvalZero /**
2516*042d53a7SEvalZero * Called when a Link Layer Control pdu has been transmitted successfully.
2517*042d53a7SEvalZero * This is called when we have a received a PDU during the ISR.
2518*042d53a7SEvalZero *
2519*042d53a7SEvalZero * Context: ISR
2520*042d53a7SEvalZero *
2521*042d53a7SEvalZero * @param txpdu
2522*042d53a7SEvalZero *
2523*042d53a7SEvalZero * @return int
2524*042d53a7SEvalZero */
2525*042d53a7SEvalZero int
ble_ll_ctrl_tx_done(struct os_mbuf * txpdu,struct ble_ll_conn_sm * connsm)2526*042d53a7SEvalZero ble_ll_ctrl_tx_done(struct os_mbuf *txpdu, struct ble_ll_conn_sm *connsm)
2527*042d53a7SEvalZero {
2528*042d53a7SEvalZero int rc;
2529*042d53a7SEvalZero uint8_t opcode;
2530*042d53a7SEvalZero
2531*042d53a7SEvalZero rc = 0;
2532*042d53a7SEvalZero opcode = txpdu->om_data[0];
2533*042d53a7SEvalZero switch (opcode) {
2534*042d53a7SEvalZero case BLE_LL_CTRL_TERMINATE_IND:
2535*042d53a7SEvalZero connsm->csmflags.cfbit.terminate_ind_txd = 1;
2536*042d53a7SEvalZero rc = -1;
2537*042d53a7SEvalZero break;
2538*042d53a7SEvalZero case BLE_LL_CTRL_REJECT_IND_EXT:
2539*042d53a7SEvalZero if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_CONN_PARAM_REQ) {
2540*042d53a7SEvalZero /* If rejecting opcode is BLE_LL_CTRL_PROC_CONN_PARAM_REQ and
2541*042d53a7SEvalZero * reason is LMP collision that means we are master on the link and
2542*042d53a7SEvalZero * peer wanted to start procedure which we already started.
2543*042d53a7SEvalZero * Let's wait for response and do not close procedure. */
2544*042d53a7SEvalZero if (txpdu->om_data[1] == BLE_LL_CTRL_CONN_PARM_REQ &&
2545*042d53a7SEvalZero txpdu->om_data[2] != BLE_ERR_LMP_COLLISION) {
2546*042d53a7SEvalZero connsm->reject_reason = txpdu->om_data[2];
2547*042d53a7SEvalZero connsm->csmflags.cfbit.host_expects_upd_event = 1;
2548*042d53a7SEvalZero }
2549*042d53a7SEvalZero }
2550*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
2551*042d53a7SEvalZero if (connsm->enc_data.enc_state > CONN_ENC_S_ENCRYPTED) {
2552*042d53a7SEvalZero connsm->enc_data.enc_state = CONN_ENC_S_UNENCRYPTED;
2553*042d53a7SEvalZero }
2554*042d53a7SEvalZero #endif
2555*042d53a7SEvalZero break;
2556*042d53a7SEvalZero case BLE_LL_CTRL_REJECT_IND:
2557*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
2558*042d53a7SEvalZero connsm->enc_data.enc_state = CONN_ENC_S_UNENCRYPTED;
2559*042d53a7SEvalZero #endif
2560*042d53a7SEvalZero break;
2561*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
2562*042d53a7SEvalZero case BLE_LL_CTRL_PAUSE_ENC_REQ:
2563*042d53a7SEvalZero /* note: fall-through intentional */
2564*042d53a7SEvalZero case BLE_LL_CTRL_ENC_REQ:
2565*042d53a7SEvalZero connsm->enc_data.enc_state = CONN_ENC_S_ENC_RSP_WAIT;
2566*042d53a7SEvalZero break;
2567*042d53a7SEvalZero case BLE_LL_CTRL_ENC_RSP:
2568*042d53a7SEvalZero connsm->enc_data.enc_state = CONN_ENC_S_LTK_REQ_WAIT;
2569*042d53a7SEvalZero connsm->csmflags.cfbit.send_ltk_req = 1;
2570*042d53a7SEvalZero break;
2571*042d53a7SEvalZero case BLE_LL_CTRL_START_ENC_RSP:
2572*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
2573*042d53a7SEvalZero connsm->enc_data.enc_state = CONN_ENC_S_ENCRYPTED;
2574*042d53a7SEvalZero if (CONN_F_LE_PING_SUPP(connsm)) {
2575*042d53a7SEvalZero ble_ll_conn_auth_pyld_timer_start(connsm);
2576*042d53a7SEvalZero }
2577*042d53a7SEvalZero }
2578*042d53a7SEvalZero break;
2579*042d53a7SEvalZero case BLE_LL_CTRL_PAUSE_ENC_RSP:
2580*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
2581*042d53a7SEvalZero connsm->enc_data.enc_state = CONN_ENC_S_PAUSE_ENC_RSP_WAIT;
2582*042d53a7SEvalZero }
2583*042d53a7SEvalZero break;
2584*042d53a7SEvalZero #endif
2585*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
2586*042d53a7SEvalZero case BLE_LL_CTRL_PHY_REQ:
2587*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
2588*042d53a7SEvalZero if (connsm->phy_data.req_pref_tx_phys_mask & BLE_PHY_MASK_1M) {
2589*042d53a7SEvalZero connsm->phy_tx_transition = BLE_PHY_1M;
2590*042d53a7SEvalZero } else if (connsm->phy_data.req_pref_tx_phys_mask & BLE_PHY_MASK_2M) {
2591*042d53a7SEvalZero connsm->phy_tx_transition = BLE_PHY_2M;
2592*042d53a7SEvalZero } else if (connsm->phy_data.req_pref_tx_phys_mask & BLE_PHY_MASK_CODED) {
2593*042d53a7SEvalZero connsm->phy_tx_transition = BLE_PHY_CODED;
2594*042d53a7SEvalZero }
2595*042d53a7SEvalZero }
2596*042d53a7SEvalZero break;
2597*042d53a7SEvalZero #endif
2598*042d53a7SEvalZero default:
2599*042d53a7SEvalZero break;
2600*042d53a7SEvalZero }
2601*042d53a7SEvalZero
2602*042d53a7SEvalZero os_mbuf_free_chain(txpdu);
2603*042d53a7SEvalZero return rc;
2604*042d53a7SEvalZero }
2605