1*042d53a7SEvalZero /*
2*042d53a7SEvalZero * Licensed to the Apache Software Foundation (ASF) under one
3*042d53a7SEvalZero * or more contributor license agreements. See the NOTICE file
4*042d53a7SEvalZero * distributed with this work for additional information
5*042d53a7SEvalZero * regarding copyright ownership. The ASF licenses this file
6*042d53a7SEvalZero * to you under the Apache License, Version 2.0 (the
7*042d53a7SEvalZero * "License"); you may not use this file except in compliance
8*042d53a7SEvalZero * with the License. You may obtain a copy of the License at
9*042d53a7SEvalZero *
10*042d53a7SEvalZero * http://www.apache.org/licenses/LICENSE-2.0
11*042d53a7SEvalZero *
12*042d53a7SEvalZero * Unless required by applicable law or agreed to in writing,
13*042d53a7SEvalZero * software distributed under the License is distributed on an
14*042d53a7SEvalZero * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15*042d53a7SEvalZero * KIND, either express or implied. See the License for the
16*042d53a7SEvalZero * specific language governing permissions and limitations
17*042d53a7SEvalZero * under the License.
18*042d53a7SEvalZero */
19*042d53a7SEvalZero
20*042d53a7SEvalZero #include <stdint.h>
21*042d53a7SEvalZero #include <stdlib.h>
22*042d53a7SEvalZero #include <string.h>
23*042d53a7SEvalZero #include <assert.h>
24*042d53a7SEvalZero #include "syscfg/syscfg.h"
25*042d53a7SEvalZero #include "os/os.h"
26*042d53a7SEvalZero #include "os/os_cputime.h"
27*042d53a7SEvalZero #include "nimble/ble.h"
28*042d53a7SEvalZero #include "nimble/nimble_opt.h"
29*042d53a7SEvalZero #include "nimble/hci_common.h"
30*042d53a7SEvalZero #include "nimble/ble_hci_trans.h"
31*042d53a7SEvalZero #include "ble/xcvr.h"
32*042d53a7SEvalZero #include "controller/ble_ll.h"
33*042d53a7SEvalZero #include "controller/ble_ll_hci.h"
34*042d53a7SEvalZero #include "controller/ble_ll_scan.h"
35*042d53a7SEvalZero #include "controller/ble_ll_whitelist.h"
36*042d53a7SEvalZero #include "controller/ble_ll_sched.h"
37*042d53a7SEvalZero #include "controller/ble_ll_ctrl.h"
38*042d53a7SEvalZero #include "controller/ble_ll_resolv.h"
39*042d53a7SEvalZero #include "controller/ble_ll_adv.h"
40*042d53a7SEvalZero #include "controller/ble_ll_trace.h"
41*042d53a7SEvalZero #include "controller/ble_phy.h"
42*042d53a7SEvalZero #include "controller/ble_hw.h"
43*042d53a7SEvalZero #include "ble_ll_conn_priv.h"
44*042d53a7SEvalZero
45*042d53a7SEvalZero #if (BLETEST_THROUGHPUT_TEST == 1)
46*042d53a7SEvalZero extern void bletest_completed_pkt(uint16_t handle);
47*042d53a7SEvalZero #endif
48*042d53a7SEvalZero
49*042d53a7SEvalZero /* XXX TODO
50*042d53a7SEvalZero * 1) I think if we are initiating and we already have a connection with
51*042d53a7SEvalZero * a device that we will still try and connect to it. Fix this.
52*042d53a7SEvalZero * -> This is true. There are a couple things to do
53*042d53a7SEvalZero * i) When a connection create is issued, if we already are connected
54*042d53a7SEvalZero * deny it. BLE ERROR = 0x0B (ACL connection exists).
55*042d53a7SEvalZero * ii) If we receive an advertisement while initiating and want to send
56*042d53a7SEvalZero * a connect request to the device, make sure we dont have it.
57*042d53a7SEvalZero * iii) I think I need to do something like this: I am initiating and
58*042d53a7SEvalZero * advertising. Suppose the device I want to connect to sends me a connect
59*042d53a7SEvalZero * request because I am advertising? What happens to connection? Deal
60*042d53a7SEvalZero * with this!
61*042d53a7SEvalZero *
62*042d53a7SEvalZero * 2) Make sure we check incoming data packets for size and all that. You
63*042d53a7SEvalZero * know, supported octets and all that. For both rx and tx.
64*042d53a7SEvalZero *
65*042d53a7SEvalZero * 3) Make sure we are setting the schedule end time properly for both slave
66*042d53a7SEvalZero * and master. We should just set this to the end of the connection event.
67*042d53a7SEvalZero * We might want to guarantee a IFS time as well since the next event needs
68*042d53a7SEvalZero * to be scheduled prior to the start of the event to account for the time it
69*042d53a7SEvalZero * takes to get a frame ready (which is pretty much the IFS time).
70*042d53a7SEvalZero *
71*042d53a7SEvalZero * 4) looks like the current code will allow the 1st packet in a
72*042d53a7SEvalZero * connection to extend past the end of the allocated connection end
73*042d53a7SEvalZero * time. That is not good. Need to deal with that. Need to extend connection
74*042d53a7SEvalZero * end time.
75*042d53a7SEvalZero *
76*042d53a7SEvalZero * 6) Use error code 0x3E correctly! Connection failed to establish. If you
77*042d53a7SEvalZero * read the LE connection complete event, it says that if the connection
78*042d53a7SEvalZero * fails to be established that the connection complete event gets sent to
79*042d53a7SEvalZero * the host that issued the create connection. Need to resolve this.
80*042d53a7SEvalZero *
81*042d53a7SEvalZero * 7) How does peer address get set if we are using whitelist? Look at filter
82*042d53a7SEvalZero * policy and make sure you are doing this correctly.
83*042d53a7SEvalZero *
84*042d53a7SEvalZero * 8) Right now I use a fixed definition for required slots. CHange this.
85*042d53a7SEvalZero *
86*042d53a7SEvalZero * 10) See what connection state machine elements are purely master and
87*042d53a7SEvalZero * purely slave. We can make a union of them.
88*042d53a7SEvalZero *
89*042d53a7SEvalZero * 11) Not sure I am dealing with the connection terminate timeout perfectly.
90*042d53a7SEvalZero * I may extend a connection event too long although if it is always in terms
91*042d53a7SEvalZero * of connection events I am probably fine. Checking at end that the next
92*042d53a7SEvalZero * connection event will occur past terminate timeould would be fine.
93*042d53a7SEvalZero *
94*042d53a7SEvalZero * 12) When a slave receives a data packet in a connection it has to send a
95*042d53a7SEvalZero * response. Well, it should. If this packet will overrun the next scheduled
96*042d53a7SEvalZero * event, what should we do? Transmit anyway? Not transmit? For now, we just
97*042d53a7SEvalZero * transmit.
98*042d53a7SEvalZero *
99*042d53a7SEvalZero * 32kHz crystal
100*042d53a7SEvalZero * 1) When scheduling, I need to make sure I have time between
101*042d53a7SEvalZero * this one and the next. Should I deal with this in the sched. Or
102*042d53a7SEvalZero * is this basically accounted for given a slot? I really just need to
103*042d53a7SEvalZero * make sure everything is over N ticks before the next sched start!
104*042d53a7SEvalZero * Just add to end time?
105*042d53a7SEvalZero *
106*042d53a7SEvalZero * 2) I think one way to handle the problem of losing up to a microsecond
107*042d53a7SEvalZero * every time we call ble_ll_conn_next_event in a loop is to do everything by
108*042d53a7SEvalZero * keeping track of last anchor point. Would need last anchor usecs too. I guess
109*042d53a7SEvalZero * we could also keep last anchor usecs as a uint32 or something and when we
110*042d53a7SEvalZero * do the next event keep track of the residual using a different ticks to
111*042d53a7SEvalZero * usecs calculation. Not sure.
112*042d53a7SEvalZero */
113*042d53a7SEvalZero
114*042d53a7SEvalZero /*
115*042d53a7SEvalZero * XXX: How should we deal with a late connection event? We need to determine
116*042d53a7SEvalZero * what we want to do under the following cases:
117*042d53a7SEvalZero * 1) The current connection event has not ended but a schedule item starts
118*042d53a7SEvalZero */
119*042d53a7SEvalZero
120*042d53a7SEvalZero /* This is a dummy structure we use for the empty PDU */
121*042d53a7SEvalZero struct ble_ll_empty_pdu
122*042d53a7SEvalZero {
123*042d53a7SEvalZero struct os_mbuf om;
124*042d53a7SEvalZero struct os_mbuf_pkthdr pkt_hdr;
125*042d53a7SEvalZero struct ble_mbuf_hdr ble_hdr;
126*042d53a7SEvalZero };
127*042d53a7SEvalZero
128*042d53a7SEvalZero /* We cannot have more than 254 connections given our current implementation */
129*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_MAX_CONNECTIONS) >= 255)
130*042d53a7SEvalZero #error "Maximum # of connections is 254"
131*042d53a7SEvalZero #endif
132*042d53a7SEvalZero
133*042d53a7SEvalZero /* Sleep clock accuracy table (in ppm) */
134*042d53a7SEvalZero static const uint16_t g_ble_sca_ppm_tbl[8] =
135*042d53a7SEvalZero {
136*042d53a7SEvalZero 500, 250, 150, 100, 75, 50, 30, 20
137*042d53a7SEvalZero };
138*042d53a7SEvalZero
139*042d53a7SEvalZero /* Global connection complete event. Used when initiating */
140*042d53a7SEvalZero uint8_t *g_ble_ll_conn_comp_ev;
141*042d53a7SEvalZero
142*042d53a7SEvalZero /* Global LL connection parameters */
143*042d53a7SEvalZero struct ble_ll_conn_global_params g_ble_ll_conn_params;
144*042d53a7SEvalZero
145*042d53a7SEvalZero /* Pointer to connection state machine we are trying to create */
146*042d53a7SEvalZero struct ble_ll_conn_sm *g_ble_ll_conn_create_sm;
147*042d53a7SEvalZero
148*042d53a7SEvalZero /* Pointer to current connection */
149*042d53a7SEvalZero struct ble_ll_conn_sm *g_ble_ll_conn_cur_sm;
150*042d53a7SEvalZero
151*042d53a7SEvalZero /* Connection state machine array */
152*042d53a7SEvalZero struct ble_ll_conn_sm g_ble_ll_conn_sm[MYNEWT_VAL(BLE_MAX_CONNECTIONS)];
153*042d53a7SEvalZero
154*042d53a7SEvalZero /* List of active connections */
155*042d53a7SEvalZero struct ble_ll_conn_active_list g_ble_ll_conn_active_list;
156*042d53a7SEvalZero
157*042d53a7SEvalZero /* List of free connections */
158*042d53a7SEvalZero struct ble_ll_conn_free_list g_ble_ll_conn_free_list;
159*042d53a7SEvalZero
160*042d53a7SEvalZero STATS_SECT_START(ble_ll_conn_stats)
161*042d53a7SEvalZero STATS_SECT_ENTRY(cant_set_sched)
162*042d53a7SEvalZero STATS_SECT_ENTRY(conn_ev_late)
163*042d53a7SEvalZero STATS_SECT_ENTRY(wfr_expirations)
164*042d53a7SEvalZero STATS_SECT_ENTRY(handle_not_found)
165*042d53a7SEvalZero STATS_SECT_ENTRY(no_conn_sm)
166*042d53a7SEvalZero STATS_SECT_ENTRY(no_free_conn_sm)
167*042d53a7SEvalZero STATS_SECT_ENTRY(rx_data_pdu_no_conn)
168*042d53a7SEvalZero STATS_SECT_ENTRY(rx_data_pdu_bad_aa)
169*042d53a7SEvalZero STATS_SECT_ENTRY(slave_rxd_bad_conn_req_params)
170*042d53a7SEvalZero STATS_SECT_ENTRY(slave_ce_failures)
171*042d53a7SEvalZero STATS_SECT_ENTRY(data_pdu_rx_dup)
172*042d53a7SEvalZero STATS_SECT_ENTRY(data_pdu_txg)
173*042d53a7SEvalZero STATS_SECT_ENTRY(data_pdu_txf)
174*042d53a7SEvalZero STATS_SECT_ENTRY(conn_req_txd)
175*042d53a7SEvalZero STATS_SECT_ENTRY(l2cap_enqueued)
176*042d53a7SEvalZero STATS_SECT_ENTRY(rx_ctrl_pdus)
177*042d53a7SEvalZero STATS_SECT_ENTRY(rx_l2cap_pdus)
178*042d53a7SEvalZero STATS_SECT_ENTRY(rx_l2cap_bytes)
179*042d53a7SEvalZero STATS_SECT_ENTRY(rx_malformed_ctrl_pdus)
180*042d53a7SEvalZero STATS_SECT_ENTRY(rx_bad_llid)
181*042d53a7SEvalZero STATS_SECT_ENTRY(tx_ctrl_pdus)
182*042d53a7SEvalZero STATS_SECT_ENTRY(tx_ctrl_bytes)
183*042d53a7SEvalZero STATS_SECT_ENTRY(tx_l2cap_pdus)
184*042d53a7SEvalZero STATS_SECT_ENTRY(tx_l2cap_bytes)
185*042d53a7SEvalZero STATS_SECT_ENTRY(tx_empty_pdus)
186*042d53a7SEvalZero STATS_SECT_ENTRY(mic_failures)
187*042d53a7SEvalZero STATS_SECT_END
188*042d53a7SEvalZero STATS_SECT_DECL(ble_ll_conn_stats) ble_ll_conn_stats;
189*042d53a7SEvalZero
190*042d53a7SEvalZero STATS_NAME_START(ble_ll_conn_stats)
191*042d53a7SEvalZero STATS_NAME(ble_ll_conn_stats, cant_set_sched)
192*042d53a7SEvalZero STATS_NAME(ble_ll_conn_stats, conn_ev_late)
193*042d53a7SEvalZero STATS_NAME(ble_ll_conn_stats, wfr_expirations)
194*042d53a7SEvalZero STATS_NAME(ble_ll_conn_stats, handle_not_found)
195*042d53a7SEvalZero STATS_NAME(ble_ll_conn_stats, no_conn_sm)
196*042d53a7SEvalZero STATS_NAME(ble_ll_conn_stats, no_free_conn_sm)
197*042d53a7SEvalZero STATS_NAME(ble_ll_conn_stats, rx_data_pdu_no_conn)
198*042d53a7SEvalZero STATS_NAME(ble_ll_conn_stats, rx_data_pdu_bad_aa)
199*042d53a7SEvalZero STATS_NAME(ble_ll_conn_stats, slave_rxd_bad_conn_req_params)
200*042d53a7SEvalZero STATS_NAME(ble_ll_conn_stats, slave_ce_failures)
201*042d53a7SEvalZero STATS_NAME(ble_ll_conn_stats, data_pdu_rx_dup)
202*042d53a7SEvalZero STATS_NAME(ble_ll_conn_stats, data_pdu_txg)
203*042d53a7SEvalZero STATS_NAME(ble_ll_conn_stats, data_pdu_txf)
204*042d53a7SEvalZero STATS_NAME(ble_ll_conn_stats, conn_req_txd)
205*042d53a7SEvalZero STATS_NAME(ble_ll_conn_stats, l2cap_enqueued)
206*042d53a7SEvalZero STATS_NAME(ble_ll_conn_stats, rx_ctrl_pdus)
207*042d53a7SEvalZero STATS_NAME(ble_ll_conn_stats, rx_l2cap_pdus)
208*042d53a7SEvalZero STATS_NAME(ble_ll_conn_stats, rx_l2cap_bytes)
209*042d53a7SEvalZero STATS_NAME(ble_ll_conn_stats, rx_malformed_ctrl_pdus)
210*042d53a7SEvalZero STATS_NAME(ble_ll_conn_stats, rx_bad_llid)
211*042d53a7SEvalZero STATS_NAME(ble_ll_conn_stats, tx_ctrl_pdus)
212*042d53a7SEvalZero STATS_NAME(ble_ll_conn_stats, tx_ctrl_bytes)
213*042d53a7SEvalZero STATS_NAME(ble_ll_conn_stats, tx_l2cap_pdus)
214*042d53a7SEvalZero STATS_NAME(ble_ll_conn_stats, tx_l2cap_bytes)
215*042d53a7SEvalZero STATS_NAME(ble_ll_conn_stats, tx_empty_pdus)
216*042d53a7SEvalZero STATS_NAME(ble_ll_conn_stats, mic_failures)
217*042d53a7SEvalZero STATS_NAME_END(ble_ll_conn_stats)
218*042d53a7SEvalZero
219*042d53a7SEvalZero static void ble_ll_conn_event_end(struct ble_npl_event *ev);
220*042d53a7SEvalZero
221*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
222*042d53a7SEvalZero /**
223*042d53a7SEvalZero * Checks to see if we should start a PHY update procedure
224*042d53a7SEvalZero *
225*042d53a7SEvalZero * If current phy is not one of the preferred we need to start control
226*042d53a7SEvalZero * procedure.
227*042d53a7SEvalZero *
228*042d53a7SEvalZero * XXX: we could also decide to change the PHY if RSSI is really good
229*042d53a7SEvalZero * and we are currently at 1Mbps or lower data rate and we could use
230*042d53a7SEvalZero * a higher data rate.
231*042d53a7SEvalZero *
232*042d53a7SEvalZero * @param connsm
233*042d53a7SEvalZero * @return 0: success; -1: no phy update procedure started
234*042d53a7SEvalZero */
235*042d53a7SEvalZero int
ble_ll_conn_chk_phy_upd_start(struct ble_ll_conn_sm * csm)236*042d53a7SEvalZero ble_ll_conn_chk_phy_upd_start(struct ble_ll_conn_sm *csm)
237*042d53a7SEvalZero {
238*042d53a7SEvalZero int rc;
239*042d53a7SEvalZero
240*042d53a7SEvalZero /* If no host preferences or */
241*042d53a7SEvalZero if (((csm->phy_data.host_pref_tx_phys_mask == 0) &&
242*042d53a7SEvalZero (csm->phy_data.host_pref_rx_phys_mask == 0)) ||
243*042d53a7SEvalZero ((csm->phy_data.host_pref_tx_phys_mask & CONN_CUR_TX_PHY_MASK(csm)) &&
244*042d53a7SEvalZero (csm->phy_data.host_pref_rx_phys_mask & CONN_CUR_RX_PHY_MASK(csm)))) {
245*042d53a7SEvalZero rc = -1;
246*042d53a7SEvalZero } else {
247*042d53a7SEvalZero csm->phy_data.req_pref_tx_phys_mask = csm->phy_data.host_pref_tx_phys_mask;
248*042d53a7SEvalZero csm->phy_data.req_pref_rx_phys_mask = csm->phy_data.host_pref_rx_phys_mask;
249*042d53a7SEvalZero ble_ll_ctrl_proc_start(csm, BLE_LL_CTRL_PROC_PHY_UPDATE);
250*042d53a7SEvalZero rc = 0;
251*042d53a7SEvalZero }
252*042d53a7SEvalZero
253*042d53a7SEvalZero return rc;
254*042d53a7SEvalZero }
255*042d53a7SEvalZero #endif
256*042d53a7SEvalZero
257*042d53a7SEvalZero static void
ble_ll_conn_calc_itvl_ticks(struct ble_ll_conn_sm * connsm)258*042d53a7SEvalZero ble_ll_conn_calc_itvl_ticks(struct ble_ll_conn_sm *connsm)
259*042d53a7SEvalZero {
260*042d53a7SEvalZero uint32_t ticks;
261*042d53a7SEvalZero uint32_t usecs;
262*042d53a7SEvalZero
263*042d53a7SEvalZero /*
264*042d53a7SEvalZero * Precalculate the number of ticks and remaining microseconds for
265*042d53a7SEvalZero * the connection interval
266*042d53a7SEvalZero */
267*042d53a7SEvalZero usecs = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS;
268*042d53a7SEvalZero ticks = os_cputime_usecs_to_ticks(usecs);
269*042d53a7SEvalZero connsm->conn_itvl_usecs = (uint8_t)(usecs -
270*042d53a7SEvalZero os_cputime_ticks_to_usecs(ticks));
271*042d53a7SEvalZero if (connsm->conn_itvl_usecs == 31) {
272*042d53a7SEvalZero connsm->conn_itvl_usecs = 0;
273*042d53a7SEvalZero ++ticks;
274*042d53a7SEvalZero }
275*042d53a7SEvalZero connsm->conn_itvl_ticks = ticks;
276*042d53a7SEvalZero }
277*042d53a7SEvalZero
278*042d53a7SEvalZero /**
279*042d53a7SEvalZero * Get the event buffer allocated to send the connection complete event
280*042d53a7SEvalZero * when we are initiating.
281*042d53a7SEvalZero *
282*042d53a7SEvalZero * @return uint8_t*
283*042d53a7SEvalZero */
284*042d53a7SEvalZero static uint8_t *
ble_ll_init_get_conn_comp_ev(void)285*042d53a7SEvalZero ble_ll_init_get_conn_comp_ev(void)
286*042d53a7SEvalZero {
287*042d53a7SEvalZero uint8_t *evbuf;
288*042d53a7SEvalZero
289*042d53a7SEvalZero evbuf = g_ble_ll_conn_comp_ev;
290*042d53a7SEvalZero BLE_LL_ASSERT(evbuf != NULL);
291*042d53a7SEvalZero g_ble_ll_conn_comp_ev = NULL;
292*042d53a7SEvalZero
293*042d53a7SEvalZero return evbuf;
294*042d53a7SEvalZero }
295*042d53a7SEvalZero
296*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
297*042d53a7SEvalZero /**
298*042d53a7SEvalZero * Called to determine if the received PDU is an empty PDU or not.
299*042d53a7SEvalZero */
300*042d53a7SEvalZero static int
ble_ll_conn_is_empty_pdu(uint8_t * rxbuf)301*042d53a7SEvalZero ble_ll_conn_is_empty_pdu(uint8_t *rxbuf)
302*042d53a7SEvalZero {
303*042d53a7SEvalZero int rc;
304*042d53a7SEvalZero uint8_t llid;
305*042d53a7SEvalZero
306*042d53a7SEvalZero llid = rxbuf[0] & BLE_LL_DATA_HDR_LLID_MASK;
307*042d53a7SEvalZero if ((llid == BLE_LL_LLID_DATA_FRAG) && (rxbuf[1] == 0)) {
308*042d53a7SEvalZero rc = 1;
309*042d53a7SEvalZero } else {
310*042d53a7SEvalZero rc = 0;
311*042d53a7SEvalZero }
312*042d53a7SEvalZero return rc;
313*042d53a7SEvalZero }
314*042d53a7SEvalZero #endif
315*042d53a7SEvalZero
316*042d53a7SEvalZero /**
317*042d53a7SEvalZero * Called to return the currently running connection state machine end time.
318*042d53a7SEvalZero * Always called when interrupts are disabled.
319*042d53a7SEvalZero *
320*042d53a7SEvalZero * @return int 0: s1 is not least recently used. 1: s1 is least recently used
321*042d53a7SEvalZero */
322*042d53a7SEvalZero int
ble_ll_conn_is_lru(struct ble_ll_conn_sm * s1,struct ble_ll_conn_sm * s2)323*042d53a7SEvalZero ble_ll_conn_is_lru(struct ble_ll_conn_sm *s1, struct ble_ll_conn_sm *s2)
324*042d53a7SEvalZero {
325*042d53a7SEvalZero int rc;
326*042d53a7SEvalZero
327*042d53a7SEvalZero /* Set time that we last serviced the schedule */
328*042d53a7SEvalZero if ((int32_t)(s1->last_scheduled - s2->last_scheduled) < 0) {
329*042d53a7SEvalZero rc = 1;
330*042d53a7SEvalZero } else {
331*042d53a7SEvalZero rc = 0;
332*042d53a7SEvalZero }
333*042d53a7SEvalZero
334*042d53a7SEvalZero return rc;
335*042d53a7SEvalZero }
336*042d53a7SEvalZero
337*042d53a7SEvalZero /**
338*042d53a7SEvalZero * Called to return the currently running connection state machine end time.
339*042d53a7SEvalZero * Always called when interrupts are disabled.
340*042d53a7SEvalZero *
341*042d53a7SEvalZero * @return uint32_t
342*042d53a7SEvalZero */
343*042d53a7SEvalZero uint32_t
ble_ll_conn_get_ce_end_time(void)344*042d53a7SEvalZero ble_ll_conn_get_ce_end_time(void)
345*042d53a7SEvalZero {
346*042d53a7SEvalZero uint32_t ce_end_time;
347*042d53a7SEvalZero
348*042d53a7SEvalZero if (g_ble_ll_conn_cur_sm) {
349*042d53a7SEvalZero ce_end_time = g_ble_ll_conn_cur_sm->ce_end_time;
350*042d53a7SEvalZero } else {
351*042d53a7SEvalZero ce_end_time = os_cputime_get32();
352*042d53a7SEvalZero }
353*042d53a7SEvalZero return ce_end_time;
354*042d53a7SEvalZero }
355*042d53a7SEvalZero
356*042d53a7SEvalZero /**
357*042d53a7SEvalZero * Called when the current connection state machine is no longer being used.
358*042d53a7SEvalZero * This function will:
359*042d53a7SEvalZero * -> Disable the PHY, which will prevent any transmit/receive interrupts.
360*042d53a7SEvalZero * -> Disable the wait for response timer, if running.
361*042d53a7SEvalZero * -> Remove the connection state machine from the scheduler.
362*042d53a7SEvalZero * -> Sets the Link Layer state to standby.
363*042d53a7SEvalZero * -> Sets the current state machine to NULL.
364*042d53a7SEvalZero *
365*042d53a7SEvalZero * NOTE: the ordering of these function calls is important! We have to stop
366*042d53a7SEvalZero * the PHY and remove the schedule item before we can set the state to
367*042d53a7SEvalZero * standby and set the current state machine pointer to NULL.
368*042d53a7SEvalZero */
369*042d53a7SEvalZero static void
ble_ll_conn_current_sm_over(struct ble_ll_conn_sm * connsm)370*042d53a7SEvalZero ble_ll_conn_current_sm_over(struct ble_ll_conn_sm *connsm)
371*042d53a7SEvalZero {
372*042d53a7SEvalZero /* Disable the PHY */
373*042d53a7SEvalZero ble_phy_disable();
374*042d53a7SEvalZero
375*042d53a7SEvalZero /* Disable the wfr timer */
376*042d53a7SEvalZero ble_ll_wfr_disable();
377*042d53a7SEvalZero
378*042d53a7SEvalZero /* Link-layer is in standby state now */
379*042d53a7SEvalZero ble_ll_state_set(BLE_LL_STATE_STANDBY);
380*042d53a7SEvalZero
381*042d53a7SEvalZero /* Set current LL connection to NULL */
382*042d53a7SEvalZero g_ble_ll_conn_cur_sm = NULL;
383*042d53a7SEvalZero
384*042d53a7SEvalZero /*
385*042d53a7SEvalZero * NOTE: the connection state machine may be NULL if we are calling
386*042d53a7SEvalZero * this when we are ending the connection. In that case, there is no
387*042d53a7SEvalZero * need to post to the LL the connection event end event
388*042d53a7SEvalZero */
389*042d53a7SEvalZero if (connsm) {
390*042d53a7SEvalZero ble_ll_event_send(&connsm->conn_ev_end);
391*042d53a7SEvalZero }
392*042d53a7SEvalZero }
393*042d53a7SEvalZero
394*042d53a7SEvalZero /**
395*042d53a7SEvalZero * Given a handle, find an active connection matching the handle
396*042d53a7SEvalZero *
397*042d53a7SEvalZero * @param handle
398*042d53a7SEvalZero *
399*042d53a7SEvalZero * @return struct ble_ll_conn_sm*
400*042d53a7SEvalZero */
401*042d53a7SEvalZero struct ble_ll_conn_sm *
ble_ll_conn_find_active_conn(uint16_t handle)402*042d53a7SEvalZero ble_ll_conn_find_active_conn(uint16_t handle)
403*042d53a7SEvalZero {
404*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
405*042d53a7SEvalZero
406*042d53a7SEvalZero connsm = NULL;
407*042d53a7SEvalZero if ((handle != 0) && (handle <= MYNEWT_VAL(BLE_MAX_CONNECTIONS))) {
408*042d53a7SEvalZero connsm = &g_ble_ll_conn_sm[handle - 1];
409*042d53a7SEvalZero if (connsm->conn_state == BLE_LL_CONN_STATE_IDLE) {
410*042d53a7SEvalZero connsm = NULL;
411*042d53a7SEvalZero }
412*042d53a7SEvalZero }
413*042d53a7SEvalZero return connsm;
414*042d53a7SEvalZero }
415*042d53a7SEvalZero
416*042d53a7SEvalZero /**
417*042d53a7SEvalZero * Get a connection state machine.
418*042d53a7SEvalZero */
419*042d53a7SEvalZero struct ble_ll_conn_sm *
ble_ll_conn_sm_get(void)420*042d53a7SEvalZero ble_ll_conn_sm_get(void)
421*042d53a7SEvalZero {
422*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
423*042d53a7SEvalZero
424*042d53a7SEvalZero connsm = STAILQ_FIRST(&g_ble_ll_conn_free_list);
425*042d53a7SEvalZero if (connsm) {
426*042d53a7SEvalZero STAILQ_REMOVE_HEAD(&g_ble_ll_conn_free_list, free_stqe);
427*042d53a7SEvalZero } else {
428*042d53a7SEvalZero STATS_INC(ble_ll_conn_stats, no_free_conn_sm);
429*042d53a7SEvalZero }
430*042d53a7SEvalZero
431*042d53a7SEvalZero return connsm;
432*042d53a7SEvalZero }
433*042d53a7SEvalZero
434*042d53a7SEvalZero /**
435*042d53a7SEvalZero * Calculate the amount of window widening for a given connection event. This
436*042d53a7SEvalZero * is the amount of time that a slave has to account for when listening for
437*042d53a7SEvalZero * the start of a connection event.
438*042d53a7SEvalZero *
439*042d53a7SEvalZero * @param connsm Pointer to connection state machine.
440*042d53a7SEvalZero *
441*042d53a7SEvalZero * @return uint32_t The current window widening amount (in microseconds)
442*042d53a7SEvalZero */
443*042d53a7SEvalZero uint32_t
ble_ll_conn_calc_window_widening(struct ble_ll_conn_sm * connsm)444*042d53a7SEvalZero ble_ll_conn_calc_window_widening(struct ble_ll_conn_sm *connsm)
445*042d53a7SEvalZero {
446*042d53a7SEvalZero uint32_t total_sca_ppm;
447*042d53a7SEvalZero uint32_t window_widening;
448*042d53a7SEvalZero int32_t time_since_last_anchor;
449*042d53a7SEvalZero uint32_t delta_msec;
450*042d53a7SEvalZero
451*042d53a7SEvalZero window_widening = 0;
452*042d53a7SEvalZero
453*042d53a7SEvalZero time_since_last_anchor = (int32_t)(connsm->anchor_point -
454*042d53a7SEvalZero connsm->last_anchor_point);
455*042d53a7SEvalZero if (time_since_last_anchor > 0) {
456*042d53a7SEvalZero delta_msec = os_cputime_ticks_to_usecs(time_since_last_anchor) / 1000;
457*042d53a7SEvalZero total_sca_ppm = g_ble_sca_ppm_tbl[connsm->master_sca] +
458*042d53a7SEvalZero MYNEWT_VAL(BLE_LL_OUR_SCA);
459*042d53a7SEvalZero window_widening = (total_sca_ppm * delta_msec) / 1000;
460*042d53a7SEvalZero }
461*042d53a7SEvalZero
462*042d53a7SEvalZero return window_widening;
463*042d53a7SEvalZero }
464*042d53a7SEvalZero
465*042d53a7SEvalZero /**
466*042d53a7SEvalZero * Calculates the number of used channels in the channel map
467*042d53a7SEvalZero *
468*042d53a7SEvalZero * @param chmap
469*042d53a7SEvalZero *
470*042d53a7SEvalZero * @return uint8_t Number of used channels
471*042d53a7SEvalZero */
472*042d53a7SEvalZero uint8_t
ble_ll_conn_calc_used_chans(uint8_t * chmap)473*042d53a7SEvalZero ble_ll_conn_calc_used_chans(uint8_t *chmap)
474*042d53a7SEvalZero {
475*042d53a7SEvalZero int i;
476*042d53a7SEvalZero int j;
477*042d53a7SEvalZero uint8_t mask;
478*042d53a7SEvalZero uint8_t chanbyte;
479*042d53a7SEvalZero uint8_t used_channels;
480*042d53a7SEvalZero
481*042d53a7SEvalZero used_channels = 0;
482*042d53a7SEvalZero for (i = 0; i < BLE_LL_CONN_CHMAP_LEN; ++i) {
483*042d53a7SEvalZero chanbyte = chmap[i];
484*042d53a7SEvalZero if (chanbyte) {
485*042d53a7SEvalZero if (chanbyte == 0xff) {
486*042d53a7SEvalZero used_channels += 8;
487*042d53a7SEvalZero } else {
488*042d53a7SEvalZero mask = 0x01;
489*042d53a7SEvalZero for (j = 0; j < 8; ++j) {
490*042d53a7SEvalZero if (chanbyte & mask) {
491*042d53a7SEvalZero ++used_channels;
492*042d53a7SEvalZero }
493*042d53a7SEvalZero mask <<= 1;
494*042d53a7SEvalZero }
495*042d53a7SEvalZero }
496*042d53a7SEvalZero }
497*042d53a7SEvalZero }
498*042d53a7SEvalZero return used_channels;
499*042d53a7SEvalZero }
500*042d53a7SEvalZero
501*042d53a7SEvalZero static uint32_t
ble_ll_conn_calc_access_addr(void)502*042d53a7SEvalZero ble_ll_conn_calc_access_addr(void)
503*042d53a7SEvalZero {
504*042d53a7SEvalZero uint32_t aa;
505*042d53a7SEvalZero uint16_t aa_low;
506*042d53a7SEvalZero uint16_t aa_high;
507*042d53a7SEvalZero uint32_t temp;
508*042d53a7SEvalZero uint32_t mask;
509*042d53a7SEvalZero uint32_t prev_bit;
510*042d53a7SEvalZero uint8_t bits_diff;
511*042d53a7SEvalZero uint8_t consecutive;
512*042d53a7SEvalZero uint8_t transitions;
513*042d53a7SEvalZero uint8_t ones;
514*042d53a7SEvalZero
515*042d53a7SEvalZero /* Calculate a random access address */
516*042d53a7SEvalZero aa = 0;
517*042d53a7SEvalZero while (1) {
518*042d53a7SEvalZero /* Get two, 16-bit random numbers */
519*042d53a7SEvalZero aa_low = rand() & 0xFFFF;
520*042d53a7SEvalZero aa_high = rand() & 0xFFFF;
521*042d53a7SEvalZero
522*042d53a7SEvalZero /* All four bytes cannot be equal */
523*042d53a7SEvalZero if (aa_low == aa_high) {
524*042d53a7SEvalZero continue;
525*042d53a7SEvalZero }
526*042d53a7SEvalZero
527*042d53a7SEvalZero /* Upper 6 bits must have 2 transitions */
528*042d53a7SEvalZero temp = aa_high & 0xFC00;
529*042d53a7SEvalZero if ((temp == 0) || (temp == 0xFC00)) {
530*042d53a7SEvalZero continue;
531*042d53a7SEvalZero }
532*042d53a7SEvalZero
533*042d53a7SEvalZero /* Cannot be access address or be 1 bit different */
534*042d53a7SEvalZero aa = aa_high;
535*042d53a7SEvalZero aa = (aa << 16) | aa_low;
536*042d53a7SEvalZero bits_diff = 0;
537*042d53a7SEvalZero temp = aa ^ BLE_ACCESS_ADDR_ADV;
538*042d53a7SEvalZero for (mask = 0x00000001; mask != 0; mask <<= 1) {
539*042d53a7SEvalZero if (mask & temp) {
540*042d53a7SEvalZero ++bits_diff;
541*042d53a7SEvalZero if (bits_diff > 1) {
542*042d53a7SEvalZero break;
543*042d53a7SEvalZero }
544*042d53a7SEvalZero }
545*042d53a7SEvalZero }
546*042d53a7SEvalZero if (bits_diff <= 1) {
547*042d53a7SEvalZero continue;
548*042d53a7SEvalZero }
549*042d53a7SEvalZero
550*042d53a7SEvalZero /* Cannot have more than 24 transitions */
551*042d53a7SEvalZero transitions = 0;
552*042d53a7SEvalZero consecutive = 1;
553*042d53a7SEvalZero ones = 0;
554*042d53a7SEvalZero mask = 0x00000001;
555*042d53a7SEvalZero while (mask < 0x80000000) {
556*042d53a7SEvalZero prev_bit = aa & mask;
557*042d53a7SEvalZero mask <<= 1;
558*042d53a7SEvalZero if (mask & aa) {
559*042d53a7SEvalZero if (prev_bit == 0) {
560*042d53a7SEvalZero ++transitions;
561*042d53a7SEvalZero consecutive = 1;
562*042d53a7SEvalZero } else {
563*042d53a7SEvalZero ++consecutive;
564*042d53a7SEvalZero }
565*042d53a7SEvalZero } else {
566*042d53a7SEvalZero if (prev_bit == 0) {
567*042d53a7SEvalZero ++consecutive;
568*042d53a7SEvalZero } else {
569*042d53a7SEvalZero ++transitions;
570*042d53a7SEvalZero consecutive = 1;
571*042d53a7SEvalZero }
572*042d53a7SEvalZero }
573*042d53a7SEvalZero
574*042d53a7SEvalZero if (prev_bit) {
575*042d53a7SEvalZero ones++;
576*042d53a7SEvalZero }
577*042d53a7SEvalZero
578*042d53a7SEvalZero /* 8 lsb should have at least three 1 */
579*042d53a7SEvalZero if (mask == 0x00000100 && ones < 3) {
580*042d53a7SEvalZero break;
581*042d53a7SEvalZero }
582*042d53a7SEvalZero
583*042d53a7SEvalZero /* 16 lsb should have no more than 11 transitions */
584*042d53a7SEvalZero if (mask == 0x00010000 && transitions > 11) {
585*042d53a7SEvalZero break;
586*042d53a7SEvalZero }
587*042d53a7SEvalZero
588*042d53a7SEvalZero /* This is invalid! */
589*042d53a7SEvalZero if (consecutive > 6) {
590*042d53a7SEvalZero /* Make sure we always detect invalid sequence below */
591*042d53a7SEvalZero mask = 0;
592*042d53a7SEvalZero break;
593*042d53a7SEvalZero }
594*042d53a7SEvalZero }
595*042d53a7SEvalZero
596*042d53a7SEvalZero /* Invalid sequence found */
597*042d53a7SEvalZero if (mask != 0x80000000) {
598*042d53a7SEvalZero continue;
599*042d53a7SEvalZero }
600*042d53a7SEvalZero
601*042d53a7SEvalZero /* Cannot be more than 24 transitions */
602*042d53a7SEvalZero if (transitions > 24) {
603*042d53a7SEvalZero continue;
604*042d53a7SEvalZero }
605*042d53a7SEvalZero
606*042d53a7SEvalZero /* We have a valid access address */
607*042d53a7SEvalZero break;
608*042d53a7SEvalZero }
609*042d53a7SEvalZero return aa;
610*042d53a7SEvalZero }
611*042d53a7SEvalZero
612*042d53a7SEvalZero static uint8_t
ble_ll_conn_remapped_channel(uint8_t remap_index,const uint8_t * chanmap)613*042d53a7SEvalZero ble_ll_conn_remapped_channel(uint8_t remap_index, const uint8_t *chanmap)
614*042d53a7SEvalZero {
615*042d53a7SEvalZero uint8_t cntr;
616*042d53a7SEvalZero uint8_t mask;
617*042d53a7SEvalZero uint8_t usable_chans;
618*042d53a7SEvalZero uint8_t chan;
619*042d53a7SEvalZero int i, j;
620*042d53a7SEvalZero
621*042d53a7SEvalZero /* NOTE: possible to build a map but this would use memory. For now,
622*042d53a7SEvalZero we just calculate */
623*042d53a7SEvalZero /* Iterate through channel map to find this channel */
624*042d53a7SEvalZero chan = 0;
625*042d53a7SEvalZero cntr = 0;
626*042d53a7SEvalZero for (i = 0; i < BLE_LL_CONN_CHMAP_LEN; i++) {
627*042d53a7SEvalZero usable_chans = chanmap[i];
628*042d53a7SEvalZero if (usable_chans != 0) {
629*042d53a7SEvalZero mask = 0x01;
630*042d53a7SEvalZero for (j = 0; j < 8; j++) {
631*042d53a7SEvalZero if (usable_chans & mask) {
632*042d53a7SEvalZero if (cntr == remap_index) {
633*042d53a7SEvalZero return (chan + j);
634*042d53a7SEvalZero }
635*042d53a7SEvalZero ++cntr;
636*042d53a7SEvalZero }
637*042d53a7SEvalZero mask <<= 1;
638*042d53a7SEvalZero }
639*042d53a7SEvalZero }
640*042d53a7SEvalZero chan += 8;
641*042d53a7SEvalZero }
642*042d53a7SEvalZero
643*042d53a7SEvalZero /* we should never reach here */
644*042d53a7SEvalZero BLE_LL_ASSERT(0);
645*042d53a7SEvalZero return 0;
646*042d53a7SEvalZero }
647*042d53a7SEvalZero
648*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) == 1)
649*042d53a7SEvalZero static uint16_t
ble_ll_conn_csa2_perm(uint16_t in)650*042d53a7SEvalZero ble_ll_conn_csa2_perm(uint16_t in)
651*042d53a7SEvalZero {
652*042d53a7SEvalZero uint16_t out = 0;
653*042d53a7SEvalZero int i;
654*042d53a7SEvalZero
655*042d53a7SEvalZero for (i = 0; i < 8; i++) {
656*042d53a7SEvalZero out |= ((in >> i) & 0x00000001) << (7 - i);
657*042d53a7SEvalZero }
658*042d53a7SEvalZero
659*042d53a7SEvalZero for (i = 8; i < 16; i++) {
660*042d53a7SEvalZero out |= ((in >> i) & 0x00000001) << (15 + 8 - i);
661*042d53a7SEvalZero }
662*042d53a7SEvalZero
663*042d53a7SEvalZero return out;
664*042d53a7SEvalZero }
665*042d53a7SEvalZero
666*042d53a7SEvalZero static uint16_t
ble_ll_conn_csa2_prng(uint16_t counter,uint16_t ch_id)667*042d53a7SEvalZero ble_ll_conn_csa2_prng(uint16_t counter, uint16_t ch_id)
668*042d53a7SEvalZero {
669*042d53a7SEvalZero uint16_t prn_e;
670*042d53a7SEvalZero
671*042d53a7SEvalZero prn_e = counter ^ ch_id;
672*042d53a7SEvalZero
673*042d53a7SEvalZero prn_e = ble_ll_conn_csa2_perm(prn_e);
674*042d53a7SEvalZero prn_e = (prn_e * 17) + ch_id;
675*042d53a7SEvalZero
676*042d53a7SEvalZero prn_e = ble_ll_conn_csa2_perm(prn_e);
677*042d53a7SEvalZero prn_e = (prn_e * 17) + ch_id;
678*042d53a7SEvalZero
679*042d53a7SEvalZero prn_e = ble_ll_conn_csa2_perm(prn_e);
680*042d53a7SEvalZero prn_e = (prn_e * 17) + ch_id;
681*042d53a7SEvalZero
682*042d53a7SEvalZero prn_e = prn_e ^ ch_id;
683*042d53a7SEvalZero
684*042d53a7SEvalZero return prn_e;
685*042d53a7SEvalZero }
686*042d53a7SEvalZero
687*042d53a7SEvalZero static uint8_t
ble_ll_conn_calc_dci_csa2(struct ble_ll_conn_sm * conn)688*042d53a7SEvalZero ble_ll_conn_calc_dci_csa2(struct ble_ll_conn_sm *conn)
689*042d53a7SEvalZero {
690*042d53a7SEvalZero uint16_t channel_unmapped;
691*042d53a7SEvalZero uint8_t remap_index;
692*042d53a7SEvalZero
693*042d53a7SEvalZero uint16_t prn_e;
694*042d53a7SEvalZero uint8_t bitpos;
695*042d53a7SEvalZero
696*042d53a7SEvalZero prn_e = ble_ll_conn_csa2_prng(conn->event_cntr, conn->channel_id);
697*042d53a7SEvalZero
698*042d53a7SEvalZero channel_unmapped = prn_e % 37;
699*042d53a7SEvalZero
700*042d53a7SEvalZero /*
701*042d53a7SEvalZero * If unmapped channel is the channel index of a used channel it is used
702*042d53a7SEvalZero * as channel index.
703*042d53a7SEvalZero */
704*042d53a7SEvalZero bitpos = 1 << (channel_unmapped & 0x07);
705*042d53a7SEvalZero if (conn->chanmap[channel_unmapped >> 3] & bitpos) {
706*042d53a7SEvalZero return channel_unmapped;
707*042d53a7SEvalZero }
708*042d53a7SEvalZero
709*042d53a7SEvalZero remap_index = (conn->num_used_chans * prn_e) / 0x10000;
710*042d53a7SEvalZero
711*042d53a7SEvalZero return ble_ll_conn_remapped_channel(remap_index, conn->chanmap);
712*042d53a7SEvalZero }
713*042d53a7SEvalZero #endif
714*042d53a7SEvalZero
715*042d53a7SEvalZero static uint8_t
ble_ll_conn_calc_dci_csa1(struct ble_ll_conn_sm * conn)716*042d53a7SEvalZero ble_ll_conn_calc_dci_csa1(struct ble_ll_conn_sm *conn)
717*042d53a7SEvalZero {
718*042d53a7SEvalZero uint8_t curchan;
719*042d53a7SEvalZero uint8_t remap_index;
720*042d53a7SEvalZero uint8_t bitpos;
721*042d53a7SEvalZero
722*042d53a7SEvalZero /* Get next unmapped channel */
723*042d53a7SEvalZero curchan = conn->last_unmapped_chan + conn->hop_inc;
724*042d53a7SEvalZero if (curchan > BLE_PHY_NUM_DATA_CHANS) {
725*042d53a7SEvalZero curchan -= BLE_PHY_NUM_DATA_CHANS;
726*042d53a7SEvalZero }
727*042d53a7SEvalZero
728*042d53a7SEvalZero /* Save unmapped channel */
729*042d53a7SEvalZero conn->last_unmapped_chan = curchan;
730*042d53a7SEvalZero
731*042d53a7SEvalZero /* Is this a valid channel? */
732*042d53a7SEvalZero bitpos = 1 << (curchan & 0x07);
733*042d53a7SEvalZero if (conn->chanmap[curchan >> 3] & bitpos) {
734*042d53a7SEvalZero return curchan;
735*042d53a7SEvalZero }
736*042d53a7SEvalZero
737*042d53a7SEvalZero /* Calculate remap index */
738*042d53a7SEvalZero remap_index = curchan % conn->num_used_chans;
739*042d53a7SEvalZero
740*042d53a7SEvalZero return ble_ll_conn_remapped_channel(remap_index, conn->chanmap);
741*042d53a7SEvalZero }
742*042d53a7SEvalZero
743*042d53a7SEvalZero /**
744*042d53a7SEvalZero * Determine data channel index to be used for the upcoming/current
745*042d53a7SEvalZero * connection event
746*042d53a7SEvalZero *
747*042d53a7SEvalZero * @param conn
748*042d53a7SEvalZero * @param latency Used only for CSA #1
749*042d53a7SEvalZero *
750*042d53a7SEvalZero * @return uint8_t
751*042d53a7SEvalZero */
752*042d53a7SEvalZero uint8_t
ble_ll_conn_calc_dci(struct ble_ll_conn_sm * conn,uint16_t latency)753*042d53a7SEvalZero ble_ll_conn_calc_dci(struct ble_ll_conn_sm *conn, uint16_t latency)
754*042d53a7SEvalZero {
755*042d53a7SEvalZero uint8_t index;
756*042d53a7SEvalZero
757*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) == 1)
758*042d53a7SEvalZero if (CONN_F_CSA2_SUPP(conn)) {
759*042d53a7SEvalZero return ble_ll_conn_calc_dci_csa2(conn);
760*042d53a7SEvalZero }
761*042d53a7SEvalZero #endif
762*042d53a7SEvalZero
763*042d53a7SEvalZero index = conn->data_chan_index;
764*042d53a7SEvalZero
765*042d53a7SEvalZero while (latency > 0) {
766*042d53a7SEvalZero index = ble_ll_conn_calc_dci_csa1(conn);
767*042d53a7SEvalZero latency--;
768*042d53a7SEvalZero }
769*042d53a7SEvalZero
770*042d53a7SEvalZero return index;
771*042d53a7SEvalZero }
772*042d53a7SEvalZero
773*042d53a7SEvalZero /**
774*042d53a7SEvalZero * Called when we are in the connection state and the wait for response timer
775*042d53a7SEvalZero * fires off.
776*042d53a7SEvalZero *
777*042d53a7SEvalZero * Context: Interrupt
778*042d53a7SEvalZero */
779*042d53a7SEvalZero void
ble_ll_conn_wfr_timer_exp(void)780*042d53a7SEvalZero ble_ll_conn_wfr_timer_exp(void)
781*042d53a7SEvalZero {
782*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
783*042d53a7SEvalZero
784*042d53a7SEvalZero connsm = g_ble_ll_conn_cur_sm;
785*042d53a7SEvalZero ble_ll_conn_current_sm_over(connsm);
786*042d53a7SEvalZero STATS_INC(ble_ll_conn_stats, wfr_expirations);
787*042d53a7SEvalZero }
788*042d53a7SEvalZero
789*042d53a7SEvalZero void
ble_ll_conn_reset_pending_aux_conn_rsp(void)790*042d53a7SEvalZero ble_ll_conn_reset_pending_aux_conn_rsp(void)
791*042d53a7SEvalZero {
792*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
793*042d53a7SEvalZero return;
794*042d53a7SEvalZero #endif
795*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
796*042d53a7SEvalZero
797*042d53a7SEvalZero connsm = g_ble_ll_conn_create_sm;
798*042d53a7SEvalZero if (!connsm) {
799*042d53a7SEvalZero return;
800*042d53a7SEvalZero }
801*042d53a7SEvalZero
802*042d53a7SEvalZero if (CONN_F_AUX_CONN_REQ(connsm)) {
803*042d53a7SEvalZero STATS_INC(ble_ll_stats, aux_conn_rsp_err);
804*042d53a7SEvalZero CONN_F_CONN_REQ_TXD(connsm) = 0;
805*042d53a7SEvalZero CONN_F_AUX_CONN_REQ(connsm) = 0;
806*042d53a7SEvalZero ble_ll_sched_rmv_elem(&connsm->conn_sch);
807*042d53a7SEvalZero return;
808*042d53a7SEvalZero }
809*042d53a7SEvalZero
810*042d53a7SEvalZero return;
811*042d53a7SEvalZero }
812*042d53a7SEvalZero
813*042d53a7SEvalZero bool
ble_ll_conn_init_pending_aux_conn_rsp(void)814*042d53a7SEvalZero ble_ll_conn_init_pending_aux_conn_rsp(void)
815*042d53a7SEvalZero {
816*042d53a7SEvalZero #if !MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
817*042d53a7SEvalZero return false;
818*042d53a7SEvalZero #endif
819*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
820*042d53a7SEvalZero
821*042d53a7SEvalZero connsm = g_ble_ll_conn_create_sm;
822*042d53a7SEvalZero if (!connsm) {
823*042d53a7SEvalZero return false;
824*042d53a7SEvalZero }
825*042d53a7SEvalZero
826*042d53a7SEvalZero return CONN_F_AUX_CONN_REQ(connsm);
827*042d53a7SEvalZero }
828*042d53a7SEvalZero
829*042d53a7SEvalZero void
ble_ll_conn_init_wfr_timer_exp(void)830*042d53a7SEvalZero ble_ll_conn_init_wfr_timer_exp(void)
831*042d53a7SEvalZero {
832*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
833*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
834*042d53a7SEvalZero struct ble_ll_scan_sm *scansm;
835*042d53a7SEvalZero
836*042d53a7SEvalZero connsm = g_ble_ll_conn_create_sm;
837*042d53a7SEvalZero if (!connsm) {
838*042d53a7SEvalZero return;
839*042d53a7SEvalZero }
840*042d53a7SEvalZero
841*042d53a7SEvalZero ble_ll_conn_reset_pending_aux_conn_rsp();
842*042d53a7SEvalZero
843*042d53a7SEvalZero scansm = connsm->scansm;
844*042d53a7SEvalZero if (scansm && scansm->cur_aux_data) {
845*042d53a7SEvalZero if (ble_ll_scan_aux_data_unref(scansm->cur_aux_data)) {
846*042d53a7SEvalZero ble_ll_scan_aux_data_unref(scansm->cur_aux_data);
847*042d53a7SEvalZero }
848*042d53a7SEvalZero scansm->cur_aux_data = NULL;
849*042d53a7SEvalZero STATS_INC(ble_ll_stats, aux_missed_adv);
850*042d53a7SEvalZero ble_ll_event_send(&scansm->scan_sched_ev);
851*042d53a7SEvalZero }
852*042d53a7SEvalZero
853*042d53a7SEvalZero connsm->inita_identity_used = 0;
854*042d53a7SEvalZero #endif
855*042d53a7SEvalZero }
856*042d53a7SEvalZero /**
857*042d53a7SEvalZero * Callback for slave when it transmits a data pdu and the connection event
858*042d53a7SEvalZero * ends after the transmission.
859*042d53a7SEvalZero *
860*042d53a7SEvalZero * Context: Interrupt
861*042d53a7SEvalZero *
862*042d53a7SEvalZero * @param sch
863*042d53a7SEvalZero *
864*042d53a7SEvalZero */
865*042d53a7SEvalZero static void
ble_ll_conn_wait_txend(void * arg)866*042d53a7SEvalZero ble_ll_conn_wait_txend(void *arg)
867*042d53a7SEvalZero {
868*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
869*042d53a7SEvalZero
870*042d53a7SEvalZero connsm = (struct ble_ll_conn_sm *)arg;
871*042d53a7SEvalZero ble_ll_conn_current_sm_over(connsm);
872*042d53a7SEvalZero }
873*042d53a7SEvalZero
874*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
875*042d53a7SEvalZero static void
ble_ll_conn_start_rx_encrypt(void * arg)876*042d53a7SEvalZero ble_ll_conn_start_rx_encrypt(void *arg)
877*042d53a7SEvalZero {
878*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
879*042d53a7SEvalZero
880*042d53a7SEvalZero connsm = (struct ble_ll_conn_sm *)arg;
881*042d53a7SEvalZero CONN_F_ENCRYPTED(connsm) = 1;
882*042d53a7SEvalZero ble_phy_encrypt_enable(connsm->enc_data.rx_pkt_cntr,
883*042d53a7SEvalZero connsm->enc_data.iv,
884*042d53a7SEvalZero connsm->enc_data.enc_block.cipher_text,
885*042d53a7SEvalZero !CONN_IS_MASTER(connsm));
886*042d53a7SEvalZero }
887*042d53a7SEvalZero
888*042d53a7SEvalZero static void
ble_ll_conn_start_rx_unencrypt(void * arg)889*042d53a7SEvalZero ble_ll_conn_start_rx_unencrypt(void *arg)
890*042d53a7SEvalZero {
891*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
892*042d53a7SEvalZero
893*042d53a7SEvalZero connsm = (struct ble_ll_conn_sm *)arg;
894*042d53a7SEvalZero CONN_F_ENCRYPTED(connsm) = 0;
895*042d53a7SEvalZero ble_phy_encrypt_disable();
896*042d53a7SEvalZero }
897*042d53a7SEvalZero
898*042d53a7SEvalZero static void
ble_ll_conn_txend_encrypt(void * arg)899*042d53a7SEvalZero ble_ll_conn_txend_encrypt(void *arg)
900*042d53a7SEvalZero {
901*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
902*042d53a7SEvalZero
903*042d53a7SEvalZero connsm = (struct ble_ll_conn_sm *)arg;
904*042d53a7SEvalZero CONN_F_ENCRYPTED(connsm) = 1;
905*042d53a7SEvalZero ble_ll_conn_current_sm_over(connsm);
906*042d53a7SEvalZero }
907*042d53a7SEvalZero
908*042d53a7SEvalZero static void
ble_ll_conn_rxend_unencrypt(void * arg)909*042d53a7SEvalZero ble_ll_conn_rxend_unencrypt(void *arg)
910*042d53a7SEvalZero {
911*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
912*042d53a7SEvalZero
913*042d53a7SEvalZero connsm = (struct ble_ll_conn_sm *)arg;
914*042d53a7SEvalZero CONN_F_ENCRYPTED(connsm) = 0;
915*042d53a7SEvalZero ble_ll_conn_current_sm_over(connsm);
916*042d53a7SEvalZero }
917*042d53a7SEvalZero
918*042d53a7SEvalZero static void
ble_ll_conn_continue_rx_encrypt(void * arg)919*042d53a7SEvalZero ble_ll_conn_continue_rx_encrypt(void *arg)
920*042d53a7SEvalZero {
921*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
922*042d53a7SEvalZero
923*042d53a7SEvalZero connsm = (struct ble_ll_conn_sm *)arg;
924*042d53a7SEvalZero ble_phy_encrypt_set_pkt_cntr(connsm->enc_data.rx_pkt_cntr,
925*042d53a7SEvalZero !CONN_IS_MASTER(connsm));
926*042d53a7SEvalZero }
927*042d53a7SEvalZero #endif
928*042d53a7SEvalZero
929*042d53a7SEvalZero /**
930*042d53a7SEvalZero * Returns the cputime of the next scheduled item on the scheduler list or
931*042d53a7SEvalZero * when the current connection will start its next interval (whichever is
932*042d53a7SEvalZero * earlier). This API is called when determining at what time we should end
933*042d53a7SEvalZero * the current connection event. The current connection event must end before
934*042d53a7SEvalZero * the next scheduled item. However, the current connection itself is not
935*042d53a7SEvalZero * in the scheduler list! Thus, we need to calculate the time at which the
936*042d53a7SEvalZero * next connection will start (the schedule start time; not the anchor point)
937*042d53a7SEvalZero * and not overrun it.
938*042d53a7SEvalZero *
939*042d53a7SEvalZero * Context: Interrupt
940*042d53a7SEvalZero *
941*042d53a7SEvalZero * @param connsm
942*042d53a7SEvalZero *
943*042d53a7SEvalZero * @return uint32_t
944*042d53a7SEvalZero */
945*042d53a7SEvalZero static uint32_t
ble_ll_conn_get_next_sched_time(struct ble_ll_conn_sm * connsm)946*042d53a7SEvalZero ble_ll_conn_get_next_sched_time(struct ble_ll_conn_sm *connsm)
947*042d53a7SEvalZero {
948*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING)
949*042d53a7SEvalZero uint32_t ce_end;
950*042d53a7SEvalZero ce_end = connsm->ce_end_time;
951*042d53a7SEvalZero #else
952*042d53a7SEvalZero uint32_t ce_end;
953*042d53a7SEvalZero uint32_t next_sched_time;
954*042d53a7SEvalZero
955*042d53a7SEvalZero /* Calculate time at which next connection event will start */
956*042d53a7SEvalZero /* NOTE: We dont care if this time is tick short. */
957*042d53a7SEvalZero ce_end = connsm->anchor_point + connsm->conn_itvl_ticks -
958*042d53a7SEvalZero g_ble_ll_sched_offset_ticks;
959*042d53a7SEvalZero if ((connsm->anchor_point_usecs + connsm->conn_itvl_usecs) >= 31) {
960*042d53a7SEvalZero ++ce_end;
961*042d53a7SEvalZero }
962*042d53a7SEvalZero
963*042d53a7SEvalZero if (ble_ll_sched_next_time(&next_sched_time)) {
964*042d53a7SEvalZero if (CPUTIME_LT(next_sched_time, ce_end)) {
965*042d53a7SEvalZero ce_end = next_sched_time;
966*042d53a7SEvalZero }
967*042d53a7SEvalZero }
968*042d53a7SEvalZero #endif
969*042d53a7SEvalZero
970*042d53a7SEvalZero return ce_end;
971*042d53a7SEvalZero }
972*042d53a7SEvalZero
973*042d53a7SEvalZero /**
974*042d53a7SEvalZero * Called to check if certain connection state machine flags have been
975*042d53a7SEvalZero * set.
976*042d53a7SEvalZero *
977*042d53a7SEvalZero * @param connsm
978*042d53a7SEvalZero */
979*042d53a7SEvalZero static void
ble_ll_conn_chk_csm_flags(struct ble_ll_conn_sm * connsm)980*042d53a7SEvalZero ble_ll_conn_chk_csm_flags(struct ble_ll_conn_sm *connsm)
981*042d53a7SEvalZero {
982*042d53a7SEvalZero uint8_t update_status;
983*042d53a7SEvalZero
984*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
985*042d53a7SEvalZero if (connsm->csmflags.cfbit.send_ltk_req) {
986*042d53a7SEvalZero /*
987*042d53a7SEvalZero * Send Long term key request event to host. If masked, we need to
988*042d53a7SEvalZero * send a REJECT_IND.
989*042d53a7SEvalZero */
990*042d53a7SEvalZero if (ble_ll_hci_ev_ltk_req(connsm)) {
991*042d53a7SEvalZero ble_ll_ctrl_reject_ind_send(connsm, BLE_LL_CTRL_ENC_REQ,
992*042d53a7SEvalZero BLE_ERR_PINKEY_MISSING);
993*042d53a7SEvalZero }
994*042d53a7SEvalZero connsm->csmflags.cfbit.send_ltk_req = 0;
995*042d53a7SEvalZero }
996*042d53a7SEvalZero #endif
997*042d53a7SEvalZero
998*042d53a7SEvalZero /*
999*042d53a7SEvalZero * There are two cases where this flag gets set:
1000*042d53a7SEvalZero * 1) A connection update procedure was started and the event counter
1001*042d53a7SEvalZero * has passed the instant.
1002*042d53a7SEvalZero * 2) We successfully sent the reject reason.
1003*042d53a7SEvalZero */
1004*042d53a7SEvalZero if (connsm->csmflags.cfbit.host_expects_upd_event) {
1005*042d53a7SEvalZero update_status = BLE_ERR_SUCCESS;
1006*042d53a7SEvalZero if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_UPDATE)) {
1007*042d53a7SEvalZero ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CONN_UPDATE);
1008*042d53a7SEvalZero } else {
1009*042d53a7SEvalZero if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ)) {
1010*042d53a7SEvalZero ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ);
1011*042d53a7SEvalZero update_status = connsm->reject_reason;
1012*042d53a7SEvalZero }
1013*042d53a7SEvalZero }
1014*042d53a7SEvalZero ble_ll_hci_ev_conn_update(connsm, update_status);
1015*042d53a7SEvalZero connsm->csmflags.cfbit.host_expects_upd_event = 0;
1016*042d53a7SEvalZero }
1017*042d53a7SEvalZero
1018*042d53a7SEvalZero /* Check if we need to send PHY update complete event */
1019*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
1020*042d53a7SEvalZero if (CONN_F_PHY_UPDATE_EVENT(connsm)) {
1021*042d53a7SEvalZero if (!ble_ll_hci_ev_phy_update(connsm, BLE_ERR_SUCCESS)) {
1022*042d53a7SEvalZero /* Sent event. Clear flag */
1023*042d53a7SEvalZero CONN_F_PHY_UPDATE_EVENT(connsm) = 0;
1024*042d53a7SEvalZero }
1025*042d53a7SEvalZero }
1026*042d53a7SEvalZero #endif
1027*042d53a7SEvalZero }
1028*042d53a7SEvalZero
1029*042d53a7SEvalZero /**
1030*042d53a7SEvalZero * Called when we want to send a data channel pdu inside a connection event.
1031*042d53a7SEvalZero *
1032*042d53a7SEvalZero * Context: interrupt
1033*042d53a7SEvalZero *
1034*042d53a7SEvalZero * @param connsm
1035*042d53a7SEvalZero *
1036*042d53a7SEvalZero * @return int 0: success; otherwise failure to transmit
1037*042d53a7SEvalZero */
1038*042d53a7SEvalZero static uint16_t
ble_ll_conn_adjust_pyld_len(struct ble_ll_conn_sm * connsm,uint16_t pyld_len)1039*042d53a7SEvalZero ble_ll_conn_adjust_pyld_len(struct ble_ll_conn_sm *connsm, uint16_t pyld_len)
1040*042d53a7SEvalZero {
1041*042d53a7SEvalZero uint16_t phy_max_tx_octets;
1042*042d53a7SEvalZero uint16_t ret;
1043*042d53a7SEvalZero
1044*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
1045*042d53a7SEvalZero uint8_t phy_mode;
1046*042d53a7SEvalZero
1047*042d53a7SEvalZero if (connsm->phy_tx_transition != BLE_PHY_TRANSITION_INVALID) {
1048*042d53a7SEvalZero phy_mode = ble_ll_phy_to_phy_mode(connsm->phy_tx_transition,
1049*042d53a7SEvalZero connsm->phy_data.phy_options);
1050*042d53a7SEvalZero } else {
1051*042d53a7SEvalZero phy_mode = connsm->phy_data.tx_phy_mode;
1052*042d53a7SEvalZero }
1053*042d53a7SEvalZero
1054*042d53a7SEvalZero phy_max_tx_octets = ble_ll_pdu_max_tx_octets_get(connsm->eff_max_tx_time,
1055*042d53a7SEvalZero phy_mode);
1056*042d53a7SEvalZero
1057*042d53a7SEvalZero #else
1058*042d53a7SEvalZero phy_max_tx_octets = ble_ll_pdu_max_tx_octets_get(connsm->eff_max_tx_time,
1059*042d53a7SEvalZero BLE_PHY_MODE_1M);
1060*042d53a7SEvalZero #endif
1061*042d53a7SEvalZero
1062*042d53a7SEvalZero ret = pyld_len;
1063*042d53a7SEvalZero
1064*042d53a7SEvalZero if (ret > connsm->eff_max_tx_octets) {
1065*042d53a7SEvalZero ret = connsm->eff_max_tx_octets;
1066*042d53a7SEvalZero }
1067*042d53a7SEvalZero
1068*042d53a7SEvalZero if (ret > phy_max_tx_octets) {
1069*042d53a7SEvalZero ret = phy_max_tx_octets;
1070*042d53a7SEvalZero }
1071*042d53a7SEvalZero
1072*042d53a7SEvalZero return ret;
1073*042d53a7SEvalZero }
1074*042d53a7SEvalZero
1075*042d53a7SEvalZero static int
ble_ll_conn_tx_data_pdu(struct ble_ll_conn_sm * connsm)1076*042d53a7SEvalZero ble_ll_conn_tx_data_pdu(struct ble_ll_conn_sm *connsm)
1077*042d53a7SEvalZero {
1078*042d53a7SEvalZero int rc;
1079*042d53a7SEvalZero uint8_t md;
1080*042d53a7SEvalZero uint8_t hdr_byte;
1081*042d53a7SEvalZero uint8_t end_transition;
1082*042d53a7SEvalZero uint8_t cur_txlen;
1083*042d53a7SEvalZero uint8_t next_txlen;
1084*042d53a7SEvalZero uint8_t cur_offset;
1085*042d53a7SEvalZero uint16_t pktlen;
1086*042d53a7SEvalZero uint32_t next_event_time;
1087*042d53a7SEvalZero uint32_t ticks;
1088*042d53a7SEvalZero struct os_mbuf *m;
1089*042d53a7SEvalZero struct ble_mbuf_hdr *ble_hdr;
1090*042d53a7SEvalZero struct os_mbuf_pkthdr *pkthdr;
1091*042d53a7SEvalZero struct os_mbuf_pkthdr *nextpkthdr;
1092*042d53a7SEvalZero struct ble_ll_empty_pdu empty_pdu;
1093*042d53a7SEvalZero ble_phy_tx_end_func txend_func;
1094*042d53a7SEvalZero int tx_phy_mode;
1095*042d53a7SEvalZero
1096*042d53a7SEvalZero /* For compiler warnings... */
1097*042d53a7SEvalZero ble_hdr = NULL;
1098*042d53a7SEvalZero m = NULL;
1099*042d53a7SEvalZero md = 0;
1100*042d53a7SEvalZero hdr_byte = BLE_LL_LLID_DATA_FRAG;
1101*042d53a7SEvalZero
1102*042d53a7SEvalZero /*
1103*042d53a7SEvalZero * We need to check if we are retrying a pdu or if there is a pdu on
1104*042d53a7SEvalZero * the transmit queue.
1105*042d53a7SEvalZero */
1106*042d53a7SEvalZero pkthdr = STAILQ_FIRST(&connsm->conn_txq);
1107*042d53a7SEvalZero if (!connsm->cur_tx_pdu && !CONN_F_EMPTY_PDU_TXD(connsm) && !pkthdr) {
1108*042d53a7SEvalZero CONN_F_EMPTY_PDU_TXD(connsm) = 1;
1109*042d53a7SEvalZero goto conn_tx_pdu;
1110*042d53a7SEvalZero }
1111*042d53a7SEvalZero
1112*042d53a7SEvalZero /*
1113*042d53a7SEvalZero * If we dont have a pdu we have previously transmitted, take it off
1114*042d53a7SEvalZero * the connection transmit queue
1115*042d53a7SEvalZero */
1116*042d53a7SEvalZero cur_offset = 0;
1117*042d53a7SEvalZero if (!connsm->cur_tx_pdu && !CONN_F_EMPTY_PDU_TXD(connsm)) {
1118*042d53a7SEvalZero /* Convert packet header to mbuf */
1119*042d53a7SEvalZero m = OS_MBUF_PKTHDR_TO_MBUF(pkthdr);
1120*042d53a7SEvalZero nextpkthdr = STAILQ_NEXT(pkthdr, omp_next);
1121*042d53a7SEvalZero
1122*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
1123*042d53a7SEvalZero /*
1124*042d53a7SEvalZero * If we are encrypting, we are only allowed to send certain
1125*042d53a7SEvalZero * kinds of LL control PDU's. If none is enqueued, send empty pdu!
1126*042d53a7SEvalZero */
1127*042d53a7SEvalZero if (connsm->enc_data.enc_state > CONN_ENC_S_ENCRYPTED) {
1128*042d53a7SEvalZero if (!ble_ll_ctrl_enc_allowed_pdu_tx(pkthdr)) {
1129*042d53a7SEvalZero CONN_F_EMPTY_PDU_TXD(connsm) = 1;
1130*042d53a7SEvalZero goto conn_tx_pdu;
1131*042d53a7SEvalZero }
1132*042d53a7SEvalZero
1133*042d53a7SEvalZero /*
1134*042d53a7SEvalZero * We will allow a next packet if it itself is allowed or we are
1135*042d53a7SEvalZero * a slave and we are sending the START_ENC_RSP. The master has
1136*042d53a7SEvalZero * to wait to receive the START_ENC_RSP from the slave before
1137*042d53a7SEvalZero * packets can be let go.
1138*042d53a7SEvalZero */
1139*042d53a7SEvalZero if (nextpkthdr && !ble_ll_ctrl_enc_allowed_pdu_tx(nextpkthdr)
1140*042d53a7SEvalZero && ((connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) ||
1141*042d53a7SEvalZero !ble_ll_ctrl_is_start_enc_rsp(m))) {
1142*042d53a7SEvalZero nextpkthdr = NULL;
1143*042d53a7SEvalZero }
1144*042d53a7SEvalZero }
1145*042d53a7SEvalZero #endif
1146*042d53a7SEvalZero /* Take packet off queue*/
1147*042d53a7SEvalZero STAILQ_REMOVE_HEAD(&connsm->conn_txq, omp_next);
1148*042d53a7SEvalZero ble_hdr = BLE_MBUF_HDR_PTR(m);
1149*042d53a7SEvalZero
1150*042d53a7SEvalZero /*
1151*042d53a7SEvalZero * We dequeued new packet for transmission so need to calculate payload
1152*042d53a7SEvalZero * length we can send over current PHY. Effectively, this determines
1153*042d53a7SEvalZero * fragmentation of packet into PDUs.
1154*042d53a7SEvalZero */
1155*042d53a7SEvalZero pktlen = pkthdr->omp_len;
1156*042d53a7SEvalZero cur_txlen = ble_ll_conn_adjust_pyld_len(connsm, pktlen);
1157*042d53a7SEvalZero ble_hdr->txinfo.pyld_len = cur_txlen;
1158*042d53a7SEvalZero
1159*042d53a7SEvalZero /* NOTE: header was set when first enqueued */
1160*042d53a7SEvalZero hdr_byte = ble_hdr->txinfo.hdr_byte;
1161*042d53a7SEvalZero connsm->cur_tx_pdu = m;
1162*042d53a7SEvalZero } else {
1163*042d53a7SEvalZero nextpkthdr = pkthdr;
1164*042d53a7SEvalZero if (connsm->cur_tx_pdu) {
1165*042d53a7SEvalZero m = connsm->cur_tx_pdu;
1166*042d53a7SEvalZero ble_hdr = BLE_MBUF_HDR_PTR(m);
1167*042d53a7SEvalZero pktlen = OS_MBUF_PKTLEN(m);
1168*042d53a7SEvalZero cur_txlen = ble_hdr->txinfo.pyld_len;
1169*042d53a7SEvalZero cur_offset = ble_hdr->txinfo.offset;
1170*042d53a7SEvalZero if (cur_offset == 0) {
1171*042d53a7SEvalZero hdr_byte = ble_hdr->txinfo.hdr_byte & BLE_LL_DATA_HDR_LLID_MASK;
1172*042d53a7SEvalZero }
1173*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
1174*042d53a7SEvalZero if (connsm->enc_data.enc_state > CONN_ENC_S_ENCRYPTED) {
1175*042d53a7SEvalZero /* We will allow a next packet if it itself is allowed */
1176*042d53a7SEvalZero pkthdr = OS_MBUF_PKTHDR(connsm->cur_tx_pdu);
1177*042d53a7SEvalZero if (nextpkthdr && !ble_ll_ctrl_enc_allowed_pdu_tx(nextpkthdr)
1178*042d53a7SEvalZero && ((connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) ||
1179*042d53a7SEvalZero !ble_ll_ctrl_is_start_enc_rsp(connsm->cur_tx_pdu))) {
1180*042d53a7SEvalZero nextpkthdr = NULL;
1181*042d53a7SEvalZero }
1182*042d53a7SEvalZero }
1183*042d53a7SEvalZero #endif
1184*042d53a7SEvalZero } else {
1185*042d53a7SEvalZero /* Empty PDU here. NOTE: header byte gets set later */
1186*042d53a7SEvalZero pktlen = 0;
1187*042d53a7SEvalZero cur_txlen = 0;
1188*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
1189*042d53a7SEvalZero if (connsm->enc_data.enc_state > CONN_ENC_S_ENCRYPTED) {
1190*042d53a7SEvalZero /* We will allow a next packet if it itself is allowed */
1191*042d53a7SEvalZero if (nextpkthdr && !ble_ll_ctrl_enc_allowed_pdu_tx(nextpkthdr)) {
1192*042d53a7SEvalZero nextpkthdr = NULL;
1193*042d53a7SEvalZero }
1194*042d53a7SEvalZero }
1195*042d53a7SEvalZero #endif
1196*042d53a7SEvalZero }
1197*042d53a7SEvalZero }
1198*042d53a7SEvalZero
1199*042d53a7SEvalZero /*
1200*042d53a7SEvalZero * Set the more data data flag if we have more data to send and we
1201*042d53a7SEvalZero * have not been asked to terminate
1202*042d53a7SEvalZero */
1203*042d53a7SEvalZero if ((nextpkthdr || ((cur_offset + cur_txlen) < pktlen)) &&
1204*042d53a7SEvalZero !connsm->csmflags.cfbit.terminate_ind_rxd) {
1205*042d53a7SEvalZero /* Get next event time */
1206*042d53a7SEvalZero next_event_time = ble_ll_conn_get_next_sched_time(connsm);
1207*042d53a7SEvalZero
1208*042d53a7SEvalZero /* XXX: TODO: need to check this with phy update procedure. There are
1209*042d53a7SEvalZero limitations if we have started update */
1210*042d53a7SEvalZero
1211*042d53a7SEvalZero /*
1212*042d53a7SEvalZero * Dont bother to set the MD bit if we cannot do the following:
1213*042d53a7SEvalZero * -> wait IFS, send the current frame.
1214*042d53a7SEvalZero * -> wait IFS, receive a maximum size frame.
1215*042d53a7SEvalZero * -> wait IFS, send the next frame.
1216*042d53a7SEvalZero * -> wait IFS, receive a maximum size frame.
1217*042d53a7SEvalZero *
1218*042d53a7SEvalZero * For slave:
1219*042d53a7SEvalZero * -> wait IFS, send current frame.
1220*042d53a7SEvalZero * -> wait IFS, receive maximum size frame.
1221*042d53a7SEvalZero * -> wait IFS, send next frame.
1222*042d53a7SEvalZero */
1223*042d53a7SEvalZero if ((cur_offset + cur_txlen) < pktlen) {
1224*042d53a7SEvalZero next_txlen = pktlen - (cur_offset + cur_txlen);
1225*042d53a7SEvalZero } else {
1226*042d53a7SEvalZero if (nextpkthdr->omp_len > connsm->eff_max_tx_octets) {
1227*042d53a7SEvalZero next_txlen = connsm->eff_max_tx_octets;
1228*042d53a7SEvalZero } else {
1229*042d53a7SEvalZero next_txlen = nextpkthdr->omp_len;
1230*042d53a7SEvalZero }
1231*042d53a7SEvalZero }
1232*042d53a7SEvalZero
1233*042d53a7SEvalZero /*
1234*042d53a7SEvalZero * XXX: this calculation is based on using the current time
1235*042d53a7SEvalZero * and assuming the transmission will occur an IFS time from
1236*042d53a7SEvalZero * now. This is not the most accurate especially if we have
1237*042d53a7SEvalZero * received a frame and we are replying to it.
1238*042d53a7SEvalZero */
1239*042d53a7SEvalZero #if BLE_LL_BT5_PHY_SUPPORTED
1240*042d53a7SEvalZero tx_phy_mode = connsm->phy_data.tx_phy_mode;
1241*042d53a7SEvalZero #else
1242*042d53a7SEvalZero tx_phy_mode = BLE_PHY_MODE_1M;
1243*042d53a7SEvalZero #endif
1244*042d53a7SEvalZero
1245*042d53a7SEvalZero ticks = (BLE_LL_IFS * 3) + connsm->eff_max_rx_time +
1246*042d53a7SEvalZero ble_ll_pdu_tx_time_get(next_txlen, tx_phy_mode) +
1247*042d53a7SEvalZero ble_ll_pdu_tx_time_get(cur_txlen, tx_phy_mode);
1248*042d53a7SEvalZero
1249*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
1250*042d53a7SEvalZero ticks += (BLE_LL_IFS + connsm->eff_max_rx_time);
1251*042d53a7SEvalZero }
1252*042d53a7SEvalZero
1253*042d53a7SEvalZero ticks = os_cputime_usecs_to_ticks(ticks);
1254*042d53a7SEvalZero if ((int32_t)((os_cputime_get32() + ticks) - next_event_time) < 0) {
1255*042d53a7SEvalZero md = 1;
1256*042d53a7SEvalZero }
1257*042d53a7SEvalZero }
1258*042d53a7SEvalZero
1259*042d53a7SEvalZero /* If we send an empty PDU we need to initialize the header */
1260*042d53a7SEvalZero conn_tx_pdu:
1261*042d53a7SEvalZero if (CONN_F_EMPTY_PDU_TXD(connsm)) {
1262*042d53a7SEvalZero /*
1263*042d53a7SEvalZero * This looks strange, but we dont use the data pointer in the mbuf
1264*042d53a7SEvalZero * when we have an empty pdu.
1265*042d53a7SEvalZero */
1266*042d53a7SEvalZero m = (struct os_mbuf *)&empty_pdu;
1267*042d53a7SEvalZero m->om_data = (uint8_t *)&empty_pdu;
1268*042d53a7SEvalZero m->om_data += BLE_MBUF_MEMBLOCK_OVERHEAD;
1269*042d53a7SEvalZero ble_hdr = &empty_pdu.ble_hdr;
1270*042d53a7SEvalZero ble_hdr->txinfo.flags = 0;
1271*042d53a7SEvalZero ble_hdr->txinfo.offset = 0;
1272*042d53a7SEvalZero ble_hdr->txinfo.pyld_len = 0;
1273*042d53a7SEvalZero }
1274*042d53a7SEvalZero
1275*042d53a7SEvalZero /* Set tx seqnum */
1276*042d53a7SEvalZero if (connsm->tx_seqnum) {
1277*042d53a7SEvalZero hdr_byte |= BLE_LL_DATA_HDR_SN_MASK;
1278*042d53a7SEvalZero }
1279*042d53a7SEvalZero
1280*042d53a7SEvalZero /* If we have more data, set the bit */
1281*042d53a7SEvalZero if (md) {
1282*042d53a7SEvalZero hdr_byte |= BLE_LL_DATA_HDR_MD_MASK;
1283*042d53a7SEvalZero }
1284*042d53a7SEvalZero
1285*042d53a7SEvalZero /* Set NESN (next expected sequence number) bit */
1286*042d53a7SEvalZero if (connsm->next_exp_seqnum) {
1287*042d53a7SEvalZero hdr_byte |= BLE_LL_DATA_HDR_NESN_MASK;
1288*042d53a7SEvalZero }
1289*042d53a7SEvalZero
1290*042d53a7SEvalZero /* Set the header byte in the outgoing frame */
1291*042d53a7SEvalZero ble_hdr->txinfo.hdr_byte = hdr_byte;
1292*042d53a7SEvalZero
1293*042d53a7SEvalZero /*
1294*042d53a7SEvalZero * If we are a slave, check to see if this transmission will end the
1295*042d53a7SEvalZero * connection event. We will end the connection event if we have
1296*042d53a7SEvalZero * received a valid frame with the more data bit set to 0 and we dont
1297*042d53a7SEvalZero * have more data.
1298*042d53a7SEvalZero *
1299*042d53a7SEvalZero * XXX: for a slave, we dont check to see if we can:
1300*042d53a7SEvalZero * -> wait IFS, rx frame from master (either big or small).
1301*042d53a7SEvalZero * -> wait IFS, send empty pdu or next pdu.
1302*042d53a7SEvalZero *
1303*042d53a7SEvalZero * We could do this. Now, we just keep going and hope that we dont
1304*042d53a7SEvalZero * overrun next scheduled item.
1305*042d53a7SEvalZero */
1306*042d53a7SEvalZero if ((connsm->csmflags.cfbit.terminate_ind_rxd) ||
1307*042d53a7SEvalZero ((connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) && (md == 0) &&
1308*042d53a7SEvalZero (connsm->cons_rxd_bad_crc == 0) &&
1309*042d53a7SEvalZero ((connsm->last_rxd_hdr_byte & BLE_LL_DATA_HDR_MD_MASK) == 0) &&
1310*042d53a7SEvalZero !ble_ll_ctrl_is_terminate_ind(hdr_byte, m->om_data[0]))) {
1311*042d53a7SEvalZero /* We will end the connection event */
1312*042d53a7SEvalZero end_transition = BLE_PHY_TRANSITION_NONE;
1313*042d53a7SEvalZero txend_func = ble_ll_conn_wait_txend;
1314*042d53a7SEvalZero } else {
1315*042d53a7SEvalZero /* Wait for a response here */
1316*042d53a7SEvalZero end_transition = BLE_PHY_TRANSITION_TX_RX;
1317*042d53a7SEvalZero txend_func = NULL;
1318*042d53a7SEvalZero }
1319*042d53a7SEvalZero
1320*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
1321*042d53a7SEvalZero int is_ctrl;
1322*042d53a7SEvalZero uint8_t llid;
1323*042d53a7SEvalZero uint8_t opcode;
1324*042d53a7SEvalZero
1325*042d53a7SEvalZero llid = ble_hdr->txinfo.hdr_byte & BLE_LL_DATA_HDR_LLID_MASK;
1326*042d53a7SEvalZero if (llid == BLE_LL_LLID_CTRL) {
1327*042d53a7SEvalZero is_ctrl = 1;
1328*042d53a7SEvalZero opcode = m->om_data[0];
1329*042d53a7SEvalZero } else {
1330*042d53a7SEvalZero is_ctrl = 0;
1331*042d53a7SEvalZero opcode = 0;
1332*042d53a7SEvalZero }
1333*042d53a7SEvalZero
1334*042d53a7SEvalZero if (is_ctrl && (opcode == BLE_LL_CTRL_START_ENC_RSP)) {
1335*042d53a7SEvalZero /*
1336*042d53a7SEvalZero * Both master and slave send the START_ENC_RSP encrypted and receive
1337*042d53a7SEvalZero * encrypted
1338*042d53a7SEvalZero */
1339*042d53a7SEvalZero CONN_F_ENCRYPTED(connsm) = 1;
1340*042d53a7SEvalZero connsm->enc_data.tx_encrypted = 1;
1341*042d53a7SEvalZero ble_phy_encrypt_enable(connsm->enc_data.tx_pkt_cntr,
1342*042d53a7SEvalZero connsm->enc_data.iv,
1343*042d53a7SEvalZero connsm->enc_data.enc_block.cipher_text,
1344*042d53a7SEvalZero CONN_IS_MASTER(connsm));
1345*042d53a7SEvalZero } else if (is_ctrl && (opcode == BLE_LL_CTRL_START_ENC_REQ)) {
1346*042d53a7SEvalZero /*
1347*042d53a7SEvalZero * Only the slave sends this and it gets sent unencrypted but
1348*042d53a7SEvalZero * we receive encrypted
1349*042d53a7SEvalZero */
1350*042d53a7SEvalZero CONN_F_ENCRYPTED(connsm) = 0;
1351*042d53a7SEvalZero connsm->enc_data.enc_state = CONN_ENC_S_START_ENC_RSP_WAIT;
1352*042d53a7SEvalZero connsm->enc_data.tx_encrypted = 0;
1353*042d53a7SEvalZero ble_phy_encrypt_disable();
1354*042d53a7SEvalZero if (txend_func == NULL) {
1355*042d53a7SEvalZero txend_func = ble_ll_conn_start_rx_encrypt;
1356*042d53a7SEvalZero } else {
1357*042d53a7SEvalZero txend_func = ble_ll_conn_txend_encrypt;
1358*042d53a7SEvalZero }
1359*042d53a7SEvalZero } else if (is_ctrl && (opcode == BLE_LL_CTRL_PAUSE_ENC_RSP)) {
1360*042d53a7SEvalZero /*
1361*042d53a7SEvalZero * The slave sends the PAUSE_ENC_RSP encrypted. The master sends
1362*042d53a7SEvalZero * it unencrypted (note that link was already set unencrypted).
1363*042d53a7SEvalZero */
1364*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
1365*042d53a7SEvalZero CONN_F_ENCRYPTED(connsm) = 1;
1366*042d53a7SEvalZero connsm->enc_data.tx_encrypted = 1;
1367*042d53a7SEvalZero ble_phy_encrypt_enable(connsm->enc_data.tx_pkt_cntr,
1368*042d53a7SEvalZero connsm->enc_data.iv,
1369*042d53a7SEvalZero connsm->enc_data.enc_block.cipher_text,
1370*042d53a7SEvalZero CONN_IS_MASTER(connsm));
1371*042d53a7SEvalZero if (txend_func == NULL) {
1372*042d53a7SEvalZero txend_func = ble_ll_conn_start_rx_unencrypt;
1373*042d53a7SEvalZero } else {
1374*042d53a7SEvalZero txend_func = ble_ll_conn_rxend_unencrypt;
1375*042d53a7SEvalZero }
1376*042d53a7SEvalZero } else {
1377*042d53a7SEvalZero CONN_F_ENCRYPTED(connsm) = 0;
1378*042d53a7SEvalZero connsm->enc_data.enc_state = CONN_ENC_S_PAUSED;
1379*042d53a7SEvalZero connsm->enc_data.tx_encrypted = 0;
1380*042d53a7SEvalZero ble_phy_encrypt_disable();
1381*042d53a7SEvalZero }
1382*042d53a7SEvalZero } else {
1383*042d53a7SEvalZero /* If encrypted set packet counter */
1384*042d53a7SEvalZero if (CONN_F_ENCRYPTED(connsm)) {
1385*042d53a7SEvalZero connsm->enc_data.tx_encrypted = 1;
1386*042d53a7SEvalZero ble_phy_encrypt_set_pkt_cntr(connsm->enc_data.tx_pkt_cntr,
1387*042d53a7SEvalZero CONN_IS_MASTER(connsm));
1388*042d53a7SEvalZero if (txend_func == NULL) {
1389*042d53a7SEvalZero txend_func = ble_ll_conn_continue_rx_encrypt;
1390*042d53a7SEvalZero }
1391*042d53a7SEvalZero }
1392*042d53a7SEvalZero }
1393*042d53a7SEvalZero #endif
1394*042d53a7SEvalZero
1395*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
1396*042d53a7SEvalZero ble_phy_mode_set(connsm->phy_data.tx_phy_mode,connsm->phy_data.rx_phy_mode);
1397*042d53a7SEvalZero #endif
1398*042d53a7SEvalZero
1399*042d53a7SEvalZero /* Set transmit end callback */
1400*042d53a7SEvalZero ble_phy_set_txend_cb(txend_func, connsm);
1401*042d53a7SEvalZero rc = ble_phy_tx(ble_ll_tx_mbuf_pducb, m, end_transition);
1402*042d53a7SEvalZero if (!rc) {
1403*042d53a7SEvalZero /* Log transmit on connection state */
1404*042d53a7SEvalZero cur_txlen = ble_hdr->txinfo.pyld_len;
1405*042d53a7SEvalZero ble_ll_trace_u32x2(BLE_LL_TRACE_ID_CONN_TX, cur_txlen,
1406*042d53a7SEvalZero ble_hdr->txinfo.offset);
1407*042d53a7SEvalZero
1408*042d53a7SEvalZero /* Set last transmitted MD bit */
1409*042d53a7SEvalZero CONN_F_LAST_TXD_MD(connsm) = md;
1410*042d53a7SEvalZero
1411*042d53a7SEvalZero /* Increment packets transmitted */
1412*042d53a7SEvalZero if (CONN_F_EMPTY_PDU_TXD(connsm)) {
1413*042d53a7SEvalZero STATS_INC(ble_ll_conn_stats, tx_empty_pdus);
1414*042d53a7SEvalZero } else if ((hdr_byte & BLE_LL_DATA_HDR_LLID_MASK) == BLE_LL_LLID_CTRL) {
1415*042d53a7SEvalZero STATS_INC(ble_ll_conn_stats, tx_ctrl_pdus);
1416*042d53a7SEvalZero STATS_INCN(ble_ll_conn_stats, tx_ctrl_bytes, cur_txlen);
1417*042d53a7SEvalZero } else {
1418*042d53a7SEvalZero STATS_INC(ble_ll_conn_stats, tx_l2cap_pdus);
1419*042d53a7SEvalZero STATS_INCN(ble_ll_conn_stats, tx_l2cap_bytes, cur_txlen);
1420*042d53a7SEvalZero }
1421*042d53a7SEvalZero }
1422*042d53a7SEvalZero return rc;
1423*042d53a7SEvalZero }
1424*042d53a7SEvalZero
1425*042d53a7SEvalZero /**
1426*042d53a7SEvalZero * Schedule callback for start of connection event.
1427*042d53a7SEvalZero *
1428*042d53a7SEvalZero * Context: Interrupt
1429*042d53a7SEvalZero *
1430*042d53a7SEvalZero * @param sch
1431*042d53a7SEvalZero *
1432*042d53a7SEvalZero * @return int 0: scheduled item is still running. 1: schedule item is done.
1433*042d53a7SEvalZero */
1434*042d53a7SEvalZero static int
ble_ll_conn_event_start_cb(struct ble_ll_sched_item * sch)1435*042d53a7SEvalZero ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch)
1436*042d53a7SEvalZero {
1437*042d53a7SEvalZero int rc;
1438*042d53a7SEvalZero uint32_t usecs;
1439*042d53a7SEvalZero uint32_t start;
1440*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
1441*042d53a7SEvalZero
1442*042d53a7SEvalZero /* XXX: note that we can extend end time here if we want. Look at this */
1443*042d53a7SEvalZero
1444*042d53a7SEvalZero /* Set current connection state machine */
1445*042d53a7SEvalZero connsm = (struct ble_ll_conn_sm *)sch->cb_arg;
1446*042d53a7SEvalZero g_ble_ll_conn_cur_sm = connsm;
1447*042d53a7SEvalZero BLE_LL_ASSERT(connsm);
1448*042d53a7SEvalZero
1449*042d53a7SEvalZero /* Log connection event start */
1450*042d53a7SEvalZero ble_ll_trace_u32(BLE_LL_TRACE_ID_CONN_EV_START, connsm->conn_handle);
1451*042d53a7SEvalZero
1452*042d53a7SEvalZero /* Disable whitelisting as connections do not use it */
1453*042d53a7SEvalZero ble_ll_whitelist_disable();
1454*042d53a7SEvalZero
1455*042d53a7SEvalZero /* Set LL state */
1456*042d53a7SEvalZero ble_ll_state_set(BLE_LL_STATE_CONNECTION);
1457*042d53a7SEvalZero
1458*042d53a7SEvalZero /* Set channel */
1459*042d53a7SEvalZero ble_phy_setchan(connsm->data_chan_index, connsm->access_addr,
1460*042d53a7SEvalZero connsm->crcinit);
1461*042d53a7SEvalZero
1462*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
1463*042d53a7SEvalZero ble_phy_resolv_list_disable();
1464*042d53a7SEvalZero #endif
1465*042d53a7SEvalZero
1466*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
1467*042d53a7SEvalZero /* Set start time of transmission */
1468*042d53a7SEvalZero start = sch->start_time + g_ble_ll_sched_offset_ticks;
1469*042d53a7SEvalZero rc = ble_phy_tx_set_start_time(start, sch->remainder);
1470*042d53a7SEvalZero if (!rc) {
1471*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
1472*042d53a7SEvalZero if (CONN_F_ENCRYPTED(connsm)) {
1473*042d53a7SEvalZero ble_phy_encrypt_enable(connsm->enc_data.tx_pkt_cntr,
1474*042d53a7SEvalZero connsm->enc_data.iv,
1475*042d53a7SEvalZero connsm->enc_data.enc_block.cipher_text,
1476*042d53a7SEvalZero 1);
1477*042d53a7SEvalZero } else {
1478*042d53a7SEvalZero ble_phy_encrypt_disable();
1479*042d53a7SEvalZero }
1480*042d53a7SEvalZero #endif
1481*042d53a7SEvalZero rc = ble_ll_conn_tx_data_pdu(connsm);
1482*042d53a7SEvalZero if (!rc) {
1483*042d53a7SEvalZero rc = BLE_LL_SCHED_STATE_RUNNING;
1484*042d53a7SEvalZero } else {
1485*042d53a7SEvalZero /* Inform LL task of connection event end */
1486*042d53a7SEvalZero rc = BLE_LL_SCHED_STATE_DONE;
1487*042d53a7SEvalZero }
1488*042d53a7SEvalZero } else {
1489*042d53a7SEvalZero STATS_INC(ble_ll_conn_stats, conn_ev_late);
1490*042d53a7SEvalZero rc = BLE_LL_SCHED_STATE_DONE;
1491*042d53a7SEvalZero }
1492*042d53a7SEvalZero } else {
1493*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
1494*042d53a7SEvalZero if (CONN_F_ENCRYPTED(connsm)) {
1495*042d53a7SEvalZero ble_phy_encrypt_enable(connsm->enc_data.rx_pkt_cntr,
1496*042d53a7SEvalZero connsm->enc_data.iv,
1497*042d53a7SEvalZero connsm->enc_data.enc_block.cipher_text,
1498*042d53a7SEvalZero 1);
1499*042d53a7SEvalZero } else {
1500*042d53a7SEvalZero ble_phy_encrypt_disable();
1501*042d53a7SEvalZero }
1502*042d53a7SEvalZero #endif
1503*042d53a7SEvalZero
1504*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
1505*042d53a7SEvalZero ble_phy_mode_set(connsm->phy_data.rx_phy_mode,
1506*042d53a7SEvalZero connsm->phy_data.rx_phy_mode);
1507*042d53a7SEvalZero #endif
1508*042d53a7SEvalZero
1509*042d53a7SEvalZero /* XXX: what is this really for the slave? */
1510*042d53a7SEvalZero start = sch->start_time + g_ble_ll_sched_offset_ticks;
1511*042d53a7SEvalZero rc = ble_phy_rx_set_start_time(start, sch->remainder);
1512*042d53a7SEvalZero if (rc) {
1513*042d53a7SEvalZero /* End the connection event as we have no more buffers */
1514*042d53a7SEvalZero STATS_INC(ble_ll_conn_stats, slave_ce_failures);
1515*042d53a7SEvalZero rc = BLE_LL_SCHED_STATE_DONE;
1516*042d53a7SEvalZero } else {
1517*042d53a7SEvalZero /*
1518*042d53a7SEvalZero * Set flag that tells slave to set last anchor point if a packet
1519*042d53a7SEvalZero * has been received.
1520*042d53a7SEvalZero */
1521*042d53a7SEvalZero connsm->csmflags.cfbit.slave_set_last_anchor = 1;
1522*042d53a7SEvalZero
1523*042d53a7SEvalZero /*
1524*042d53a7SEvalZero * Set the wait for response time. The anchor point is when we
1525*042d53a7SEvalZero * expect the master to start transmitting. Worst-case, we expect
1526*042d53a7SEvalZero * to hear a reply within the anchor point plus:
1527*042d53a7SEvalZero * -> current tx window size
1528*042d53a7SEvalZero * -> current window widening amount (includes +/- 16 usec jitter)
1529*042d53a7SEvalZero * -> Amount of time it takes to detect packet start.
1530*042d53a7SEvalZero * -> Some extra time (16 usec) to insure timing is OK
1531*042d53a7SEvalZero */
1532*042d53a7SEvalZero
1533*042d53a7SEvalZero /*
1534*042d53a7SEvalZero * For the 32 kHz crystal, the amount of usecs we have to wait
1535*042d53a7SEvalZero * is not from the anchor point; we have to account for the time
1536*042d53a7SEvalZero * from when the receiver is enabled until the anchor point. The
1537*042d53a7SEvalZero * time we start before the anchor point is this:
1538*042d53a7SEvalZero * -> current window widening.
1539*042d53a7SEvalZero * -> up to one 32 kHz tick since we discard remainder.
1540*042d53a7SEvalZero * -> Up to one tick since the usecs to ticks calc can be off
1541*042d53a7SEvalZero * by up to one tick.
1542*042d53a7SEvalZero * NOTES:
1543*042d53a7SEvalZero * 1) the 61 we add is for the two ticks mentioned above.
1544*042d53a7SEvalZero * 2) The address rx time and jitter is accounted for in the
1545*042d53a7SEvalZero * phy function
1546*042d53a7SEvalZero */
1547*042d53a7SEvalZero usecs = connsm->slave_cur_tx_win_usecs + 61 +
1548*042d53a7SEvalZero (2 * connsm->slave_cur_window_widening);
1549*042d53a7SEvalZero ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_RX, 0, usecs);
1550*042d53a7SEvalZero /* Set next wakeup time to connection event end time */
1551*042d53a7SEvalZero rc = BLE_LL_SCHED_STATE_RUNNING;
1552*042d53a7SEvalZero }
1553*042d53a7SEvalZero }
1554*042d53a7SEvalZero
1555*042d53a7SEvalZero if (rc == BLE_LL_SCHED_STATE_DONE) {
1556*042d53a7SEvalZero ble_ll_event_send(&connsm->conn_ev_end);
1557*042d53a7SEvalZero ble_phy_disable();
1558*042d53a7SEvalZero ble_ll_state_set(BLE_LL_STATE_STANDBY);
1559*042d53a7SEvalZero g_ble_ll_conn_cur_sm = NULL;
1560*042d53a7SEvalZero }
1561*042d53a7SEvalZero
1562*042d53a7SEvalZero /* Set time that we last serviced the schedule */
1563*042d53a7SEvalZero connsm->last_scheduled = os_cputime_get32();
1564*042d53a7SEvalZero return rc;
1565*042d53a7SEvalZero }
1566*042d53a7SEvalZero
1567*042d53a7SEvalZero /**
1568*042d53a7SEvalZero * Called to determine if the device is allowed to send the next pdu in the
1569*042d53a7SEvalZero * connection event. This will always return 'true' if we are a slave. If we
1570*042d53a7SEvalZero * are a master, we must be able to send the next fragment and get a minimum
1571*042d53a7SEvalZero * sized response from the slave.
1572*042d53a7SEvalZero *
1573*042d53a7SEvalZero * Context: Interrupt context (rx end isr).
1574*042d53a7SEvalZero *
1575*042d53a7SEvalZero * @param connsm
1576*042d53a7SEvalZero * @param begtime Time at which IFS before pdu transmission starts
1577*042d53a7SEvalZero *
1578*042d53a7SEvalZero * @return int 0: not allowed to send 1: allowed to send
1579*042d53a7SEvalZero */
1580*042d53a7SEvalZero static int
ble_ll_conn_can_send_next_pdu(struct ble_ll_conn_sm * connsm,uint32_t begtime,uint32_t add_usecs)1581*042d53a7SEvalZero ble_ll_conn_can_send_next_pdu(struct ble_ll_conn_sm *connsm, uint32_t begtime,
1582*042d53a7SEvalZero uint32_t add_usecs)
1583*042d53a7SEvalZero {
1584*042d53a7SEvalZero int rc;
1585*042d53a7SEvalZero uint8_t rem_bytes;
1586*042d53a7SEvalZero uint32_t ticks;
1587*042d53a7SEvalZero uint32_t usecs;
1588*042d53a7SEvalZero uint32_t next_sched_time;
1589*042d53a7SEvalZero struct os_mbuf *txpdu;
1590*042d53a7SEvalZero struct os_mbuf_pkthdr *pkthdr;
1591*042d53a7SEvalZero struct ble_mbuf_hdr *txhdr;
1592*042d53a7SEvalZero uint32_t allowed_usecs;
1593*042d53a7SEvalZero int tx_phy_mode;
1594*042d53a7SEvalZero
1595*042d53a7SEvalZero #if BLE_LL_BT5_PHY_SUPPORTED
1596*042d53a7SEvalZero tx_phy_mode = connsm->phy_data.tx_phy_mode;
1597*042d53a7SEvalZero #else
1598*042d53a7SEvalZero tx_phy_mode = BLE_PHY_MODE_1M;
1599*042d53a7SEvalZero #endif
1600*042d53a7SEvalZero
1601*042d53a7SEvalZero rc = 1;
1602*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
1603*042d53a7SEvalZero /* Get next scheduled item time */
1604*042d53a7SEvalZero next_sched_time = ble_ll_conn_get_next_sched_time(connsm);
1605*042d53a7SEvalZero
1606*042d53a7SEvalZero txpdu = connsm->cur_tx_pdu;
1607*042d53a7SEvalZero if (!txpdu) {
1608*042d53a7SEvalZero pkthdr = STAILQ_FIRST(&connsm->conn_txq);
1609*042d53a7SEvalZero if (pkthdr) {
1610*042d53a7SEvalZero txpdu = OS_MBUF_PKTHDR_TO_MBUF(pkthdr);
1611*042d53a7SEvalZero }
1612*042d53a7SEvalZero } else {
1613*042d53a7SEvalZero pkthdr = OS_MBUF_PKTHDR(txpdu);
1614*042d53a7SEvalZero }
1615*042d53a7SEvalZero
1616*042d53a7SEvalZero /* XXX: TODO: need to check this with phy update procedure. There are
1617*042d53a7SEvalZero limitations if we have started update */
1618*042d53a7SEvalZero if (txpdu) {
1619*042d53a7SEvalZero txhdr = BLE_MBUF_HDR_PTR(txpdu);
1620*042d53a7SEvalZero rem_bytes = pkthdr->omp_len - txhdr->txinfo.offset;
1621*042d53a7SEvalZero if (rem_bytes > connsm->eff_max_tx_octets) {
1622*042d53a7SEvalZero rem_bytes = connsm->eff_max_tx_octets;
1623*042d53a7SEvalZero }
1624*042d53a7SEvalZero usecs = ble_ll_pdu_tx_time_get(rem_bytes, tx_phy_mode);
1625*042d53a7SEvalZero } else {
1626*042d53a7SEvalZero /* We will send empty pdu (just a LL header) */
1627*042d53a7SEvalZero usecs = ble_ll_pdu_tx_time_get(0, tx_phy_mode);
1628*042d53a7SEvalZero }
1629*042d53a7SEvalZero usecs += (BLE_LL_IFS * 2) + connsm->eff_max_rx_time;
1630*042d53a7SEvalZero
1631*042d53a7SEvalZero ticks = (uint32_t)(next_sched_time - begtime);
1632*042d53a7SEvalZero allowed_usecs = os_cputime_ticks_to_usecs(ticks);
1633*042d53a7SEvalZero if ((usecs + add_usecs) >= allowed_usecs) {
1634*042d53a7SEvalZero rc = 0;
1635*042d53a7SEvalZero }
1636*042d53a7SEvalZero }
1637*042d53a7SEvalZero
1638*042d53a7SEvalZero return rc;
1639*042d53a7SEvalZero }
1640*042d53a7SEvalZero
1641*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING)
1642*042d53a7SEvalZero /**
1643*042d53a7SEvalZero * Callback for the Authenticated payload timer. This function is called
1644*042d53a7SEvalZero * when the authenticated payload timer expires. When the authenticated
1645*042d53a7SEvalZero * payload timeout expires, we should
1646*042d53a7SEvalZero * -> Send the authenticated payload timeout event.
1647*042d53a7SEvalZero * -> Start the LE ping procedure.
1648*042d53a7SEvalZero * -> Restart the timer.
1649*042d53a7SEvalZero *
1650*042d53a7SEvalZero * @param arg
1651*042d53a7SEvalZero */
1652*042d53a7SEvalZero void
ble_ll_conn_auth_pyld_timer_cb(struct ble_npl_event * ev)1653*042d53a7SEvalZero ble_ll_conn_auth_pyld_timer_cb(struct ble_npl_event *ev)
1654*042d53a7SEvalZero {
1655*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
1656*042d53a7SEvalZero
1657*042d53a7SEvalZero connsm = (struct ble_ll_conn_sm *)ble_npl_event_get_arg(ev);
1658*042d53a7SEvalZero ble_ll_auth_pyld_tmo_event_send(connsm);
1659*042d53a7SEvalZero ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_LE_PING);
1660*042d53a7SEvalZero ble_ll_conn_auth_pyld_timer_start(connsm);
1661*042d53a7SEvalZero }
1662*042d53a7SEvalZero
1663*042d53a7SEvalZero void
ble_ll_conn_rd_features_timer_cb(struct ble_npl_event * ev)1664*042d53a7SEvalZero ble_ll_conn_rd_features_timer_cb(struct ble_npl_event *ev)
1665*042d53a7SEvalZero {
1666*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
1667*042d53a7SEvalZero
1668*042d53a7SEvalZero connsm = (struct ble_ll_conn_sm *)ble_npl_event_get_arg(ev);
1669*042d53a7SEvalZero
1670*042d53a7SEvalZero if (!connsm->csmflags.cfbit.pending_hci_rd_features ||
1671*042d53a7SEvalZero !connsm->csmflags.cfbit.rxd_features) {
1672*042d53a7SEvalZero return;
1673*042d53a7SEvalZero }
1674*042d53a7SEvalZero
1675*042d53a7SEvalZero ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_SUCCESS);
1676*042d53a7SEvalZero connsm->csmflags.cfbit.pending_hci_rd_features = 0;
1677*042d53a7SEvalZero }
1678*042d53a7SEvalZero
1679*042d53a7SEvalZero /**
1680*042d53a7SEvalZero * Start (or restart) the authenticated payload timer
1681*042d53a7SEvalZero *
1682*042d53a7SEvalZero * @param connsm
1683*042d53a7SEvalZero */
1684*042d53a7SEvalZero void
ble_ll_conn_auth_pyld_timer_start(struct ble_ll_conn_sm * connsm)1685*042d53a7SEvalZero ble_ll_conn_auth_pyld_timer_start(struct ble_ll_conn_sm *connsm)
1686*042d53a7SEvalZero {
1687*042d53a7SEvalZero int32_t tmo;
1688*042d53a7SEvalZero
1689*042d53a7SEvalZero /* Timeout in is in 10 msec units */
1690*042d53a7SEvalZero tmo = (int32_t)BLE_LL_CONN_AUTH_PYLD_OS_TMO(connsm->auth_pyld_tmo);
1691*042d53a7SEvalZero ble_npl_callout_reset(&connsm->auth_pyld_timer, tmo);
1692*042d53a7SEvalZero }
1693*042d53a7SEvalZero #endif
1694*042d53a7SEvalZero
1695*042d53a7SEvalZero static void
ble_ll_conn_master_common_init(struct ble_ll_conn_sm * connsm)1696*042d53a7SEvalZero ble_ll_conn_master_common_init(struct ble_ll_conn_sm *connsm)
1697*042d53a7SEvalZero {
1698*042d53a7SEvalZero
1699*042d53a7SEvalZero /* Set master role */
1700*042d53a7SEvalZero connsm->conn_role = BLE_LL_CONN_ROLE_MASTER;
1701*042d53a7SEvalZero
1702*042d53a7SEvalZero /* Set default ce parameters */
1703*042d53a7SEvalZero
1704*042d53a7SEvalZero /*
1705*042d53a7SEvalZero * XXX: for now, we need twice the transmit window as our calculations
1706*042d53a7SEvalZero * for the transmit window offset could be off.
1707*042d53a7SEvalZero */
1708*042d53a7SEvalZero connsm->tx_win_size = BLE_LL_CONN_TX_WIN_MIN + 1;
1709*042d53a7SEvalZero connsm->tx_win_off = 0;
1710*042d53a7SEvalZero connsm->master_sca = MYNEWT_VAL(BLE_LL_MASTER_SCA);
1711*042d53a7SEvalZero
1712*042d53a7SEvalZero /* Hop increment is a random value between 5 and 16. */
1713*042d53a7SEvalZero connsm->hop_inc = (rand() % 12) + 5;
1714*042d53a7SEvalZero
1715*042d53a7SEvalZero /* Set channel map to map requested by host */
1716*042d53a7SEvalZero connsm->num_used_chans = g_ble_ll_conn_params.num_used_chans;
1717*042d53a7SEvalZero memcpy(connsm->chanmap, g_ble_ll_conn_params.master_chan_map,
1718*042d53a7SEvalZero BLE_LL_CONN_CHMAP_LEN);
1719*042d53a7SEvalZero
1720*042d53a7SEvalZero /* Calculate random access address and crc initialization value */
1721*042d53a7SEvalZero connsm->access_addr = ble_ll_conn_calc_access_addr();
1722*042d53a7SEvalZero connsm->crcinit = rand() & 0xffffff;
1723*042d53a7SEvalZero
1724*042d53a7SEvalZero /* Set initial schedule callback */
1725*042d53a7SEvalZero connsm->conn_sch.sched_cb = ble_ll_conn_event_start_cb;
1726*042d53a7SEvalZero }
1727*042d53a7SEvalZero /**
1728*042d53a7SEvalZero * Called when a create connection command has been received. This initializes
1729*042d53a7SEvalZero * a connection state machine in the master role.
1730*042d53a7SEvalZero *
1731*042d53a7SEvalZero * NOTE: Must be called before the state machine is started
1732*042d53a7SEvalZero *
1733*042d53a7SEvalZero * @param connsm
1734*042d53a7SEvalZero * @param hcc
1735*042d53a7SEvalZero */
1736*042d53a7SEvalZero void
ble_ll_conn_master_init(struct ble_ll_conn_sm * connsm,struct hci_create_conn * hcc)1737*042d53a7SEvalZero ble_ll_conn_master_init(struct ble_ll_conn_sm *connsm,
1738*042d53a7SEvalZero struct hci_create_conn *hcc)
1739*042d53a7SEvalZero {
1740*042d53a7SEvalZero
1741*042d53a7SEvalZero ble_ll_conn_master_common_init(connsm);
1742*042d53a7SEvalZero
1743*042d53a7SEvalZero /* Set slave latency and supervision timeout */
1744*042d53a7SEvalZero connsm->slave_latency = hcc->conn_latency;
1745*042d53a7SEvalZero connsm->supervision_tmo = hcc->supervision_timeout;
1746*042d53a7SEvalZero
1747*042d53a7SEvalZero /* Set own address type and peer address if needed */
1748*042d53a7SEvalZero connsm->own_addr_type = hcc->own_addr_type;
1749*042d53a7SEvalZero if (hcc->filter_policy == 0) {
1750*042d53a7SEvalZero memcpy(&connsm->peer_addr, &hcc->peer_addr, BLE_DEV_ADDR_LEN);
1751*042d53a7SEvalZero connsm->peer_addr_type = hcc->peer_addr_type;
1752*042d53a7SEvalZero }
1753*042d53a7SEvalZero
1754*042d53a7SEvalZero /* XXX: for now, just make connection interval equal to max */
1755*042d53a7SEvalZero connsm->conn_itvl = hcc->conn_itvl_max;
1756*042d53a7SEvalZero
1757*042d53a7SEvalZero /* Check the min/max CE lengths are less than connection interval */
1758*042d53a7SEvalZero if (hcc->min_ce_len > (connsm->conn_itvl * 2)) {
1759*042d53a7SEvalZero connsm->min_ce_len = connsm->conn_itvl * 2;
1760*042d53a7SEvalZero } else {
1761*042d53a7SEvalZero connsm->min_ce_len = hcc->min_ce_len;
1762*042d53a7SEvalZero }
1763*042d53a7SEvalZero
1764*042d53a7SEvalZero if (hcc->max_ce_len > (connsm->conn_itvl * 2)) {
1765*042d53a7SEvalZero connsm->max_ce_len = connsm->conn_itvl * 2;
1766*042d53a7SEvalZero } else {
1767*042d53a7SEvalZero connsm->max_ce_len = hcc->max_ce_len;
1768*042d53a7SEvalZero }
1769*042d53a7SEvalZero }
1770*042d53a7SEvalZero
1771*042d53a7SEvalZero static void
ble_ll_update_max_tx_octets_phy_mode(struct ble_ll_conn_sm * connsm)1772*042d53a7SEvalZero ble_ll_update_max_tx_octets_phy_mode(struct ble_ll_conn_sm *connsm)
1773*042d53a7SEvalZero {
1774*042d53a7SEvalZero uint32_t usecs;
1775*042d53a7SEvalZero
1776*042d53a7SEvalZero usecs = connsm->eff_max_tx_time;
1777*042d53a7SEvalZero
1778*042d53a7SEvalZero connsm->max_tx_octets_phy_mode[BLE_PHY_MODE_1M] =
1779*042d53a7SEvalZero ble_ll_pdu_max_tx_octets_get(usecs, BLE_PHY_MODE_1M);
1780*042d53a7SEvalZero connsm->max_tx_octets_phy_mode[BLE_PHY_MODE_2M] =
1781*042d53a7SEvalZero ble_ll_pdu_max_tx_octets_get(usecs, BLE_PHY_MODE_2M);
1782*042d53a7SEvalZero connsm->max_tx_octets_phy_mode[BLE_PHY_MODE_CODED_125KBPS] =
1783*042d53a7SEvalZero ble_ll_pdu_max_tx_octets_get(usecs, BLE_PHY_MODE_CODED_125KBPS);
1784*042d53a7SEvalZero connsm->max_tx_octets_phy_mode[BLE_PHY_MODE_CODED_500KBPS] =
1785*042d53a7SEvalZero ble_ll_pdu_max_tx_octets_get(usecs, BLE_PHY_MODE_CODED_500KBPS);
1786*042d53a7SEvalZero }
1787*042d53a7SEvalZero
1788*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
1789*042d53a7SEvalZero
1790*042d53a7SEvalZero static void
ble_ll_conn_set_phy(struct ble_ll_conn_sm * connsm,int tx_phy,int rx_phy)1791*042d53a7SEvalZero ble_ll_conn_set_phy(struct ble_ll_conn_sm *connsm, int tx_phy, int rx_phy)
1792*042d53a7SEvalZero {
1793*042d53a7SEvalZero
1794*042d53a7SEvalZero struct ble_ll_conn_phy_data *phy_data = &connsm->phy_data;
1795*042d53a7SEvalZero
1796*042d53a7SEvalZero phy_data->rx_phy_mode = ble_ll_phy_to_phy_mode(rx_phy,
1797*042d53a7SEvalZero BLE_HCI_LE_PHY_CODED_ANY);
1798*042d53a7SEvalZero phy_data->cur_rx_phy = rx_phy;
1799*042d53a7SEvalZero
1800*042d53a7SEvalZero phy_data->tx_phy_mode = ble_ll_phy_to_phy_mode(tx_phy,
1801*042d53a7SEvalZero BLE_HCI_LE_PHY_CODED_ANY);
1802*042d53a7SEvalZero phy_data->cur_tx_phy = tx_phy;
1803*042d53a7SEvalZero
1804*042d53a7SEvalZero }
1805*042d53a7SEvalZero
1806*042d53a7SEvalZero static void
ble_ll_conn_init_phy(struct ble_ll_conn_sm * connsm,int phy)1807*042d53a7SEvalZero ble_ll_conn_init_phy(struct ble_ll_conn_sm *connsm, int phy)
1808*042d53a7SEvalZero {
1809*042d53a7SEvalZero struct ble_ll_conn_global_params *conngp;
1810*042d53a7SEvalZero
1811*042d53a7SEvalZero /* Always initialize symmetric PHY - controller can change this later */
1812*042d53a7SEvalZero ble_ll_conn_set_phy(connsm, phy, phy);
1813*042d53a7SEvalZero
1814*042d53a7SEvalZero /* Update data length management to match initial PHY */
1815*042d53a7SEvalZero conngp = &g_ble_ll_conn_params;
1816*042d53a7SEvalZero connsm->max_tx_octets = conngp->conn_init_max_tx_octets;
1817*042d53a7SEvalZero connsm->max_rx_octets = conngp->supp_max_rx_octets;
1818*042d53a7SEvalZero if (phy == BLE_PHY_CODED) {
1819*042d53a7SEvalZero connsm->max_tx_time = conngp->conn_init_max_tx_time_coded;
1820*042d53a7SEvalZero connsm->max_rx_time = BLE_LL_CONN_SUPP_TIME_MAX_CODED;
1821*042d53a7SEvalZero connsm->rem_max_tx_time = BLE_LL_CONN_SUPP_TIME_MIN_CODED;
1822*042d53a7SEvalZero connsm->rem_max_rx_time = BLE_LL_CONN_SUPP_TIME_MIN_CODED;
1823*042d53a7SEvalZero } else {
1824*042d53a7SEvalZero connsm->max_tx_time = conngp->conn_init_max_tx_time_uncoded;
1825*042d53a7SEvalZero connsm->max_rx_time = BLE_LL_CONN_SUPP_TIME_MAX_UNCODED;
1826*042d53a7SEvalZero connsm->rem_max_tx_time = BLE_LL_CONN_SUPP_TIME_MIN_UNCODED;
1827*042d53a7SEvalZero connsm->rem_max_rx_time = BLE_LL_CONN_SUPP_TIME_MIN_UNCODED;
1828*042d53a7SEvalZero }
1829*042d53a7SEvalZero connsm->eff_max_tx_time = connsm->rem_max_tx_time;
1830*042d53a7SEvalZero connsm->eff_max_rx_time = connsm->rem_max_rx_time;
1831*042d53a7SEvalZero connsm->rem_max_tx_octets = BLE_LL_CONN_SUPP_BYTES_MIN;
1832*042d53a7SEvalZero connsm->rem_max_rx_octets = BLE_LL_CONN_SUPP_BYTES_MIN;
1833*042d53a7SEvalZero connsm->eff_max_tx_octets = BLE_LL_CONN_SUPP_BYTES_MIN;
1834*042d53a7SEvalZero connsm->eff_max_rx_octets = BLE_LL_CONN_SUPP_BYTES_MIN;
1835*042d53a7SEvalZero
1836*042d53a7SEvalZero ble_ll_update_max_tx_octets_phy_mode(connsm);
1837*042d53a7SEvalZero }
1838*042d53a7SEvalZero
1839*042d53a7SEvalZero #endif
1840*042d53a7SEvalZero
1841*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
1842*042d53a7SEvalZero
1843*042d53a7SEvalZero void
ble_ll_conn_ext_master_init(struct ble_ll_conn_sm * connsm,struct hci_ext_create_conn * hcc)1844*042d53a7SEvalZero ble_ll_conn_ext_master_init(struct ble_ll_conn_sm *connsm,
1845*042d53a7SEvalZero struct hci_ext_create_conn *hcc)
1846*042d53a7SEvalZero {
1847*042d53a7SEvalZero
1848*042d53a7SEvalZero ble_ll_conn_master_common_init(connsm);
1849*042d53a7SEvalZero
1850*042d53a7SEvalZero /* Set own address type and peer address if needed */
1851*042d53a7SEvalZero connsm->own_addr_type = hcc->own_addr_type;
1852*042d53a7SEvalZero if (hcc->filter_policy == 0) {
1853*042d53a7SEvalZero memcpy(&connsm->peer_addr, &hcc->peer_addr, BLE_DEV_ADDR_LEN);
1854*042d53a7SEvalZero connsm->peer_addr_type = hcc->peer_addr_type;
1855*042d53a7SEvalZero }
1856*042d53a7SEvalZero
1857*042d53a7SEvalZero connsm->initial_params = *hcc;
1858*042d53a7SEvalZero }
1859*042d53a7SEvalZero
1860*042d53a7SEvalZero void
ble_ll_conn_ext_set_params(struct ble_ll_conn_sm * connsm,struct hci_ext_conn_params * hcc_params,int phy)1861*042d53a7SEvalZero ble_ll_conn_ext_set_params(struct ble_ll_conn_sm *connsm,
1862*042d53a7SEvalZero struct hci_ext_conn_params *hcc_params, int phy)
1863*042d53a7SEvalZero {
1864*042d53a7SEvalZero /* Set slave latency and supervision timeout */
1865*042d53a7SEvalZero connsm->slave_latency = hcc_params->conn_latency;
1866*042d53a7SEvalZero connsm->supervision_tmo = hcc_params->supervision_timeout;
1867*042d53a7SEvalZero
1868*042d53a7SEvalZero /* XXX: for now, just make connection interval equal to max */
1869*042d53a7SEvalZero connsm->conn_itvl = hcc_params->conn_itvl_max;
1870*042d53a7SEvalZero
1871*042d53a7SEvalZero
1872*042d53a7SEvalZero /* Check the min/max CE lengths are less than connection interval */
1873*042d53a7SEvalZero if (hcc_params->min_ce_len > (connsm->conn_itvl * 2)) {
1874*042d53a7SEvalZero connsm->min_ce_len = connsm->conn_itvl * 2;
1875*042d53a7SEvalZero } else {
1876*042d53a7SEvalZero connsm->min_ce_len = hcc_params->min_ce_len;
1877*042d53a7SEvalZero }
1878*042d53a7SEvalZero
1879*042d53a7SEvalZero if (hcc_params->max_ce_len > (connsm->conn_itvl * 2)) {
1880*042d53a7SEvalZero connsm->max_ce_len = connsm->conn_itvl * 2;
1881*042d53a7SEvalZero } else {
1882*042d53a7SEvalZero connsm->max_ce_len = hcc_params->max_ce_len;
1883*042d53a7SEvalZero }
1884*042d53a7SEvalZero
1885*042d53a7SEvalZero ble_ll_conn_calc_itvl_ticks(connsm);
1886*042d53a7SEvalZero
1887*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
1888*042d53a7SEvalZero ble_ll_conn_init_phy(connsm, phy);
1889*042d53a7SEvalZero #endif
1890*042d53a7SEvalZero }
1891*042d53a7SEvalZero
1892*042d53a7SEvalZero
1893*042d53a7SEvalZero #endif
1894*042d53a7SEvalZero
1895*042d53a7SEvalZero static void
ble_ll_conn_set_csa(struct ble_ll_conn_sm * connsm,bool chsel)1896*042d53a7SEvalZero ble_ll_conn_set_csa(struct ble_ll_conn_sm *connsm, bool chsel)
1897*042d53a7SEvalZero {
1898*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) == 1)
1899*042d53a7SEvalZero if (chsel) {
1900*042d53a7SEvalZero CONN_F_CSA2_SUPP(connsm) = 1;
1901*042d53a7SEvalZero connsm->channel_id = ((connsm->access_addr & 0xffff0000) >> 16) ^
1902*042d53a7SEvalZero (connsm->access_addr & 0x0000ffff);
1903*042d53a7SEvalZero
1904*042d53a7SEvalZero /* calculate the next data channel */
1905*042d53a7SEvalZero connsm->data_chan_index = ble_ll_conn_calc_dci(connsm, 0);
1906*042d53a7SEvalZero return;
1907*042d53a7SEvalZero }
1908*042d53a7SEvalZero #endif
1909*042d53a7SEvalZero
1910*042d53a7SEvalZero connsm->last_unmapped_chan = 0;
1911*042d53a7SEvalZero
1912*042d53a7SEvalZero /* calculate the next data channel */
1913*042d53a7SEvalZero connsm->data_chan_index = ble_ll_conn_calc_dci(connsm, 1);
1914*042d53a7SEvalZero }
1915*042d53a7SEvalZero
1916*042d53a7SEvalZero /**
1917*042d53a7SEvalZero * Create a new connection state machine. This is done once per
1918*042d53a7SEvalZero * connection when the HCI command "create connection" is issued to the
1919*042d53a7SEvalZero * controller or when a slave receives a connect request.
1920*042d53a7SEvalZero *
1921*042d53a7SEvalZero * Context: Link Layer task
1922*042d53a7SEvalZero *
1923*042d53a7SEvalZero * @param connsm
1924*042d53a7SEvalZero */
1925*042d53a7SEvalZero void
ble_ll_conn_sm_new(struct ble_ll_conn_sm * connsm)1926*042d53a7SEvalZero ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm)
1927*042d53a7SEvalZero {
1928*042d53a7SEvalZero struct ble_ll_conn_global_params *conn_params;
1929*042d53a7SEvalZero
1930*042d53a7SEvalZero /* Reset following elements */
1931*042d53a7SEvalZero connsm->csmflags.conn_flags = 0;
1932*042d53a7SEvalZero connsm->event_cntr = 0;
1933*042d53a7SEvalZero connsm->conn_state = BLE_LL_CONN_STATE_IDLE;
1934*042d53a7SEvalZero connsm->disconnect_reason = 0;
1935*042d53a7SEvalZero connsm->conn_features = BLE_LL_CONN_INITIAL_FEATURES;
1936*042d53a7SEvalZero memset(connsm->remote_features, 0, sizeof(connsm->remote_features));
1937*042d53a7SEvalZero connsm->vers_nr = 0;
1938*042d53a7SEvalZero connsm->comp_id = 0;
1939*042d53a7SEvalZero connsm->sub_vers_nr = 0;
1940*042d53a7SEvalZero connsm->reject_reason = BLE_ERR_SUCCESS;
1941*042d53a7SEvalZero connsm->conn_rssi = BLE_LL_CONN_UNKNOWN_RSSI;
1942*042d53a7SEvalZero connsm->rpa_index = -1;
1943*042d53a7SEvalZero
1944*042d53a7SEvalZero /* XXX: TODO set these based on PHY that started connection */
1945*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
1946*042d53a7SEvalZero connsm->phy_data.cur_tx_phy = BLE_PHY_1M;
1947*042d53a7SEvalZero connsm->phy_data.cur_rx_phy = BLE_PHY_1M;
1948*042d53a7SEvalZero connsm->phy_data.tx_phy_mode = BLE_PHY_MODE_1M;
1949*042d53a7SEvalZero connsm->phy_data.rx_phy_mode = BLE_PHY_MODE_1M;
1950*042d53a7SEvalZero connsm->phy_data.req_pref_tx_phys_mask = 0;
1951*042d53a7SEvalZero connsm->phy_data.req_pref_rx_phys_mask = 0;
1952*042d53a7SEvalZero connsm->phy_data.host_pref_tx_phys_mask = g_ble_ll_data.ll_pref_tx_phys;
1953*042d53a7SEvalZero connsm->phy_data.host_pref_rx_phys_mask = g_ble_ll_data.ll_pref_rx_phys;
1954*042d53a7SEvalZero connsm->phy_data.phy_options = 0;
1955*042d53a7SEvalZero connsm->phy_tx_transition = BLE_PHY_TRANSITION_INVALID;
1956*042d53a7SEvalZero #endif
1957*042d53a7SEvalZero
1958*042d53a7SEvalZero /* Reset current control procedure */
1959*042d53a7SEvalZero connsm->cur_ctrl_proc = BLE_LL_CTRL_PROC_IDLE;
1960*042d53a7SEvalZero connsm->pending_ctrl_procs = 0;
1961*042d53a7SEvalZero
1962*042d53a7SEvalZero /*
1963*042d53a7SEvalZero * Set handle in connection update procedure to 0. If the handle
1964*042d53a7SEvalZero * is non-zero it means that the host initiated the connection
1965*042d53a7SEvalZero * parameter update request and the rest of the parameters are valid.
1966*042d53a7SEvalZero */
1967*042d53a7SEvalZero connsm->conn_param_req.handle = 0;
1968*042d53a7SEvalZero
1969*042d53a7SEvalZero /* Connection end event */
1970*042d53a7SEvalZero ble_npl_event_init(&connsm->conn_ev_end, ble_ll_conn_event_end, connsm);
1971*042d53a7SEvalZero
1972*042d53a7SEvalZero /* Initialize transmit queue and ack/flow control elements */
1973*042d53a7SEvalZero STAILQ_INIT(&connsm->conn_txq);
1974*042d53a7SEvalZero connsm->cur_tx_pdu = NULL;
1975*042d53a7SEvalZero connsm->tx_seqnum = 0;
1976*042d53a7SEvalZero connsm->next_exp_seqnum = 0;
1977*042d53a7SEvalZero connsm->cons_rxd_bad_crc = 0;
1978*042d53a7SEvalZero connsm->last_rxd_sn = 1;
1979*042d53a7SEvalZero connsm->completed_pkts = 0;
1980*042d53a7SEvalZero
1981*042d53a7SEvalZero /* initialize data length mgmt */
1982*042d53a7SEvalZero conn_params = &g_ble_ll_conn_params;
1983*042d53a7SEvalZero connsm->max_tx_octets = conn_params->conn_init_max_tx_octets;
1984*042d53a7SEvalZero connsm->max_rx_octets = conn_params->supp_max_rx_octets;
1985*042d53a7SEvalZero connsm->max_tx_time = conn_params->conn_init_max_tx_time;
1986*042d53a7SEvalZero connsm->max_rx_time = conn_params->supp_max_rx_time;
1987*042d53a7SEvalZero connsm->rem_max_tx_time = BLE_LL_CONN_SUPP_TIME_MIN;
1988*042d53a7SEvalZero connsm->rem_max_rx_time = BLE_LL_CONN_SUPP_TIME_MIN;
1989*042d53a7SEvalZero connsm->eff_max_tx_time = BLE_LL_CONN_SUPP_TIME_MIN;
1990*042d53a7SEvalZero connsm->eff_max_rx_time = BLE_LL_CONN_SUPP_TIME_MIN;
1991*042d53a7SEvalZero connsm->rem_max_tx_octets = BLE_LL_CONN_SUPP_BYTES_MIN;
1992*042d53a7SEvalZero connsm->rem_max_rx_octets = BLE_LL_CONN_SUPP_BYTES_MIN;
1993*042d53a7SEvalZero connsm->eff_max_tx_octets = BLE_LL_CONN_SUPP_BYTES_MIN;
1994*042d53a7SEvalZero connsm->eff_max_rx_octets = BLE_LL_CONN_SUPP_BYTES_MIN;
1995*042d53a7SEvalZero
1996*042d53a7SEvalZero ble_ll_update_max_tx_octets_phy_mode(connsm);
1997*042d53a7SEvalZero
1998*042d53a7SEvalZero /* Reset encryption data */
1999*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
2000*042d53a7SEvalZero memset(&connsm->enc_data, 0, sizeof(struct ble_ll_conn_enc_data));
2001*042d53a7SEvalZero connsm->enc_data.enc_state = CONN_ENC_S_UNENCRYPTED;
2002*042d53a7SEvalZero #endif
2003*042d53a7SEvalZero
2004*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING)
2005*042d53a7SEvalZero connsm->auth_pyld_tmo = BLE_LL_CONN_DEF_AUTH_PYLD_TMO;
2006*042d53a7SEvalZero CONN_F_LE_PING_SUPP(connsm) = 1;
2007*042d53a7SEvalZero ble_npl_callout_init(&connsm->auth_pyld_timer,
2008*042d53a7SEvalZero &g_ble_ll_data.ll_evq,
2009*042d53a7SEvalZero ble_ll_conn_auth_pyld_timer_cb,
2010*042d53a7SEvalZero connsm);
2011*042d53a7SEvalZero #endif
2012*042d53a7SEvalZero
2013*042d53a7SEvalZero ble_ll_conn_calc_itvl_ticks(connsm);
2014*042d53a7SEvalZero
2015*042d53a7SEvalZero /* Add to list of active connections */
2016*042d53a7SEvalZero SLIST_INSERT_HEAD(&g_ble_ll_conn_active_list, connsm, act_sle);
2017*042d53a7SEvalZero }
2018*042d53a7SEvalZero
2019*042d53a7SEvalZero /**
2020*042d53a7SEvalZero * Called when a remotes data length parameters change.
2021*042d53a7SEvalZero *
2022*042d53a7SEvalZero * Context: Link Layer task
2023*042d53a7SEvalZero *
2024*042d53a7SEvalZero * @param connsm
2025*042d53a7SEvalZero * @param req
2026*042d53a7SEvalZero */
2027*042d53a7SEvalZero void
ble_ll_conn_datalen_update(struct ble_ll_conn_sm * connsm,struct ble_ll_len_req * req)2028*042d53a7SEvalZero ble_ll_conn_datalen_update(struct ble_ll_conn_sm *connsm,
2029*042d53a7SEvalZero struct ble_ll_len_req *req)
2030*042d53a7SEvalZero {
2031*042d53a7SEvalZero int send_event;
2032*042d53a7SEvalZero uint16_t eff_time;
2033*042d53a7SEvalZero uint16_t eff_bytes;
2034*042d53a7SEvalZero
2035*042d53a7SEvalZero /* Update parameters */
2036*042d53a7SEvalZero connsm->rem_max_rx_time = req->max_rx_time;
2037*042d53a7SEvalZero connsm->rem_max_tx_time = req->max_tx_time;
2038*042d53a7SEvalZero connsm->rem_max_rx_octets = req->max_rx_bytes;
2039*042d53a7SEvalZero connsm->rem_max_tx_octets = req->max_tx_bytes;
2040*042d53a7SEvalZero
2041*042d53a7SEvalZero /* Assume no event sent */
2042*042d53a7SEvalZero send_event = 0;
2043*042d53a7SEvalZero
2044*042d53a7SEvalZero /* See if effective times have changed */
2045*042d53a7SEvalZero eff_time = min(connsm->rem_max_tx_time, connsm->max_rx_time);
2046*042d53a7SEvalZero if (eff_time != connsm->eff_max_rx_time) {
2047*042d53a7SEvalZero connsm->eff_max_rx_time = eff_time;
2048*042d53a7SEvalZero send_event = 1;
2049*042d53a7SEvalZero }
2050*042d53a7SEvalZero eff_time = min(connsm->rem_max_rx_time, connsm->max_tx_time);
2051*042d53a7SEvalZero if (eff_time != connsm->eff_max_tx_time) {
2052*042d53a7SEvalZero connsm->eff_max_tx_time = eff_time;
2053*042d53a7SEvalZero send_event = 1;
2054*042d53a7SEvalZero
2055*042d53a7SEvalZero ble_ll_update_max_tx_octets_phy_mode(connsm);
2056*042d53a7SEvalZero }
2057*042d53a7SEvalZero eff_bytes = min(connsm->rem_max_tx_octets, connsm->max_rx_octets);
2058*042d53a7SEvalZero if (eff_bytes != connsm->eff_max_rx_octets) {
2059*042d53a7SEvalZero connsm->eff_max_rx_octets = eff_bytes;
2060*042d53a7SEvalZero send_event = 1;
2061*042d53a7SEvalZero }
2062*042d53a7SEvalZero eff_bytes = min(connsm->rem_max_rx_octets, connsm->max_tx_octets);
2063*042d53a7SEvalZero if (eff_bytes != connsm->eff_max_tx_octets) {
2064*042d53a7SEvalZero connsm->eff_max_tx_octets = eff_bytes;
2065*042d53a7SEvalZero send_event = 1;
2066*042d53a7SEvalZero }
2067*042d53a7SEvalZero
2068*042d53a7SEvalZero if (send_event) {
2069*042d53a7SEvalZero ble_ll_hci_ev_datalen_chg(connsm);
2070*042d53a7SEvalZero }
2071*042d53a7SEvalZero }
2072*042d53a7SEvalZero
2073*042d53a7SEvalZero /**
2074*042d53a7SEvalZero * Called when a connection is terminated
2075*042d53a7SEvalZero *
2076*042d53a7SEvalZero * Context: Link Layer task.
2077*042d53a7SEvalZero *
2078*042d53a7SEvalZero * @param connsm
2079*042d53a7SEvalZero * @param ble_err
2080*042d53a7SEvalZero */
2081*042d53a7SEvalZero void
ble_ll_conn_end(struct ble_ll_conn_sm * connsm,uint8_t ble_err)2082*042d53a7SEvalZero ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
2083*042d53a7SEvalZero {
2084*042d53a7SEvalZero struct os_mbuf *m;
2085*042d53a7SEvalZero struct os_mbuf_pkthdr *pkthdr;
2086*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING)
2087*042d53a7SEvalZero os_sr_t sr;
2088*042d53a7SEvalZero #endif
2089*042d53a7SEvalZero
2090*042d53a7SEvalZero /* Remove scheduler events just in case */
2091*042d53a7SEvalZero ble_ll_sched_rmv_elem(&connsm->conn_sch);
2092*042d53a7SEvalZero
2093*042d53a7SEvalZero /* Stop any control procedures that might be running */
2094*042d53a7SEvalZero ble_npl_callout_stop(&connsm->ctrl_proc_rsp_timer);
2095*042d53a7SEvalZero
2096*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING)
2097*042d53a7SEvalZero ble_npl_callout_stop(&connsm->auth_pyld_timer);
2098*042d53a7SEvalZero #endif
2099*042d53a7SEvalZero
2100*042d53a7SEvalZero /* Remove from the active connection list */
2101*042d53a7SEvalZero SLIST_REMOVE(&g_ble_ll_conn_active_list, connsm, ble_ll_conn_sm, act_sle);
2102*042d53a7SEvalZero
2103*042d53a7SEvalZero /* Free the current transmit pdu if there is one. */
2104*042d53a7SEvalZero if (connsm->cur_tx_pdu) {
2105*042d53a7SEvalZero os_mbuf_free_chain(connsm->cur_tx_pdu);
2106*042d53a7SEvalZero connsm->cur_tx_pdu = NULL;
2107*042d53a7SEvalZero }
2108*042d53a7SEvalZero
2109*042d53a7SEvalZero /* Free all packets on transmit queue */
2110*042d53a7SEvalZero while (1) {
2111*042d53a7SEvalZero /* Get mbuf pointer from packet header pointer */
2112*042d53a7SEvalZero pkthdr = STAILQ_FIRST(&connsm->conn_txq);
2113*042d53a7SEvalZero if (!pkthdr) {
2114*042d53a7SEvalZero break;
2115*042d53a7SEvalZero }
2116*042d53a7SEvalZero STAILQ_REMOVE_HEAD(&connsm->conn_txq, omp_next);
2117*042d53a7SEvalZero
2118*042d53a7SEvalZero m = (struct os_mbuf *)((uint8_t *)pkthdr - sizeof(struct os_mbuf));
2119*042d53a7SEvalZero os_mbuf_free_chain(m);
2120*042d53a7SEvalZero }
2121*042d53a7SEvalZero
2122*042d53a7SEvalZero /* Make sure events off queue */
2123*042d53a7SEvalZero ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &connsm->conn_ev_end);
2124*042d53a7SEvalZero
2125*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING)
2126*042d53a7SEvalZero /* Remove from occupied periods */
2127*042d53a7SEvalZero OS_ENTER_CRITICAL(sr);
2128*042d53a7SEvalZero BLE_LL_ASSERT(g_ble_ll_sched_data.sch_num_occ_periods > 0);
2129*042d53a7SEvalZero BLE_LL_ASSERT(g_ble_ll_sched_data.sch_occ_period_mask & connsm->period_occ_mask);
2130*042d53a7SEvalZero --g_ble_ll_sched_data.sch_num_occ_periods;
2131*042d53a7SEvalZero g_ble_ll_sched_data.sch_occ_period_mask &= ~connsm->period_occ_mask;
2132*042d53a7SEvalZero OS_EXIT_CRITICAL(sr);
2133*042d53a7SEvalZero #endif
2134*042d53a7SEvalZero
2135*042d53a7SEvalZero /* Connection state machine is now idle */
2136*042d53a7SEvalZero connsm->conn_state = BLE_LL_CONN_STATE_IDLE;
2137*042d53a7SEvalZero
2138*042d53a7SEvalZero /*
2139*042d53a7SEvalZero * If we have features and there's pending HCI command, send an event before
2140*042d53a7SEvalZero * disconnection event so it does make sense to host.
2141*042d53a7SEvalZero */
2142*042d53a7SEvalZero if (connsm->csmflags.cfbit.pending_hci_rd_features &&
2143*042d53a7SEvalZero connsm->csmflags.cfbit.rxd_features) {
2144*042d53a7SEvalZero ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_SUCCESS);
2145*042d53a7SEvalZero connsm->csmflags.cfbit.pending_hci_rd_features = 0;
2146*042d53a7SEvalZero }
2147*042d53a7SEvalZero
2148*042d53a7SEvalZero /*
2149*042d53a7SEvalZero * If there is still pending read features request HCI command, send an
2150*042d53a7SEvalZero * event to complete it.
2151*042d53a7SEvalZero */
2152*042d53a7SEvalZero if (connsm->csmflags.cfbit.pending_hci_rd_features) {
2153*042d53a7SEvalZero ble_ll_hci_ev_rd_rem_used_feat(connsm, ble_err);
2154*042d53a7SEvalZero connsm->csmflags.cfbit.pending_hci_rd_features = 0;
2155*042d53a7SEvalZero }
2156*042d53a7SEvalZero
2157*042d53a7SEvalZero /*
2158*042d53a7SEvalZero * We need to send a disconnection complete event. Connection Complete for
2159*042d53a7SEvalZero * canceling connection creation is sent from LE Create Connection Cancel
2160*042d53a7SEvalZero * Command handler.
2161*042d53a7SEvalZero *
2162*042d53a7SEvalZero * If the ble error is "success" it means that the reset command was
2163*042d53a7SEvalZero * received and we should not send an event.
2164*042d53a7SEvalZero */
2165*042d53a7SEvalZero if (ble_err && (ble_err != BLE_ERR_UNK_CONN_ID ||
2166*042d53a7SEvalZero connsm->csmflags.cfbit.terminate_ind_rxd)) {
2167*042d53a7SEvalZero ble_ll_disconn_comp_event_send(connsm, ble_err);
2168*042d53a7SEvalZero }
2169*042d53a7SEvalZero
2170*042d53a7SEvalZero /* Put connection state machine back on free list */
2171*042d53a7SEvalZero STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe);
2172*042d53a7SEvalZero
2173*042d53a7SEvalZero /* Log connection end */
2174*042d53a7SEvalZero ble_ll_trace_u32x3(BLE_LL_TRACE_ID_CONN_END, connsm->conn_handle,
2175*042d53a7SEvalZero connsm->event_cntr, (uint32_t)ble_err);
2176*042d53a7SEvalZero }
2177*042d53a7SEvalZero
2178*042d53a7SEvalZero /**
2179*042d53a7SEvalZero * Called to move to the next connection event.
2180*042d53a7SEvalZero *
2181*042d53a7SEvalZero * Context: Link Layer task.
2182*042d53a7SEvalZero *
2183*042d53a7SEvalZero * @param connsm
2184*042d53a7SEvalZero *
2185*042d53a7SEvalZero * @return int
2186*042d53a7SEvalZero */
2187*042d53a7SEvalZero static int
ble_ll_conn_next_event(struct ble_ll_conn_sm * connsm)2188*042d53a7SEvalZero ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
2189*042d53a7SEvalZero {
2190*042d53a7SEvalZero uint16_t latency;
2191*042d53a7SEvalZero uint32_t itvl;
2192*042d53a7SEvalZero uint32_t cur_ww;
2193*042d53a7SEvalZero uint32_t max_ww;
2194*042d53a7SEvalZero struct ble_ll_conn_upd_req *upd;
2195*042d53a7SEvalZero uint32_t ticks;
2196*042d53a7SEvalZero uint32_t usecs;
2197*042d53a7SEvalZero
2198*042d53a7SEvalZero /* XXX: deal with connection request procedure here as well */
2199*042d53a7SEvalZero ble_ll_conn_chk_csm_flags(connsm);
2200*042d53a7SEvalZero
2201*042d53a7SEvalZero /* If unable to start terminate procedure, start it now */
2202*042d53a7SEvalZero if (connsm->disconnect_reason && !CONN_F_TERMINATE_STARTED(connsm)) {
2203*042d53a7SEvalZero ble_ll_ctrl_terminate_start(connsm);
2204*042d53a7SEvalZero }
2205*042d53a7SEvalZero
2206*042d53a7SEvalZero if (CONN_F_TERMINATE_STARTED(connsm) && (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE)) {
2207*042d53a7SEvalZero /* Some of the devices waits whole connection interval to ACK our
2208*042d53a7SEvalZero * TERMINATE_IND sent as a Slave. Since we are here it means we are still waiting for ACK.
2209*042d53a7SEvalZero * Make sure we catch it in next connection event.
2210*042d53a7SEvalZero */
2211*042d53a7SEvalZero connsm->slave_latency = 0;
2212*042d53a7SEvalZero }
2213*042d53a7SEvalZero
2214*042d53a7SEvalZero /*
2215*042d53a7SEvalZero * XXX: TODO Probably want to add checks to see if we need to start
2216*042d53a7SEvalZero * a control procedure here as an instant may have prevented us from
2217*042d53a7SEvalZero * starting one.
2218*042d53a7SEvalZero */
2219*042d53a7SEvalZero
2220*042d53a7SEvalZero /*
2221*042d53a7SEvalZero * XXX TODO: I think this is technically incorrect. We can allow slave
2222*042d53a7SEvalZero * latency if we are doing one of these updates as long as we
2223*042d53a7SEvalZero * know that the master has received the ACK to the PDU that set
2224*042d53a7SEvalZero * the instant
2225*042d53a7SEvalZero */
2226*042d53a7SEvalZero /* Set event counter to the next connection event that we will tx/rx in */
2227*042d53a7SEvalZero itvl = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS;
2228*042d53a7SEvalZero latency = 1;
2229*042d53a7SEvalZero if (connsm->csmflags.cfbit.allow_slave_latency &&
2230*042d53a7SEvalZero !connsm->csmflags.cfbit.conn_update_sched &&
2231*042d53a7SEvalZero !CONN_F_PHY_UPDATE_SCHED(connsm) &&
2232*042d53a7SEvalZero !connsm->csmflags.cfbit.chanmap_update_scheduled) {
2233*042d53a7SEvalZero if (connsm->csmflags.cfbit.pkt_rxd) {
2234*042d53a7SEvalZero latency += connsm->slave_latency;
2235*042d53a7SEvalZero itvl = itvl * latency;
2236*042d53a7SEvalZero }
2237*042d53a7SEvalZero }
2238*042d53a7SEvalZero connsm->event_cntr += latency;
2239*042d53a7SEvalZero
2240*042d53a7SEvalZero /* Set next connection event start time */
2241*042d53a7SEvalZero /* We can use pre-calculated values for one interval if latency is 1. */
2242*042d53a7SEvalZero if (latency == 1) {
2243*042d53a7SEvalZero connsm->anchor_point += connsm->conn_itvl_ticks;
2244*042d53a7SEvalZero connsm->anchor_point_usecs += connsm->conn_itvl_usecs;
2245*042d53a7SEvalZero } else {
2246*042d53a7SEvalZero uint32_t ticks;
2247*042d53a7SEvalZero ticks = os_cputime_usecs_to_ticks(itvl);
2248*042d53a7SEvalZero connsm->anchor_point += ticks;
2249*042d53a7SEvalZero connsm->anchor_point_usecs += (itvl - os_cputime_ticks_to_usecs(ticks));
2250*042d53a7SEvalZero }
2251*042d53a7SEvalZero if (connsm->anchor_point_usecs >= 31) {
2252*042d53a7SEvalZero ++connsm->anchor_point;
2253*042d53a7SEvalZero connsm->anchor_point_usecs -= 31;
2254*042d53a7SEvalZero }
2255*042d53a7SEvalZero
2256*042d53a7SEvalZero /*
2257*042d53a7SEvalZero * If a connection update has been scheduled and the event counter
2258*042d53a7SEvalZero * is now equal to the instant, we need to adjust the start of the
2259*042d53a7SEvalZero * connection by the the transmit window offset. We also copy in the
2260*042d53a7SEvalZero * update parameters as they now should take effect.
2261*042d53a7SEvalZero */
2262*042d53a7SEvalZero if (connsm->csmflags.cfbit.conn_update_sched &&
2263*042d53a7SEvalZero (connsm->event_cntr == connsm->conn_update_req.instant)) {
2264*042d53a7SEvalZero
2265*042d53a7SEvalZero /* Set flag so we send connection update event */
2266*042d53a7SEvalZero upd = &connsm->conn_update_req;
2267*042d53a7SEvalZero if ((connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) ||
2268*042d53a7SEvalZero ((connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) &&
2269*042d53a7SEvalZero IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ)) ||
2270*042d53a7SEvalZero (connsm->conn_itvl != upd->interval) ||
2271*042d53a7SEvalZero (connsm->slave_latency != upd->latency) ||
2272*042d53a7SEvalZero (connsm->supervision_tmo != upd->timeout)) {
2273*042d53a7SEvalZero connsm->csmflags.cfbit.host_expects_upd_event = 1;
2274*042d53a7SEvalZero }
2275*042d53a7SEvalZero
2276*042d53a7SEvalZero connsm->supervision_tmo = upd->timeout;
2277*042d53a7SEvalZero connsm->slave_latency = upd->latency;
2278*042d53a7SEvalZero connsm->tx_win_size = upd->winsize;
2279*042d53a7SEvalZero connsm->slave_cur_tx_win_usecs =
2280*042d53a7SEvalZero connsm->tx_win_size * BLE_LL_CONN_TX_WIN_USECS;
2281*042d53a7SEvalZero connsm->tx_win_off = upd->winoffset;
2282*042d53a7SEvalZero connsm->conn_itvl = upd->interval;
2283*042d53a7SEvalZero ble_ll_conn_calc_itvl_ticks(connsm);
2284*042d53a7SEvalZero if (upd->winoffset != 0) {
2285*042d53a7SEvalZero usecs = upd->winoffset * BLE_LL_CONN_ITVL_USECS;
2286*042d53a7SEvalZero ticks = os_cputime_usecs_to_ticks(usecs);
2287*042d53a7SEvalZero connsm->anchor_point += ticks;
2288*042d53a7SEvalZero usecs = usecs - os_cputime_ticks_to_usecs(ticks);
2289*042d53a7SEvalZero connsm->anchor_point_usecs += usecs;
2290*042d53a7SEvalZero if (connsm->anchor_point_usecs >= 31) {
2291*042d53a7SEvalZero ++connsm->anchor_point;
2292*042d53a7SEvalZero connsm->anchor_point_usecs -= 31;
2293*042d53a7SEvalZero }
2294*042d53a7SEvalZero }
2295*042d53a7SEvalZero
2296*042d53a7SEvalZero /* Reset the starting point of the connection supervision timeout */
2297*042d53a7SEvalZero connsm->last_rxd_pdu_cputime = connsm->anchor_point;
2298*042d53a7SEvalZero
2299*042d53a7SEvalZero /* Reset update scheduled flag */
2300*042d53a7SEvalZero connsm->csmflags.cfbit.conn_update_sched = 0;
2301*042d53a7SEvalZero }
2302*042d53a7SEvalZero
2303*042d53a7SEvalZero /*
2304*042d53a7SEvalZero * If there is a channel map request pending and we have reached the
2305*042d53a7SEvalZero * instant, change to new channel map. Note there is a special case here.
2306*042d53a7SEvalZero * If we received a channel map update with an instant equal to the event
2307*042d53a7SEvalZero * counter, when we get here the event counter has already been
2308*042d53a7SEvalZero * incremented by 1. That is why we do a signed comparison and change to
2309*042d53a7SEvalZero * new channel map once the event counter equals or has passed channel
2310*042d53a7SEvalZero * map update instant.
2311*042d53a7SEvalZero */
2312*042d53a7SEvalZero if (connsm->csmflags.cfbit.chanmap_update_scheduled &&
2313*042d53a7SEvalZero ((int16_t)(connsm->chanmap_instant - connsm->event_cntr) <= 0)) {
2314*042d53a7SEvalZero
2315*042d53a7SEvalZero /* XXX: there is a chance that the control packet is still on
2316*042d53a7SEvalZero * the queue of the master. This means that we never successfully
2317*042d53a7SEvalZero * transmitted update request. Would end up killing connection
2318*042d53a7SEvalZero on slave side. Could ignore it or see if still enqueued. */
2319*042d53a7SEvalZero connsm->num_used_chans =
2320*042d53a7SEvalZero ble_ll_conn_calc_used_chans(connsm->req_chanmap);
2321*042d53a7SEvalZero memcpy(connsm->chanmap, connsm->req_chanmap, BLE_LL_CONN_CHMAP_LEN);
2322*042d53a7SEvalZero
2323*042d53a7SEvalZero connsm->csmflags.cfbit.chanmap_update_scheduled = 0;
2324*042d53a7SEvalZero
2325*042d53a7SEvalZero ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CHAN_MAP_UPD);
2326*042d53a7SEvalZero
2327*042d53a7SEvalZero /* XXX: host could have resent channel map command. Need to
2328*042d53a7SEvalZero check to make sure we dont have to restart! */
2329*042d53a7SEvalZero }
2330*042d53a7SEvalZero
2331*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
2332*042d53a7SEvalZero if (CONN_F_PHY_UPDATE_SCHED(connsm) &&
2333*042d53a7SEvalZero (connsm->event_cntr == connsm->phy_instant)) {
2334*042d53a7SEvalZero
2335*042d53a7SEvalZero /* Set cur phy to new phy */
2336*042d53a7SEvalZero if (connsm->phy_data.new_tx_phy) {
2337*042d53a7SEvalZero connsm->phy_data.cur_tx_phy = connsm->phy_data.new_tx_phy;
2338*042d53a7SEvalZero connsm->phy_data.tx_phy_mode =
2339*042d53a7SEvalZero ble_ll_phy_to_phy_mode(connsm->phy_data.cur_tx_phy,
2340*042d53a7SEvalZero connsm->phy_data.phy_options);
2341*042d53a7SEvalZero }
2342*042d53a7SEvalZero
2343*042d53a7SEvalZero if (connsm->phy_data.new_rx_phy) {
2344*042d53a7SEvalZero connsm->phy_data.cur_rx_phy = connsm->phy_data.new_rx_phy;
2345*042d53a7SEvalZero connsm->phy_data.rx_phy_mode =
2346*042d53a7SEvalZero ble_ll_phy_to_phy_mode(connsm->phy_data.cur_rx_phy,
2347*042d53a7SEvalZero connsm->phy_data.phy_options);
2348*042d53a7SEvalZero }
2349*042d53a7SEvalZero
2350*042d53a7SEvalZero /* Clear flags and set flag to send event at next instant */
2351*042d53a7SEvalZero CONN_F_PHY_UPDATE_SCHED(connsm) = 0;
2352*042d53a7SEvalZero CONN_F_PHY_UPDATE_EVENT(connsm) = 1;
2353*042d53a7SEvalZero
2354*042d53a7SEvalZero ble_ll_ctrl_phy_update_proc_complete(connsm);
2355*042d53a7SEvalZero }
2356*042d53a7SEvalZero #endif
2357*042d53a7SEvalZero
2358*042d53a7SEvalZero /* Calculate data channel index of next connection event */
2359*042d53a7SEvalZero connsm->data_chan_index = ble_ll_conn_calc_dci(connsm, latency);
2360*042d53a7SEvalZero
2361*042d53a7SEvalZero /*
2362*042d53a7SEvalZero * If we are trying to terminate connection, check if next wake time is
2363*042d53a7SEvalZero * passed the termination timeout. If so, no need to continue with
2364*042d53a7SEvalZero * connection as we will time out anyway.
2365*042d53a7SEvalZero */
2366*042d53a7SEvalZero if (CONN_F_TERMINATE_STARTED(connsm)) {
2367*042d53a7SEvalZero if ((int32_t)(connsm->terminate_timeout - connsm->anchor_point) <= 0) {
2368*042d53a7SEvalZero return -1;
2369*042d53a7SEvalZero }
2370*042d53a7SEvalZero }
2371*042d53a7SEvalZero
2372*042d53a7SEvalZero /*
2373*042d53a7SEvalZero * Calculate ce end time. For a slave, we need to add window widening and
2374*042d53a7SEvalZero * the transmit window if we still have one.
2375*042d53a7SEvalZero */
2376*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING)
2377*042d53a7SEvalZero itvl = g_ble_ll_sched_data.sch_ticks_per_period;
2378*042d53a7SEvalZero #else
2379*042d53a7SEvalZero itvl = MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT;
2380*042d53a7SEvalZero #endif
2381*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
2382*042d53a7SEvalZero cur_ww = ble_ll_conn_calc_window_widening(connsm);
2383*042d53a7SEvalZero max_ww = (connsm->conn_itvl * (BLE_LL_CONN_ITVL_USECS/2)) - BLE_LL_IFS;
2384*042d53a7SEvalZero if (cur_ww >= max_ww) {
2385*042d53a7SEvalZero return -1;
2386*042d53a7SEvalZero }
2387*042d53a7SEvalZero cur_ww += BLE_LL_JITTER_USECS;
2388*042d53a7SEvalZero connsm->slave_cur_window_widening = cur_ww;
2389*042d53a7SEvalZero itvl += os_cputime_usecs_to_ticks(cur_ww + connsm->slave_cur_tx_win_usecs);
2390*042d53a7SEvalZero }
2391*042d53a7SEvalZero itvl -= g_ble_ll_sched_offset_ticks;
2392*042d53a7SEvalZero connsm->ce_end_time = connsm->anchor_point + itvl;
2393*042d53a7SEvalZero
2394*042d53a7SEvalZero return 0;
2395*042d53a7SEvalZero }
2396*042d53a7SEvalZero
2397*042d53a7SEvalZero /**
2398*042d53a7SEvalZero * Called when a connection has been created. This function will
2399*042d53a7SEvalZero * -> Set the connection state to created.
2400*042d53a7SEvalZero * -> Start the connection supervision timer
2401*042d53a7SEvalZero * -> Set the Link Layer state to connection.
2402*042d53a7SEvalZero * -> Send a connection complete event.
2403*042d53a7SEvalZero *
2404*042d53a7SEvalZero * See Section 4.5.2 Vol 6 Part B
2405*042d53a7SEvalZero *
2406*042d53a7SEvalZero * Context: Link Layer
2407*042d53a7SEvalZero *
2408*042d53a7SEvalZero * @param connsm
2409*042d53a7SEvalZero *
2410*042d53a7SEvalZero * @ return 0: connection NOT created. 1: connection created
2411*042d53a7SEvalZero */
2412*042d53a7SEvalZero static int
ble_ll_conn_created(struct ble_ll_conn_sm * connsm,struct ble_mbuf_hdr * rxhdr)2413*042d53a7SEvalZero ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr)
2414*042d53a7SEvalZero {
2415*042d53a7SEvalZero int rc;
2416*042d53a7SEvalZero uint8_t *evbuf;
2417*042d53a7SEvalZero uint32_t endtime;
2418*042d53a7SEvalZero uint32_t usecs;
2419*042d53a7SEvalZero
2420*042d53a7SEvalZero /* XXX: TODO this assumes we received in 1M phy */
2421*042d53a7SEvalZero
2422*042d53a7SEvalZero /* Set state to created */
2423*042d53a7SEvalZero connsm->conn_state = BLE_LL_CONN_STATE_CREATED;
2424*042d53a7SEvalZero
2425*042d53a7SEvalZero /* Clear packet received flag */
2426*042d53a7SEvalZero connsm->csmflags.cfbit.pkt_rxd = 0;
2427*042d53a7SEvalZero
2428*042d53a7SEvalZero /* Consider time created the last scheduled time */
2429*042d53a7SEvalZero connsm->last_scheduled = os_cputime_get32();
2430*042d53a7SEvalZero
2431*042d53a7SEvalZero /*
2432*042d53a7SEvalZero * Set the last rxd pdu time since this is where we want to start the
2433*042d53a7SEvalZero * supervision timer from.
2434*042d53a7SEvalZero */
2435*042d53a7SEvalZero connsm->last_rxd_pdu_cputime = connsm->last_scheduled;
2436*042d53a7SEvalZero
2437*042d53a7SEvalZero /*
2438*042d53a7SEvalZero * Set first connection event time. If slave the endtime is the receive end
2439*042d53a7SEvalZero * time of the connect request. The actual connection starts 1.25 msecs plus
2440*042d53a7SEvalZero * the transmit window offset from the end of the connection request.
2441*042d53a7SEvalZero */
2442*042d53a7SEvalZero rc = 1;
2443*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
2444*042d53a7SEvalZero /*
2445*042d53a7SEvalZero * With a 32.768 kHz crystal we dont care about the remaining usecs
2446*042d53a7SEvalZero * when setting last anchor point. The only thing last anchor is used
2447*042d53a7SEvalZero * for is to calculate window widening. The effect of this is
2448*042d53a7SEvalZero * negligible.
2449*042d53a7SEvalZero */
2450*042d53a7SEvalZero connsm->last_anchor_point = rxhdr->beg_cputime;
2451*042d53a7SEvalZero
2452*042d53a7SEvalZero usecs = rxhdr->rem_usecs + 1250 +
2453*042d53a7SEvalZero (connsm->tx_win_off * BLE_LL_CONN_TX_WIN_USECS) +
2454*042d53a7SEvalZero ble_ll_pdu_tx_time_get(BLE_CONNECT_REQ_LEN,
2455*042d53a7SEvalZero rxhdr->rxinfo.phy_mode);
2456*042d53a7SEvalZero
2457*042d53a7SEvalZero if (rxhdr->rxinfo.channel < BLE_PHY_NUM_DATA_CHANS) {
2458*042d53a7SEvalZero switch (rxhdr->rxinfo.phy) {
2459*042d53a7SEvalZero case BLE_PHY_1M:
2460*042d53a7SEvalZero case BLE_PHY_2M:
2461*042d53a7SEvalZero usecs += 1250;
2462*042d53a7SEvalZero break;
2463*042d53a7SEvalZero case BLE_PHY_CODED:
2464*042d53a7SEvalZero usecs += 2500;
2465*042d53a7SEvalZero break;
2466*042d53a7SEvalZero default:
2467*042d53a7SEvalZero BLE_LL_ASSERT(0);
2468*042d53a7SEvalZero break;
2469*042d53a7SEvalZero }
2470*042d53a7SEvalZero }
2471*042d53a7SEvalZero
2472*042d53a7SEvalZero /* Anchor point is cputime. */
2473*042d53a7SEvalZero endtime = os_cputime_usecs_to_ticks(usecs);
2474*042d53a7SEvalZero connsm->anchor_point = rxhdr->beg_cputime + endtime;
2475*042d53a7SEvalZero connsm->anchor_point_usecs = usecs - os_cputime_ticks_to_usecs(endtime);
2476*042d53a7SEvalZero if (connsm->anchor_point_usecs == 31) {
2477*042d53a7SEvalZero ++connsm->anchor_point;
2478*042d53a7SEvalZero connsm->anchor_point_usecs = 0;
2479*042d53a7SEvalZero }
2480*042d53a7SEvalZero
2481*042d53a7SEvalZero connsm->slave_cur_tx_win_usecs =
2482*042d53a7SEvalZero connsm->tx_win_size * BLE_LL_CONN_TX_WIN_USECS;
2483*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING)
2484*042d53a7SEvalZero connsm->ce_end_time = connsm->anchor_point +
2485*042d53a7SEvalZero g_ble_ll_sched_data.sch_ticks_per_period +
2486*042d53a7SEvalZero os_cputime_usecs_to_ticks(connsm->slave_cur_tx_win_usecs) + 1;
2487*042d53a7SEvalZero
2488*042d53a7SEvalZero #else
2489*042d53a7SEvalZero connsm->ce_end_time = connsm->anchor_point +
2490*042d53a7SEvalZero (MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT)
2491*042d53a7SEvalZero + os_cputime_usecs_to_ticks(connsm->slave_cur_tx_win_usecs) + 1;
2492*042d53a7SEvalZero #endif
2493*042d53a7SEvalZero connsm->slave_cur_window_widening = BLE_LL_JITTER_USECS;
2494*042d53a7SEvalZero
2495*042d53a7SEvalZero /* Start the scheduler for the first connection event */
2496*042d53a7SEvalZero while (ble_ll_sched_slave_new(connsm)) {
2497*042d53a7SEvalZero if (ble_ll_conn_next_event(connsm)) {
2498*042d53a7SEvalZero STATS_INC(ble_ll_conn_stats, cant_set_sched);
2499*042d53a7SEvalZero rc = 0;
2500*042d53a7SEvalZero break;
2501*042d53a7SEvalZero }
2502*042d53a7SEvalZero }
2503*042d53a7SEvalZero }
2504*042d53a7SEvalZero
2505*042d53a7SEvalZero /* Send connection complete event to inform host of connection */
2506*042d53a7SEvalZero if (rc) {
2507*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
2508*042d53a7SEvalZero /*
2509*042d53a7SEvalZero * If we have default phy preferences and they are different than
2510*042d53a7SEvalZero * the current PHY's in use, start update procedure.
2511*042d53a7SEvalZero */
2512*042d53a7SEvalZero /*
2513*042d53a7SEvalZero * XXX: should we attempt to start this without knowing if
2514*042d53a7SEvalZero * the other side can support it?
2515*042d53a7SEvalZero */
2516*042d53a7SEvalZero if (!ble_ll_conn_chk_phy_upd_start(connsm)) {
2517*042d53a7SEvalZero CONN_F_CTRLR_PHY_UPDATE(connsm) = 1;
2518*042d53a7SEvalZero }
2519*042d53a7SEvalZero #endif
2520*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
2521*042d53a7SEvalZero ble_ll_adv_send_conn_comp_ev(connsm, rxhdr);
2522*042d53a7SEvalZero } else {
2523*042d53a7SEvalZero evbuf = ble_ll_init_get_conn_comp_ev();
2524*042d53a7SEvalZero ble_ll_conn_comp_event_send(connsm, BLE_ERR_SUCCESS, evbuf, NULL);
2525*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) == 1)
2526*042d53a7SEvalZero ble_ll_hci_ev_le_csa(connsm);
2527*042d53a7SEvalZero #endif
2528*042d53a7SEvalZero
2529*042d53a7SEvalZero /*
2530*042d53a7SEvalZero * Initiate features exchange
2531*042d53a7SEvalZero *
2532*042d53a7SEvalZero * XXX we do this only as a master as it was observed that sending
2533*042d53a7SEvalZero * LL_SLAVE_FEATURE_REQ after connection breaks some recent iPhone
2534*042d53a7SEvalZero * models; for slave just assume master will initiate features xchg
2535*042d53a7SEvalZero * if it has some additional features to use.
2536*042d53a7SEvalZero */
2537*042d53a7SEvalZero ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG);
2538*042d53a7SEvalZero }
2539*042d53a7SEvalZero }
2540*042d53a7SEvalZero
2541*042d53a7SEvalZero return rc;
2542*042d53a7SEvalZero }
2543*042d53a7SEvalZero
2544*042d53a7SEvalZero /**
2545*042d53a7SEvalZero * Called upon end of connection event
2546*042d53a7SEvalZero *
2547*042d53a7SEvalZero * Context: Link-layer task
2548*042d53a7SEvalZero *
2549*042d53a7SEvalZero * @param void *arg Pointer to connection state machine
2550*042d53a7SEvalZero *
2551*042d53a7SEvalZero */
2552*042d53a7SEvalZero static void
ble_ll_conn_event_end(struct ble_npl_event * ev)2553*042d53a7SEvalZero ble_ll_conn_event_end(struct ble_npl_event *ev)
2554*042d53a7SEvalZero {
2555*042d53a7SEvalZero uint8_t ble_err;
2556*042d53a7SEvalZero uint32_t tmo;
2557*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
2558*042d53a7SEvalZero
2559*042d53a7SEvalZero /* Better be a connection state machine! */
2560*042d53a7SEvalZero connsm = (struct ble_ll_conn_sm *)ble_npl_event_get_arg(ev);
2561*042d53a7SEvalZero BLE_LL_ASSERT(connsm);
2562*042d53a7SEvalZero
2563*042d53a7SEvalZero /* Log event end */
2564*042d53a7SEvalZero ble_ll_trace_u32x2(BLE_LL_TRACE_ID_CONN_EV_END, connsm->conn_handle,
2565*042d53a7SEvalZero connsm->event_cntr);
2566*042d53a7SEvalZero
2567*042d53a7SEvalZero /* Check if we need to resume scanning */
2568*042d53a7SEvalZero ble_ll_scan_chk_resume();
2569*042d53a7SEvalZero
2570*042d53a7SEvalZero #ifdef BLE_XCVR_RFCLK
2571*042d53a7SEvalZero ble_ll_sched_rfclk_chk_restart();
2572*042d53a7SEvalZero #endif
2573*042d53a7SEvalZero
2574*042d53a7SEvalZero /* If we have transmitted the terminate IND successfully, we are done */
2575*042d53a7SEvalZero if ((connsm->csmflags.cfbit.terminate_ind_txd) ||
2576*042d53a7SEvalZero (connsm->csmflags.cfbit.terminate_ind_rxd)) {
2577*042d53a7SEvalZero if (connsm->csmflags.cfbit.terminate_ind_txd) {
2578*042d53a7SEvalZero ble_err = BLE_ERR_CONN_TERM_LOCAL;
2579*042d53a7SEvalZero } else {
2580*042d53a7SEvalZero /* Make sure the disconnect reason is valid! */
2581*042d53a7SEvalZero ble_err = connsm->rxd_disconnect_reason;
2582*042d53a7SEvalZero if (ble_err == 0) {
2583*042d53a7SEvalZero ble_err = BLE_ERR_REM_USER_CONN_TERM;
2584*042d53a7SEvalZero }
2585*042d53a7SEvalZero }
2586*042d53a7SEvalZero ble_ll_conn_end(connsm, ble_err);
2587*042d53a7SEvalZero return;
2588*042d53a7SEvalZero }
2589*042d53a7SEvalZero
2590*042d53a7SEvalZero /* Remove any connection end events that might be enqueued */
2591*042d53a7SEvalZero ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &connsm->conn_ev_end);
2592*042d53a7SEvalZero
2593*042d53a7SEvalZero /*
2594*042d53a7SEvalZero * If we have received a packet, we can set the current transmit window
2595*042d53a7SEvalZero * usecs to 0 since we dont need to listen in the transmit window.
2596*042d53a7SEvalZero */
2597*042d53a7SEvalZero if (connsm->csmflags.cfbit.pkt_rxd) {
2598*042d53a7SEvalZero connsm->slave_cur_tx_win_usecs = 0;
2599*042d53a7SEvalZero }
2600*042d53a7SEvalZero
2601*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING)
2602*042d53a7SEvalZero /*
2603*042d53a7SEvalZero * If we are encrypted and have passed the authenticated payload timeout
2604*042d53a7SEvalZero * we need to send an event to tell the host. Unfortunately, I think we
2605*042d53a7SEvalZero * need one of these per connection and we have to set this timer
2606*042d53a7SEvalZero * fairly accurately. So we need to another event in the connection.
2607*042d53a7SEvalZero * This sucks.
2608*042d53a7SEvalZero *
2609*042d53a7SEvalZero * The way this works is that whenever the timer expires it just gets reset
2610*042d53a7SEvalZero * and we send the autheticated payload timeout event. Note that this timer
2611*042d53a7SEvalZero * should run even when encryption is paused.
2612*042d53a7SEvalZero * XXX: what should be here? Was there code here that got deleted?
2613*042d53a7SEvalZero */
2614*042d53a7SEvalZero #endif
2615*042d53a7SEvalZero
2616*042d53a7SEvalZero /* Move to next connection event */
2617*042d53a7SEvalZero if (ble_ll_conn_next_event(connsm)) {
2618*042d53a7SEvalZero ble_ll_conn_end(connsm, BLE_ERR_CONN_TERM_LOCAL);
2619*042d53a7SEvalZero return;
2620*042d53a7SEvalZero }
2621*042d53a7SEvalZero
2622*042d53a7SEvalZero /* Reset "per connection event" variables */
2623*042d53a7SEvalZero connsm->cons_rxd_bad_crc = 0;
2624*042d53a7SEvalZero connsm->csmflags.cfbit.pkt_rxd = 0;
2625*042d53a7SEvalZero
2626*042d53a7SEvalZero /* See if we need to start any control procedures */
2627*042d53a7SEvalZero ble_ll_ctrl_chk_proc_start(connsm);
2628*042d53a7SEvalZero
2629*042d53a7SEvalZero /* Set initial schedule callback */
2630*042d53a7SEvalZero connsm->conn_sch.sched_cb = ble_ll_conn_event_start_cb;
2631*042d53a7SEvalZero
2632*042d53a7SEvalZero /* XXX: I think all this fine for when we do connection updates, but
2633*042d53a7SEvalZero we may want to force the first event to be scheduled. Not sure */
2634*042d53a7SEvalZero /* Schedule the next connection event */
2635*042d53a7SEvalZero while (ble_ll_sched_conn_reschedule(connsm)) {
2636*042d53a7SEvalZero if (ble_ll_conn_next_event(connsm)) {
2637*042d53a7SEvalZero ble_ll_conn_end(connsm, BLE_ERR_CONN_TERM_LOCAL);
2638*042d53a7SEvalZero return;
2639*042d53a7SEvalZero }
2640*042d53a7SEvalZero }
2641*042d53a7SEvalZero
2642*042d53a7SEvalZero /*
2643*042d53a7SEvalZero * This is definitely not perfect but hopefully will be fine in regards to
2644*042d53a7SEvalZero * the specification. We check the supervision timer at connection event
2645*042d53a7SEvalZero * end. If the next connection event is going to start past the supervision
2646*042d53a7SEvalZero * timeout we end the connection here. I guess this goes against the spec
2647*042d53a7SEvalZero * in two ways:
2648*042d53a7SEvalZero * 1) We are actually causing a supervision timeout before the time
2649*042d53a7SEvalZero * specified. However, this is really a moot point because the supervision
2650*042d53a7SEvalZero * timeout would have expired before we could possibly receive a packet.
2651*042d53a7SEvalZero * 2) We may end the supervision timeout a bit later than specified as
2652*042d53a7SEvalZero * we only check this at event end and a bad CRC could cause us to continue
2653*042d53a7SEvalZero * the connection event longer than the supervision timeout. Given that two
2654*042d53a7SEvalZero * bad CRC's consecutively ends the connection event, I dont regard this as
2655*042d53a7SEvalZero * a big deal but it could cause a slightly longer supervision timeout.
2656*042d53a7SEvalZero */
2657*042d53a7SEvalZero if (connsm->conn_state == BLE_LL_CONN_STATE_CREATED) {
2658*042d53a7SEvalZero tmo = (uint32_t)connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS * 6UL;
2659*042d53a7SEvalZero ble_err = BLE_ERR_CONN_ESTABLISHMENT;
2660*042d53a7SEvalZero } else {
2661*042d53a7SEvalZero tmo = connsm->supervision_tmo * BLE_HCI_CONN_SPVN_TMO_UNITS * 1000UL;
2662*042d53a7SEvalZero ble_err = BLE_ERR_CONN_SPVN_TMO;
2663*042d53a7SEvalZero }
2664*042d53a7SEvalZero /* XXX: Convert to ticks to usecs calculation instead??? */
2665*042d53a7SEvalZero tmo = os_cputime_usecs_to_ticks(tmo);
2666*042d53a7SEvalZero if ((int32_t)(connsm->anchor_point - connsm->last_rxd_pdu_cputime) >= tmo) {
2667*042d53a7SEvalZero ble_ll_conn_end(connsm, ble_err);
2668*042d53a7SEvalZero return;
2669*042d53a7SEvalZero }
2670*042d53a7SEvalZero
2671*042d53a7SEvalZero /* If we have completed packets, send an event */
2672*042d53a7SEvalZero ble_ll_conn_num_comp_pkts_event_send(connsm);
2673*042d53a7SEvalZero
2674*042d53a7SEvalZero /* If we have features and there's pending HCI command, send an event */
2675*042d53a7SEvalZero if (connsm->csmflags.cfbit.pending_hci_rd_features &&
2676*042d53a7SEvalZero connsm->csmflags.cfbit.rxd_features) {
2677*042d53a7SEvalZero ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_SUCCESS);
2678*042d53a7SEvalZero connsm->csmflags.cfbit.pending_hci_rd_features = 0;
2679*042d53a7SEvalZero }
2680*042d53a7SEvalZero }
2681*042d53a7SEvalZero
2682*042d53a7SEvalZero /**
2683*042d53a7SEvalZero * Update the connection request PDU with the address type and address of
2684*042d53a7SEvalZero * advertiser we are going to send connect request to.
2685*042d53a7SEvalZero *
2686*042d53a7SEvalZero * @param m
2687*042d53a7SEvalZero * @param adva
2688*042d53a7SEvalZero * @param addr_type Address type of ADVA from received advertisement.
2689*042d53a7SEvalZero * @param inita
2690*042d53a7SEvalZero * @param inita_type Address type of INITA from received advertisement.
2691*042d53a7SEvalZero
2692*042d53a7SEvalZero * @param txoffset The tx window offset for this connection
2693*042d53a7SEvalZero */
2694*042d53a7SEvalZero static void
ble_ll_conn_req_pdu_update(struct os_mbuf * m,uint8_t * adva,uint8_t addr_type,uint8_t * inita,uint8_t inita_type,uint16_t txoffset,int rpa_index)2695*042d53a7SEvalZero ble_ll_conn_req_pdu_update(struct os_mbuf *m, uint8_t *adva, uint8_t addr_type,
2696*042d53a7SEvalZero uint8_t *inita, uint8_t inita_type,
2697*042d53a7SEvalZero uint16_t txoffset, int rpa_index)
2698*042d53a7SEvalZero {
2699*042d53a7SEvalZero uint8_t hdr;
2700*042d53a7SEvalZero uint8_t *dptr;
2701*042d53a7SEvalZero uint8_t *addr;
2702*042d53a7SEvalZero struct ble_mbuf_hdr *ble_hdr;
2703*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
2704*042d53a7SEvalZero
2705*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
2706*042d53a7SEvalZero int is_rpa;
2707*042d53a7SEvalZero struct ble_ll_resolv_entry *rl;
2708*042d53a7SEvalZero #endif
2709*042d53a7SEvalZero
2710*042d53a7SEvalZero BLE_LL_ASSERT(m != NULL);
2711*042d53a7SEvalZero
2712*042d53a7SEvalZero /* clear txadd/rxadd bits only */
2713*042d53a7SEvalZero ble_hdr = BLE_MBUF_HDR_PTR(m);
2714*042d53a7SEvalZero hdr = ble_hdr->txinfo.hdr_byte &
2715*042d53a7SEvalZero ~(BLE_ADV_PDU_HDR_RXADD_MASK | BLE_ADV_PDU_HDR_TXADD_MASK);
2716*042d53a7SEvalZero
2717*042d53a7SEvalZero if (addr_type) {
2718*042d53a7SEvalZero /* Set random address */
2719*042d53a7SEvalZero hdr |= BLE_ADV_PDU_HDR_RXADD_MASK;
2720*042d53a7SEvalZero }
2721*042d53a7SEvalZero
2722*042d53a7SEvalZero dptr = m->om_data;
2723*042d53a7SEvalZero
2724*042d53a7SEvalZero if (inita) {
2725*042d53a7SEvalZero memcpy(dptr, inita, BLE_DEV_ADDR_LEN);
2726*042d53a7SEvalZero if (inita_type) {
2727*042d53a7SEvalZero hdr |= BLE_ADV_PDU_HDR_TXADD_RAND;
2728*042d53a7SEvalZero }
2729*042d53a7SEvalZero } else {
2730*042d53a7SEvalZero /* Get pointer to our device address */
2731*042d53a7SEvalZero connsm = g_ble_ll_conn_create_sm;
2732*042d53a7SEvalZero if ((connsm->own_addr_type & 1) == 0) {
2733*042d53a7SEvalZero addr = g_dev_addr;
2734*042d53a7SEvalZero } else {
2735*042d53a7SEvalZero hdr |= BLE_ADV_PDU_HDR_TXADD_RAND;
2736*042d53a7SEvalZero addr = g_random_addr;
2737*042d53a7SEvalZero }
2738*042d53a7SEvalZero
2739*042d53a7SEvalZero /* XXX: do this ahead of time? Calculate the local rpa I mean */
2740*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
2741*042d53a7SEvalZero if (connsm->own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) {
2742*042d53a7SEvalZero rl = NULL;
2743*042d53a7SEvalZero is_rpa = ble_ll_is_rpa(adva, addr_type);
2744*042d53a7SEvalZero if (is_rpa) {
2745*042d53a7SEvalZero if (rpa_index >= 0) {
2746*042d53a7SEvalZero rl = &g_ble_ll_resolv_list[rpa_index];
2747*042d53a7SEvalZero }
2748*042d53a7SEvalZero } else {
2749*042d53a7SEvalZero if (ble_ll_resolv_enabled()) {
2750*042d53a7SEvalZero rl = ble_ll_resolv_list_find(adva, addr_type);
2751*042d53a7SEvalZero }
2752*042d53a7SEvalZero }
2753*042d53a7SEvalZero
2754*042d53a7SEvalZero /*
2755*042d53a7SEvalZero * If peer in on resolving list, we use RPA generated with Local IRK
2756*042d53a7SEvalZero * from resolving list entry. In other case, we need to use our identity
2757*042d53a7SEvalZero * address (see Core 5.0, Vol 6, Part B, section 6.4).
2758*042d53a7SEvalZero */
2759*042d53a7SEvalZero if (rl) {
2760*042d53a7SEvalZero hdr |= BLE_ADV_PDU_HDR_TXADD_RAND;
2761*042d53a7SEvalZero ble_ll_resolv_get_priv_addr(rl, 1, dptr);
2762*042d53a7SEvalZero addr = NULL;
2763*042d53a7SEvalZero }
2764*042d53a7SEvalZero }
2765*042d53a7SEvalZero #endif
2766*042d53a7SEvalZero
2767*042d53a7SEvalZero if (addr) {
2768*042d53a7SEvalZero memcpy(dptr, addr, BLE_DEV_ADDR_LEN);
2769*042d53a7SEvalZero }
2770*042d53a7SEvalZero }
2771*042d53a7SEvalZero
2772*042d53a7SEvalZero memcpy(dptr + BLE_DEV_ADDR_LEN, adva, BLE_DEV_ADDR_LEN);
2773*042d53a7SEvalZero put_le16(dptr + 20, txoffset);
2774*042d53a7SEvalZero
2775*042d53a7SEvalZero /* Set BLE transmit header */
2776*042d53a7SEvalZero ble_hdr->txinfo.hdr_byte = hdr;
2777*042d53a7SEvalZero }
2778*042d53a7SEvalZero
2779*042d53a7SEvalZero /* Returns true if the address matches the connection peer address having in
2780*042d53a7SEvalZero * mind privacy mode
2781*042d53a7SEvalZero */
2782*042d53a7SEvalZero static int
ble_ll_conn_is_peer_adv(uint8_t addr_type,uint8_t * adva,int index)2783*042d53a7SEvalZero ble_ll_conn_is_peer_adv(uint8_t addr_type, uint8_t *adva, int index)
2784*042d53a7SEvalZero {
2785*042d53a7SEvalZero int rc;
2786*042d53a7SEvalZero uint8_t *peer_addr;
2787*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
2788*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
2789*042d53a7SEvalZero struct ble_ll_resolv_entry *rl;
2790*042d53a7SEvalZero #endif
2791*042d53a7SEvalZero
2792*042d53a7SEvalZero /* XXX: Deal with different types of random addresses here! */
2793*042d53a7SEvalZero connsm = g_ble_ll_conn_create_sm;
2794*042d53a7SEvalZero if (!connsm) {
2795*042d53a7SEvalZero return 0;
2796*042d53a7SEvalZero }
2797*042d53a7SEvalZero
2798*042d53a7SEvalZero switch (connsm->peer_addr_type) {
2799*042d53a7SEvalZero /* Fall-through intentional */
2800*042d53a7SEvalZero case BLE_HCI_CONN_PEER_ADDR_PUBLIC:
2801*042d53a7SEvalZero case BLE_HCI_CONN_PEER_ADDR_RANDOM:
2802*042d53a7SEvalZero if (addr_type == connsm->peer_addr_type) {
2803*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
2804*042d53a7SEvalZero /* Peer uses its identity address. Let's verify privacy mode.
2805*042d53a7SEvalZero *
2806*042d53a7SEvalZero * Note: Core Spec 5.0 Vol 6, Part B
2807*042d53a7SEvalZero * If the Host has added the peer device to the resolving list
2808*042d53a7SEvalZero * with an all-zero peer IRK, the Controller shall only accept
2809*042d53a7SEvalZero * the peer's identity address.
2810*042d53a7SEvalZero */
2811*042d53a7SEvalZero if (ble_ll_resolv_enabled()) {
2812*042d53a7SEvalZero rl = ble_ll_resolv_list_find(adva, addr_type);
2813*042d53a7SEvalZero if (rl && (rl->rl_priv_mode == BLE_HCI_PRIVACY_NETWORK) &&
2814*042d53a7SEvalZero ble_ll_resolv_irk_nonzero(rl->rl_peer_irk)) {
2815*042d53a7SEvalZero return 0;
2816*042d53a7SEvalZero }
2817*042d53a7SEvalZero }
2818*042d53a7SEvalZero #endif
2819*042d53a7SEvalZero peer_addr = adva;
2820*042d53a7SEvalZero break;
2821*042d53a7SEvalZero }
2822*042d53a7SEvalZero
2823*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
2824*042d53a7SEvalZero /* Check if peer uses RPA. If so and it match, use it as controller
2825*042d53a7SEvalZero * supports privacy mode
2826*042d53a7SEvalZero */
2827*042d53a7SEvalZero if ((index < 0) ||
2828*042d53a7SEvalZero (g_ble_ll_resolv_list[index].rl_addr_type != connsm->peer_addr_type)) {
2829*042d53a7SEvalZero return 0;
2830*042d53a7SEvalZero }
2831*042d53a7SEvalZero
2832*042d53a7SEvalZero peer_addr = g_ble_ll_resolv_list[index].rl_identity_addr;
2833*042d53a7SEvalZero
2834*042d53a7SEvalZero break;
2835*042d53a7SEvalZero case BLE_HCI_CONN_PEER_ADDR_PUBLIC_IDENT:
2836*042d53a7SEvalZero if ((index < 0) ||
2837*042d53a7SEvalZero (g_ble_ll_resolv_list[index].rl_addr_type != 0)) {
2838*042d53a7SEvalZero return 0;
2839*042d53a7SEvalZero }
2840*042d53a7SEvalZero peer_addr = g_ble_ll_resolv_list[index].rl_identity_addr;
2841*042d53a7SEvalZero break;
2842*042d53a7SEvalZero case BLE_HCI_CONN_PEER_ADDR_RANDOM_IDENT:
2843*042d53a7SEvalZero if ((index < 0) ||
2844*042d53a7SEvalZero (g_ble_ll_resolv_list[index].rl_addr_type != 1)) {
2845*042d53a7SEvalZero return 0;
2846*042d53a7SEvalZero }
2847*042d53a7SEvalZero peer_addr = g_ble_ll_resolv_list[index].rl_identity_addr;
2848*042d53a7SEvalZero break;
2849*042d53a7SEvalZero #endif
2850*042d53a7SEvalZero default:
2851*042d53a7SEvalZero peer_addr = NULL;
2852*042d53a7SEvalZero break;
2853*042d53a7SEvalZero }
2854*042d53a7SEvalZero
2855*042d53a7SEvalZero rc = 0;
2856*042d53a7SEvalZero if (peer_addr) {
2857*042d53a7SEvalZero if (!memcmp(peer_addr, connsm->peer_addr, BLE_DEV_ADDR_LEN)) {
2858*042d53a7SEvalZero rc = 1;
2859*042d53a7SEvalZero }
2860*042d53a7SEvalZero }
2861*042d53a7SEvalZero
2862*042d53a7SEvalZero return rc;
2863*042d53a7SEvalZero }
2864*042d53a7SEvalZero
2865*042d53a7SEvalZero /**
2866*042d53a7SEvalZero * Called when a connect request transmission is done.
2867*042d53a7SEvalZero *
2868*042d53a7SEvalZero * Context: ISR
2869*042d53a7SEvalZero *
2870*042d53a7SEvalZero * @param arg
2871*042d53a7SEvalZero */
2872*042d53a7SEvalZero static void
ble_ll_conn_req_txend(void * arg)2873*042d53a7SEvalZero ble_ll_conn_req_txend(void *arg)
2874*042d53a7SEvalZero {
2875*042d53a7SEvalZero ble_ll_state_set(BLE_LL_STATE_STANDBY);
2876*042d53a7SEvalZero }
2877*042d53a7SEvalZero
2878*042d53a7SEvalZero static void
ble_ll_conn_req_txend_init(void * arg)2879*042d53a7SEvalZero ble_ll_conn_req_txend_init(void *arg)
2880*042d53a7SEvalZero {
2881*042d53a7SEvalZero ble_ll_state_set(BLE_LL_STATE_INITIATING);
2882*042d53a7SEvalZero }
2883*042d53a7SEvalZero /**
2884*042d53a7SEvalZero * Send a connection requestion to an advertiser
2885*042d53a7SEvalZero *
2886*042d53a7SEvalZero * Context: Interrupt
2887*042d53a7SEvalZero *
2888*042d53a7SEvalZero * @param addr_type Address type of advertiser
2889*042d53a7SEvalZero * @param adva Address of advertiser
2890*042d53a7SEvalZero */
2891*042d53a7SEvalZero int
ble_ll_conn_request_send(uint8_t addr_type,uint8_t * adva,uint8_t inita_type,uint8_t * inita,uint16_t txoffset,int rpa_index,uint8_t end_trans)2892*042d53a7SEvalZero ble_ll_conn_request_send(uint8_t addr_type, uint8_t *adva,
2893*042d53a7SEvalZero uint8_t inita_type, uint8_t *inita,
2894*042d53a7SEvalZero uint16_t txoffset,
2895*042d53a7SEvalZero int rpa_index, uint8_t end_trans)
2896*042d53a7SEvalZero {
2897*042d53a7SEvalZero struct os_mbuf *m;
2898*042d53a7SEvalZero int rc;
2899*042d53a7SEvalZero
2900*042d53a7SEvalZero /* XXX: TODO: assume we are already on correct phy */
2901*042d53a7SEvalZero m = ble_ll_scan_get_pdu();
2902*042d53a7SEvalZero ble_ll_conn_req_pdu_update(m, adva, addr_type, inita, inita_type,
2903*042d53a7SEvalZero txoffset, rpa_index);
2904*042d53a7SEvalZero if (end_trans == BLE_PHY_TRANSITION_NONE) {
2905*042d53a7SEvalZero ble_phy_set_txend_cb(ble_ll_conn_req_txend, NULL);
2906*042d53a7SEvalZero } else {
2907*042d53a7SEvalZero ble_phy_set_txend_cb(ble_ll_conn_req_txend_init, NULL);
2908*042d53a7SEvalZero }
2909*042d53a7SEvalZero rc = ble_phy_tx(ble_ll_tx_flat_mbuf_pducb, m, end_trans);
2910*042d53a7SEvalZero return rc;
2911*042d53a7SEvalZero }
2912*042d53a7SEvalZero
2913*042d53a7SEvalZero /**
2914*042d53a7SEvalZero * Called when a schedule item overlaps the currently running connection
2915*042d53a7SEvalZero * event. This generally should not happen, but if it does we stop the
2916*042d53a7SEvalZero * current connection event to let the schedule item run.
2917*042d53a7SEvalZero *
2918*042d53a7SEvalZero * NOTE: the phy has been disabled as well as the wfr timer before this is
2919*042d53a7SEvalZero * called.
2920*042d53a7SEvalZero */
2921*042d53a7SEvalZero void
ble_ll_conn_event_halt(void)2922*042d53a7SEvalZero ble_ll_conn_event_halt(void)
2923*042d53a7SEvalZero {
2924*042d53a7SEvalZero ble_ll_state_set(BLE_LL_STATE_STANDBY);
2925*042d53a7SEvalZero if (g_ble_ll_conn_cur_sm) {
2926*042d53a7SEvalZero g_ble_ll_conn_cur_sm->csmflags.cfbit.pkt_rxd = 0;
2927*042d53a7SEvalZero ble_ll_event_send(&g_ble_ll_conn_cur_sm->conn_ev_end);
2928*042d53a7SEvalZero g_ble_ll_conn_cur_sm = NULL;
2929*042d53a7SEvalZero }
2930*042d53a7SEvalZero }
2931*042d53a7SEvalZero
2932*042d53a7SEvalZero /**
2933*042d53a7SEvalZero * Process a received PDU while in the initiating state.
2934*042d53a7SEvalZero *
2935*042d53a7SEvalZero * Context: Link Layer task.
2936*042d53a7SEvalZero *
2937*042d53a7SEvalZero * @param pdu_type
2938*042d53a7SEvalZero * @param rxbuf
2939*042d53a7SEvalZero * @param ble_hdr
2940*042d53a7SEvalZero */
2941*042d53a7SEvalZero void
ble_ll_init_rx_pkt_in(uint8_t pdu_type,uint8_t * rxbuf,struct ble_mbuf_hdr * ble_hdr)2942*042d53a7SEvalZero ble_ll_init_rx_pkt_in(uint8_t pdu_type, uint8_t *rxbuf,
2943*042d53a7SEvalZero struct ble_mbuf_hdr *ble_hdr)
2944*042d53a7SEvalZero {
2945*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
2946*042d53a7SEvalZero int8_t rpa_index;
2947*042d53a7SEvalZero #endif
2948*042d53a7SEvalZero uint8_t addr_type;
2949*042d53a7SEvalZero uint8_t *addr;
2950*042d53a7SEvalZero uint8_t *adv_addr;
2951*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
2952*042d53a7SEvalZero int ext_adv_mode = -1;
2953*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2954*042d53a7SEvalZero struct ble_ll_aux_data *aux_data = ble_hdr->rxinfo.user_data;
2955*042d53a7SEvalZero
2956*042d53a7SEvalZero /*
2957*042d53a7SEvalZero * Let's take the reference for handover to LL.
2958*042d53a7SEvalZero * There shall be one more, if not something went very wrong
2959*042d53a7SEvalZero */
2960*042d53a7SEvalZero if (aux_data && !ble_ll_scan_aux_data_unref(aux_data)) {
2961*042d53a7SEvalZero BLE_LL_ASSERT(0);
2962*042d53a7SEvalZero }
2963*042d53a7SEvalZero
2964*042d53a7SEvalZero #endif
2965*042d53a7SEvalZero
2966*042d53a7SEvalZero /* Get the connection state machine we are trying to create */
2967*042d53a7SEvalZero connsm = g_ble_ll_conn_create_sm;
2968*042d53a7SEvalZero if (!connsm) {
2969*042d53a7SEvalZero return;
2970*042d53a7SEvalZero }
2971*042d53a7SEvalZero
2972*042d53a7SEvalZero if (!BLE_MBUF_HDR_CRC_OK(ble_hdr)) {
2973*042d53a7SEvalZero goto scan_continue;
2974*042d53a7SEvalZero }
2975*042d53a7SEvalZero
2976*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2977*042d53a7SEvalZero if (BLE_MBUF_HDR_AUX_INVALID(ble_hdr)) {
2978*042d53a7SEvalZero goto scan_continue;
2979*042d53a7SEvalZero }
2980*042d53a7SEvalZero
2981*042d53a7SEvalZero if (pdu_type == BLE_ADV_PDU_TYPE_ADV_EXT_IND) {
2982*042d53a7SEvalZero if (BLE_MBUF_HDR_WAIT_AUX(ble_hdr)) {
2983*042d53a7SEvalZero /* Just continue scanning. We are waiting for AUX */
2984*042d53a7SEvalZero if (!ble_ll_sched_aux_scan(ble_hdr, connsm->scansm, aux_data)) {
2985*042d53a7SEvalZero ble_ll_scan_aux_data_ref(aux_data);
2986*042d53a7SEvalZero ble_ll_scan_chk_resume();
2987*042d53a7SEvalZero return;
2988*042d53a7SEvalZero }
2989*042d53a7SEvalZero goto scan_continue;
2990*042d53a7SEvalZero }
2991*042d53a7SEvalZero }
2992*042d53a7SEvalZero
2993*042d53a7SEvalZero if (CONN_F_AUX_CONN_REQ(connsm)) {
2994*042d53a7SEvalZero /* Wait for connection response */
2995*042d53a7SEvalZero if (pdu_type != BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP) {
2996*042d53a7SEvalZero return;
2997*042d53a7SEvalZero }
2998*042d53a7SEvalZero }
2999*042d53a7SEvalZero #endif
3000*042d53a7SEvalZero
3001*042d53a7SEvalZero /* If we have sent a connect request, we need to enter CONNECTION state */
3002*042d53a7SEvalZero if (connsm && CONN_F_CONN_REQ_TXD(connsm)) {
3003*042d53a7SEvalZero /* Set address of advertiser to which we are connecting. */
3004*042d53a7SEvalZero
3005*042d53a7SEvalZero if (ble_ll_scan_adv_decode_addr(pdu_type, rxbuf, ble_hdr,
3006*042d53a7SEvalZero &adv_addr, &addr_type,
3007*042d53a7SEvalZero NULL, NULL, &ext_adv_mode)) {
3008*042d53a7SEvalZero /* Something got wrong, keep trying to connect */
3009*042d53a7SEvalZero goto scan_continue;
3010*042d53a7SEvalZero }
3011*042d53a7SEvalZero
3012*042d53a7SEvalZero if (ble_ll_scan_whitelist_enabled()) {
3013*042d53a7SEvalZero
3014*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
3015*042d53a7SEvalZero /*
3016*042d53a7SEvalZero * Did we resolve this address? If so, set correct peer address
3017*042d53a7SEvalZero * and peer address type.
3018*042d53a7SEvalZero */
3019*042d53a7SEvalZero rpa_index = connsm->rpa_index;
3020*042d53a7SEvalZero
3021*042d53a7SEvalZero if (rpa_index >= 0) {
3022*042d53a7SEvalZero addr_type = g_ble_ll_resolv_list[rpa_index].rl_addr_type + 2;
3023*042d53a7SEvalZero addr = g_ble_ll_resolv_list[rpa_index].rl_identity_addr;
3024*042d53a7SEvalZero } else {
3025*042d53a7SEvalZero addr = adv_addr;
3026*042d53a7SEvalZero }
3027*042d53a7SEvalZero #else
3028*042d53a7SEvalZero addr = adv_addr;
3029*042d53a7SEvalZero #endif
3030*042d53a7SEvalZero
3031*042d53a7SEvalZero connsm->peer_addr_type = addr_type;
3032*042d53a7SEvalZero memcpy(connsm->peer_addr, addr, BLE_DEV_ADDR_LEN);
3033*042d53a7SEvalZero }
3034*042d53a7SEvalZero
3035*042d53a7SEvalZero if (connsm->rpa_index >= 0) {
3036*042d53a7SEvalZero ble_ll_scan_set_peer_rpa(rxbuf + BLE_LL_PDU_HDR_LEN);
3037*042d53a7SEvalZero
3038*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
3039*042d53a7SEvalZero /* Update resolving list with current peer RPA */
3040*042d53a7SEvalZero ble_ll_resolv_set_peer_rpa(connsm->rpa_index, rxbuf + BLE_LL_PDU_HDR_LEN);
3041*042d53a7SEvalZero #endif
3042*042d53a7SEvalZero }
3043*042d53a7SEvalZero
3044*042d53a7SEvalZero /* Connection has been created. Stop scanning */
3045*042d53a7SEvalZero g_ble_ll_conn_create_sm = NULL;
3046*042d53a7SEvalZero ble_ll_scan_sm_stop(0);
3047*042d53a7SEvalZero
3048*042d53a7SEvalZero /* For AUX Connect CSA2 is mandatory. Otherwise we need to check bit
3049*042d53a7SEvalZero * mask
3050*042d53a7SEvalZero */
3051*042d53a7SEvalZero if (ble_hdr->rxinfo.channel < BLE_PHY_NUM_DATA_CHANS) {
3052*042d53a7SEvalZero ble_ll_conn_set_csa(connsm, 1);
3053*042d53a7SEvalZero } else {
3054*042d53a7SEvalZero ble_ll_conn_set_csa(connsm, rxbuf[0] & BLE_ADV_PDU_HDR_CHSEL_MASK);
3055*042d53a7SEvalZero }
3056*042d53a7SEvalZero
3057*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3058*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
3059*042d53a7SEvalZero /* Lets take last used phy */
3060*042d53a7SEvalZero ble_ll_conn_init_phy(connsm, ble_hdr->rxinfo.phy);
3061*042d53a7SEvalZero #endif
3062*042d53a7SEvalZero ble_ll_scan_aux_data_unref(aux_data);
3063*042d53a7SEvalZero #endif
3064*042d53a7SEvalZero ble_ll_conn_created(connsm, NULL);
3065*042d53a7SEvalZero return;
3066*042d53a7SEvalZero }
3067*042d53a7SEvalZero
3068*042d53a7SEvalZero scan_continue:
3069*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3070*042d53a7SEvalZero /* Drop last reference and keep continue to connect */
3071*042d53a7SEvalZero ble_ll_scan_aux_data_unref(aux_data);
3072*042d53a7SEvalZero #endif
3073*042d53a7SEvalZero ble_ll_scan_chk_resume();
3074*042d53a7SEvalZero }
3075*042d53a7SEvalZero
3076*042d53a7SEvalZero /**
3077*042d53a7SEvalZero * Called when a receive PDU has started and we are in the initiating state.
3078*042d53a7SEvalZero *
3079*042d53a7SEvalZero * Context: Interrupt
3080*042d53a7SEvalZero *
3081*042d53a7SEvalZero * @param pdu_type
3082*042d53a7SEvalZero * @param ble_hdr
3083*042d53a7SEvalZero *
3084*042d53a7SEvalZero * @return int
3085*042d53a7SEvalZero * 0: we will not attempt to reply to this frame
3086*042d53a7SEvalZero * 1: we may send a response to this frame.
3087*042d53a7SEvalZero */
3088*042d53a7SEvalZero int
ble_ll_init_rx_isr_start(uint8_t pdu_type,struct ble_mbuf_hdr * ble_hdr)3089*042d53a7SEvalZero ble_ll_init_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *ble_hdr)
3090*042d53a7SEvalZero {
3091*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
3092*042d53a7SEvalZero
3093*042d53a7SEvalZero connsm = g_ble_ll_conn_create_sm;
3094*042d53a7SEvalZero if (!connsm) {
3095*042d53a7SEvalZero return 0;
3096*042d53a7SEvalZero }
3097*042d53a7SEvalZero
3098*042d53a7SEvalZero if ((pdu_type == BLE_ADV_PDU_TYPE_ADV_IND) ||
3099*042d53a7SEvalZero (pdu_type == BLE_ADV_PDU_TYPE_ADV_DIRECT_IND ||
3100*042d53a7SEvalZero pdu_type == BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP)) {
3101*042d53a7SEvalZero return 1;
3102*042d53a7SEvalZero }
3103*042d53a7SEvalZero
3104*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3105*042d53a7SEvalZero if (pdu_type == BLE_ADV_PDU_TYPE_ADV_EXT_IND &&
3106*042d53a7SEvalZero connsm->scansm->ext_scanning) {
3107*042d53a7SEvalZero if (connsm->scansm->cur_aux_data) {
3108*042d53a7SEvalZero STATS_INC(ble_ll_stats, aux_received);
3109*042d53a7SEvalZero }
3110*042d53a7SEvalZero
3111*042d53a7SEvalZero ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_EXT_ADV;
3112*042d53a7SEvalZero return 1;
3113*042d53a7SEvalZero }
3114*042d53a7SEvalZero #endif
3115*042d53a7SEvalZero
3116*042d53a7SEvalZero return 0;
3117*042d53a7SEvalZero }
3118*042d53a7SEvalZero
3119*042d53a7SEvalZero /**
3120*042d53a7SEvalZero * Make a connect request PDU
3121*042d53a7SEvalZero *
3122*042d53a7SEvalZero * @param connsm
3123*042d53a7SEvalZero */
3124*042d53a7SEvalZero static void
ble_ll_conn_req_pdu_make(struct ble_ll_conn_sm * connsm,uint8_t chan)3125*042d53a7SEvalZero ble_ll_conn_req_pdu_make(struct ble_ll_conn_sm *connsm, uint8_t chan)
3126*042d53a7SEvalZero {
3127*042d53a7SEvalZero uint8_t pdu_type;
3128*042d53a7SEvalZero uint8_t *dptr;
3129*042d53a7SEvalZero struct os_mbuf *m;
3130*042d53a7SEvalZero
3131*042d53a7SEvalZero m = ble_ll_scan_get_pdu();
3132*042d53a7SEvalZero BLE_LL_ASSERT(m != NULL);
3133*042d53a7SEvalZero
3134*042d53a7SEvalZero /* Construct first PDU header byte */
3135*042d53a7SEvalZero pdu_type = BLE_ADV_PDU_TYPE_CONNECT_REQ;
3136*042d53a7SEvalZero
3137*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) == 1)
3138*042d53a7SEvalZero /* We need CSA2 bit only for legacy connect */
3139*042d53a7SEvalZero if (chan >= BLE_PHY_NUM_DATA_CHANS) {
3140*042d53a7SEvalZero pdu_type |= BLE_ADV_PDU_HDR_CHSEL;
3141*042d53a7SEvalZero }
3142*042d53a7SEvalZero #endif
3143*042d53a7SEvalZero
3144*042d53a7SEvalZero /* Set BLE transmit header */
3145*042d53a7SEvalZero ble_ll_mbuf_init(m, BLE_CONNECT_REQ_LEN, pdu_type);
3146*042d53a7SEvalZero
3147*042d53a7SEvalZero /* Construct the connect request */
3148*042d53a7SEvalZero dptr = m->om_data;
3149*042d53a7SEvalZero
3150*042d53a7SEvalZero /* Skip inita and adva advertiser's address as we dont know that yet */
3151*042d53a7SEvalZero dptr += (2 * BLE_DEV_ADDR_LEN);
3152*042d53a7SEvalZero
3153*042d53a7SEvalZero /* Access address */
3154*042d53a7SEvalZero put_le32(dptr, connsm->access_addr);
3155*042d53a7SEvalZero dptr[4] = (uint8_t)connsm->crcinit;
3156*042d53a7SEvalZero dptr[5] = (uint8_t)(connsm->crcinit >> 8);
3157*042d53a7SEvalZero dptr[6] = (uint8_t)(connsm->crcinit >> 16);
3158*042d53a7SEvalZero dptr[7] = connsm->tx_win_size;
3159*042d53a7SEvalZero put_le16(dptr + 8, connsm->tx_win_off);
3160*042d53a7SEvalZero put_le16(dptr + 10, connsm->conn_itvl);
3161*042d53a7SEvalZero put_le16(dptr + 12, connsm->slave_latency);
3162*042d53a7SEvalZero put_le16(dptr + 14, connsm->supervision_tmo);
3163*042d53a7SEvalZero memcpy(dptr + 16, &connsm->chanmap, BLE_LL_CONN_CHMAP_LEN);
3164*042d53a7SEvalZero dptr[21] = connsm->hop_inc | (connsm->master_sca << 5);
3165*042d53a7SEvalZero }
3166*042d53a7SEvalZero
3167*042d53a7SEvalZero /**
3168*042d53a7SEvalZero * Called when a receive PDU has ended and we are in the initiating state.
3169*042d53a7SEvalZero *
3170*042d53a7SEvalZero * Context: Interrupt
3171*042d53a7SEvalZero *
3172*042d53a7SEvalZero * @param rxpdu
3173*042d53a7SEvalZero * @param crcok
3174*042d53a7SEvalZero * @param ble_hdr
3175*042d53a7SEvalZero *
3176*042d53a7SEvalZero * @return int
3177*042d53a7SEvalZero * < 0: Disable the phy after reception.
3178*042d53a7SEvalZero * == 0: Success. Do not disable the PHY.
3179*042d53a7SEvalZero * > 0: Do not disable PHY as that has already been done.
3180*042d53a7SEvalZero */
3181*042d53a7SEvalZero int
ble_ll_init_rx_isr_end(uint8_t * rxbuf,uint8_t crcok,struct ble_mbuf_hdr * ble_hdr)3182*042d53a7SEvalZero ble_ll_init_rx_isr_end(uint8_t *rxbuf, uint8_t crcok,
3183*042d53a7SEvalZero struct ble_mbuf_hdr *ble_hdr)
3184*042d53a7SEvalZero {
3185*042d53a7SEvalZero int rc;
3186*042d53a7SEvalZero int resolved;
3187*042d53a7SEvalZero int chk_wl;
3188*042d53a7SEvalZero int index;
3189*042d53a7SEvalZero uint8_t pdu_type;
3190*042d53a7SEvalZero uint8_t addr_type;
3191*042d53a7SEvalZero uint8_t peer_addr_type;
3192*042d53a7SEvalZero uint8_t *adv_addr = NULL;
3193*042d53a7SEvalZero uint8_t *peer;
3194*042d53a7SEvalZero uint8_t *init_addr = NULL;
3195*042d53a7SEvalZero uint8_t init_addr_type;
3196*042d53a7SEvalZero uint8_t pyld_len;
3197*042d53a7SEvalZero uint8_t inita_is_rpa;
3198*042d53a7SEvalZero uint8_t conn_req_end_trans;
3199*042d53a7SEvalZero struct os_mbuf *rxpdu;
3200*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
3201*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
3202*042d53a7SEvalZero struct ble_ll_resolv_entry *rl;
3203*042d53a7SEvalZero #endif
3204*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3205*042d53a7SEvalZero struct ble_ll_scan_sm *scansm;
3206*042d53a7SEvalZero uint8_t phy;
3207*042d53a7SEvalZero #endif
3208*042d53a7SEvalZero int ext_adv_mode = -1;
3209*042d53a7SEvalZero
3210*042d53a7SEvalZero /* Get connection state machine to use if connection to be established */
3211*042d53a7SEvalZero connsm = g_ble_ll_conn_create_sm;
3212*042d53a7SEvalZero
3213*042d53a7SEvalZero rc = -1;
3214*042d53a7SEvalZero pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK;
3215*042d53a7SEvalZero pyld_len = rxbuf[1];
3216*042d53a7SEvalZero
3217*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3218*042d53a7SEvalZero scansm = connsm->scansm;
3219*042d53a7SEvalZero if (scansm->cur_aux_data) {
3220*042d53a7SEvalZero ble_hdr->rxinfo.user_data = scansm->cur_aux_data;
3221*042d53a7SEvalZero scansm->cur_aux_data = NULL;
3222*042d53a7SEvalZero if (ble_ll_scan_aux_data_unref(ble_hdr->rxinfo.user_data) == 0) {
3223*042d53a7SEvalZero ble_hdr->rxinfo.user_data = 0;
3224*042d53a7SEvalZero goto init_rx_isr_exit;
3225*042d53a7SEvalZero }
3226*042d53a7SEvalZero }
3227*042d53a7SEvalZero #endif
3228*042d53a7SEvalZero
3229*042d53a7SEvalZero if (!crcok) {
3230*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3231*042d53a7SEvalZero /* Invalid packet - make sure we do not wait for AUX_CONNECT_RSP */
3232*042d53a7SEvalZero ble_ll_conn_reset_pending_aux_conn_rsp();
3233*042d53a7SEvalZero #endif
3234*042d53a7SEvalZero
3235*042d53a7SEvalZero /* Ignore this packet */
3236*042d53a7SEvalZero goto init_rx_isr_exit;
3237*042d53a7SEvalZero }
3238*042d53a7SEvalZero
3239*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3240*042d53a7SEvalZero /* If we sent AUX_CONNECT_REQ, we only expect AUX_CONNECT_RSP here */
3241*042d53a7SEvalZero if (CONN_F_AUX_CONN_REQ(connsm)) {
3242*042d53a7SEvalZero if (pdu_type != BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP) {
3243*042d53a7SEvalZero STATS_INC(ble_ll_stats, aux_conn_rsp_err);
3244*042d53a7SEvalZero CONN_F_CONN_REQ_TXD(connsm) = 0;
3245*042d53a7SEvalZero CONN_F_AUX_CONN_REQ(connsm) = 0;
3246*042d53a7SEvalZero ble_ll_sched_rmv_elem(&connsm->conn_sch);
3247*042d53a7SEvalZero }
3248*042d53a7SEvalZero goto init_rx_isr_exit;
3249*042d53a7SEvalZero }
3250*042d53a7SEvalZero #endif
3251*042d53a7SEvalZero
3252*042d53a7SEvalZero inita_is_rpa = 0;
3253*042d53a7SEvalZero
3254*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3255*042d53a7SEvalZero if (pdu_type == BLE_ADV_PDU_TYPE_ADV_EXT_IND) {
3256*042d53a7SEvalZero if (!scansm) {
3257*042d53a7SEvalZero goto init_rx_isr_exit;
3258*042d53a7SEvalZero }
3259*042d53a7SEvalZero if (!scansm->ext_scanning) {
3260*042d53a7SEvalZero goto init_rx_isr_exit;
3261*042d53a7SEvalZero }
3262*042d53a7SEvalZero
3263*042d53a7SEvalZero rc = ble_ll_scan_get_aux_data(ble_hdr, rxbuf);
3264*042d53a7SEvalZero if (rc < 0) {
3265*042d53a7SEvalZero /* No memory or broken packet */
3266*042d53a7SEvalZero ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_AUX_INVALID;
3267*042d53a7SEvalZero ble_ll_scan_aux_data_unref(ble_hdr->rxinfo.user_data);
3268*042d53a7SEvalZero ble_hdr->rxinfo.user_data = NULL;
3269*042d53a7SEvalZero goto init_rx_isr_exit;
3270*042d53a7SEvalZero }
3271*042d53a7SEvalZero }
3272*042d53a7SEvalZero #endif
3273*042d53a7SEvalZero
3274*042d53a7SEvalZero /* Lets get addresses from advertising report*/
3275*042d53a7SEvalZero if (ble_ll_scan_adv_decode_addr(pdu_type, rxbuf, ble_hdr,
3276*042d53a7SEvalZero &adv_addr, &addr_type,
3277*042d53a7SEvalZero &init_addr, &init_addr_type,
3278*042d53a7SEvalZero &ext_adv_mode)) {
3279*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3280*042d53a7SEvalZero ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_AUX_INVALID;
3281*042d53a7SEvalZero #endif
3282*042d53a7SEvalZero goto init_rx_isr_exit;
3283*042d53a7SEvalZero }
3284*042d53a7SEvalZero
3285*042d53a7SEvalZero switch (pdu_type) {
3286*042d53a7SEvalZero case BLE_ADV_PDU_TYPE_ADV_IND:
3287*042d53a7SEvalZero break;
3288*042d53a7SEvalZero
3289*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3290*042d53a7SEvalZero case BLE_ADV_PDU_TYPE_ADV_EXT_IND:
3291*042d53a7SEvalZero rc = -1;
3292*042d53a7SEvalZero
3293*042d53a7SEvalZero /* If this is not connectable adv mode, lets skip it */
3294*042d53a7SEvalZero if (!(ext_adv_mode & BLE_LL_EXT_ADV_MODE_CONN)) {
3295*042d53a7SEvalZero goto init_rx_isr_exit;
3296*042d53a7SEvalZero }
3297*042d53a7SEvalZero
3298*042d53a7SEvalZero if (!adv_addr) {
3299*042d53a7SEvalZero ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_AUX_PTR_WAIT;
3300*042d53a7SEvalZero goto init_rx_isr_exit;
3301*042d53a7SEvalZero }
3302*042d53a7SEvalZero
3303*042d53a7SEvalZero if (!init_addr) {
3304*042d53a7SEvalZero break;
3305*042d53a7SEvalZero }
3306*042d53a7SEvalZero /* if there is direct address lets fall down and check it.*/
3307*042d53a7SEvalZero // no break
3308*042d53a7SEvalZero #endif
3309*042d53a7SEvalZero case BLE_ADV_PDU_TYPE_ADV_DIRECT_IND:
3310*042d53a7SEvalZero inita_is_rpa = (uint8_t)ble_ll_is_rpa(init_addr, init_addr_type);
3311*042d53a7SEvalZero if (!inita_is_rpa) {
3312*042d53a7SEvalZero
3313*042d53a7SEvalZero /* Resolving will be done later. Check if identity InitA matches */
3314*042d53a7SEvalZero if (!ble_ll_is_our_devaddr(init_addr, init_addr_type)) {
3315*042d53a7SEvalZero goto init_rx_isr_exit;
3316*042d53a7SEvalZero }
3317*042d53a7SEvalZero }
3318*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 0
3319*042d53a7SEvalZero else {
3320*042d53a7SEvalZero /* If privacy is off - reject RPA InitA*/
3321*042d53a7SEvalZero goto init_rx_isr_exit;
3322*042d53a7SEvalZero }
3323*042d53a7SEvalZero #endif
3324*042d53a7SEvalZero
3325*042d53a7SEvalZero break;
3326*042d53a7SEvalZero default:
3327*042d53a7SEvalZero goto init_rx_isr_exit;
3328*042d53a7SEvalZero }
3329*042d53a7SEvalZero
3330*042d53a7SEvalZero /* Should we send a connect request? */
3331*042d53a7SEvalZero index = -1;
3332*042d53a7SEvalZero peer = adv_addr;
3333*042d53a7SEvalZero peer_addr_type = addr_type;
3334*042d53a7SEvalZero
3335*042d53a7SEvalZero resolved = 0;
3336*042d53a7SEvalZero chk_wl = ble_ll_scan_whitelist_enabled();
3337*042d53a7SEvalZero
3338*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
3339*042d53a7SEvalZero if (ble_ll_is_rpa(adv_addr, addr_type) && ble_ll_resolv_enabled()) {
3340*042d53a7SEvalZero index = ble_hw_resolv_list_match();
3341*042d53a7SEvalZero if (index >= 0) {
3342*042d53a7SEvalZero rl = &g_ble_ll_resolv_list[index];
3343*042d53a7SEvalZero
3344*042d53a7SEvalZero ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_RESOLVED;
3345*042d53a7SEvalZero connsm->rpa_index = index;
3346*042d53a7SEvalZero peer = rl->rl_identity_addr;
3347*042d53a7SEvalZero peer_addr_type = rl->rl_addr_type;
3348*042d53a7SEvalZero resolved = 1;
3349*042d53a7SEvalZero
3350*042d53a7SEvalZero /* Assure privacy */
3351*042d53a7SEvalZero if ((rl->rl_priv_mode == BLE_HCI_PRIVACY_NETWORK) &&
3352*042d53a7SEvalZero init_addr && !inita_is_rpa &&
3353*042d53a7SEvalZero ble_ll_resolv_irk_nonzero(rl->rl_local_irk)) {
3354*042d53a7SEvalZero goto init_rx_isr_exit;
3355*042d53a7SEvalZero }
3356*042d53a7SEvalZero
3357*042d53a7SEvalZero /*
3358*042d53a7SEvalZero * If the InitA is a RPA, we must see if it resolves based on the
3359*042d53a7SEvalZero * identity address of the resolved ADVA.
3360*042d53a7SEvalZero */
3361*042d53a7SEvalZero if (init_addr && inita_is_rpa &&
3362*042d53a7SEvalZero !ble_ll_resolv_rpa(init_addr,
3363*042d53a7SEvalZero g_ble_ll_resolv_list[index].rl_local_irk)) {
3364*042d53a7SEvalZero goto init_rx_isr_exit;
3365*042d53a7SEvalZero }
3366*042d53a7SEvalZero
3367*042d53a7SEvalZero } else {
3368*042d53a7SEvalZero if (chk_wl) {
3369*042d53a7SEvalZero goto init_rx_isr_exit;
3370*042d53a7SEvalZero }
3371*042d53a7SEvalZero
3372*042d53a7SEvalZero /* Could not resolved InitA */
3373*042d53a7SEvalZero if (init_addr && inita_is_rpa) {
3374*042d53a7SEvalZero goto init_rx_isr_exit;
3375*042d53a7SEvalZero }
3376*042d53a7SEvalZero }
3377*042d53a7SEvalZero } else if (init_addr) {
3378*042d53a7SEvalZero
3379*042d53a7SEvalZero /* If resolving is off and InitA is RPA we reject advertising */
3380*042d53a7SEvalZero if (inita_is_rpa && !ble_ll_resolv_enabled()) {
3381*042d53a7SEvalZero goto init_rx_isr_exit;
3382*042d53a7SEvalZero }
3383*042d53a7SEvalZero
3384*042d53a7SEvalZero /* Let's see if we have IRK with that peer.*/
3385*042d53a7SEvalZero rl = ble_ll_resolv_list_find(adv_addr, addr_type);
3386*042d53a7SEvalZero
3387*042d53a7SEvalZero /* Lets make sure privacy mode is correct together with InitA in case it
3388*042d53a7SEvalZero * is identity address
3389*042d53a7SEvalZero */
3390*042d53a7SEvalZero if (rl && !inita_is_rpa &&
3391*042d53a7SEvalZero (rl->rl_priv_mode == BLE_HCI_PRIVACY_NETWORK) &&
3392*042d53a7SEvalZero ble_ll_resolv_irk_nonzero(rl->rl_local_irk)) {
3393*042d53a7SEvalZero goto init_rx_isr_exit;
3394*042d53a7SEvalZero }
3395*042d53a7SEvalZero
3396*042d53a7SEvalZero /*
3397*042d53a7SEvalZero * If the InitA is a RPA, we must see if it resolves based on the
3398*042d53a7SEvalZero * identity address of the resolved ADVA.
3399*042d53a7SEvalZero */
3400*042d53a7SEvalZero if (inita_is_rpa) {
3401*042d53a7SEvalZero if (!rl || !ble_ll_resolv_rpa(init_addr, rl->rl_local_irk)) {
3402*042d53a7SEvalZero goto init_rx_isr_exit;
3403*042d53a7SEvalZero }
3404*042d53a7SEvalZero }
3405*042d53a7SEvalZero }
3406*042d53a7SEvalZero #endif
3407*042d53a7SEvalZero
3408*042d53a7SEvalZero /* Check filter policy */
3409*042d53a7SEvalZero if (chk_wl) {
3410*042d53a7SEvalZero if (!ble_ll_whitelist_match(peer, peer_addr_type, resolved)) {
3411*042d53a7SEvalZero goto init_rx_isr_exit;
3412*042d53a7SEvalZero }
3413*042d53a7SEvalZero } else {
3414*042d53a7SEvalZero /* Must match the connection address */
3415*042d53a7SEvalZero if (!ble_ll_conn_is_peer_adv(addr_type, adv_addr, index)) {
3416*042d53a7SEvalZero goto init_rx_isr_exit;
3417*042d53a7SEvalZero }
3418*042d53a7SEvalZero }
3419*042d53a7SEvalZero ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_DEVMATCH;
3420*042d53a7SEvalZero
3421*042d53a7SEvalZero /* For CONNECT_IND we don't go into RX state */
3422*042d53a7SEvalZero conn_req_end_trans = BLE_PHY_TRANSITION_NONE;
3423*042d53a7SEvalZero
3424*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3425*042d53a7SEvalZero /* Check if we should send AUX_CONNECT_REQ and wait for AUX_CONNECT_RSP */
3426*042d53a7SEvalZero if (ble_hdr->rxinfo.channel < BLE_PHY_NUM_DATA_CHANS) {
3427*042d53a7SEvalZero conn_req_end_trans = BLE_PHY_TRANSITION_TX_RX;
3428*042d53a7SEvalZero }
3429*042d53a7SEvalZero
3430*042d53a7SEvalZero if (connsm->scansm->ext_scanning) {
3431*042d53a7SEvalZero phy = ble_hdr->rxinfo.phy;
3432*042d53a7SEvalZero
3433*042d53a7SEvalZero /* Update connection state machine with appropriate parameters for
3434*042d53a7SEvalZero * certain PHY
3435*042d53a7SEvalZero */
3436*042d53a7SEvalZero ble_ll_conn_ext_set_params(connsm,
3437*042d53a7SEvalZero &connsm->initial_params.params[phy - 1],
3438*042d53a7SEvalZero phy);
3439*042d53a7SEvalZero
3440*042d53a7SEvalZero }
3441*042d53a7SEvalZero #endif
3442*042d53a7SEvalZero
3443*042d53a7SEvalZero /* Create the connection request */
3444*042d53a7SEvalZero ble_ll_conn_req_pdu_make(connsm, ble_hdr->rxinfo.channel);
3445*042d53a7SEvalZero
3446*042d53a7SEvalZero if (ble_ll_sched_master_new(connsm, ble_hdr, pyld_len)) {
3447*042d53a7SEvalZero STATS_INC(ble_ll_conn_stats, cant_set_sched);
3448*042d53a7SEvalZero goto init_rx_isr_exit;
3449*042d53a7SEvalZero }
3450*042d53a7SEvalZero
3451*042d53a7SEvalZero /* Setup to transmit the connect request */
3452*042d53a7SEvalZero rc = ble_ll_conn_request_send(addr_type, adv_addr,
3453*042d53a7SEvalZero init_addr_type, init_addr,
3454*042d53a7SEvalZero connsm->tx_win_off, index,
3455*042d53a7SEvalZero conn_req_end_trans);
3456*042d53a7SEvalZero if (rc) {
3457*042d53a7SEvalZero ble_ll_sched_rmv_elem(&connsm->conn_sch);
3458*042d53a7SEvalZero goto init_rx_isr_exit;
3459*042d53a7SEvalZero }
3460*042d53a7SEvalZero
3461*042d53a7SEvalZero if (init_addr && !inita_is_rpa) {
3462*042d53a7SEvalZero connsm->inita_identity_used = 1;
3463*042d53a7SEvalZero }
3464*042d53a7SEvalZero
3465*042d53a7SEvalZero CONN_F_CONN_REQ_TXD(connsm) = 1;
3466*042d53a7SEvalZero
3467*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3468*042d53a7SEvalZero if (ble_hdr->rxinfo.channel < BLE_PHY_NUM_DATA_CHANS) {
3469*042d53a7SEvalZero /* Lets wait for AUX_CONNECT_RSP */
3470*042d53a7SEvalZero CONN_F_AUX_CONN_REQ(connsm) = 1;
3471*042d53a7SEvalZero /* Keep aux data until we get scan response */
3472*042d53a7SEvalZero scansm->cur_aux_data = ble_hdr->rxinfo.user_data;
3473*042d53a7SEvalZero ble_hdr->rxinfo.user_data = NULL;
3474*042d53a7SEvalZero STATS_INC(ble_ll_stats, aux_conn_req_tx);
3475*042d53a7SEvalZero }
3476*042d53a7SEvalZero #endif
3477*042d53a7SEvalZero
3478*042d53a7SEvalZero STATS_INC(ble_ll_conn_stats, conn_req_txd);
3479*042d53a7SEvalZero
3480*042d53a7SEvalZero init_rx_isr_exit:
3481*042d53a7SEvalZero
3482*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3483*042d53a7SEvalZero if (ble_hdr->rxinfo.user_data) {
3484*042d53a7SEvalZero ble_ll_scan_aux_data_ref(ble_hdr->rxinfo.user_data);
3485*042d53a7SEvalZero }
3486*042d53a7SEvalZero #endif
3487*042d53a7SEvalZero /*
3488*042d53a7SEvalZero * We have to restart receive if we cant hand up pdu. We return 0 so that
3489*042d53a7SEvalZero * the phy does not get disabled.
3490*042d53a7SEvalZero */
3491*042d53a7SEvalZero rxpdu = ble_ll_rxpdu_alloc(pyld_len + BLE_LL_PDU_HDR_LEN);
3492*042d53a7SEvalZero if (rxpdu == NULL) {
3493*042d53a7SEvalZero /*
3494*042d53a7SEvalZero * XXX: possible allocate the PDU when we start initiating?
3495*042d53a7SEvalZero * I cannot say I like this solution, but if we cannot allocate a PDU
3496*042d53a7SEvalZero * to hand up to the LL, we need to remove the connection we just
3497*042d53a7SEvalZero * scheduled since the connection state machine will not get processed
3498*042d53a7SEvalZero * by link layer properly. For now, just remove it from the scheduler
3499*042d53a7SEvalZero */
3500*042d53a7SEvalZero if (CONN_F_CONN_REQ_TXD(connsm) == 1) {
3501*042d53a7SEvalZero CONN_F_CONN_REQ_TXD(connsm) = 0;
3502*042d53a7SEvalZero CONN_F_AUX_CONN_REQ(connsm) = 0;
3503*042d53a7SEvalZero ble_ll_sched_rmv_elem(&connsm->conn_sch);
3504*042d53a7SEvalZero }
3505*042d53a7SEvalZero ble_phy_restart_rx();
3506*042d53a7SEvalZero rc = 0;
3507*042d53a7SEvalZero } else {
3508*042d53a7SEvalZero ble_phy_rxpdu_copy(rxbuf, rxpdu);
3509*042d53a7SEvalZero ble_ll_rx_pdu_in(rxpdu);
3510*042d53a7SEvalZero }
3511*042d53a7SEvalZero
3512*042d53a7SEvalZero if (rc) {
3513*042d53a7SEvalZero ble_ll_state_set(BLE_LL_STATE_STANDBY);
3514*042d53a7SEvalZero }
3515*042d53a7SEvalZero
3516*042d53a7SEvalZero return rc;
3517*042d53a7SEvalZero }
3518*042d53a7SEvalZero
3519*042d53a7SEvalZero /**
3520*042d53a7SEvalZero * Function called when a timeout has occurred for a connection. There are
3521*042d53a7SEvalZero * two types of timeouts: a connection supervision timeout and control
3522*042d53a7SEvalZero * procedure timeout.
3523*042d53a7SEvalZero *
3524*042d53a7SEvalZero * Context: Link Layer task
3525*042d53a7SEvalZero *
3526*042d53a7SEvalZero * @param connsm
3527*042d53a7SEvalZero * @param ble_err
3528*042d53a7SEvalZero */
3529*042d53a7SEvalZero void
ble_ll_conn_timeout(struct ble_ll_conn_sm * connsm,uint8_t ble_err)3530*042d53a7SEvalZero ble_ll_conn_timeout(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
3531*042d53a7SEvalZero {
3532*042d53a7SEvalZero int was_current;
3533*042d53a7SEvalZero os_sr_t sr;
3534*042d53a7SEvalZero
3535*042d53a7SEvalZero was_current = 0;
3536*042d53a7SEvalZero OS_ENTER_CRITICAL(sr);
3537*042d53a7SEvalZero if (g_ble_ll_conn_cur_sm == connsm) {
3538*042d53a7SEvalZero ble_ll_conn_current_sm_over(NULL);
3539*042d53a7SEvalZero was_current = 1;
3540*042d53a7SEvalZero }
3541*042d53a7SEvalZero OS_EXIT_CRITICAL(sr);
3542*042d53a7SEvalZero
3543*042d53a7SEvalZero /* Check if we need to resume scanning */
3544*042d53a7SEvalZero if (was_current) {
3545*042d53a7SEvalZero ble_ll_scan_chk_resume();
3546*042d53a7SEvalZero }
3547*042d53a7SEvalZero
3548*042d53a7SEvalZero ble_ll_conn_end(connsm, ble_err);
3549*042d53a7SEvalZero }
3550*042d53a7SEvalZero
3551*042d53a7SEvalZero /**
3552*042d53a7SEvalZero * Called when a data channel PDU has started that matches the access
3553*042d53a7SEvalZero * address of the current connection. Note that the CRC of the PDU has not
3554*042d53a7SEvalZero * been checked yet.
3555*042d53a7SEvalZero *
3556*042d53a7SEvalZero * Context: Interrupt
3557*042d53a7SEvalZero *
3558*042d53a7SEvalZero * @param rxhdr
3559*042d53a7SEvalZero */
3560*042d53a7SEvalZero int
ble_ll_conn_rx_isr_start(struct ble_mbuf_hdr * rxhdr,uint32_t aa)3561*042d53a7SEvalZero ble_ll_conn_rx_isr_start(struct ble_mbuf_hdr *rxhdr, uint32_t aa)
3562*042d53a7SEvalZero {
3563*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
3564*042d53a7SEvalZero
3565*042d53a7SEvalZero /*
3566*042d53a7SEvalZero * Disable wait for response timer since we receive a response. We dont
3567*042d53a7SEvalZero * care if this is the response we were waiting for or not; the code
3568*042d53a7SEvalZero * called at receive end will deal with ending the connection event
3569*042d53a7SEvalZero * if needed
3570*042d53a7SEvalZero */
3571*042d53a7SEvalZero ble_ll_wfr_disable();
3572*042d53a7SEvalZero connsm = g_ble_ll_conn_cur_sm;
3573*042d53a7SEvalZero if (connsm) {
3574*042d53a7SEvalZero /* Double check access address. Better match connection state machine */
3575*042d53a7SEvalZero if (aa != connsm->access_addr) {
3576*042d53a7SEvalZero STATS_INC(ble_ll_conn_stats, rx_data_pdu_bad_aa);
3577*042d53a7SEvalZero ble_ll_state_set(BLE_LL_STATE_STANDBY);
3578*042d53a7SEvalZero ble_ll_event_send(&connsm->conn_ev_end);
3579*042d53a7SEvalZero g_ble_ll_conn_cur_sm = NULL;
3580*042d53a7SEvalZero return -1;
3581*042d53a7SEvalZero }
3582*042d53a7SEvalZero
3583*042d53a7SEvalZero /* Set connection handle in mbuf header */
3584*042d53a7SEvalZero rxhdr->rxinfo.handle = connsm->conn_handle;
3585*042d53a7SEvalZero
3586*042d53a7SEvalZero /* Set flag denoting we have received a packet in connection event */
3587*042d53a7SEvalZero connsm->csmflags.cfbit.pkt_rxd = 1;
3588*042d53a7SEvalZero
3589*042d53a7SEvalZero /* Connection is established */
3590*042d53a7SEvalZero connsm->conn_state = BLE_LL_CONN_STATE_ESTABLISHED;
3591*042d53a7SEvalZero
3592*042d53a7SEvalZero /* Set anchor point (and last) if 1st rxd frame in connection event */
3593*042d53a7SEvalZero if (connsm->csmflags.cfbit.slave_set_last_anchor) {
3594*042d53a7SEvalZero connsm->csmflags.cfbit.slave_set_last_anchor = 0;
3595*042d53a7SEvalZero connsm->last_anchor_point = rxhdr->beg_cputime;
3596*042d53a7SEvalZero connsm->anchor_point = connsm->last_anchor_point;
3597*042d53a7SEvalZero connsm->anchor_point_usecs = rxhdr->rem_usecs;
3598*042d53a7SEvalZero }
3599*042d53a7SEvalZero }
3600*042d53a7SEvalZero return 1;
3601*042d53a7SEvalZero }
3602*042d53a7SEvalZero
3603*042d53a7SEvalZero /**
3604*042d53a7SEvalZero * Called from the Link Layer task when a data PDU has been received
3605*042d53a7SEvalZero *
3606*042d53a7SEvalZero * Context: Link layer task
3607*042d53a7SEvalZero *
3608*042d53a7SEvalZero * @param rxpdu Pointer to received pdu
3609*042d53a7SEvalZero * @param rxpdu Pointer to ble mbuf header of received pdu
3610*042d53a7SEvalZero */
3611*042d53a7SEvalZero void
ble_ll_conn_rx_data_pdu(struct os_mbuf * rxpdu,struct ble_mbuf_hdr * hdr)3612*042d53a7SEvalZero ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr)
3613*042d53a7SEvalZero {
3614*042d53a7SEvalZero uint8_t hdr_byte;
3615*042d53a7SEvalZero uint8_t rxd_sn;
3616*042d53a7SEvalZero uint8_t *rxbuf;
3617*042d53a7SEvalZero uint8_t llid;
3618*042d53a7SEvalZero uint16_t acl_len;
3619*042d53a7SEvalZero uint16_t acl_hdr;
3620*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
3621*042d53a7SEvalZero
3622*042d53a7SEvalZero if (BLE_MBUF_HDR_CRC_OK(hdr)) {
3623*042d53a7SEvalZero /* XXX: there is a chance that the connection was thrown away and
3624*042d53a7SEvalZero re-used before processing packets here. Fix this. */
3625*042d53a7SEvalZero /* We better have a connection state machine */
3626*042d53a7SEvalZero connsm = ble_ll_conn_find_active_conn(hdr->rxinfo.handle);
3627*042d53a7SEvalZero if (connsm) {
3628*042d53a7SEvalZero /* Check state machine */
3629*042d53a7SEvalZero ble_ll_conn_chk_csm_flags(connsm);
3630*042d53a7SEvalZero
3631*042d53a7SEvalZero /* Validate rx data pdu */
3632*042d53a7SEvalZero rxbuf = rxpdu->om_data;
3633*042d53a7SEvalZero hdr_byte = rxbuf[0];
3634*042d53a7SEvalZero acl_len = rxbuf[1];
3635*042d53a7SEvalZero llid = hdr_byte & BLE_LL_DATA_HDR_LLID_MASK;
3636*042d53a7SEvalZero
3637*042d53a7SEvalZero /*
3638*042d53a7SEvalZero * Check that the LLID and payload length are reasonable.
3639*042d53a7SEvalZero * Empty payload is only allowed for LLID == 01b.
3640*042d53a7SEvalZero * */
3641*042d53a7SEvalZero if ((llid == 0) ||
3642*042d53a7SEvalZero ((acl_len == 0) && (llid != BLE_LL_LLID_DATA_FRAG))) {
3643*042d53a7SEvalZero STATS_INC(ble_ll_conn_stats, rx_bad_llid);
3644*042d53a7SEvalZero goto conn_rx_data_pdu_end;
3645*042d53a7SEvalZero }
3646*042d53a7SEvalZero
3647*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
3648*042d53a7SEvalZero /* Check if PDU is allowed when encryption is started. If not,
3649*042d53a7SEvalZero * terminate connection.
3650*042d53a7SEvalZero *
3651*042d53a7SEvalZero * Reference: Core 5.0, Vol 6, Part B, 5.1.3.1
3652*042d53a7SEvalZero */
3653*042d53a7SEvalZero if ((connsm->enc_data.enc_state > CONN_ENC_S_PAUSE_ENC_RSP_WAIT) &&
3654*042d53a7SEvalZero !ble_ll_ctrl_enc_allowed_pdu_rx(rxpdu)) {
3655*042d53a7SEvalZero ble_ll_conn_timeout(connsm, BLE_ERR_CONN_TERM_MIC);
3656*042d53a7SEvalZero goto conn_rx_data_pdu_end;
3657*042d53a7SEvalZero }
3658*042d53a7SEvalZero #endif
3659*042d53a7SEvalZero
3660*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING)
3661*042d53a7SEvalZero /*
3662*042d53a7SEvalZero * Reset authenticated payload timeout if valid MIC. NOTE: we dont
3663*042d53a7SEvalZero * check the MIC failure bit as that would have terminated the
3664*042d53a7SEvalZero * connection
3665*042d53a7SEvalZero */
3666*042d53a7SEvalZero if ((connsm->enc_data.enc_state == CONN_ENC_S_ENCRYPTED) &&
3667*042d53a7SEvalZero CONN_F_LE_PING_SUPP(connsm) && (acl_len != 0)) {
3668*042d53a7SEvalZero ble_ll_conn_auth_pyld_timer_start(connsm);
3669*042d53a7SEvalZero }
3670*042d53a7SEvalZero #endif
3671*042d53a7SEvalZero
3672*042d53a7SEvalZero /* Update RSSI */
3673*042d53a7SEvalZero connsm->conn_rssi = hdr->rxinfo.rssi;
3674*042d53a7SEvalZero
3675*042d53a7SEvalZero /*
3676*042d53a7SEvalZero * If we are a slave, we can only start to use slave latency
3677*042d53a7SEvalZero * once we have received a NESN of 1 from the master
3678*042d53a7SEvalZero */
3679*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
3680*042d53a7SEvalZero if (hdr_byte & BLE_LL_DATA_HDR_NESN_MASK) {
3681*042d53a7SEvalZero connsm->csmflags.cfbit.allow_slave_latency = 1;
3682*042d53a7SEvalZero }
3683*042d53a7SEvalZero }
3684*042d53a7SEvalZero
3685*042d53a7SEvalZero /*
3686*042d53a7SEvalZero * Discard the received PDU if the sequence number is the same
3687*042d53a7SEvalZero * as the last received sequence number
3688*042d53a7SEvalZero */
3689*042d53a7SEvalZero rxd_sn = hdr_byte & BLE_LL_DATA_HDR_SN_MASK;
3690*042d53a7SEvalZero if (rxd_sn != connsm->last_rxd_sn) {
3691*042d53a7SEvalZero /* Update last rxd sn */
3692*042d53a7SEvalZero connsm->last_rxd_sn = rxd_sn;
3693*042d53a7SEvalZero
3694*042d53a7SEvalZero /* No need to do anything if empty pdu */
3695*042d53a7SEvalZero if ((llid == BLE_LL_LLID_DATA_FRAG) && (acl_len == 0)) {
3696*042d53a7SEvalZero goto conn_rx_data_pdu_end;
3697*042d53a7SEvalZero }
3698*042d53a7SEvalZero
3699*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
3700*042d53a7SEvalZero /*
3701*042d53a7SEvalZero * XXX: should we check to see if we are in a state where we
3702*042d53a7SEvalZero * might expect to get an encrypted PDU?
3703*042d53a7SEvalZero */
3704*042d53a7SEvalZero if (BLE_MBUF_HDR_MIC_FAILURE(hdr)) {
3705*042d53a7SEvalZero STATS_INC(ble_ll_conn_stats, mic_failures);
3706*042d53a7SEvalZero ble_ll_conn_timeout(connsm, BLE_ERR_CONN_TERM_MIC);
3707*042d53a7SEvalZero goto conn_rx_data_pdu_end;
3708*042d53a7SEvalZero }
3709*042d53a7SEvalZero #endif
3710*042d53a7SEvalZero
3711*042d53a7SEvalZero if (llid == BLE_LL_LLID_CTRL) {
3712*042d53a7SEvalZero /* Process control frame */
3713*042d53a7SEvalZero STATS_INC(ble_ll_conn_stats, rx_ctrl_pdus);
3714*042d53a7SEvalZero if (ble_ll_ctrl_rx_pdu(connsm, rxpdu)) {
3715*042d53a7SEvalZero STATS_INC(ble_ll_conn_stats, rx_malformed_ctrl_pdus);
3716*042d53a7SEvalZero }
3717*042d53a7SEvalZero } else {
3718*042d53a7SEvalZero /* Count # of received l2cap frames and byes */
3719*042d53a7SEvalZero STATS_INC(ble_ll_conn_stats, rx_l2cap_pdus);
3720*042d53a7SEvalZero STATS_INCN(ble_ll_conn_stats, rx_l2cap_bytes, acl_len);
3721*042d53a7SEvalZero
3722*042d53a7SEvalZero /* NOTE: there should be at least two bytes available */
3723*042d53a7SEvalZero BLE_LL_ASSERT(OS_MBUF_LEADINGSPACE(rxpdu) >= 2);
3724*042d53a7SEvalZero os_mbuf_prepend(rxpdu, 2);
3725*042d53a7SEvalZero rxbuf = rxpdu->om_data;
3726*042d53a7SEvalZero
3727*042d53a7SEvalZero acl_hdr = (llid << 12) | connsm->conn_handle;
3728*042d53a7SEvalZero put_le16(rxbuf, acl_hdr);
3729*042d53a7SEvalZero put_le16(rxbuf + 2, acl_len);
3730*042d53a7SEvalZero ble_hci_trans_ll_acl_tx(rxpdu);
3731*042d53a7SEvalZero }
3732*042d53a7SEvalZero
3733*042d53a7SEvalZero /* NOTE: we dont free the mbuf since we handed it off! */
3734*042d53a7SEvalZero return;
3735*042d53a7SEvalZero } else {
3736*042d53a7SEvalZero STATS_INC(ble_ll_conn_stats, data_pdu_rx_dup);
3737*042d53a7SEvalZero }
3738*042d53a7SEvalZero } else {
3739*042d53a7SEvalZero STATS_INC(ble_ll_conn_stats, no_conn_sm);
3740*042d53a7SEvalZero }
3741*042d53a7SEvalZero }
3742*042d53a7SEvalZero
3743*042d53a7SEvalZero /* Free buffer */
3744*042d53a7SEvalZero conn_rx_data_pdu_end:
3745*042d53a7SEvalZero os_mbuf_free_chain(rxpdu);
3746*042d53a7SEvalZero }
3747*042d53a7SEvalZero
3748*042d53a7SEvalZero /**
3749*042d53a7SEvalZero * Called when a packet has been received while in the connection state.
3750*042d53a7SEvalZero *
3751*042d53a7SEvalZero * Context: Interrupt
3752*042d53a7SEvalZero *
3753*042d53a7SEvalZero * @param rxpdu
3754*042d53a7SEvalZero * @param crcok
3755*042d53a7SEvalZero *
3756*042d53a7SEvalZero * @return int
3757*042d53a7SEvalZero * < 0: Disable the phy after reception.
3758*042d53a7SEvalZero * == 0: Success. Do not disable the PHY.
3759*042d53a7SEvalZero * > 0: Do not disable PHY as that has already been done.
3760*042d53a7SEvalZero */
3761*042d53a7SEvalZero int
ble_ll_conn_rx_isr_end(uint8_t * rxbuf,struct ble_mbuf_hdr * rxhdr)3762*042d53a7SEvalZero ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
3763*042d53a7SEvalZero {
3764*042d53a7SEvalZero int rc;
3765*042d53a7SEvalZero int is_ctrl;
3766*042d53a7SEvalZero uint8_t hdr_byte;
3767*042d53a7SEvalZero uint8_t hdr_sn;
3768*042d53a7SEvalZero uint8_t hdr_nesn;
3769*042d53a7SEvalZero uint8_t conn_sn;
3770*042d53a7SEvalZero uint8_t conn_nesn;
3771*042d53a7SEvalZero uint8_t reply;
3772*042d53a7SEvalZero uint8_t rem_bytes;
3773*042d53a7SEvalZero uint8_t opcode = 0;
3774*042d53a7SEvalZero uint8_t rx_pyld_len;
3775*042d53a7SEvalZero uint32_t begtime;
3776*042d53a7SEvalZero uint32_t add_usecs;
3777*042d53a7SEvalZero struct os_mbuf *txpdu;
3778*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
3779*042d53a7SEvalZero struct os_mbuf *rxpdu;
3780*042d53a7SEvalZero struct ble_mbuf_hdr *txhdr;
3781*042d53a7SEvalZero int rx_phy_mode;
3782*042d53a7SEvalZero
3783*042d53a7SEvalZero /* Retrieve the header and payload length */
3784*042d53a7SEvalZero hdr_byte = rxbuf[0];
3785*042d53a7SEvalZero rx_pyld_len = rxbuf[1];
3786*042d53a7SEvalZero
3787*042d53a7SEvalZero /*
3788*042d53a7SEvalZero * We need to attempt to allocate a buffer here. The reason we do this
3789*042d53a7SEvalZero * now is that we should not ack the packet if we have no receive
3790*042d53a7SEvalZero * buffers available. We want to free up our transmit PDU if it was
3791*042d53a7SEvalZero * acked, but we should not ack the received frame if we cant hand it up.
3792*042d53a7SEvalZero * NOTE: we hand up empty pdu's to the LL task!
3793*042d53a7SEvalZero */
3794*042d53a7SEvalZero rxpdu = ble_ll_rxpdu_alloc(rx_pyld_len + BLE_LL_PDU_HDR_LEN);
3795*042d53a7SEvalZero
3796*042d53a7SEvalZero /*
3797*042d53a7SEvalZero * We should have a current connection state machine. If we dont, we just
3798*042d53a7SEvalZero * hand the packet to the higher layer to count it.
3799*042d53a7SEvalZero */
3800*042d53a7SEvalZero rc = -1;
3801*042d53a7SEvalZero connsm = g_ble_ll_conn_cur_sm;
3802*042d53a7SEvalZero if (!connsm) {
3803*042d53a7SEvalZero STATS_INC(ble_ll_conn_stats, rx_data_pdu_no_conn);
3804*042d53a7SEvalZero goto conn_exit;
3805*042d53a7SEvalZero }
3806*042d53a7SEvalZero
3807*042d53a7SEvalZero /*
3808*042d53a7SEvalZero * Calculate the end time of the received PDU. NOTE: this looks strange
3809*042d53a7SEvalZero * but for the 32768 crystal we add the time it takes to send the packet
3810*042d53a7SEvalZero * to the 'additional usecs' field to save some calculations.
3811*042d53a7SEvalZero */
3812*042d53a7SEvalZero begtime = rxhdr->beg_cputime;
3813*042d53a7SEvalZero #if BLE_LL_BT5_PHY_SUPPORTED
3814*042d53a7SEvalZero rx_phy_mode = connsm->phy_data.rx_phy_mode;
3815*042d53a7SEvalZero #else
3816*042d53a7SEvalZero rx_phy_mode = BLE_PHY_MODE_1M;
3817*042d53a7SEvalZero #endif
3818*042d53a7SEvalZero add_usecs = rxhdr->rem_usecs +
3819*042d53a7SEvalZero ble_ll_pdu_tx_time_get(rx_pyld_len, rx_phy_mode);
3820*042d53a7SEvalZero
3821*042d53a7SEvalZero /*
3822*042d53a7SEvalZero * Check the packet CRC. A connection event can continue even if the
3823*042d53a7SEvalZero * received PDU does not pass the CRC check. If we receive two consecutive
3824*042d53a7SEvalZero * CRC errors we end the conection event.
3825*042d53a7SEvalZero */
3826*042d53a7SEvalZero if (!BLE_MBUF_HDR_CRC_OK(rxhdr)) {
3827*042d53a7SEvalZero /*
3828*042d53a7SEvalZero * Increment # of consecutively received CRC errors. If more than
3829*042d53a7SEvalZero * one we will end the connection event.
3830*042d53a7SEvalZero */
3831*042d53a7SEvalZero ++connsm->cons_rxd_bad_crc;
3832*042d53a7SEvalZero if (connsm->cons_rxd_bad_crc >= 2) {
3833*042d53a7SEvalZero reply = 0;
3834*042d53a7SEvalZero } else {
3835*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
3836*042d53a7SEvalZero reply = CONN_F_LAST_TXD_MD(connsm);
3837*042d53a7SEvalZero } else {
3838*042d53a7SEvalZero /* A slave always responds with a packet */
3839*042d53a7SEvalZero reply = 1;
3840*042d53a7SEvalZero }
3841*042d53a7SEvalZero }
3842*042d53a7SEvalZero } else {
3843*042d53a7SEvalZero /* Reset consecutively received bad crcs (since this one was good!) */
3844*042d53a7SEvalZero connsm->cons_rxd_bad_crc = 0;
3845*042d53a7SEvalZero
3846*042d53a7SEvalZero /* Set last valid received pdu time (resets supervision timer) */
3847*042d53a7SEvalZero connsm->last_rxd_pdu_cputime = begtime +
3848*042d53a7SEvalZero os_cputime_usecs_to_ticks(add_usecs);
3849*042d53a7SEvalZero
3850*042d53a7SEvalZero /*
3851*042d53a7SEvalZero * Check for valid LLID before proceeding. We have seen some weird
3852*042d53a7SEvalZero * things with the PHY where the CRC is OK but we dont have a valid
3853*042d53a7SEvalZero * LLID. This should really never happen but if it does we will just
3854*042d53a7SEvalZero * bail. An error stat will get incremented at the LL.
3855*042d53a7SEvalZero */
3856*042d53a7SEvalZero if ((hdr_byte & BLE_LL_DATA_HDR_LLID_MASK) == 0) {
3857*042d53a7SEvalZero goto conn_exit;
3858*042d53a7SEvalZero }
3859*042d53a7SEvalZero
3860*042d53a7SEvalZero /* Set last received header byte */
3861*042d53a7SEvalZero connsm->last_rxd_hdr_byte = hdr_byte;
3862*042d53a7SEvalZero
3863*042d53a7SEvalZero is_ctrl = 0;
3864*042d53a7SEvalZero if ((hdr_byte & BLE_LL_DATA_HDR_LLID_MASK) == BLE_LL_LLID_CTRL) {
3865*042d53a7SEvalZero is_ctrl = 1;
3866*042d53a7SEvalZero opcode = rxbuf[2];
3867*042d53a7SEvalZero }
3868*042d53a7SEvalZero
3869*042d53a7SEvalZero /*
3870*042d53a7SEvalZero * If SN bit from header does not match NESN in connection, this is
3871*042d53a7SEvalZero * a resent PDU and should be ignored.
3872*042d53a7SEvalZero */
3873*042d53a7SEvalZero hdr_sn = hdr_byte & BLE_LL_DATA_HDR_SN_MASK;
3874*042d53a7SEvalZero conn_nesn = connsm->next_exp_seqnum;
3875*042d53a7SEvalZero if (rxpdu && ((hdr_sn && conn_nesn) || (!hdr_sn && !conn_nesn))) {
3876*042d53a7SEvalZero connsm->next_exp_seqnum ^= 1;
3877*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
3878*042d53a7SEvalZero if (CONN_F_ENCRYPTED(connsm) && !ble_ll_conn_is_empty_pdu(rxbuf)) {
3879*042d53a7SEvalZero ++connsm->enc_data.rx_pkt_cntr;
3880*042d53a7SEvalZero }
3881*042d53a7SEvalZero #endif
3882*042d53a7SEvalZero }
3883*042d53a7SEvalZero
3884*042d53a7SEvalZero ble_ll_trace_u32x2(BLE_LL_TRACE_ID_CONN_RX, connsm->tx_seqnum,
3885*042d53a7SEvalZero !!(hdr_byte & BLE_LL_DATA_HDR_NESN_MASK));
3886*042d53a7SEvalZero
3887*042d53a7SEvalZero /*
3888*042d53a7SEvalZero * Check NESN bit from header. If same as tx seq num, the transmission
3889*042d53a7SEvalZero * is acknowledged. Otherwise we need to resend this PDU.
3890*042d53a7SEvalZero */
3891*042d53a7SEvalZero if (CONN_F_EMPTY_PDU_TXD(connsm) || connsm->cur_tx_pdu) {
3892*042d53a7SEvalZero hdr_nesn = hdr_byte & BLE_LL_DATA_HDR_NESN_MASK;
3893*042d53a7SEvalZero conn_sn = connsm->tx_seqnum;
3894*042d53a7SEvalZero if ((hdr_nesn && conn_sn) || (!hdr_nesn && !conn_sn)) {
3895*042d53a7SEvalZero /* We did not get an ACK. Must retry the PDU */
3896*042d53a7SEvalZero STATS_INC(ble_ll_conn_stats, data_pdu_txf);
3897*042d53a7SEvalZero } else {
3898*042d53a7SEvalZero /* Transmit success */
3899*042d53a7SEvalZero connsm->tx_seqnum ^= 1;
3900*042d53a7SEvalZero STATS_INC(ble_ll_conn_stats, data_pdu_txg);
3901*042d53a7SEvalZero
3902*042d53a7SEvalZero /* If we transmitted the empty pdu, clear flag */
3903*042d53a7SEvalZero if (CONN_F_EMPTY_PDU_TXD(connsm)) {
3904*042d53a7SEvalZero CONN_F_EMPTY_PDU_TXD(connsm) = 0;
3905*042d53a7SEvalZero goto chk_rx_terminate_ind;
3906*042d53a7SEvalZero }
3907*042d53a7SEvalZero
3908*042d53a7SEvalZero /*
3909*042d53a7SEvalZero * Determine if we should remove packet from queue or if there
3910*042d53a7SEvalZero * are more fragments to send.
3911*042d53a7SEvalZero */
3912*042d53a7SEvalZero txpdu = connsm->cur_tx_pdu;
3913*042d53a7SEvalZero if (txpdu) {
3914*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
3915*042d53a7SEvalZero if (connsm->enc_data.tx_encrypted) {
3916*042d53a7SEvalZero ++connsm->enc_data.tx_pkt_cntr;
3917*042d53a7SEvalZero }
3918*042d53a7SEvalZero #endif
3919*042d53a7SEvalZero txhdr = BLE_MBUF_HDR_PTR(txpdu);
3920*042d53a7SEvalZero if ((txhdr->txinfo.hdr_byte & BLE_LL_DATA_HDR_LLID_MASK)
3921*042d53a7SEvalZero == BLE_LL_LLID_CTRL) {
3922*042d53a7SEvalZero connsm->cur_tx_pdu = NULL;
3923*042d53a7SEvalZero /* Note: the mbuf is freed by this call */
3924*042d53a7SEvalZero rc = ble_ll_ctrl_tx_done(txpdu, connsm);
3925*042d53a7SEvalZero if (rc) {
3926*042d53a7SEvalZero /* Means we transmitted a TERMINATE_IND */
3927*042d53a7SEvalZero goto conn_exit;
3928*042d53a7SEvalZero } else {
3929*042d53a7SEvalZero goto chk_rx_terminate_ind;
3930*042d53a7SEvalZero }
3931*042d53a7SEvalZero }
3932*042d53a7SEvalZero
3933*042d53a7SEvalZero /* Increment offset based on number of bytes sent */
3934*042d53a7SEvalZero txhdr->txinfo.offset += txhdr->txinfo.pyld_len;
3935*042d53a7SEvalZero if (txhdr->txinfo.offset >= OS_MBUF_PKTLEN(txpdu)) {
3936*042d53a7SEvalZero /* If l2cap pdu, increment # of completed packets */
3937*042d53a7SEvalZero if (txhdr->txinfo.pyld_len != 0) {
3938*042d53a7SEvalZero #if (BLETEST_THROUGHPUT_TEST == 1)
3939*042d53a7SEvalZero bletest_completed_pkt(connsm->conn_handle);
3940*042d53a7SEvalZero #endif
3941*042d53a7SEvalZero ++connsm->completed_pkts;
3942*042d53a7SEvalZero if (connsm->completed_pkts > 2) {
3943*042d53a7SEvalZero ble_npl_eventq_put(&g_ble_ll_data.ll_evq,
3944*042d53a7SEvalZero &g_ble_ll_data.ll_comp_pkt_ev);
3945*042d53a7SEvalZero }
3946*042d53a7SEvalZero }
3947*042d53a7SEvalZero os_mbuf_free_chain(txpdu);
3948*042d53a7SEvalZero connsm->cur_tx_pdu = NULL;
3949*042d53a7SEvalZero } else {
3950*042d53a7SEvalZero rem_bytes = OS_MBUF_PKTLEN(txpdu) - txhdr->txinfo.offset;
3951*042d53a7SEvalZero /* Adjust payload for max TX time and octets */
3952*042d53a7SEvalZero
3953*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
3954*042d53a7SEvalZero if (is_ctrl && (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE)
3955*042d53a7SEvalZero && (opcode == BLE_LL_CTRL_PHY_UPDATE_IND)) {
3956*042d53a7SEvalZero connsm->phy_tx_transition = rxbuf[3];
3957*042d53a7SEvalZero }
3958*042d53a7SEvalZero #endif
3959*042d53a7SEvalZero
3960*042d53a7SEvalZero rem_bytes = ble_ll_conn_adjust_pyld_len(connsm, rem_bytes);
3961*042d53a7SEvalZero txhdr->txinfo.pyld_len = rem_bytes;
3962*042d53a7SEvalZero }
3963*042d53a7SEvalZero }
3964*042d53a7SEvalZero }
3965*042d53a7SEvalZero }
3966*042d53a7SEvalZero
3967*042d53a7SEvalZero /* Should we continue connection event? */
3968*042d53a7SEvalZero /* If this is a TERMINATE_IND, we have to reply */
3969*042d53a7SEvalZero chk_rx_terminate_ind:
3970*042d53a7SEvalZero /* If we received a terminate IND, we must set some flags */
3971*042d53a7SEvalZero if (is_ctrl && (opcode == BLE_LL_CTRL_TERMINATE_IND)
3972*042d53a7SEvalZero && (rx_pyld_len == (1 + BLE_LL_CTRL_TERMINATE_IND_LEN))) {
3973*042d53a7SEvalZero connsm->csmflags.cfbit.terminate_ind_rxd = 1;
3974*042d53a7SEvalZero connsm->rxd_disconnect_reason = rxbuf[3];
3975*042d53a7SEvalZero }
3976*042d53a7SEvalZero
3977*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
3978*042d53a7SEvalZero reply = CONN_F_LAST_TXD_MD(connsm) || (hdr_byte & BLE_LL_DATA_HDR_MD_MASK);
3979*042d53a7SEvalZero } else {
3980*042d53a7SEvalZero /* A slave always replies */
3981*042d53a7SEvalZero reply = 1;
3982*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
3983*042d53a7SEvalZero if (is_ctrl && (opcode == BLE_LL_CTRL_PAUSE_ENC_RSP)) {
3984*042d53a7SEvalZero connsm->enc_data.enc_state = CONN_ENC_S_PAUSED;
3985*042d53a7SEvalZero }
3986*042d53a7SEvalZero #endif
3987*042d53a7SEvalZero }
3988*042d53a7SEvalZero }
3989*042d53a7SEvalZero
3990*042d53a7SEvalZero /* If reply flag set, send data pdu and continue connection event */
3991*042d53a7SEvalZero rc = -1;
3992*042d53a7SEvalZero if (rx_pyld_len && CONN_F_ENCRYPTED(connsm)) {
3993*042d53a7SEvalZero rx_pyld_len += BLE_LL_DATA_MIC_LEN;
3994*042d53a7SEvalZero }
3995*042d53a7SEvalZero if (reply && ble_ll_conn_can_send_next_pdu(connsm, begtime, add_usecs)) {
3996*042d53a7SEvalZero rc = ble_ll_conn_tx_data_pdu(connsm);
3997*042d53a7SEvalZero }
3998*042d53a7SEvalZero
3999*042d53a7SEvalZero conn_exit:
4000*042d53a7SEvalZero /* Copy the received pdu and hand it up */
4001*042d53a7SEvalZero if (rxpdu) {
4002*042d53a7SEvalZero ble_phy_rxpdu_copy(rxbuf, rxpdu);
4003*042d53a7SEvalZero ble_ll_rx_pdu_in(rxpdu);
4004*042d53a7SEvalZero }
4005*042d53a7SEvalZero
4006*042d53a7SEvalZero /* Send link layer a connection end event if over */
4007*042d53a7SEvalZero if (rc) {
4008*042d53a7SEvalZero ble_ll_conn_current_sm_over(connsm);
4009*042d53a7SEvalZero }
4010*042d53a7SEvalZero
4011*042d53a7SEvalZero return rc;
4012*042d53a7SEvalZero }
4013*042d53a7SEvalZero
4014*042d53a7SEvalZero /**
4015*042d53a7SEvalZero * Called to adjust payload length to fit into max effective octets and TX time
4016*042d53a7SEvalZero * on current PHY.
4017*042d53a7SEvalZero */
4018*042d53a7SEvalZero /**
4019*042d53a7SEvalZero * Called to enqueue a packet on the transmit queue of a connection. Should
4020*042d53a7SEvalZero * only be called by the controller.
4021*042d53a7SEvalZero *
4022*042d53a7SEvalZero * Context: Link Layer
4023*042d53a7SEvalZero *
4024*042d53a7SEvalZero *
4025*042d53a7SEvalZero * @param connsm
4026*042d53a7SEvalZero * @param om
4027*042d53a7SEvalZero */
4028*042d53a7SEvalZero void
ble_ll_conn_enqueue_pkt(struct ble_ll_conn_sm * connsm,struct os_mbuf * om,uint8_t hdr_byte,uint8_t length)4029*042d53a7SEvalZero ble_ll_conn_enqueue_pkt(struct ble_ll_conn_sm *connsm, struct os_mbuf *om,
4030*042d53a7SEvalZero uint8_t hdr_byte, uint8_t length)
4031*042d53a7SEvalZero {
4032*042d53a7SEvalZero os_sr_t sr;
4033*042d53a7SEvalZero struct os_mbuf_pkthdr *pkthdr;
4034*042d53a7SEvalZero struct ble_mbuf_hdr *ble_hdr;
4035*042d53a7SEvalZero int lifo;
4036*042d53a7SEvalZero
4037*042d53a7SEvalZero /* Set mbuf length and packet length if a control PDU */
4038*042d53a7SEvalZero if (hdr_byte == BLE_LL_LLID_CTRL) {
4039*042d53a7SEvalZero om->om_len = length;
4040*042d53a7SEvalZero OS_MBUF_PKTHDR(om)->omp_len = length;
4041*042d53a7SEvalZero }
4042*042d53a7SEvalZero
4043*042d53a7SEvalZero /* Set BLE transmit header */
4044*042d53a7SEvalZero ble_hdr = BLE_MBUF_HDR_PTR(om);
4045*042d53a7SEvalZero ble_hdr->txinfo.flags = 0;
4046*042d53a7SEvalZero ble_hdr->txinfo.offset = 0;
4047*042d53a7SEvalZero ble_hdr->txinfo.hdr_byte = hdr_byte;
4048*042d53a7SEvalZero
4049*042d53a7SEvalZero /*
4050*042d53a7SEvalZero * Initial payload length is calculate when packet is dequeued, there's no
4051*042d53a7SEvalZero * need to do this now.
4052*042d53a7SEvalZero */
4053*042d53a7SEvalZero
4054*042d53a7SEvalZero lifo = 0;
4055*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
4056*042d53a7SEvalZero if (connsm->enc_data.enc_state > CONN_ENC_S_ENCRYPTED) {
4057*042d53a7SEvalZero uint8_t llid;
4058*042d53a7SEvalZero
4059*042d53a7SEvalZero /*
4060*042d53a7SEvalZero * If this is one of the following types we need to insert it at
4061*042d53a7SEvalZero * head of queue.
4062*042d53a7SEvalZero */
4063*042d53a7SEvalZero llid = ble_hdr->txinfo.hdr_byte & BLE_LL_DATA_HDR_LLID_MASK;
4064*042d53a7SEvalZero if (llid == BLE_LL_LLID_CTRL) {
4065*042d53a7SEvalZero switch (om->om_data[0]) {
4066*042d53a7SEvalZero case BLE_LL_CTRL_TERMINATE_IND:
4067*042d53a7SEvalZero case BLE_LL_CTRL_REJECT_IND:
4068*042d53a7SEvalZero case BLE_LL_CTRL_REJECT_IND_EXT:
4069*042d53a7SEvalZero case BLE_LL_CTRL_START_ENC_REQ:
4070*042d53a7SEvalZero case BLE_LL_CTRL_START_ENC_RSP:
4071*042d53a7SEvalZero lifo = 1;
4072*042d53a7SEvalZero break;
4073*042d53a7SEvalZero case BLE_LL_CTRL_PAUSE_ENC_RSP:
4074*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
4075*042d53a7SEvalZero lifo = 1;
4076*042d53a7SEvalZero }
4077*042d53a7SEvalZero break;
4078*042d53a7SEvalZero case BLE_LL_CTRL_ENC_REQ:
4079*042d53a7SEvalZero case BLE_LL_CTRL_ENC_RSP:
4080*042d53a7SEvalZero /* If encryption has been paused, we don't want to send any packets from the
4081*042d53a7SEvalZero * TX queue, as they would go unencrypted.
4082*042d53a7SEvalZero */
4083*042d53a7SEvalZero if (connsm->enc_data.enc_state == CONN_ENC_S_PAUSED) {
4084*042d53a7SEvalZero lifo = 1;
4085*042d53a7SEvalZero }
4086*042d53a7SEvalZero break;
4087*042d53a7SEvalZero default:
4088*042d53a7SEvalZero break;
4089*042d53a7SEvalZero }
4090*042d53a7SEvalZero }
4091*042d53a7SEvalZero }
4092*042d53a7SEvalZero #endif
4093*042d53a7SEvalZero
4094*042d53a7SEvalZero /* Add to transmit queue for the connection */
4095*042d53a7SEvalZero pkthdr = OS_MBUF_PKTHDR(om);
4096*042d53a7SEvalZero OS_ENTER_CRITICAL(sr);
4097*042d53a7SEvalZero if (lifo) {
4098*042d53a7SEvalZero STAILQ_INSERT_HEAD(&connsm->conn_txq, pkthdr, omp_next);
4099*042d53a7SEvalZero } else {
4100*042d53a7SEvalZero STAILQ_INSERT_TAIL(&connsm->conn_txq, pkthdr, omp_next);
4101*042d53a7SEvalZero }
4102*042d53a7SEvalZero OS_EXIT_CRITICAL(sr);
4103*042d53a7SEvalZero }
4104*042d53a7SEvalZero
4105*042d53a7SEvalZero /**
4106*042d53a7SEvalZero * Data packet from host.
4107*042d53a7SEvalZero *
4108*042d53a7SEvalZero * Context: Link Layer task
4109*042d53a7SEvalZero *
4110*042d53a7SEvalZero * @param om
4111*042d53a7SEvalZero * @param handle
4112*042d53a7SEvalZero * @param length
4113*042d53a7SEvalZero *
4114*042d53a7SEvalZero * @return int
4115*042d53a7SEvalZero */
4116*042d53a7SEvalZero void
ble_ll_conn_tx_pkt_in(struct os_mbuf * om,uint16_t handle,uint16_t length)4117*042d53a7SEvalZero ble_ll_conn_tx_pkt_in(struct os_mbuf *om, uint16_t handle, uint16_t length)
4118*042d53a7SEvalZero {
4119*042d53a7SEvalZero uint8_t hdr_byte;
4120*042d53a7SEvalZero uint16_t conn_handle;
4121*042d53a7SEvalZero uint16_t pb;
4122*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
4123*042d53a7SEvalZero
4124*042d53a7SEvalZero /* See if we have an active matching connection handle */
4125*042d53a7SEvalZero conn_handle = handle & 0x0FFF;
4126*042d53a7SEvalZero connsm = ble_ll_conn_find_active_conn(conn_handle);
4127*042d53a7SEvalZero if (connsm) {
4128*042d53a7SEvalZero /* Construct LL header in buffer (NOTE: pb already checked) */
4129*042d53a7SEvalZero pb = handle & 0x3000;
4130*042d53a7SEvalZero if (pb == 0) {
4131*042d53a7SEvalZero hdr_byte = BLE_LL_LLID_DATA_START;
4132*042d53a7SEvalZero } else {
4133*042d53a7SEvalZero hdr_byte = BLE_LL_LLID_DATA_FRAG;
4134*042d53a7SEvalZero }
4135*042d53a7SEvalZero
4136*042d53a7SEvalZero /* Add to total l2cap pdus enqueue */
4137*042d53a7SEvalZero STATS_INC(ble_ll_conn_stats, l2cap_enqueued);
4138*042d53a7SEvalZero
4139*042d53a7SEvalZero /* Clear flags field in BLE header */
4140*042d53a7SEvalZero ble_ll_conn_enqueue_pkt(connsm, om, hdr_byte, length);
4141*042d53a7SEvalZero } else {
4142*042d53a7SEvalZero /* No connection found! */
4143*042d53a7SEvalZero STATS_INC(ble_ll_conn_stats, handle_not_found);
4144*042d53a7SEvalZero os_mbuf_free_chain(om);
4145*042d53a7SEvalZero }
4146*042d53a7SEvalZero }
4147*042d53a7SEvalZero
4148*042d53a7SEvalZero /**
4149*042d53a7SEvalZero * Called to set the global channel mask that we use for all connections.
4150*042d53a7SEvalZero *
4151*042d53a7SEvalZero * @param num_used_chans
4152*042d53a7SEvalZero * @param chanmap
4153*042d53a7SEvalZero */
4154*042d53a7SEvalZero void
ble_ll_conn_set_global_chanmap(uint8_t num_used_chans,uint8_t * chanmap)4155*042d53a7SEvalZero ble_ll_conn_set_global_chanmap(uint8_t num_used_chans, uint8_t *chanmap)
4156*042d53a7SEvalZero {
4157*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
4158*042d53a7SEvalZero struct ble_ll_conn_global_params *conn_params;
4159*042d53a7SEvalZero
4160*042d53a7SEvalZero /* Do nothing if same channel map */
4161*042d53a7SEvalZero conn_params = &g_ble_ll_conn_params;
4162*042d53a7SEvalZero if (!memcmp(conn_params->master_chan_map, chanmap, BLE_LL_CONN_CHMAP_LEN)) {
4163*042d53a7SEvalZero return;
4164*042d53a7SEvalZero }
4165*042d53a7SEvalZero
4166*042d53a7SEvalZero /* Change channel map and cause channel map update procedure to start */
4167*042d53a7SEvalZero conn_params->num_used_chans = num_used_chans;
4168*042d53a7SEvalZero memcpy(conn_params->master_chan_map, chanmap, BLE_LL_CONN_CHMAP_LEN);
4169*042d53a7SEvalZero
4170*042d53a7SEvalZero /* Perform channel map update */
4171*042d53a7SEvalZero SLIST_FOREACH(connsm, &g_ble_ll_conn_active_list, act_sle) {
4172*042d53a7SEvalZero if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
4173*042d53a7SEvalZero ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_CHAN_MAP_UPD);
4174*042d53a7SEvalZero }
4175*042d53a7SEvalZero }
4176*042d53a7SEvalZero }
4177*042d53a7SEvalZero
4178*042d53a7SEvalZero /**
4179*042d53a7SEvalZero * Called when a device has received a connect request while advertising and
4180*042d53a7SEvalZero * the connect request has passed the advertising filter policy and is for
4181*042d53a7SEvalZero * us. This will start a connection in the slave role assuming that we dont
4182*042d53a7SEvalZero * already have a connection with this device and that the connect request
4183*042d53a7SEvalZero * parameters are valid.
4184*042d53a7SEvalZero *
4185*042d53a7SEvalZero * Context: Link Layer
4186*042d53a7SEvalZero *
4187*042d53a7SEvalZero * @param rxbuf Pointer to received Connect Request PDU
4188*042d53a7SEvalZero *
4189*042d53a7SEvalZero * @return 0: connection not started; 1 connecton started
4190*042d53a7SEvalZero */
4191*042d53a7SEvalZero int
ble_ll_conn_slave_start(uint8_t * rxbuf,uint8_t pat,struct ble_mbuf_hdr * rxhdr,bool force_csa2)4192*042d53a7SEvalZero ble_ll_conn_slave_start(uint8_t *rxbuf, uint8_t pat, struct ble_mbuf_hdr *rxhdr,
4193*042d53a7SEvalZero bool force_csa2)
4194*042d53a7SEvalZero {
4195*042d53a7SEvalZero int rc;
4196*042d53a7SEvalZero uint32_t temp;
4197*042d53a7SEvalZero uint32_t crcinit;
4198*042d53a7SEvalZero uint8_t *inita;
4199*042d53a7SEvalZero uint8_t *dptr;
4200*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
4201*042d53a7SEvalZero
4202*042d53a7SEvalZero /* Ignore the connection request if we are already connected*/
4203*042d53a7SEvalZero inita = rxbuf + BLE_LL_PDU_HDR_LEN;
4204*042d53a7SEvalZero SLIST_FOREACH(connsm, &g_ble_ll_conn_active_list, act_sle) {
4205*042d53a7SEvalZero if (!memcmp(&connsm->peer_addr, inita, BLE_DEV_ADDR_LEN)) {
4206*042d53a7SEvalZero if (rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK) {
4207*042d53a7SEvalZero if (connsm->peer_addr_type & 1) {
4208*042d53a7SEvalZero return 0;
4209*042d53a7SEvalZero }
4210*042d53a7SEvalZero } else {
4211*042d53a7SEvalZero if ((connsm->peer_addr_type & 1) == 0) {
4212*042d53a7SEvalZero return 0;
4213*042d53a7SEvalZero }
4214*042d53a7SEvalZero }
4215*042d53a7SEvalZero }
4216*042d53a7SEvalZero }
4217*042d53a7SEvalZero
4218*042d53a7SEvalZero /* Allocate a connection. If none available, dont do anything */
4219*042d53a7SEvalZero connsm = ble_ll_conn_sm_get();
4220*042d53a7SEvalZero if (connsm == NULL) {
4221*042d53a7SEvalZero return 0;
4222*042d53a7SEvalZero }
4223*042d53a7SEvalZero
4224*042d53a7SEvalZero /* Set the pointer at the start of the connection data */
4225*042d53a7SEvalZero dptr = rxbuf + BLE_LL_CONN_REQ_ADVA_OFF + BLE_DEV_ADDR_LEN;
4226*042d53a7SEvalZero
4227*042d53a7SEvalZero /* Set connection state machine information */
4228*042d53a7SEvalZero connsm->access_addr = get_le32(dptr);
4229*042d53a7SEvalZero crcinit = dptr[6];
4230*042d53a7SEvalZero crcinit = (crcinit << 8) | dptr[5];
4231*042d53a7SEvalZero crcinit = (crcinit << 8) | dptr[4];
4232*042d53a7SEvalZero connsm->crcinit = crcinit;
4233*042d53a7SEvalZero connsm->tx_win_size = dptr[7];
4234*042d53a7SEvalZero connsm->tx_win_off = get_le16(dptr + 8);
4235*042d53a7SEvalZero connsm->conn_itvl = get_le16(dptr + 10);
4236*042d53a7SEvalZero connsm->slave_latency = get_le16(dptr + 12);
4237*042d53a7SEvalZero connsm->supervision_tmo = get_le16(dptr + 14);
4238*042d53a7SEvalZero memcpy(&connsm->chanmap, dptr + 16, BLE_LL_CONN_CHMAP_LEN);
4239*042d53a7SEvalZero connsm->hop_inc = dptr[21] & 0x1F;
4240*042d53a7SEvalZero connsm->master_sca = dptr[21] >> 5;
4241*042d53a7SEvalZero
4242*042d53a7SEvalZero /* Error check parameters */
4243*042d53a7SEvalZero if ((connsm->tx_win_off > connsm->conn_itvl) ||
4244*042d53a7SEvalZero (connsm->conn_itvl < BLE_HCI_CONN_ITVL_MIN) ||
4245*042d53a7SEvalZero (connsm->conn_itvl > BLE_HCI_CONN_ITVL_MAX) ||
4246*042d53a7SEvalZero (connsm->tx_win_size < BLE_LL_CONN_TX_WIN_MIN) ||
4247*042d53a7SEvalZero (connsm->slave_latency > BLE_LL_CONN_SLAVE_LATENCY_MAX)) {
4248*042d53a7SEvalZero goto err_slave_start;
4249*042d53a7SEvalZero }
4250*042d53a7SEvalZero
4251*042d53a7SEvalZero /* Slave latency cannot cause a supervision timeout */
4252*042d53a7SEvalZero temp = (connsm->slave_latency + 1) * (connsm->conn_itvl * 2) *
4253*042d53a7SEvalZero BLE_LL_CONN_ITVL_USECS;
4254*042d53a7SEvalZero if ((connsm->supervision_tmo * 10000) <= temp ) {
4255*042d53a7SEvalZero goto err_slave_start;
4256*042d53a7SEvalZero }
4257*042d53a7SEvalZero
4258*042d53a7SEvalZero /*
4259*042d53a7SEvalZero * The transmit window must be less than or equal to the lesser of 10
4260*042d53a7SEvalZero * msecs or the connection interval minus 1.25 msecs.
4261*042d53a7SEvalZero */
4262*042d53a7SEvalZero temp = connsm->conn_itvl - 1;
4263*042d53a7SEvalZero if (temp > 8) {
4264*042d53a7SEvalZero temp = 8;
4265*042d53a7SEvalZero }
4266*042d53a7SEvalZero if (connsm->tx_win_size > temp) {
4267*042d53a7SEvalZero goto err_slave_start;
4268*042d53a7SEvalZero }
4269*042d53a7SEvalZero
4270*042d53a7SEvalZero /* Set the address of device that we are connecting with */
4271*042d53a7SEvalZero memcpy(&connsm->peer_addr, inita, BLE_DEV_ADDR_LEN);
4272*042d53a7SEvalZero connsm->peer_addr_type = pat;
4273*042d53a7SEvalZero
4274*042d53a7SEvalZero /* Calculate number of used channels; make sure it meets min requirement */
4275*042d53a7SEvalZero connsm->num_used_chans = ble_ll_conn_calc_used_chans(connsm->chanmap);
4276*042d53a7SEvalZero if (connsm->num_used_chans < 2) {
4277*042d53a7SEvalZero goto err_slave_start;
4278*042d53a7SEvalZero }
4279*042d53a7SEvalZero
4280*042d53a7SEvalZero /* Start the connection state machine */
4281*042d53a7SEvalZero connsm->conn_role = BLE_LL_CONN_ROLE_SLAVE;
4282*042d53a7SEvalZero ble_ll_conn_sm_new(connsm);
4283*042d53a7SEvalZero
4284*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
4285*042d53a7SEvalZero /* Use the same PHY as we received CONNECT_REQ on */
4286*042d53a7SEvalZero ble_ll_conn_init_phy(connsm, rxhdr->rxinfo.phy);
4287*042d53a7SEvalZero #endif
4288*042d53a7SEvalZero
4289*042d53a7SEvalZero ble_ll_conn_set_csa(connsm,
4290*042d53a7SEvalZero force_csa2 || (rxbuf[0] & BLE_ADV_PDU_HDR_CHSEL_MASK));
4291*042d53a7SEvalZero
4292*042d53a7SEvalZero /* Set initial schedule callback */
4293*042d53a7SEvalZero connsm->conn_sch.sched_cb = ble_ll_conn_event_start_cb;
4294*042d53a7SEvalZero rc = ble_ll_conn_created(connsm, rxhdr);
4295*042d53a7SEvalZero if (!rc) {
4296*042d53a7SEvalZero SLIST_REMOVE(&g_ble_ll_conn_active_list, connsm, ble_ll_conn_sm, act_sle);
4297*042d53a7SEvalZero STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe);
4298*042d53a7SEvalZero }
4299*042d53a7SEvalZero return rc;
4300*042d53a7SEvalZero
4301*042d53a7SEvalZero err_slave_start:
4302*042d53a7SEvalZero STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe);
4303*042d53a7SEvalZero STATS_INC(ble_ll_conn_stats, slave_rxd_bad_conn_req_params);
4304*042d53a7SEvalZero return 0;
4305*042d53a7SEvalZero }
4306*042d53a7SEvalZero
4307*042d53a7SEvalZero #define MAX_TIME_UNCODED(_maxbytes) \
4308*042d53a7SEvalZero ble_ll_pdu_tx_time_get(_maxbytes + BLE_LL_DATA_MIC_LEN, \
4309*042d53a7SEvalZero BLE_PHY_MODE_1M);
4310*042d53a7SEvalZero #define MAX_TIME_CODED(_maxbytes) \
4311*042d53a7SEvalZero ble_ll_pdu_tx_time_get(_maxbytes + BLE_LL_DATA_MIC_LEN, \
4312*042d53a7SEvalZero BLE_PHY_MODE_CODED_125KBPS);
4313*042d53a7SEvalZero
4314*042d53a7SEvalZero /**
4315*042d53a7SEvalZero * Called to reset the connection module. When this function is called the
4316*042d53a7SEvalZero * scheduler has been stopped and the phy has been disabled. The LL should
4317*042d53a7SEvalZero * be in the standby state.
4318*042d53a7SEvalZero *
4319*042d53a7SEvalZero * Context: Link Layer task
4320*042d53a7SEvalZero */
4321*042d53a7SEvalZero void
ble_ll_conn_module_reset(void)4322*042d53a7SEvalZero ble_ll_conn_module_reset(void)
4323*042d53a7SEvalZero {
4324*042d53a7SEvalZero uint8_t max_phy_pyld;
4325*042d53a7SEvalZero uint16_t maxbytes;
4326*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
4327*042d53a7SEvalZero struct ble_ll_conn_global_params *conn_params;
4328*042d53a7SEvalZero
4329*042d53a7SEvalZero /* Kill the current one first (if one is running) */
4330*042d53a7SEvalZero if (g_ble_ll_conn_cur_sm) {
4331*042d53a7SEvalZero connsm = g_ble_ll_conn_cur_sm;
4332*042d53a7SEvalZero g_ble_ll_conn_cur_sm = NULL;
4333*042d53a7SEvalZero ble_ll_conn_end(connsm, BLE_ERR_SUCCESS);
4334*042d53a7SEvalZero }
4335*042d53a7SEvalZero
4336*042d53a7SEvalZero /* Free the global connection complete event if there is one */
4337*042d53a7SEvalZero if (g_ble_ll_conn_comp_ev) {
4338*042d53a7SEvalZero ble_hci_trans_buf_free(g_ble_ll_conn_comp_ev);
4339*042d53a7SEvalZero g_ble_ll_conn_comp_ev = NULL;
4340*042d53a7SEvalZero }
4341*042d53a7SEvalZero
4342*042d53a7SEvalZero /* Reset connection we are attempting to create */
4343*042d53a7SEvalZero g_ble_ll_conn_create_sm = NULL;
4344*042d53a7SEvalZero
4345*042d53a7SEvalZero /* Now go through and end all the connections */
4346*042d53a7SEvalZero while (1) {
4347*042d53a7SEvalZero connsm = SLIST_FIRST(&g_ble_ll_conn_active_list);
4348*042d53a7SEvalZero if (!connsm) {
4349*042d53a7SEvalZero break;
4350*042d53a7SEvalZero }
4351*042d53a7SEvalZero ble_ll_conn_end(connsm, BLE_ERR_SUCCESS);
4352*042d53a7SEvalZero }
4353*042d53a7SEvalZero
4354*042d53a7SEvalZero /* Get the maximum supported PHY PDU size from the PHY */
4355*042d53a7SEvalZero max_phy_pyld = ble_phy_max_data_pdu_pyld();
4356*042d53a7SEvalZero
4357*042d53a7SEvalZero /* Configure the global LL parameters */
4358*042d53a7SEvalZero conn_params = &g_ble_ll_conn_params;
4359*042d53a7SEvalZero
4360*042d53a7SEvalZero maxbytes = min(MYNEWT_VAL(BLE_LL_SUPP_MAX_RX_BYTES), max_phy_pyld);
4361*042d53a7SEvalZero conn_params->supp_max_rx_octets = maxbytes;
4362*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
4363*042d53a7SEvalZero conn_params->supp_max_rx_time = MAX_TIME_CODED(maxbytes);
4364*042d53a7SEvalZero #else
4365*042d53a7SEvalZero conn_params->supp_max_rx_time = MAX_TIME_UNCODED(maxbytes);
4366*042d53a7SEvalZero #endif
4367*042d53a7SEvalZero
4368*042d53a7SEvalZero maxbytes = min(MYNEWT_VAL(BLE_LL_SUPP_MAX_TX_BYTES), max_phy_pyld);
4369*042d53a7SEvalZero conn_params->supp_max_tx_octets = maxbytes;
4370*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
4371*042d53a7SEvalZero conn_params->supp_max_tx_time = MAX_TIME_CODED(maxbytes);
4372*042d53a7SEvalZero #else
4373*042d53a7SEvalZero conn_params->supp_max_tx_time = MAX_TIME_UNCODED(maxbytes);
4374*042d53a7SEvalZero #endif
4375*042d53a7SEvalZero
4376*042d53a7SEvalZero maxbytes = min(MYNEWT_VAL(BLE_LL_CONN_INIT_MAX_TX_BYTES), max_phy_pyld);
4377*042d53a7SEvalZero conn_params->conn_init_max_tx_octets = maxbytes;
4378*042d53a7SEvalZero conn_params->conn_init_max_tx_time = MAX_TIME_UNCODED(maxbytes);
4379*042d53a7SEvalZero conn_params->conn_init_max_tx_time_uncoded = MAX_TIME_UNCODED(maxbytes);
4380*042d53a7SEvalZero conn_params->conn_init_max_tx_time_coded = MAX_TIME_CODED(maxbytes);
4381*042d53a7SEvalZero
4382*042d53a7SEvalZero conn_params->sugg_tx_octets = BLE_LL_CONN_SUPP_BYTES_MIN;
4383*042d53a7SEvalZero conn_params->sugg_tx_time = BLE_LL_CONN_SUPP_TIME_MIN;
4384*042d53a7SEvalZero
4385*042d53a7SEvalZero /* Mask in all channels by default */
4386*042d53a7SEvalZero conn_params->num_used_chans = BLE_PHY_NUM_DATA_CHANS;
4387*042d53a7SEvalZero memset(conn_params->master_chan_map, 0xff, BLE_LL_CONN_CHMAP_LEN - 1);
4388*042d53a7SEvalZero conn_params->master_chan_map[4] = 0x1f;
4389*042d53a7SEvalZero
4390*042d53a7SEvalZero /* Reset statistics */
4391*042d53a7SEvalZero STATS_RESET(ble_ll_conn_stats);
4392*042d53a7SEvalZero }
4393*042d53a7SEvalZero
4394*042d53a7SEvalZero /* Initialize the connection module */
4395*042d53a7SEvalZero void
ble_ll_conn_module_init(void)4396*042d53a7SEvalZero ble_ll_conn_module_init(void)
4397*042d53a7SEvalZero {
4398*042d53a7SEvalZero int rc;
4399*042d53a7SEvalZero uint16_t i;
4400*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
4401*042d53a7SEvalZero
4402*042d53a7SEvalZero /* Initialize list of active conections */
4403*042d53a7SEvalZero SLIST_INIT(&g_ble_ll_conn_active_list);
4404*042d53a7SEvalZero STAILQ_INIT(&g_ble_ll_conn_free_list);
4405*042d53a7SEvalZero
4406*042d53a7SEvalZero /*
4407*042d53a7SEvalZero * Take all the connections off the free memory pool and add them to
4408*042d53a7SEvalZero * the free connection list, assigning handles in linear order. Note:
4409*042d53a7SEvalZero * the specification allows a handle of zero; we just avoid using it.
4410*042d53a7SEvalZero */
4411*042d53a7SEvalZero connsm = &g_ble_ll_conn_sm[0];
4412*042d53a7SEvalZero for (i = 0; i < MYNEWT_VAL(BLE_MAX_CONNECTIONS); ++i) {
4413*042d53a7SEvalZero
4414*042d53a7SEvalZero memset(connsm, 0, sizeof(struct ble_ll_conn_sm));
4415*042d53a7SEvalZero connsm->conn_handle = i + 1;
4416*042d53a7SEvalZero STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe);
4417*042d53a7SEvalZero
4418*042d53a7SEvalZero /* Initialize fixed schedule elements */
4419*042d53a7SEvalZero connsm->conn_sch.sched_type = BLE_LL_SCHED_TYPE_CONN;
4420*042d53a7SEvalZero connsm->conn_sch.cb_arg = connsm;
4421*042d53a7SEvalZero ++connsm;
4422*042d53a7SEvalZero }
4423*042d53a7SEvalZero
4424*042d53a7SEvalZero /* Register connection statistics */
4425*042d53a7SEvalZero rc = stats_init_and_reg(STATS_HDR(ble_ll_conn_stats),
4426*042d53a7SEvalZero STATS_SIZE_INIT_PARMS(ble_ll_conn_stats, STATS_SIZE_32),
4427*042d53a7SEvalZero STATS_NAME_INIT_PARMS(ble_ll_conn_stats),
4428*042d53a7SEvalZero "ble_ll_conn");
4429*042d53a7SEvalZero BLE_LL_ASSERT(rc == 0);
4430*042d53a7SEvalZero
4431*042d53a7SEvalZero /* Call reset to finish reset of initialization */
4432*042d53a7SEvalZero ble_ll_conn_module_reset();
4433*042d53a7SEvalZero }
4434