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 "controller/ble_phy.h"
32*042d53a7SEvalZero #include "controller/ble_hw.h"
33*042d53a7SEvalZero #include "controller/ble_ll.h"
34*042d53a7SEvalZero #include "controller/ble_ll_sched.h"
35*042d53a7SEvalZero #include "controller/ble_ll_adv.h"
36*042d53a7SEvalZero #include "controller/ble_ll_scan.h"
37*042d53a7SEvalZero #include "controller/ble_ll_hci.h"
38*042d53a7SEvalZero #include "controller/ble_ll_whitelist.h"
39*042d53a7SEvalZero #include "controller/ble_ll_resolv.h"
40*042d53a7SEvalZero #include "controller/ble_ll_xcvr.h"
41*042d53a7SEvalZero #include "controller/ble_ll_trace.h"
42*042d53a7SEvalZero #include "ble_ll_conn_priv.h"
43*042d53a7SEvalZero
44*042d53a7SEvalZero /*
45*042d53a7SEvalZero * XXX:
46*042d53a7SEvalZero * 1) I think I can guarantee that we dont process things out of order if
47*042d53a7SEvalZero * I send an event when a scan request is sent. The scan_rsp_pending flag
48*042d53a7SEvalZero * code might be made simpler.
49*042d53a7SEvalZero *
50*042d53a7SEvalZero * 2) Interleave sending scan requests to different advertisers? I guess I need
51*042d53a7SEvalZero * a list of advertisers to which I sent a scan request and have yet to
52*042d53a7SEvalZero * receive a scan response from? Implement this.
53*042d53a7SEvalZero */
54*042d53a7SEvalZero
55*042d53a7SEvalZero /* Dont allow more than 255 of these entries */
56*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_NUM_SCAN_DUP_ADVS) > 255
57*042d53a7SEvalZero #error "Cannot have more than 255 duplicate entries!"
58*042d53a7SEvalZero #endif
59*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_NUM_SCAN_RSP_ADVS) > 255
60*042d53a7SEvalZero #error "Cannot have more than 255 scan response entries!"
61*042d53a7SEvalZero #endif
62*042d53a7SEvalZero
63*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
64*042d53a7SEvalZero static const uint8_t ble_ll_valid_scan_phy_mask = (BLE_HCI_LE_PHY_1M_PREF_MASK
65*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
66*042d53a7SEvalZero | BLE_HCI_LE_PHY_CODED_PREF_MASK
67*042d53a7SEvalZero #endif
68*042d53a7SEvalZero );
69*042d53a7SEvalZero #endif
70*042d53a7SEvalZero
71*042d53a7SEvalZero /* The scanning parameters set by host */
72*042d53a7SEvalZero static struct ble_ll_scan_params g_ble_ll_scan_params[BLE_LL_SCAN_PHY_NUMBER];
73*042d53a7SEvalZero
74*042d53a7SEvalZero /* The scanning state machine global object */
75*042d53a7SEvalZero static struct ble_ll_scan_sm g_ble_ll_scan_sm;
76*042d53a7SEvalZero
77*042d53a7SEvalZero #define BLE_LL_EXT_ADV_ADVA_BIT (0)
78*042d53a7SEvalZero #define BLE_LL_EXT_ADV_TARGETA_BIT (1)
79*042d53a7SEvalZero #define BLE_LL_EXT_ADV_RFU_BIT (2)
80*042d53a7SEvalZero #define BLE_LL_EXT_ADV_DATA_INFO_BIT (3)
81*042d53a7SEvalZero #define BLE_LL_EXT_ADV_AUX_PTR_BIT (4)
82*042d53a7SEvalZero #define BLE_LL_EXT_ADV_SYNC_INFO_BIT (5)
83*042d53a7SEvalZero #define BLE_LL_EXT_ADV_TX_POWER_BIT (6)
84*042d53a7SEvalZero
85*042d53a7SEvalZero #define BLE_LL_EXT_ADV_ADVA_SIZE (6)
86*042d53a7SEvalZero #define BLE_LL_EXT_ADV_TARGETA_SIZE (6)
87*042d53a7SEvalZero #define BLE_LL_EXT_ADV_DATA_INFO_SIZE (2)
88*042d53a7SEvalZero #define BLE_LL_EXT_ADV_AUX_PTR_SIZE (3)
89*042d53a7SEvalZero #define BLE_LL_EXT_ADV_SYNC_INFO_SIZE (18)
90*042d53a7SEvalZero #define BLE_LL_EXT_ADV_TX_POWER_SIZE (1)
91*042d53a7SEvalZero
92*042d53a7SEvalZero struct ble_ll_ext_adv_hdr
93*042d53a7SEvalZero {
94*042d53a7SEvalZero uint8_t mode;
95*042d53a7SEvalZero uint8_t hdr_len;
96*042d53a7SEvalZero uint8_t hdr[0];
97*042d53a7SEvalZero };
98*042d53a7SEvalZero
99*042d53a7SEvalZero struct ble_ll_ext_adv_report {
100*042d53a7SEvalZero /* We support one report per event for now */
101*042d53a7SEvalZero uint8_t event_meta; /* BLE_HCI_EVCODE_LE_META */
102*042d53a7SEvalZero uint8_t event_len;
103*042d53a7SEvalZero uint8_t subevt;
104*042d53a7SEvalZero uint8_t num_reports;
105*042d53a7SEvalZero
106*042d53a7SEvalZero uint16_t evt_type;
107*042d53a7SEvalZero uint8_t addr_type;
108*042d53a7SEvalZero uint8_t addr[6];
109*042d53a7SEvalZero uint8_t prim_phy;
110*042d53a7SEvalZero uint8_t sec_phy;
111*042d53a7SEvalZero uint8_t sid;
112*042d53a7SEvalZero uint8_t tx_power;
113*042d53a7SEvalZero int8_t rssi;
114*042d53a7SEvalZero uint16_t per_adv_itvl;
115*042d53a7SEvalZero uint8_t dir_addr_type;
116*042d53a7SEvalZero uint8_t dir_addr[6];
117*042d53a7SEvalZero uint8_t adv_data_len;
118*042d53a7SEvalZero uint8_t adv_data[0];
119*042d53a7SEvalZero } __attribute__((packed));
120*042d53a7SEvalZero
121*042d53a7SEvalZero /*
122*042d53a7SEvalZero * Structure used to store advertisers. This is used to limit sending scan
123*042d53a7SEvalZero * requests to the same advertiser and also to filter duplicate events sent
124*042d53a7SEvalZero * to the host.
125*042d53a7SEvalZero */
126*042d53a7SEvalZero struct ble_ll_scan_advertisers
127*042d53a7SEvalZero {
128*042d53a7SEvalZero uint16_t sc_adv_flags;
129*042d53a7SEvalZero uint16_t adi;
130*042d53a7SEvalZero struct ble_dev_addr adv_addr;
131*042d53a7SEvalZero };
132*042d53a7SEvalZero
133*042d53a7SEvalZero #define BLE_LL_SC_ADV_F_RANDOM_ADDR (0x01)
134*042d53a7SEvalZero #define BLE_LL_SC_ADV_F_SCAN_RSP_RXD (0x02)
135*042d53a7SEvalZero #define BLE_LL_SC_ADV_F_DIRECT_RPT_SENT (0x04)
136*042d53a7SEvalZero #define BLE_LL_SC_ADV_F_ADV_RPT_SENT (0x08)
137*042d53a7SEvalZero #define BLE_LL_SC_ADV_F_SCAN_RSP_SENT (0x10)
138*042d53a7SEvalZero
139*042d53a7SEvalZero /* Contains list of advertisers that we have heard scan responses from */
140*042d53a7SEvalZero static uint8_t g_ble_ll_scan_num_rsp_advs;
141*042d53a7SEvalZero struct ble_ll_scan_advertisers
142*042d53a7SEvalZero g_ble_ll_scan_rsp_advs[MYNEWT_VAL(BLE_LL_NUM_SCAN_RSP_ADVS)];
143*042d53a7SEvalZero
144*042d53a7SEvalZero /* Used to filter duplicate advertising events to host */
145*042d53a7SEvalZero static uint8_t g_ble_ll_scan_num_dup_advs;
146*042d53a7SEvalZero struct ble_ll_scan_advertisers
147*042d53a7SEvalZero g_ble_ll_scan_dup_advs[MYNEWT_VAL(BLE_LL_NUM_SCAN_DUP_ADVS)];
148*042d53a7SEvalZero
149*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
150*042d53a7SEvalZero static os_membuf_t ext_adv_mem[ OS_MEMPOOL_SIZE(
151*042d53a7SEvalZero MYNEWT_VAL(BLE_LL_EXT_ADV_AUX_PTR_CNT),
152*042d53a7SEvalZero sizeof (struct ble_ll_aux_data))
153*042d53a7SEvalZero ];
154*042d53a7SEvalZero
155*042d53a7SEvalZero static struct os_mempool ext_adv_pool;
156*042d53a7SEvalZero
157*042d53a7SEvalZero static int ble_ll_scan_start(struct ble_ll_scan_sm *scansm,
158*042d53a7SEvalZero struct ble_ll_sched_item *sch);
159*042d53a7SEvalZero
160*042d53a7SEvalZero static int
ble_ll_aux_scan_cb(struct ble_ll_sched_item * sch)161*042d53a7SEvalZero ble_ll_aux_scan_cb(struct ble_ll_sched_item *sch)
162*042d53a7SEvalZero {
163*042d53a7SEvalZero struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm;
164*042d53a7SEvalZero uint8_t lls = ble_ll_state_get();
165*042d53a7SEvalZero uint32_t wfr_usec;
166*042d53a7SEvalZero
167*042d53a7SEvalZero STATS_INC(ble_ll_stats, aux_sched_cb);
168*042d53a7SEvalZero
169*042d53a7SEvalZero /* In case scan has been disabled or there is other aux ptr in progress
170*042d53a7SEvalZero * just drop the scheduled item
171*042d53a7SEvalZero */
172*042d53a7SEvalZero if (!scansm->scan_enabled || scansm->cur_aux_data) {
173*042d53a7SEvalZero ble_ll_scan_aux_data_unref(sch->cb_arg);
174*042d53a7SEvalZero goto done;
175*042d53a7SEvalZero }
176*042d53a7SEvalZero
177*042d53a7SEvalZero /* Check if there is no aux connect sent. If so drop the sched item */
178*042d53a7SEvalZero if (lls == BLE_LL_STATE_INITIATING && ble_ll_conn_init_pending_aux_conn_rsp()) {
179*042d53a7SEvalZero ble_ll_scan_aux_data_unref(sch->cb_arg);
180*042d53a7SEvalZero goto done;
181*042d53a7SEvalZero }
182*042d53a7SEvalZero
183*042d53a7SEvalZero /* This function is called only when scanner is running. This can happen
184*042d53a7SEvalZero * in 3 states:
185*042d53a7SEvalZero * BLE_LL_STATE_SCANNING
186*042d53a7SEvalZero * BLE_LL_STATE_INITIATING
187*042d53a7SEvalZero * BLE_LL_STATE_STANDBY
188*042d53a7SEvalZero */
189*042d53a7SEvalZero if (lls != BLE_LL_STATE_STANDBY) {
190*042d53a7SEvalZero ble_phy_disable();
191*042d53a7SEvalZero ble_ll_wfr_disable();
192*042d53a7SEvalZero ble_ll_state_set(BLE_LL_STATE_STANDBY);
193*042d53a7SEvalZero }
194*042d53a7SEvalZero
195*042d53a7SEvalZero /* When doing RX for AUX pkt, cur_aux_data keeps valid aux data */
196*042d53a7SEvalZero scansm->cur_aux_data = sch->cb_arg;
197*042d53a7SEvalZero BLE_LL_ASSERT(scansm->cur_aux_data != NULL);
198*042d53a7SEvalZero scansm->cur_aux_data->scanning = 1;
199*042d53a7SEvalZero
200*042d53a7SEvalZero if (ble_ll_scan_start(scansm, sch)) {
201*042d53a7SEvalZero ble_ll_scan_aux_data_unref(scansm->cur_aux_data);
202*042d53a7SEvalZero scansm->cur_aux_data = NULL;
203*042d53a7SEvalZero ble_ll_scan_chk_resume();
204*042d53a7SEvalZero goto done;
205*042d53a7SEvalZero }
206*042d53a7SEvalZero
207*042d53a7SEvalZero STATS_INC(ble_ll_stats, aux_fired_for_read);
208*042d53a7SEvalZero
209*042d53a7SEvalZero wfr_usec = scansm->cur_aux_data->offset_units ? 300 : 30;
210*042d53a7SEvalZero ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_RX, 0, wfr_usec);
211*042d53a7SEvalZero
212*042d53a7SEvalZero done:
213*042d53a7SEvalZero
214*042d53a7SEvalZero return BLE_LL_SCHED_STATE_DONE;
215*042d53a7SEvalZero }
216*042d53a7SEvalZero
217*042d53a7SEvalZero static int
ble_ll_scan_ext_adv_init(struct ble_ll_aux_data ** aux_data)218*042d53a7SEvalZero ble_ll_scan_ext_adv_init(struct ble_ll_aux_data **aux_data)
219*042d53a7SEvalZero {
220*042d53a7SEvalZero struct ble_ll_aux_data *e;
221*042d53a7SEvalZero
222*042d53a7SEvalZero e = os_memblock_get(&ext_adv_pool);
223*042d53a7SEvalZero if (!e) {
224*042d53a7SEvalZero return -1;
225*042d53a7SEvalZero }
226*042d53a7SEvalZero
227*042d53a7SEvalZero memset(e, 0, sizeof(*e));
228*042d53a7SEvalZero e->sch.sched_cb = ble_ll_aux_scan_cb;
229*042d53a7SEvalZero e->sch.cb_arg = e;
230*042d53a7SEvalZero e->sch.sched_type = BLE_LL_SCHED_TYPE_AUX_SCAN;
231*042d53a7SEvalZero e->ref_cnt = 1;
232*042d53a7SEvalZero ble_ll_trace_u32x2(BLE_LL_TRACE_ID_AUX_REF, (uint32_t)e, e->ref_cnt);
233*042d53a7SEvalZero
234*042d53a7SEvalZero *aux_data = e;
235*042d53a7SEvalZero STATS_INC(ble_ll_stats, aux_allocated);
236*042d53a7SEvalZero
237*042d53a7SEvalZero return 0;
238*042d53a7SEvalZero }
239*042d53a7SEvalZero #endif
240*042d53a7SEvalZero
241*042d53a7SEvalZero /* See Vol 6 Part B Section 4.4.3.2. Active scanning backoff */
242*042d53a7SEvalZero static void
ble_ll_scan_req_backoff(struct ble_ll_scan_sm * scansm,int success)243*042d53a7SEvalZero ble_ll_scan_req_backoff(struct ble_ll_scan_sm *scansm, int success)
244*042d53a7SEvalZero {
245*042d53a7SEvalZero scansm->scan_rsp_pending = 0;
246*042d53a7SEvalZero if (success) {
247*042d53a7SEvalZero scansm->scan_rsp_cons_fails = 0;
248*042d53a7SEvalZero ++scansm->scan_rsp_cons_ok;
249*042d53a7SEvalZero if (scansm->scan_rsp_cons_ok == 2) {
250*042d53a7SEvalZero scansm->scan_rsp_cons_ok = 0;
251*042d53a7SEvalZero if (scansm->upper_limit > 1) {
252*042d53a7SEvalZero scansm->upper_limit >>= 1;
253*042d53a7SEvalZero }
254*042d53a7SEvalZero }
255*042d53a7SEvalZero STATS_INC(ble_ll_stats, scan_req_txg);
256*042d53a7SEvalZero } else {
257*042d53a7SEvalZero scansm->scan_rsp_cons_ok = 0;
258*042d53a7SEvalZero ++scansm->scan_rsp_cons_fails;
259*042d53a7SEvalZero if (scansm->scan_rsp_cons_fails == 2) {
260*042d53a7SEvalZero scansm->scan_rsp_cons_fails = 0;
261*042d53a7SEvalZero if (scansm->upper_limit < 256) {
262*042d53a7SEvalZero scansm->upper_limit <<= 1;
263*042d53a7SEvalZero }
264*042d53a7SEvalZero }
265*042d53a7SEvalZero STATS_INC(ble_ll_stats, scan_req_txf);
266*042d53a7SEvalZero }
267*042d53a7SEvalZero
268*042d53a7SEvalZero scansm->backoff_count = rand() & (scansm->upper_limit - 1);
269*042d53a7SEvalZero ++scansm->backoff_count;
270*042d53a7SEvalZero BLE_LL_ASSERT(scansm->backoff_count <= 256);
271*042d53a7SEvalZero }
272*042d53a7SEvalZero
273*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
274*042d53a7SEvalZero static void
ble_ll_scan_refresh_nrpa(struct ble_ll_scan_sm * scansm)275*042d53a7SEvalZero ble_ll_scan_refresh_nrpa(struct ble_ll_scan_sm *scansm)
276*042d53a7SEvalZero {
277*042d53a7SEvalZero ble_npl_time_t now;
278*042d53a7SEvalZero
279*042d53a7SEvalZero now = ble_npl_time_get();
280*042d53a7SEvalZero if ((ble_npl_stime_t)(now - scansm->scan_nrpa_timer) >= 0) {
281*042d53a7SEvalZero /* Generate new NRPA */
282*042d53a7SEvalZero ble_ll_rand_data_get(scansm->scan_nrpa, BLE_DEV_ADDR_LEN);
283*042d53a7SEvalZero scansm->scan_nrpa[5] &= ~0xc0;
284*042d53a7SEvalZero
285*042d53a7SEvalZero /* We'll use the same timeout as for RPA rotation */
286*042d53a7SEvalZero scansm->scan_nrpa_timer = now + ble_ll_resolv_get_rpa_tmo();
287*042d53a7SEvalZero }
288*042d53a7SEvalZero }
289*042d53a7SEvalZero #endif
290*042d53a7SEvalZero
291*042d53a7SEvalZero /**
292*042d53a7SEvalZero * ble ll scan req pdu make
293*042d53a7SEvalZero *
294*042d53a7SEvalZero * Construct a SCAN_REQ PDU.
295*042d53a7SEvalZero *
296*042d53a7SEvalZero * @param scansm Pointer to scanning state machine
297*042d53a7SEvalZero * @param adv_addr Pointer to device address of advertiser
298*042d53a7SEvalZero * @param addr_type 0 if public; non-zero if random. This is the addr type of
299*042d53a7SEvalZero * the advertiser; not our "own address type"
300*042d53a7SEvalZero */
301*042d53a7SEvalZero static void
ble_ll_scan_req_pdu_make(struct ble_ll_scan_sm * scansm,uint8_t * adv_addr,uint8_t adv_addr_type)302*042d53a7SEvalZero ble_ll_scan_req_pdu_make(struct ble_ll_scan_sm *scansm, uint8_t *adv_addr,
303*042d53a7SEvalZero uint8_t adv_addr_type)
304*042d53a7SEvalZero {
305*042d53a7SEvalZero uint8_t *dptr;
306*042d53a7SEvalZero uint8_t pdu_type;
307*042d53a7SEvalZero uint8_t *scana;
308*042d53a7SEvalZero struct os_mbuf *m;
309*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
310*042d53a7SEvalZero uint8_t rpa[BLE_DEV_ADDR_LEN];
311*042d53a7SEvalZero struct ble_ll_resolv_entry *rl;
312*042d53a7SEvalZero #endif
313*042d53a7SEvalZero
314*042d53a7SEvalZero /* Construct first PDU header byte */
315*042d53a7SEvalZero pdu_type = BLE_ADV_PDU_TYPE_SCAN_REQ;
316*042d53a7SEvalZero if (adv_addr_type) {
317*042d53a7SEvalZero pdu_type |= BLE_ADV_PDU_HDR_RXADD_RAND;
318*042d53a7SEvalZero }
319*042d53a7SEvalZero
320*042d53a7SEvalZero /* Get the advertising PDU */
321*042d53a7SEvalZero m = scansm->scan_req_pdu;
322*042d53a7SEvalZero BLE_LL_ASSERT(m != NULL);
323*042d53a7SEvalZero
324*042d53a7SEvalZero /* Get pointer to our device address */
325*042d53a7SEvalZero if ((scansm->own_addr_type & 1) == 0) {
326*042d53a7SEvalZero scana = g_dev_addr;
327*042d53a7SEvalZero } else {
328*042d53a7SEvalZero pdu_type |= BLE_ADV_PDU_HDR_TXADD_RAND;
329*042d53a7SEvalZero scana = g_random_addr;
330*042d53a7SEvalZero }
331*042d53a7SEvalZero
332*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
333*042d53a7SEvalZero if (scansm->own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) {
334*042d53a7SEvalZero rl = NULL;
335*042d53a7SEvalZero if (ble_ll_is_rpa(adv_addr, adv_addr_type)) {
336*042d53a7SEvalZero if (scansm->scan_rpa_index >= 0) {
337*042d53a7SEvalZero /* Generate a RPA to use for scana */
338*042d53a7SEvalZero rl = &g_ble_ll_resolv_list[scansm->scan_rpa_index];
339*042d53a7SEvalZero }
340*042d53a7SEvalZero } else {
341*042d53a7SEvalZero if (ble_ll_resolv_enabled()) {
342*042d53a7SEvalZero rl = ble_ll_resolv_list_find(adv_addr, adv_addr_type);
343*042d53a7SEvalZero }
344*042d53a7SEvalZero }
345*042d53a7SEvalZero
346*042d53a7SEvalZero /*
347*042d53a7SEvalZero * If advertising device is on our resolving list, we use RPA generated
348*042d53a7SEvalZero * using Local IRK from resolving list entry as ScanA. In other case,
349*042d53a7SEvalZero * we use NRPA as ScanA as allowed by spec to prevent our device from
350*042d53a7SEvalZero * being tracked when doing an active scan (see Core 5.0, Vol 6, Part B,
351*042d53a7SEvalZero * section 6.3).
352*042d53a7SEvalZero */
353*042d53a7SEvalZero if (rl) {
354*042d53a7SEvalZero ble_ll_resolv_get_priv_addr(rl, 1, rpa);
355*042d53a7SEvalZero scana = rpa;
356*042d53a7SEvalZero } else {
357*042d53a7SEvalZero ble_ll_scan_refresh_nrpa(scansm);
358*042d53a7SEvalZero scana = scansm->scan_nrpa;
359*042d53a7SEvalZero }
360*042d53a7SEvalZero
361*042d53a7SEvalZero pdu_type |= BLE_ADV_PDU_HDR_TXADD_RAND;
362*042d53a7SEvalZero }
363*042d53a7SEvalZero #endif
364*042d53a7SEvalZero
365*042d53a7SEvalZero ble_ll_mbuf_init(m, BLE_SCAN_REQ_LEN, pdu_type);
366*042d53a7SEvalZero
367*042d53a7SEvalZero /* Construct the scan request */
368*042d53a7SEvalZero dptr = m->om_data;
369*042d53a7SEvalZero memcpy(dptr, scana, BLE_DEV_ADDR_LEN);
370*042d53a7SEvalZero memcpy(dptr + BLE_DEV_ADDR_LEN, adv_addr, BLE_DEV_ADDR_LEN);
371*042d53a7SEvalZero }
372*042d53a7SEvalZero
373*042d53a7SEvalZero /**
374*042d53a7SEvalZero * Checks to see if an advertiser is on the duplicate address list.
375*042d53a7SEvalZero *
376*042d53a7SEvalZero * @param addr Pointer to address
377*042d53a7SEvalZero * @param txadd TxAdd bit. 0: public; random otherwise
378*042d53a7SEvalZero *
379*042d53a7SEvalZero * @return uint8_t 0: not on list; any other value is
380*042d53a7SEvalZero */
381*042d53a7SEvalZero static struct ble_ll_scan_advertisers *
ble_ll_scan_find_dup_adv(uint8_t * addr,uint8_t txadd)382*042d53a7SEvalZero ble_ll_scan_find_dup_adv(uint8_t *addr, uint8_t txadd)
383*042d53a7SEvalZero {
384*042d53a7SEvalZero uint8_t num_advs;
385*042d53a7SEvalZero struct ble_ll_scan_advertisers *adv;
386*042d53a7SEvalZero
387*042d53a7SEvalZero /* Do we have an address match? Must match address type */
388*042d53a7SEvalZero adv = &g_ble_ll_scan_dup_advs[0];
389*042d53a7SEvalZero num_advs = g_ble_ll_scan_num_dup_advs;
390*042d53a7SEvalZero while (num_advs) {
391*042d53a7SEvalZero if (!memcmp(&adv->adv_addr, addr, BLE_DEV_ADDR_LEN)) {
392*042d53a7SEvalZero /* Address type must match */
393*042d53a7SEvalZero if (txadd) {
394*042d53a7SEvalZero if ((adv->sc_adv_flags & BLE_LL_SC_ADV_F_RANDOM_ADDR) == 0) {
395*042d53a7SEvalZero goto next_dup_adv;
396*042d53a7SEvalZero }
397*042d53a7SEvalZero } else {
398*042d53a7SEvalZero if (adv->sc_adv_flags & BLE_LL_SC_ADV_F_RANDOM_ADDR) {
399*042d53a7SEvalZero goto next_dup_adv;
400*042d53a7SEvalZero }
401*042d53a7SEvalZero }
402*042d53a7SEvalZero
403*042d53a7SEvalZero return adv;
404*042d53a7SEvalZero }
405*042d53a7SEvalZero
406*042d53a7SEvalZero next_dup_adv:
407*042d53a7SEvalZero ++adv;
408*042d53a7SEvalZero --num_advs;
409*042d53a7SEvalZero }
410*042d53a7SEvalZero
411*042d53a7SEvalZero return NULL;
412*042d53a7SEvalZero }
413*042d53a7SEvalZero
414*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
415*042d53a7SEvalZero static struct ble_ll_ext_adv_report *
ble_ll_scan_init_ext_adv_report(struct ble_ll_ext_adv_report * copy_from)416*042d53a7SEvalZero ble_ll_scan_init_ext_adv_report(struct ble_ll_ext_adv_report *copy_from)
417*042d53a7SEvalZero {
418*042d53a7SEvalZero struct ble_ll_ext_adv_report *evt;
419*042d53a7SEvalZero
420*042d53a7SEvalZero evt = (struct ble_ll_ext_adv_report *) ble_hci_trans_buf_alloc(
421*042d53a7SEvalZero BLE_HCI_TRANS_BUF_EVT_LO);
422*042d53a7SEvalZero if (!evt) {
423*042d53a7SEvalZero return NULL;
424*042d53a7SEvalZero }
425*042d53a7SEvalZero
426*042d53a7SEvalZero if (copy_from) {
427*042d53a7SEvalZero memcpy(evt, copy_from, sizeof(*evt));
428*042d53a7SEvalZero } else {
429*042d53a7SEvalZero memset(evt, 0, sizeof(*evt));
430*042d53a7SEvalZero
431*042d53a7SEvalZero evt->event_meta = BLE_HCI_EVCODE_LE_META;
432*042d53a7SEvalZero evt->subevt = BLE_HCI_LE_SUBEV_EXT_ADV_RPT;
433*042d53a7SEvalZero /* We support only one report per event now */
434*042d53a7SEvalZero evt->num_reports = 1;
435*042d53a7SEvalZero /* Init TX Power with "Not available" which is 127 */
436*042d53a7SEvalZero evt->tx_power = 127;
437*042d53a7SEvalZero /* Init RSSI with "Not available" which is 127 */
438*042d53a7SEvalZero evt->rssi = 127;
439*042d53a7SEvalZero /* Init SID with "Not available" which is 0xFF */
440*042d53a7SEvalZero evt->sid = 0xFF;
441*042d53a7SEvalZero /* Init address type with "anonymous" which is 0xFF */
442*042d53a7SEvalZero evt->addr_type = 0xFF;
443*042d53a7SEvalZero }
444*042d53a7SEvalZero
445*042d53a7SEvalZero return evt;
446*042d53a7SEvalZero }
447*042d53a7SEvalZero
448*042d53a7SEvalZero static void
ble_ll_scan_send_truncated_if_chained(struct ble_ll_aux_data * aux_data)449*042d53a7SEvalZero ble_ll_scan_send_truncated_if_chained(struct ble_ll_aux_data *aux_data)
450*042d53a7SEvalZero {
451*042d53a7SEvalZero struct ble_ll_ext_adv_report *evt;
452*042d53a7SEvalZero
453*042d53a7SEvalZero if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) {
454*042d53a7SEvalZero goto done;
455*042d53a7SEvalZero }
456*042d53a7SEvalZero
457*042d53a7SEvalZero BLE_LL_ASSERT(aux_data);
458*042d53a7SEvalZero
459*042d53a7SEvalZero if (!BLE_LL_CHECK_AUX_FLAG(aux_data, BLE_LL_AUX_CHAIN_BIT)) {
460*042d53a7SEvalZero /* if not chained, there is nothing to do here */
461*042d53a7SEvalZero goto done;
462*042d53a7SEvalZero }
463*042d53a7SEvalZero
464*042d53a7SEvalZero if (aux_data->evt) {
465*042d53a7SEvalZero evt = aux_data->evt;
466*042d53a7SEvalZero aux_data->evt = NULL;
467*042d53a7SEvalZero } else {
468*042d53a7SEvalZero evt = ble_ll_scan_init_ext_adv_report(NULL);
469*042d53a7SEvalZero if (!evt) {
470*042d53a7SEvalZero goto done;
471*042d53a7SEvalZero }
472*042d53a7SEvalZero }
473*042d53a7SEvalZero
474*042d53a7SEvalZero evt->event_len = sizeof(*evt);
475*042d53a7SEvalZero evt->evt_type = aux_data->evt_type;
476*042d53a7SEvalZero evt->evt_type |= (BLE_HCI_ADV_DATA_STATUS_TRUNCATED);
477*042d53a7SEvalZero BLE_LL_SET_AUX_FLAG(aux_data, BLE_LL_AUX_TRUNCATED_SENT);
478*042d53a7SEvalZero
479*042d53a7SEvalZero if (BLE_LL_CHECK_AUX_FLAG(aux_data, BLE_LL_AUX_HAS_ADDRA)) {
480*042d53a7SEvalZero memcpy(evt->addr, aux_data->addr, 6);
481*042d53a7SEvalZero evt->addr_type = aux_data->addr_type;
482*042d53a7SEvalZero }
483*042d53a7SEvalZero
484*042d53a7SEvalZero if (BLE_LL_CHECK_AUX_FLAG(aux_data, BLE_LL_AUX_HAS_DIR_ADDRA)) {
485*042d53a7SEvalZero memcpy(evt->dir_addr, aux_data->dir_addr, 6);
486*042d53a7SEvalZero evt->dir_addr_type = aux_data->dir_addr_type;
487*042d53a7SEvalZero }
488*042d53a7SEvalZero
489*042d53a7SEvalZero evt->sid = (aux_data->adi >> 12);
490*042d53a7SEvalZero ble_ll_hci_event_send((uint8_t *)evt);
491*042d53a7SEvalZero
492*042d53a7SEvalZero done:
493*042d53a7SEvalZero ble_ll_scan_aux_data_unref(aux_data);
494*042d53a7SEvalZero }
495*042d53a7SEvalZero #endif
496*042d53a7SEvalZero
497*042d53a7SEvalZero void
ble_ll_scan_end_adv_evt(struct ble_ll_aux_data * aux_data)498*042d53a7SEvalZero ble_ll_scan_end_adv_evt(struct ble_ll_aux_data *aux_data)
499*042d53a7SEvalZero {
500*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
501*042d53a7SEvalZero /*
502*042d53a7SEvalZero * Check if tuncated has been sent
503*042d53a7SEvalZero *
504*042d53a7SEvalZero * Normally reference counter here should be 2. 1 for outstanding
505*042d53a7SEvalZero * complete event and one for ongoing scanning. If there is only 1
506*042d53a7SEvalZero * that means, advertising event is already completed
507*042d53a7SEvalZero * (truncated was sent to the host) and we just need to drop last reference.
508*042d53a7SEvalZero * Otherwise we should try to send truncated event to the host.
509*042d53a7SEvalZero */
510*042d53a7SEvalZero if (!BLE_LL_CHECK_AUX_FLAG(aux_data, BLE_LL_AUX_TRUNCATED_SENT)) {
511*042d53a7SEvalZero ble_ll_scan_send_truncated_if_chained(aux_data);
512*042d53a7SEvalZero }
513*042d53a7SEvalZero
514*042d53a7SEvalZero if (ble_ll_scan_aux_data_unref(aux_data) > 0) {
515*042d53a7SEvalZero BLE_LL_ASSERT(0);
516*042d53a7SEvalZero }
517*042d53a7SEvalZero
518*042d53a7SEvalZero #endif
519*042d53a7SEvalZero }
520*042d53a7SEvalZero /**
521*042d53a7SEvalZero * Do scan machine clean up on PHY disabled
522*042d53a7SEvalZero *
523*042d53a7SEvalZero */
524*042d53a7SEvalZero void
ble_ll_scan_clean_cur_aux_data(void)525*042d53a7SEvalZero ble_ll_scan_clean_cur_aux_data(void)
526*042d53a7SEvalZero {
527*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
528*042d53a7SEvalZero struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm;
529*042d53a7SEvalZero
530*042d53a7SEvalZero /* If scanner was reading aux ptr, we need to clean it up */
531*042d53a7SEvalZero if (scansm && scansm->cur_aux_data) {
532*042d53a7SEvalZero ble_ll_scan_end_adv_evt(scansm->cur_aux_data);
533*042d53a7SEvalZero scansm->cur_aux_data = NULL;
534*042d53a7SEvalZero }
535*042d53a7SEvalZero #endif
536*042d53a7SEvalZero }
537*042d53a7SEvalZero
538*042d53a7SEvalZero /**
539*042d53a7SEvalZero * Check if a packet is a duplicate advertising packet.
540*042d53a7SEvalZero *
541*042d53a7SEvalZero * @param pdu_type
542*042d53a7SEvalZero * @param rxbuf
543*042d53a7SEvalZero *
544*042d53a7SEvalZero * @return int 0: not a duplicate. 1:duplicate
545*042d53a7SEvalZero */
546*042d53a7SEvalZero int
ble_ll_scan_is_dup_adv(uint8_t pdu_type,uint8_t txadd,uint8_t * addr)547*042d53a7SEvalZero ble_ll_scan_is_dup_adv(uint8_t pdu_type, uint8_t txadd, uint8_t *addr)
548*042d53a7SEvalZero {
549*042d53a7SEvalZero struct ble_ll_scan_advertisers *adv;
550*042d53a7SEvalZero
551*042d53a7SEvalZero adv = ble_ll_scan_find_dup_adv(addr, txadd);
552*042d53a7SEvalZero if (adv) {
553*042d53a7SEvalZero /* Check appropriate flag (based on type of PDU) */
554*042d53a7SEvalZero if (pdu_type == BLE_ADV_PDU_TYPE_ADV_DIRECT_IND) {
555*042d53a7SEvalZero if (adv->sc_adv_flags & BLE_LL_SC_ADV_F_DIRECT_RPT_SENT) {
556*042d53a7SEvalZero return 1;
557*042d53a7SEvalZero }
558*042d53a7SEvalZero } else if (pdu_type == BLE_ADV_PDU_TYPE_SCAN_RSP) {
559*042d53a7SEvalZero if (adv->sc_adv_flags & BLE_LL_SC_ADV_F_SCAN_RSP_SENT) {
560*042d53a7SEvalZero return 1;
561*042d53a7SEvalZero }
562*042d53a7SEvalZero } else {
563*042d53a7SEvalZero if (adv->sc_adv_flags & BLE_LL_SC_ADV_F_ADV_RPT_SENT) {
564*042d53a7SEvalZero return 1;
565*042d53a7SEvalZero }
566*042d53a7SEvalZero }
567*042d53a7SEvalZero }
568*042d53a7SEvalZero
569*042d53a7SEvalZero return 0;
570*042d53a7SEvalZero }
571*042d53a7SEvalZero
572*042d53a7SEvalZero /**
573*042d53a7SEvalZero * Add an advertiser the list of duplicate advertisers. An address gets added to
574*042d53a7SEvalZero * the list of duplicate addresses when the controller sends an advertising
575*042d53a7SEvalZero * report to the host.
576*042d53a7SEvalZero *
577*042d53a7SEvalZero * @param addr Pointer to advertisers address or identity address
578*042d53a7SEvalZero * @param Txadd. TxAdd bit (0 public, random otherwise)
579*042d53a7SEvalZero * @param subev Type of advertising report sent (direct or normal).
580*042d53a7SEvalZero * @param evtype Advertising event type
581*042d53a7SEvalZero */
582*042d53a7SEvalZero void
ble_ll_scan_add_dup_adv(uint8_t * addr,uint8_t txadd,uint8_t subev,uint8_t evtype)583*042d53a7SEvalZero ble_ll_scan_add_dup_adv(uint8_t *addr, uint8_t txadd, uint8_t subev,
584*042d53a7SEvalZero uint8_t evtype)
585*042d53a7SEvalZero {
586*042d53a7SEvalZero uint8_t num_advs;
587*042d53a7SEvalZero struct ble_ll_scan_advertisers *adv;
588*042d53a7SEvalZero
589*042d53a7SEvalZero /* Check to see if on list. */
590*042d53a7SEvalZero adv = ble_ll_scan_find_dup_adv(addr, txadd);
591*042d53a7SEvalZero if (!adv) {
592*042d53a7SEvalZero /* XXX: for now, if we dont have room, just leave */
593*042d53a7SEvalZero num_advs = g_ble_ll_scan_num_dup_advs;
594*042d53a7SEvalZero if (num_advs == MYNEWT_VAL(BLE_LL_NUM_SCAN_DUP_ADVS)) {
595*042d53a7SEvalZero return;
596*042d53a7SEvalZero }
597*042d53a7SEvalZero
598*042d53a7SEvalZero /* Add the advertiser to the array */
599*042d53a7SEvalZero adv = &g_ble_ll_scan_dup_advs[num_advs];
600*042d53a7SEvalZero memcpy(&adv->adv_addr, addr, BLE_DEV_ADDR_LEN);
601*042d53a7SEvalZero ++g_ble_ll_scan_num_dup_advs;
602*042d53a7SEvalZero
603*042d53a7SEvalZero adv->sc_adv_flags = 0;
604*042d53a7SEvalZero if (txadd) {
605*042d53a7SEvalZero adv->sc_adv_flags |= BLE_LL_SC_ADV_F_RANDOM_ADDR;
606*042d53a7SEvalZero }
607*042d53a7SEvalZero }
608*042d53a7SEvalZero
609*042d53a7SEvalZero if (subev == BLE_HCI_LE_SUBEV_DIRECT_ADV_RPT) {
610*042d53a7SEvalZero adv->sc_adv_flags |= BLE_LL_SC_ADV_F_DIRECT_RPT_SENT;
611*042d53a7SEvalZero } else {
612*042d53a7SEvalZero if (evtype == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) {
613*042d53a7SEvalZero adv->sc_adv_flags |= BLE_LL_SC_ADV_F_SCAN_RSP_SENT;
614*042d53a7SEvalZero } else {
615*042d53a7SEvalZero adv->sc_adv_flags |= BLE_LL_SC_ADV_F_ADV_RPT_SENT;
616*042d53a7SEvalZero }
617*042d53a7SEvalZero }
618*042d53a7SEvalZero }
619*042d53a7SEvalZero
620*042d53a7SEvalZero /**
621*042d53a7SEvalZero * Checks to see if we have received a scan response from this advertiser.
622*042d53a7SEvalZero *
623*042d53a7SEvalZero * @param adv_addr Address of advertiser
624*042d53a7SEvalZero * @param txadd TxAdd bit (0: public; random otherwise)
625*042d53a7SEvalZero *
626*042d53a7SEvalZero * @return int 0: have not received a scan response; 1 otherwise.
627*042d53a7SEvalZero */
628*042d53a7SEvalZero static int
ble_ll_scan_have_rxd_scan_rsp(uint8_t * addr,uint8_t txadd,uint8_t ext_adv,uint16_t adi)629*042d53a7SEvalZero ble_ll_scan_have_rxd_scan_rsp(uint8_t *addr, uint8_t txadd,
630*042d53a7SEvalZero uint8_t ext_adv, uint16_t adi)
631*042d53a7SEvalZero {
632*042d53a7SEvalZero uint8_t num_advs;
633*042d53a7SEvalZero struct ble_ll_scan_advertisers *adv;
634*042d53a7SEvalZero
635*042d53a7SEvalZero /* Do we have an address match? Must match address type */
636*042d53a7SEvalZero adv = &g_ble_ll_scan_rsp_advs[0];
637*042d53a7SEvalZero num_advs = g_ble_ll_scan_num_rsp_advs;
638*042d53a7SEvalZero while (num_advs) {
639*042d53a7SEvalZero if (!memcmp(&adv->adv_addr, addr, BLE_DEV_ADDR_LEN)) {
640*042d53a7SEvalZero /* Address type must match */
641*042d53a7SEvalZero if (txadd) {
642*042d53a7SEvalZero if (adv->sc_adv_flags & BLE_LL_SC_ADV_F_RANDOM_ADDR) {
643*042d53a7SEvalZero if (ext_adv) {
644*042d53a7SEvalZero if (adi == adv->adi) {
645*042d53a7SEvalZero return 1;
646*042d53a7SEvalZero }
647*042d53a7SEvalZero goto next;
648*042d53a7SEvalZero }
649*042d53a7SEvalZero return 1;
650*042d53a7SEvalZero }
651*042d53a7SEvalZero } else {
652*042d53a7SEvalZero if ((adv->sc_adv_flags & BLE_LL_SC_ADV_F_RANDOM_ADDR) == 0) {
653*042d53a7SEvalZero if (ext_adv) {
654*042d53a7SEvalZero if (adi == adv->adi) {
655*042d53a7SEvalZero return 1;
656*042d53a7SEvalZero }
657*042d53a7SEvalZero goto next;
658*042d53a7SEvalZero }
659*042d53a7SEvalZero return 1;
660*042d53a7SEvalZero }
661*042d53a7SEvalZero }
662*042d53a7SEvalZero }
663*042d53a7SEvalZero next:
664*042d53a7SEvalZero ++adv;
665*042d53a7SEvalZero --num_advs;
666*042d53a7SEvalZero }
667*042d53a7SEvalZero
668*042d53a7SEvalZero return 0;
669*042d53a7SEvalZero }
670*042d53a7SEvalZero
671*042d53a7SEvalZero static void
ble_ll_scan_add_scan_rsp_adv(uint8_t * addr,uint8_t txadd,uint8_t ext_adv,uint16_t adi)672*042d53a7SEvalZero ble_ll_scan_add_scan_rsp_adv(uint8_t *addr, uint8_t txadd,
673*042d53a7SEvalZero uint8_t ext_adv, uint16_t adi)
674*042d53a7SEvalZero {
675*042d53a7SEvalZero uint8_t num_advs;
676*042d53a7SEvalZero struct ble_ll_scan_advertisers *adv;
677*042d53a7SEvalZero
678*042d53a7SEvalZero /* XXX: for now, if we dont have room, just leave */
679*042d53a7SEvalZero num_advs = g_ble_ll_scan_num_rsp_advs;
680*042d53a7SEvalZero if (num_advs == MYNEWT_VAL(BLE_LL_NUM_SCAN_RSP_ADVS)) {
681*042d53a7SEvalZero return;
682*042d53a7SEvalZero }
683*042d53a7SEvalZero
684*042d53a7SEvalZero /* Check if address is already on the list */
685*042d53a7SEvalZero if (ble_ll_scan_have_rxd_scan_rsp(addr, txadd, ext_adv, adi)) {
686*042d53a7SEvalZero return;
687*042d53a7SEvalZero }
688*042d53a7SEvalZero
689*042d53a7SEvalZero /* Add the advertiser to the array */
690*042d53a7SEvalZero adv = &g_ble_ll_scan_rsp_advs[num_advs];
691*042d53a7SEvalZero memcpy(&adv->adv_addr, addr, BLE_DEV_ADDR_LEN);
692*042d53a7SEvalZero adv->sc_adv_flags = BLE_LL_SC_ADV_F_SCAN_RSP_RXD;
693*042d53a7SEvalZero if (txadd) {
694*042d53a7SEvalZero adv->sc_adv_flags |= BLE_LL_SC_ADV_F_RANDOM_ADDR;
695*042d53a7SEvalZero }
696*042d53a7SEvalZero adv->adi = adi;
697*042d53a7SEvalZero ++g_ble_ll_scan_num_rsp_advs;
698*042d53a7SEvalZero
699*042d53a7SEvalZero return;
700*042d53a7SEvalZero }
701*042d53a7SEvalZero
702*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
703*042d53a7SEvalZero static int
ble_ll_hci_send_legacy_ext_adv_report(uint8_t evtype,uint8_t addr_type,uint8_t * addr,uint8_t rssi,uint8_t adv_data_len,struct os_mbuf * adv_data,uint8_t * inita,uint8_t inita_type)704*042d53a7SEvalZero ble_ll_hci_send_legacy_ext_adv_report(uint8_t evtype,
705*042d53a7SEvalZero uint8_t addr_type, uint8_t *addr,
706*042d53a7SEvalZero uint8_t rssi,
707*042d53a7SEvalZero uint8_t adv_data_len, struct os_mbuf *adv_data,
708*042d53a7SEvalZero uint8_t *inita, uint8_t inita_type)
709*042d53a7SEvalZero {
710*042d53a7SEvalZero struct ble_ll_ext_adv_report *evt;
711*042d53a7SEvalZero
712*042d53a7SEvalZero if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) {
713*042d53a7SEvalZero return -1;
714*042d53a7SEvalZero }
715*042d53a7SEvalZero
716*042d53a7SEvalZero /* Drop packet if it does not fit into event buffer */
717*042d53a7SEvalZero if ((sizeof(*evt) + adv_data_len) + 1 > MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) {
718*042d53a7SEvalZero STATS_INC(ble_ll_stats, adv_evt_dropped);
719*042d53a7SEvalZero return -1;
720*042d53a7SEvalZero }
721*042d53a7SEvalZero
722*042d53a7SEvalZero evt = ble_ll_scan_init_ext_adv_report(NULL);
723*042d53a7SEvalZero if (!evt) {
724*042d53a7SEvalZero return 0;
725*042d53a7SEvalZero }
726*042d53a7SEvalZero
727*042d53a7SEvalZero switch (evtype) {
728*042d53a7SEvalZero case BLE_HCI_ADV_RPT_EVTYPE_ADV_IND:
729*042d53a7SEvalZero evt->evt_type = BLE_HCI_LEGACY_ADV_EVTYPE_ADV_IND;
730*042d53a7SEvalZero break;
731*042d53a7SEvalZero case BLE_HCI_ADV_RPT_EVTYPE_DIR_IND:
732*042d53a7SEvalZero evt->evt_type = BLE_HCI_LEGACY_ADV_EVTYPE_ADV_DIRECT_IND;
733*042d53a7SEvalZero break;
734*042d53a7SEvalZero case BLE_HCI_ADV_RPT_EVTYPE_NONCONN_IND:
735*042d53a7SEvalZero evt->evt_type = BLE_HCI_LEGACY_ADV_EVTYPE_ADV_NONCON_IND;
736*042d53a7SEvalZero break;
737*042d53a7SEvalZero case BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP:
738*042d53a7SEvalZero evt->evt_type = BLE_HCI_LEGACY_ADV_EVTYPE_SCAN_RSP_ADV_IND;
739*042d53a7SEvalZero break;
740*042d53a7SEvalZero case BLE_HCI_ADV_RPT_EVTYPE_SCAN_IND:
741*042d53a7SEvalZero evt->evt_type = BLE_HCI_LEGACY_ADV_EVTYPE_ADV_SCAN_IND;
742*042d53a7SEvalZero break;
743*042d53a7SEvalZero default:
744*042d53a7SEvalZero BLE_LL_ASSERT(0);
745*042d53a7SEvalZero break;
746*042d53a7SEvalZero }
747*042d53a7SEvalZero
748*042d53a7SEvalZero evt->addr_type = addr_type;
749*042d53a7SEvalZero memcpy(evt->addr, addr, BLE_DEV_ADDR_LEN);
750*042d53a7SEvalZero
751*042d53a7SEvalZero evt->event_len = sizeof(*evt);
752*042d53a7SEvalZero
753*042d53a7SEvalZero if (inita) {
754*042d53a7SEvalZero /* TODO Really ?? */
755*042d53a7SEvalZero evt->dir_addr_type = inita_type;
756*042d53a7SEvalZero memcpy(evt->dir_addr, inita, BLE_DEV_ADDR_LEN);
757*042d53a7SEvalZero evt->event_len += BLE_DEV_ADDR_LEN + 1;
758*042d53a7SEvalZero } else if (adv_data_len <= (MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE) - sizeof(*evt))) {
759*042d53a7SEvalZero evt->adv_data_len = adv_data_len;
760*042d53a7SEvalZero os_mbuf_copydata(adv_data, 0, adv_data_len, evt->adv_data);
761*042d53a7SEvalZero evt->event_len += adv_data_len;
762*042d53a7SEvalZero }
763*042d53a7SEvalZero
764*042d53a7SEvalZero evt->rssi = rssi;
765*042d53a7SEvalZero evt->prim_phy = BLE_PHY_1M;
766*042d53a7SEvalZero
767*042d53a7SEvalZero return ble_ll_hci_event_send((uint8_t *) evt);
768*042d53a7SEvalZero }
769*042d53a7SEvalZero #endif
770*042d53a7SEvalZero
771*042d53a7SEvalZero static int
ble_ll_hci_send_adv_report(uint8_t subev,uint8_t evtype,uint8_t event_len,uint8_t addr_type,uint8_t * addr,uint8_t rssi,uint8_t adv_data_len,struct os_mbuf * adv_data,uint8_t * inita,uint8_t inita_type)772*042d53a7SEvalZero ble_ll_hci_send_adv_report(uint8_t subev, uint8_t evtype,uint8_t event_len,
773*042d53a7SEvalZero uint8_t addr_type, uint8_t *addr, uint8_t rssi,
774*042d53a7SEvalZero uint8_t adv_data_len, struct os_mbuf *adv_data,
775*042d53a7SEvalZero uint8_t *inita, uint8_t inita_type)
776*042d53a7SEvalZero {
777*042d53a7SEvalZero uint8_t *evbuf;
778*042d53a7SEvalZero uint8_t *tmp;
779*042d53a7SEvalZero
780*042d53a7SEvalZero if (!ble_ll_hci_is_le_event_enabled(subev)) {
781*042d53a7SEvalZero return -1;
782*042d53a7SEvalZero }
783*042d53a7SEvalZero
784*042d53a7SEvalZero /* Drop packet if it does not fit into event buffer */
785*042d53a7SEvalZero if (event_len + 1 > MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) {
786*042d53a7SEvalZero STATS_INC(ble_ll_stats, adv_evt_dropped);
787*042d53a7SEvalZero return -1;
788*042d53a7SEvalZero }
789*042d53a7SEvalZero
790*042d53a7SEvalZero evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO);
791*042d53a7SEvalZero if (!evbuf) {
792*042d53a7SEvalZero return -1;
793*042d53a7SEvalZero }
794*042d53a7SEvalZero
795*042d53a7SEvalZero evbuf[0] = BLE_HCI_EVCODE_LE_META;
796*042d53a7SEvalZero evbuf[1] = event_len;
797*042d53a7SEvalZero evbuf[2] = subev;
798*042d53a7SEvalZero evbuf[3] = 1; /* number of reports */
799*042d53a7SEvalZero evbuf[4] = evtype;
800*042d53a7SEvalZero evbuf[5] = addr_type;
801*042d53a7SEvalZero memcpy(&evbuf[6], addr, BLE_DEV_ADDR_LEN);
802*042d53a7SEvalZero
803*042d53a7SEvalZero tmp = &evbuf[12];
804*042d53a7SEvalZero if (subev == BLE_HCI_LE_SUBEV_DIRECT_ADV_RPT) {
805*042d53a7SEvalZero BLE_LL_ASSERT(inita);
806*042d53a7SEvalZero tmp[0] = inita_type;
807*042d53a7SEvalZero memcpy(tmp + 1, inita, BLE_DEV_ADDR_LEN);
808*042d53a7SEvalZero tmp += BLE_DEV_ADDR_LEN + 1;
809*042d53a7SEvalZero } else if (subev == BLE_HCI_LE_SUBEV_ADV_RPT) {
810*042d53a7SEvalZero tmp[0] = adv_data_len;
811*042d53a7SEvalZero os_mbuf_copydata(adv_data, 0, adv_data_len, tmp + 1);
812*042d53a7SEvalZero tmp += adv_data_len + 1;
813*042d53a7SEvalZero } else {
814*042d53a7SEvalZero BLE_LL_ASSERT(0);
815*042d53a7SEvalZero return -1;
816*042d53a7SEvalZero }
817*042d53a7SEvalZero
818*042d53a7SEvalZero tmp[0] = rssi;
819*042d53a7SEvalZero
820*042d53a7SEvalZero return ble_ll_hci_event_send(evbuf);
821*042d53a7SEvalZero }
822*042d53a7SEvalZero /**
823*042d53a7SEvalZero * Send an advertising report to the host.
824*042d53a7SEvalZero *
825*042d53a7SEvalZero * NOTE: while we are allowed to send multiple devices in one report, we
826*042d53a7SEvalZero * will just send for one for now.
827*042d53a7SEvalZero *
828*042d53a7SEvalZero * @param pdu_type
829*042d53a7SEvalZero * @param txadd
830*042d53a7SEvalZero * @param rxbuf
831*042d53a7SEvalZero * @param hdr
832*042d53a7SEvalZero * @param scansm
833*042d53a7SEvalZero */
834*042d53a7SEvalZero static void
ble_ll_scan_send_adv_report(uint8_t pdu_type,uint8_t * adva,uint8_t adva_type,uint8_t * inita,uint8_t inita_type,struct os_mbuf * om,struct ble_mbuf_hdr * hdr,struct ble_ll_scan_sm * scansm)835*042d53a7SEvalZero ble_ll_scan_send_adv_report(uint8_t pdu_type, uint8_t *adva, uint8_t adva_type,
836*042d53a7SEvalZero uint8_t *inita, uint8_t inita_type,
837*042d53a7SEvalZero struct os_mbuf *om,
838*042d53a7SEvalZero struct ble_mbuf_hdr *hdr,
839*042d53a7SEvalZero struct ble_ll_scan_sm *scansm)
840*042d53a7SEvalZero {
841*042d53a7SEvalZero int rc;
842*042d53a7SEvalZero uint8_t *rxbuf = om->om_data;
843*042d53a7SEvalZero uint8_t evtype;
844*042d53a7SEvalZero uint8_t subev;
845*042d53a7SEvalZero uint8_t adv_data_len;
846*042d53a7SEvalZero uint8_t event_len;
847*042d53a7SEvalZero
848*042d53a7SEvalZero if (pdu_type == BLE_ADV_PDU_TYPE_ADV_DIRECT_IND) {
849*042d53a7SEvalZero if (ble_ll_is_rpa(inita, inita_type)) {
850*042d53a7SEvalZero /* For resolvable we send separate event */
851*042d53a7SEvalZero subev = BLE_HCI_LE_SUBEV_DIRECT_ADV_RPT;
852*042d53a7SEvalZero event_len = BLE_HCI_LE_ADV_DIRECT_RPT_LEN;
853*042d53a7SEvalZero } else {
854*042d53a7SEvalZero subev = BLE_HCI_LE_SUBEV_ADV_RPT;
855*042d53a7SEvalZero event_len = BLE_HCI_LE_ADV_RPT_MIN_LEN;
856*042d53a7SEvalZero }
857*042d53a7SEvalZero evtype = BLE_HCI_ADV_RPT_EVTYPE_DIR_IND;
858*042d53a7SEvalZero
859*042d53a7SEvalZero adv_data_len = 0;
860*042d53a7SEvalZero } else {
861*042d53a7SEvalZero subev = BLE_HCI_LE_SUBEV_ADV_RPT;
862*042d53a7SEvalZero if (pdu_type == BLE_ADV_PDU_TYPE_ADV_IND) {
863*042d53a7SEvalZero evtype = BLE_HCI_ADV_RPT_EVTYPE_ADV_IND;
864*042d53a7SEvalZero } else if (pdu_type == BLE_ADV_PDU_TYPE_ADV_SCAN_IND) {
865*042d53a7SEvalZero evtype = BLE_HCI_ADV_RPT_EVTYPE_SCAN_IND;
866*042d53a7SEvalZero } else if (pdu_type == BLE_ADV_PDU_TYPE_ADV_NONCONN_IND) {
867*042d53a7SEvalZero evtype = BLE_HCI_ADV_RPT_EVTYPE_NONCONN_IND;
868*042d53a7SEvalZero } else {
869*042d53a7SEvalZero evtype = BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP;
870*042d53a7SEvalZero }
871*042d53a7SEvalZero adv_data_len = rxbuf[1];
872*042d53a7SEvalZero adv_data_len -= BLE_DEV_ADDR_LEN;
873*042d53a7SEvalZero event_len = BLE_HCI_LE_ADV_RPT_MIN_LEN + adv_data_len;
874*042d53a7SEvalZero os_mbuf_adj(om, BLE_LL_PDU_HDR_LEN + BLE_DEV_ADDR_LEN);
875*042d53a7SEvalZero }
876*042d53a7SEvalZero
877*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
878*042d53a7SEvalZero if (BLE_MBUF_HDR_RESOLVED(hdr)) {
879*042d53a7SEvalZero /*
880*042d53a7SEvalZero * NOTE: this looks a bit odd, but the resolved address types
881*042d53a7SEvalZero * are 2 greater than the unresolved ones in the spec, so
882*042d53a7SEvalZero * we just add 2 here.
883*042d53a7SEvalZero */
884*042d53a7SEvalZero adva_type += 2;
885*042d53a7SEvalZero }
886*042d53a7SEvalZero #endif
887*042d53a7SEvalZero
888*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
889*042d53a7SEvalZero if (scansm->ext_scanning) {
890*042d53a7SEvalZero rc = ble_ll_hci_send_legacy_ext_adv_report(evtype,
891*042d53a7SEvalZero adva_type, adva,
892*042d53a7SEvalZero hdr->rxinfo.rssi,
893*042d53a7SEvalZero adv_data_len, om,
894*042d53a7SEvalZero inita, inita_type);
895*042d53a7SEvalZero } else {
896*042d53a7SEvalZero rc = ble_ll_hci_send_adv_report(subev, evtype, event_len,
897*042d53a7SEvalZero adva_type, adva,
898*042d53a7SEvalZero hdr->rxinfo.rssi,
899*042d53a7SEvalZero adv_data_len, om,
900*042d53a7SEvalZero inita, inita_type);
901*042d53a7SEvalZero }
902*042d53a7SEvalZero #else
903*042d53a7SEvalZero rc = ble_ll_hci_send_adv_report(subev, evtype, event_len,
904*042d53a7SEvalZero adva_type, adva,
905*042d53a7SEvalZero hdr->rxinfo.rssi,
906*042d53a7SEvalZero adv_data_len, om,
907*042d53a7SEvalZero inita, inita_type);
908*042d53a7SEvalZero #endif
909*042d53a7SEvalZero if (!rc) {
910*042d53a7SEvalZero /* If filtering, add it to list of duplicate addresses */
911*042d53a7SEvalZero if (scansm->scan_filt_dups) {
912*042d53a7SEvalZero ble_ll_scan_add_dup_adv(adva, adva_type, subev, evtype);
913*042d53a7SEvalZero }
914*042d53a7SEvalZero }
915*042d53a7SEvalZero }
916*042d53a7SEvalZero
917*042d53a7SEvalZero /**
918*042d53a7SEvalZero * Checks the scanner filter policy to determine if we should allow or discard
919*042d53a7SEvalZero * the received PDU.
920*042d53a7SEvalZero *
921*042d53a7SEvalZero * NOTE: connect requests and scan requests are not passed here
922*042d53a7SEvalZero *
923*042d53a7SEvalZero * @param pdu_type
924*042d53a7SEvalZero * @param adv_addr
925*042d53a7SEvalZero * @param adv_addr_type
926*042d53a7SEvalZero * @param init_addr
927*042d53a7SEvalZero * @param init_addr_type
928*042d53a7SEvalZero * @param flags
929*042d53a7SEvalZero *
930*042d53a7SEvalZero * @return int 0: pdu allowed by filter policy. 1: pdu not allowed
931*042d53a7SEvalZero */
932*042d53a7SEvalZero static int
ble_ll_scan_chk_filter_policy(uint8_t pdu_type,uint8_t * adv_addr,uint8_t adv_addr_type,uint8_t * init_addr,uint8_t init_addr_type,uint8_t devmatch)933*042d53a7SEvalZero ble_ll_scan_chk_filter_policy(uint8_t pdu_type, uint8_t *adv_addr,
934*042d53a7SEvalZero uint8_t adv_addr_type, uint8_t *init_addr,
935*042d53a7SEvalZero uint8_t init_addr_type, uint8_t devmatch)
936*042d53a7SEvalZero {
937*042d53a7SEvalZero int use_whitelist;
938*042d53a7SEvalZero int chk_inita;
939*042d53a7SEvalZero struct ble_ll_scan_params *params =
940*042d53a7SEvalZero &g_ble_ll_scan_sm.phy_data[g_ble_ll_scan_sm.cur_phy];
941*042d53a7SEvalZero
942*042d53a7SEvalZero use_whitelist = 0;
943*042d53a7SEvalZero chk_inita = 0;
944*042d53a7SEvalZero
945*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
946*042d53a7SEvalZero if (pdu_type == BLE_ADV_PDU_TYPE_ADV_EXT_IND && adv_addr == NULL) {
947*042d53a7SEvalZero /* Note: adv_addr can be NULL (but don't have to) for ext adv. If NULL
948*042d53a7SEvalZero * that means it is beacon and skip filter policy for now */
949*042d53a7SEvalZero return 0;
950*042d53a7SEvalZero }
951*042d53a7SEvalZero #endif
952*042d53a7SEvalZero
953*042d53a7SEvalZero switch (params->scan_filt_policy) {
954*042d53a7SEvalZero case BLE_HCI_SCAN_FILT_NO_WL:
955*042d53a7SEvalZero break;
956*042d53a7SEvalZero case BLE_HCI_SCAN_FILT_USE_WL:
957*042d53a7SEvalZero use_whitelist = 1;
958*042d53a7SEvalZero break;
959*042d53a7SEvalZero case BLE_HCI_SCAN_FILT_NO_WL_INITA:
960*042d53a7SEvalZero chk_inita = 1;
961*042d53a7SEvalZero break;
962*042d53a7SEvalZero case BLE_HCI_SCAN_FILT_USE_WL_INITA:
963*042d53a7SEvalZero chk_inita = 1;
964*042d53a7SEvalZero use_whitelist = 1;
965*042d53a7SEvalZero break;
966*042d53a7SEvalZero default:
967*042d53a7SEvalZero BLE_LL_ASSERT(0);
968*042d53a7SEvalZero break;
969*042d53a7SEvalZero }
970*042d53a7SEvalZero
971*042d53a7SEvalZero /* If we are using the whitelist, check that first */
972*042d53a7SEvalZero if (use_whitelist && (pdu_type != BLE_ADV_PDU_TYPE_SCAN_RSP)) {
973*042d53a7SEvalZero /* If device does not match let us skip this PDU.
974*042d53a7SEvalZero * If device matches, lets check for InitA further in the code
975*042d53a7SEvalZero */
976*042d53a7SEvalZero if (!devmatch) {
977*042d53a7SEvalZero return 1;
978*042d53a7SEvalZero }
979*042d53a7SEvalZero }
980*042d53a7SEvalZero
981*042d53a7SEvalZero /* If this is a directed advertisement, init_addr is not NULL.
982*042d53a7SEvalZero * Check that it is for us */
983*042d53a7SEvalZero if (init_addr) {
984*042d53a7SEvalZero /* Is this for us? If not, is it resolvable */
985*042d53a7SEvalZero if (!ble_ll_is_our_devaddr(init_addr, init_addr_type)) {
986*042d53a7SEvalZero if (!chk_inita || !ble_ll_is_rpa(adv_addr, adv_addr_type)) {
987*042d53a7SEvalZero return 1;
988*042d53a7SEvalZero }
989*042d53a7SEvalZero }
990*042d53a7SEvalZero }
991*042d53a7SEvalZero
992*042d53a7SEvalZero return 0;
993*042d53a7SEvalZero }
994*042d53a7SEvalZero
995*042d53a7SEvalZero static void
ble_ll_get_chan_to_scan(struct ble_ll_scan_sm * scansm,uint8_t * chan,int * phy)996*042d53a7SEvalZero ble_ll_get_chan_to_scan(struct ble_ll_scan_sm *scansm, uint8_t *chan,
997*042d53a7SEvalZero int *phy)
998*042d53a7SEvalZero {
999*042d53a7SEvalZero struct ble_ll_scan_params *scanphy = &scansm->phy_data[scansm->cur_phy];
1000*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
1001*042d53a7SEvalZero struct ble_ll_aux_data *aux_data = scansm->cur_aux_data;
1002*042d53a7SEvalZero
1003*042d53a7SEvalZero if (!scansm->ext_scanning || !aux_data || !aux_data->scanning) {
1004*042d53a7SEvalZero *chan = scanphy->scan_chan;
1005*042d53a7SEvalZero *phy = scanphy->phy;
1006*042d53a7SEvalZero return;
1007*042d53a7SEvalZero }
1008*042d53a7SEvalZero
1009*042d53a7SEvalZero *chan = aux_data->chan;
1010*042d53a7SEvalZero *phy = aux_data->aux_phy;
1011*042d53a7SEvalZero #else
1012*042d53a7SEvalZero *chan = scanphy->scan_chan;
1013*042d53a7SEvalZero *phy = scanphy->phy;
1014*042d53a7SEvalZero #endif
1015*042d53a7SEvalZero }
1016*042d53a7SEvalZero /**
1017*042d53a7SEvalZero * Called to enable the receiver for scanning.
1018*042d53a7SEvalZero *
1019*042d53a7SEvalZero * Context: Link Layer task
1020*042d53a7SEvalZero *
1021*042d53a7SEvalZero * @param sch
1022*042d53a7SEvalZero *
1023*042d53a7SEvalZero * @return int
1024*042d53a7SEvalZero */
1025*042d53a7SEvalZero static int
ble_ll_scan_start(struct ble_ll_scan_sm * scansm,struct ble_ll_sched_item * sch)1026*042d53a7SEvalZero ble_ll_scan_start(struct ble_ll_scan_sm *scansm, struct ble_ll_sched_item *sch)
1027*042d53a7SEvalZero {
1028*042d53a7SEvalZero int rc;
1029*042d53a7SEvalZero struct ble_ll_scan_params *scanphy = &scansm->phy_data[scansm->cur_phy];
1030*042d53a7SEvalZero uint8_t scan_chan;
1031*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
1032*042d53a7SEvalZero uint8_t phy_mode;
1033*042d53a7SEvalZero #endif
1034*042d53a7SEvalZero int phy;
1035*042d53a7SEvalZero
1036*042d53a7SEvalZero ble_ll_get_chan_to_scan(scansm, &scan_chan, &phy);
1037*042d53a7SEvalZero
1038*042d53a7SEvalZero /* XXX: right now scheduled item is only present if we schedule for aux
1039*042d53a7SEvalZero * scan just make sanity check that we have proper combination of
1040*042d53a7SEvalZero * sch and resulting scan_chan
1041*042d53a7SEvalZero */
1042*042d53a7SEvalZero BLE_LL_ASSERT(!sch || scan_chan < BLE_PHY_ADV_CHAN_START);
1043*042d53a7SEvalZero BLE_LL_ASSERT(sch || scan_chan >= BLE_PHY_ADV_CHAN_START);
1044*042d53a7SEvalZero
1045*042d53a7SEvalZero /* Set channel */
1046*042d53a7SEvalZero rc = ble_phy_setchan(scan_chan, BLE_ACCESS_ADDR_ADV, BLE_LL_CRCINIT_ADV);
1047*042d53a7SEvalZero BLE_LL_ASSERT(rc == 0);
1048*042d53a7SEvalZero
1049*042d53a7SEvalZero /*
1050*042d53a7SEvalZero * Set transmit end callback to NULL in case we transmit a scan request.
1051*042d53a7SEvalZero * There is a callback for the connect request.
1052*042d53a7SEvalZero */
1053*042d53a7SEvalZero ble_phy_set_txend_cb(NULL, NULL);
1054*042d53a7SEvalZero
1055*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
1056*042d53a7SEvalZero ble_phy_encrypt_disable();
1057*042d53a7SEvalZero #endif
1058*042d53a7SEvalZero
1059*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
1060*042d53a7SEvalZero if (ble_ll_resolv_enabled()) {
1061*042d53a7SEvalZero ble_phy_resolv_list_enable();
1062*042d53a7SEvalZero } else {
1063*042d53a7SEvalZero ble_phy_resolv_list_disable();
1064*042d53a7SEvalZero }
1065*042d53a7SEvalZero #endif
1066*042d53a7SEvalZero
1067*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
1068*042d53a7SEvalZero phy_mode = ble_ll_phy_to_phy_mode(phy, BLE_HCI_LE_PHY_CODED_ANY);
1069*042d53a7SEvalZero ble_phy_mode_set(phy_mode, phy_mode);
1070*042d53a7SEvalZero #endif
1071*042d53a7SEvalZero
1072*042d53a7SEvalZero /* XXX: probably need to make sure hfxo is running too */
1073*042d53a7SEvalZero /* XXX: can make this better; want to just start asap. */
1074*042d53a7SEvalZero if (sch) {
1075*042d53a7SEvalZero rc = ble_phy_rx_set_start_time(sch->start_time +
1076*042d53a7SEvalZero g_ble_ll_sched_offset_ticks,
1077*042d53a7SEvalZero sch->remainder);
1078*042d53a7SEvalZero } else {
1079*042d53a7SEvalZero rc = ble_phy_rx_set_start_time(os_cputime_get32() +
1080*042d53a7SEvalZero g_ble_ll_sched_offset_ticks, 0);
1081*042d53a7SEvalZero }
1082*042d53a7SEvalZero if (!rc || rc == BLE_PHY_ERR_RX_LATE) {
1083*042d53a7SEvalZero /* If we are late here, it is still OK because we keep scanning.
1084*042d53a7SEvalZero * Clear error
1085*042d53a7SEvalZero */
1086*042d53a7SEvalZero rc = 0;
1087*042d53a7SEvalZero
1088*042d53a7SEvalZero /* Enable/disable whitelisting */
1089*042d53a7SEvalZero if (scanphy->scan_filt_policy & 1) {
1090*042d53a7SEvalZero ble_ll_whitelist_enable();
1091*042d53a7SEvalZero } else {
1092*042d53a7SEvalZero ble_ll_whitelist_disable();
1093*042d53a7SEvalZero }
1094*042d53a7SEvalZero
1095*042d53a7SEvalZero /* Set link layer state to scanning */
1096*042d53a7SEvalZero if (scanphy->scan_type == BLE_SCAN_TYPE_INITIATE) {
1097*042d53a7SEvalZero ble_ll_state_set(BLE_LL_STATE_INITIATING);
1098*042d53a7SEvalZero } else {
1099*042d53a7SEvalZero ble_ll_state_set(BLE_LL_STATE_SCANNING);
1100*042d53a7SEvalZero }
1101*042d53a7SEvalZero }
1102*042d53a7SEvalZero
1103*042d53a7SEvalZero /* If there is a still a scan response pending, we have failed! */
1104*042d53a7SEvalZero if (scansm->scan_rsp_pending) {
1105*042d53a7SEvalZero ble_ll_scan_req_backoff(scansm, 0);
1106*042d53a7SEvalZero }
1107*042d53a7SEvalZero
1108*042d53a7SEvalZero return rc;
1109*042d53a7SEvalZero }
1110*042d53a7SEvalZero
1111*042d53a7SEvalZero #ifdef BLE_XCVR_RFCLK
1112*042d53a7SEvalZero static void
ble_ll_scan_rfclk_chk_stop(void)1113*042d53a7SEvalZero ble_ll_scan_rfclk_chk_stop(void)
1114*042d53a7SEvalZero {
1115*042d53a7SEvalZero int stop;
1116*042d53a7SEvalZero int32_t time_till_next;
1117*042d53a7SEvalZero os_sr_t sr;
1118*042d53a7SEvalZero uint32_t next_time;
1119*042d53a7SEvalZero
1120*042d53a7SEvalZero stop = 0;
1121*042d53a7SEvalZero OS_ENTER_CRITICAL(sr);
1122*042d53a7SEvalZero if (ble_ll_sched_next_time(&next_time)) {
1123*042d53a7SEvalZero /*
1124*042d53a7SEvalZero * If the time until the next event is too close, dont bother to turn
1125*042d53a7SEvalZero * off the clock
1126*042d53a7SEvalZero */
1127*042d53a7SEvalZero time_till_next = (int32_t)(next_time - os_cputime_get32());
1128*042d53a7SEvalZero if (time_till_next > g_ble_ll_data.ll_xtal_ticks) {
1129*042d53a7SEvalZero stop = 1;
1130*042d53a7SEvalZero }
1131*042d53a7SEvalZero } else {
1132*042d53a7SEvalZero stop = 1;
1133*042d53a7SEvalZero }
1134*042d53a7SEvalZero if (stop) {
1135*042d53a7SEvalZero ble_ll_xcvr_rfclk_disable();
1136*042d53a7SEvalZero }
1137*042d53a7SEvalZero OS_EXIT_CRITICAL(sr);
1138*042d53a7SEvalZero }
1139*042d53a7SEvalZero #endif
1140*042d53a7SEvalZero
1141*042d53a7SEvalZero static uint8_t
ble_ll_scan_get_next_adv_prim_chan(uint8_t chan)1142*042d53a7SEvalZero ble_ll_scan_get_next_adv_prim_chan(uint8_t chan)
1143*042d53a7SEvalZero {
1144*042d53a7SEvalZero ++chan;
1145*042d53a7SEvalZero if (chan == BLE_PHY_NUM_CHANS) {
1146*042d53a7SEvalZero chan = BLE_PHY_ADV_CHAN_START;
1147*042d53a7SEvalZero }
1148*042d53a7SEvalZero
1149*042d53a7SEvalZero return chan;
1150*042d53a7SEvalZero }
1151*042d53a7SEvalZero
1152*042d53a7SEvalZero static uint32_t
ble_ll_scan_get_current_scan_win(struct ble_ll_scan_sm * scansm,uint32_t cputime)1153*042d53a7SEvalZero ble_ll_scan_get_current_scan_win(struct ble_ll_scan_sm *scansm, uint32_t cputime)
1154*042d53a7SEvalZero {
1155*042d53a7SEvalZero uint32_t itvl;
1156*042d53a7SEvalZero struct ble_ll_scan_params *scanphy = &scansm->phy_data[scansm->cur_phy];
1157*042d53a7SEvalZero
1158*042d53a7SEvalZero /* Well, in case we missed to schedule scan, lets move to next stan interval.
1159*042d53a7SEvalZero */
1160*042d53a7SEvalZero itvl = os_cputime_usecs_to_ticks(scanphy->scan_itvl * BLE_HCI_SCAN_ITVL);
1161*042d53a7SEvalZero while ((int32_t)(cputime - scanphy->scan_win_start_time) >= itvl) {
1162*042d53a7SEvalZero scanphy->scan_win_start_time += itvl;
1163*042d53a7SEvalZero
1164*042d53a7SEvalZero /* If we missed scan window, make sure we update scan channel */
1165*042d53a7SEvalZero scanphy->scan_chan =
1166*042d53a7SEvalZero ble_ll_scan_get_next_adv_prim_chan(scanphy->scan_chan);
1167*042d53a7SEvalZero }
1168*042d53a7SEvalZero
1169*042d53a7SEvalZero return scanphy->scan_win_start_time;
1170*042d53a7SEvalZero }
1171*042d53a7SEvalZero /**
1172*042d53a7SEvalZero * Called to determine if we are inside or outside the scan window. If we
1173*042d53a7SEvalZero * are inside the scan window it means that the device should be receiving
1174*042d53a7SEvalZero * on the scan channel.
1175*042d53a7SEvalZero *
1176*042d53a7SEvalZero * Context: Link Layer
1177*042d53a7SEvalZero *
1178*042d53a7SEvalZero * @param scansm
1179*042d53a7SEvalZero *
1180*042d53a7SEvalZero * @return int 0: inside scan window 1: outside scan window
1181*042d53a7SEvalZero */
1182*042d53a7SEvalZero static int
ble_ll_scan_window_chk(struct ble_ll_scan_sm * scansm,uint32_t cputime)1183*042d53a7SEvalZero ble_ll_scan_window_chk(struct ble_ll_scan_sm *scansm, uint32_t cputime)
1184*042d53a7SEvalZero {
1185*042d53a7SEvalZero uint32_t win;
1186*042d53a7SEvalZero uint32_t dt;
1187*042d53a7SEvalZero uint32_t win_start;
1188*042d53a7SEvalZero struct ble_ll_scan_params *scanphy = &scansm->phy_data[scansm->cur_phy];
1189*042d53a7SEvalZero
1190*042d53a7SEvalZero win_start = ble_ll_scan_get_current_scan_win(scansm, cputime);
1191*042d53a7SEvalZero
1192*042d53a7SEvalZero if (scanphy->scan_window != scanphy->scan_itvl) {
1193*042d53a7SEvalZero win = os_cputime_usecs_to_ticks(scanphy->scan_window * BLE_HCI_SCAN_ITVL);
1194*042d53a7SEvalZero dt = cputime - win_start;
1195*042d53a7SEvalZero if (dt >= win) {
1196*042d53a7SEvalZero #ifdef BLE_XCVR_RFCLK
1197*042d53a7SEvalZero if (dt < (scanphy->scan_itvl - g_ble_ll_data.ll_xtal_ticks)) {
1198*042d53a7SEvalZero ble_ll_scan_rfclk_chk_stop();
1199*042d53a7SEvalZero }
1200*042d53a7SEvalZero #endif
1201*042d53a7SEvalZero return 1;
1202*042d53a7SEvalZero }
1203*042d53a7SEvalZero }
1204*042d53a7SEvalZero
1205*042d53a7SEvalZero return 0;
1206*042d53a7SEvalZero }
1207*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
1208*042d53a7SEvalZero static void
ble_ll_scan_aux_data_free(struct ble_ll_aux_data * aux_scan)1209*042d53a7SEvalZero ble_ll_scan_aux_data_free(struct ble_ll_aux_data *aux_scan)
1210*042d53a7SEvalZero {
1211*042d53a7SEvalZero if (aux_scan) {
1212*042d53a7SEvalZero if (aux_scan->evt) {
1213*042d53a7SEvalZero ble_hci_trans_buf_free((uint8_t *)aux_scan->evt);
1214*042d53a7SEvalZero aux_scan->evt = NULL;
1215*042d53a7SEvalZero }
1216*042d53a7SEvalZero os_memblock_put(&ext_adv_pool, aux_scan);
1217*042d53a7SEvalZero STATS_INC(ble_ll_stats, aux_freed);
1218*042d53a7SEvalZero }
1219*042d53a7SEvalZero }
1220*042d53a7SEvalZero
1221*042d53a7SEvalZero void
ble_ll_scan_aux_data_ref(struct ble_ll_aux_data * aux_data)1222*042d53a7SEvalZero ble_ll_scan_aux_data_ref(struct ble_ll_aux_data *aux_data)
1223*042d53a7SEvalZero {
1224*042d53a7SEvalZero os_sr_t sr;
1225*042d53a7SEvalZero
1226*042d53a7SEvalZero if (!aux_data) {
1227*042d53a7SEvalZero return;
1228*042d53a7SEvalZero }
1229*042d53a7SEvalZero
1230*042d53a7SEvalZero OS_ENTER_CRITICAL(sr);
1231*042d53a7SEvalZero aux_data->ref_cnt++;
1232*042d53a7SEvalZero ble_ll_trace_u32x2(BLE_LL_TRACE_ID_AUX_REF, (uint32_t) aux_data, aux_data->ref_cnt);
1233*042d53a7SEvalZero
1234*042d53a7SEvalZero OS_EXIT_CRITICAL(sr);
1235*042d53a7SEvalZero }
1236*042d53a7SEvalZero
1237*042d53a7SEvalZero int
ble_ll_scan_aux_data_unref(struct ble_ll_aux_data * aux_data)1238*042d53a7SEvalZero ble_ll_scan_aux_data_unref(struct ble_ll_aux_data *aux_data)
1239*042d53a7SEvalZero {
1240*042d53a7SEvalZero os_sr_t sr;
1241*042d53a7SEvalZero int ret;
1242*042d53a7SEvalZero
1243*042d53a7SEvalZero if (!aux_data) {
1244*042d53a7SEvalZero return 0;
1245*042d53a7SEvalZero }
1246*042d53a7SEvalZero
1247*042d53a7SEvalZero OS_ENTER_CRITICAL(sr);
1248*042d53a7SEvalZero aux_data->ref_cnt--;
1249*042d53a7SEvalZero ret = aux_data->ref_cnt;
1250*042d53a7SEvalZero ble_ll_trace_u32x2(BLE_LL_TRACE_ID_AUX_UNREF, (uint32_t) aux_data, aux_data->ref_cnt);
1251*042d53a7SEvalZero
1252*042d53a7SEvalZero if (aux_data->ref_cnt == 0) {
1253*042d53a7SEvalZero ble_ll_scan_aux_data_free(aux_data);
1254*042d53a7SEvalZero }
1255*042d53a7SEvalZero
1256*042d53a7SEvalZero OS_EXIT_CRITICAL(sr);
1257*042d53a7SEvalZero
1258*042d53a7SEvalZero return ret;
1259*042d53a7SEvalZero }
1260*042d53a7SEvalZero
1261*042d53a7SEvalZero static void
ble_ll_scan_sched_remove(struct ble_ll_sched_item * sch)1262*042d53a7SEvalZero ble_ll_scan_sched_remove(struct ble_ll_sched_item *sch)
1263*042d53a7SEvalZero {
1264*042d53a7SEvalZero ble_ll_scan_aux_data_free(sch->cb_arg);
1265*042d53a7SEvalZero }
1266*042d53a7SEvalZero #endif
1267*042d53a7SEvalZero /**
1268*042d53a7SEvalZero * Stop the scanning state machine
1269*042d53a7SEvalZero */
1270*042d53a7SEvalZero void
ble_ll_scan_sm_stop(int chk_disable)1271*042d53a7SEvalZero ble_ll_scan_sm_stop(int chk_disable)
1272*042d53a7SEvalZero {
1273*042d53a7SEvalZero os_sr_t sr;
1274*042d53a7SEvalZero uint8_t lls;
1275*042d53a7SEvalZero struct ble_ll_scan_sm *scansm;
1276*042d53a7SEvalZero
1277*042d53a7SEvalZero /* Stop the scanning timer */
1278*042d53a7SEvalZero scansm = &g_ble_ll_scan_sm;
1279*042d53a7SEvalZero os_cputime_timer_stop(&scansm->scan_timer);
1280*042d53a7SEvalZero
1281*042d53a7SEvalZero /* Disable scanning state machine */
1282*042d53a7SEvalZero scansm->scan_enabled = 0;
1283*042d53a7SEvalZero scansm->restart_timer_needed = 0;
1284*042d53a7SEvalZero
1285*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
1286*042d53a7SEvalZero OS_ENTER_CRITICAL(sr);
1287*042d53a7SEvalZero ble_ll_scan_clean_cur_aux_data();
1288*042d53a7SEvalZero OS_EXIT_CRITICAL(sr);
1289*042d53a7SEvalZero
1290*042d53a7SEvalZero ble_ll_sched_rmv_elem_type(BLE_LL_SCHED_TYPE_AUX_SCAN, ble_ll_scan_sched_remove);
1291*042d53a7SEvalZero #endif
1292*042d53a7SEvalZero
1293*042d53a7SEvalZero /* Count # of times stopped */
1294*042d53a7SEvalZero STATS_INC(ble_ll_stats, scan_stops);
1295*042d53a7SEvalZero
1296*042d53a7SEvalZero /* Only set state if we are currently in a scan window */
1297*042d53a7SEvalZero if (chk_disable) {
1298*042d53a7SEvalZero OS_ENTER_CRITICAL(sr);
1299*042d53a7SEvalZero lls = ble_ll_state_get();
1300*042d53a7SEvalZero
1301*042d53a7SEvalZero if ((lls == BLE_LL_STATE_SCANNING) ||
1302*042d53a7SEvalZero (lls == BLE_LL_STATE_INITIATING && chk_disable == 1)) {
1303*042d53a7SEvalZero /* Disable phy */
1304*042d53a7SEvalZero ble_phy_disable();
1305*042d53a7SEvalZero
1306*042d53a7SEvalZero /* Set LL state to standby */
1307*042d53a7SEvalZero ble_ll_state_set(BLE_LL_STATE_STANDBY);
1308*042d53a7SEvalZero
1309*042d53a7SEvalZero /* May need to stop the rfclk */
1310*042d53a7SEvalZero #ifdef BLE_XCVR_RFCLK
1311*042d53a7SEvalZero ble_ll_scan_rfclk_chk_stop();
1312*042d53a7SEvalZero #endif
1313*042d53a7SEvalZero }
1314*042d53a7SEvalZero OS_EXIT_CRITICAL(sr);
1315*042d53a7SEvalZero }
1316*042d53a7SEvalZero }
1317*042d53a7SEvalZero
1318*042d53a7SEvalZero static int
ble_ll_scan_sm_start(struct ble_ll_scan_sm * scansm)1319*042d53a7SEvalZero ble_ll_scan_sm_start(struct ble_ll_scan_sm *scansm)
1320*042d53a7SEvalZero {
1321*042d53a7SEvalZero /*
1322*042d53a7SEvalZero * This is not in the specification. I will reject the command with a
1323*042d53a7SEvalZero * command disallowed error if no random address has been sent by the
1324*042d53a7SEvalZero * host. All the parameter errors refer to the command parameter
1325*042d53a7SEvalZero * (which in this case is just enable or disable) so that is why I chose
1326*042d53a7SEvalZero * command disallowed.
1327*042d53a7SEvalZero */
1328*042d53a7SEvalZero if (scansm->own_addr_type == BLE_HCI_ADV_OWN_ADDR_RANDOM) {
1329*042d53a7SEvalZero if (!ble_ll_is_valid_random_addr(g_random_addr)) {
1330*042d53a7SEvalZero return BLE_ERR_CMD_DISALLOWED;
1331*042d53a7SEvalZero }
1332*042d53a7SEvalZero }
1333*042d53a7SEvalZero
1334*042d53a7SEvalZero /* Count # of times started */
1335*042d53a7SEvalZero STATS_INC(ble_ll_stats, scan_starts);
1336*042d53a7SEvalZero
1337*042d53a7SEvalZero /* Set flag telling us that scanning is enabled */
1338*042d53a7SEvalZero scansm->scan_enabled = 1;
1339*042d53a7SEvalZero
1340*042d53a7SEvalZero /* Set first advertising channel */
1341*042d53a7SEvalZero BLE_LL_ASSERT(scansm->cur_phy != PHY_NOT_CONFIGURED);
1342*042d53a7SEvalZero scansm->phy_data[scansm->cur_phy].scan_chan = BLE_PHY_ADV_CHAN_START;
1343*042d53a7SEvalZero
1344*042d53a7SEvalZero if (scansm->next_phy != PHY_NOT_CONFIGURED &&
1345*042d53a7SEvalZero scansm->next_phy != scansm->cur_phy) {
1346*042d53a7SEvalZero scansm->phy_data[scansm->next_phy].scan_chan = BLE_PHY_ADV_CHAN_START;
1347*042d53a7SEvalZero }
1348*042d53a7SEvalZero
1349*042d53a7SEvalZero /* Reset scan request backoff parameters to default */
1350*042d53a7SEvalZero scansm->upper_limit = 1;
1351*042d53a7SEvalZero scansm->backoff_count = 1;
1352*042d53a7SEvalZero scansm->scan_rsp_pending = 0;
1353*042d53a7SEvalZero
1354*042d53a7SEvalZero /* Forget filtered advertisers from previous scan. */
1355*042d53a7SEvalZero g_ble_ll_scan_num_rsp_advs = 0;
1356*042d53a7SEvalZero g_ble_ll_scan_num_dup_advs = 0;
1357*042d53a7SEvalZero
1358*042d53a7SEvalZero /* XXX: align to current or next slot???. */
1359*042d53a7SEvalZero /* Schedule start time now */
1360*042d53a7SEvalZero scansm->phy_data[scansm->cur_phy].scan_win_start_time = os_cputime_get32();
1361*042d53a7SEvalZero
1362*042d53a7SEvalZero /* Post scanning event to start off the scanning process */
1363*042d53a7SEvalZero ble_ll_event_send(&scansm->scan_sched_ev);
1364*042d53a7SEvalZero
1365*042d53a7SEvalZero return BLE_ERR_SUCCESS;
1366*042d53a7SEvalZero }
1367*042d53a7SEvalZero
1368*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
1369*042d53a7SEvalZero static void
ble_ll_scan_switch_phy(struct ble_ll_scan_sm * scansm)1370*042d53a7SEvalZero ble_ll_scan_switch_phy(struct ble_ll_scan_sm *scansm)
1371*042d53a7SEvalZero {
1372*042d53a7SEvalZero uint8_t tmp;
1373*042d53a7SEvalZero
1374*042d53a7SEvalZero if (scansm->next_phy == PHY_NOT_CONFIGURED) {
1375*042d53a7SEvalZero return;
1376*042d53a7SEvalZero }
1377*042d53a7SEvalZero
1378*042d53a7SEvalZero tmp = scansm->next_phy;
1379*042d53a7SEvalZero scansm->next_phy = scansm->cur_phy;
1380*042d53a7SEvalZero scansm->cur_phy = tmp;
1381*042d53a7SEvalZero
1382*042d53a7SEvalZero /* PHY is changing in ble_ll_scan_start() */
1383*042d53a7SEvalZero }
1384*042d53a7SEvalZero
1385*042d53a7SEvalZero /**
1386*042d53a7SEvalZero * Called to change PHY if needed and set new event time
1387*042d53a7SEvalZero *
1388*042d53a7SEvalZero * Context: Link Layer task.
1389*042d53a7SEvalZero *
1390*042d53a7SEvalZero * @param arg
1391*042d53a7SEvalZero */
1392*042d53a7SEvalZero static bool
ble_ll_scan_start_next_phy(struct ble_ll_scan_sm * scansm,uint32_t * next_event_time)1393*042d53a7SEvalZero ble_ll_scan_start_next_phy(struct ble_ll_scan_sm *scansm,
1394*042d53a7SEvalZero uint32_t *next_event_time)
1395*042d53a7SEvalZero {
1396*042d53a7SEvalZero struct ble_ll_scan_params *cur_phy;
1397*042d53a7SEvalZero struct ble_ll_scan_params *next_phy;
1398*042d53a7SEvalZero uint32_t now;
1399*042d53a7SEvalZero uint32_t win;
1400*042d53a7SEvalZero
1401*042d53a7SEvalZero /* Lets check if we want to switch to other PHY */
1402*042d53a7SEvalZero if (scansm->cur_phy == scansm->next_phy ||
1403*042d53a7SEvalZero scansm->next_phy == PHY_NOT_CONFIGURED) {
1404*042d53a7SEvalZero return false;
1405*042d53a7SEvalZero }
1406*042d53a7SEvalZero
1407*042d53a7SEvalZero cur_phy = &scansm->phy_data[scansm->cur_phy];
1408*042d53a7SEvalZero next_phy = &scansm->phy_data[scansm->next_phy];
1409*042d53a7SEvalZero
1410*042d53a7SEvalZero /* Store next event for current phy */
1411*042d53a7SEvalZero cur_phy->next_event_start = *next_event_time;
1412*042d53a7SEvalZero
1413*042d53a7SEvalZero /* Other PHY already wanted to scan. Allow it */
1414*042d53a7SEvalZero ble_ll_scan_switch_phy(scansm);
1415*042d53a7SEvalZero
1416*042d53a7SEvalZero now = os_cputime_get32();
1417*042d53a7SEvalZero
1418*042d53a7SEvalZero /* Start with new channel only if PHY was scanning already */
1419*042d53a7SEvalZero if (next_phy->next_event_start != 0) {
1420*042d53a7SEvalZero next_phy->scan_chan =
1421*042d53a7SEvalZero ble_ll_scan_get_next_adv_prim_chan(next_phy->scan_chan);
1422*042d53a7SEvalZero }
1423*042d53a7SEvalZero next_phy->scan_win_start_time = now;
1424*042d53a7SEvalZero win = os_cputime_usecs_to_ticks(next_phy->scan_window *
1425*042d53a7SEvalZero BLE_HCI_SCAN_ITVL);
1426*042d53a7SEvalZero
1427*042d53a7SEvalZero next_phy->next_event_start = now + win;
1428*042d53a7SEvalZero
1429*042d53a7SEvalZero *next_event_time = next_phy->next_event_start;
1430*042d53a7SEvalZero return true;
1431*042d53a7SEvalZero }
1432*042d53a7SEvalZero
1433*042d53a7SEvalZero static void
ble_ll_aux_scan_rsp_failed(void)1434*042d53a7SEvalZero ble_ll_aux_scan_rsp_failed(void)
1435*042d53a7SEvalZero {
1436*042d53a7SEvalZero STATS_INC(ble_ll_stats, aux_scan_rsp_err);
1437*042d53a7SEvalZero ble_ll_scan_clean_cur_aux_data();
1438*042d53a7SEvalZero }
1439*042d53a7SEvalZero #endif
1440*042d53a7SEvalZero
1441*042d53a7SEvalZero /**
1442*042d53a7SEvalZero * Called to process the scanning OS event which was posted to the LL task
1443*042d53a7SEvalZero *
1444*042d53a7SEvalZero * Context: Link Layer task.
1445*042d53a7SEvalZero *
1446*042d53a7SEvalZero * @param arg
1447*042d53a7SEvalZero */
1448*042d53a7SEvalZero static void
ble_ll_scan_event_proc(struct ble_npl_event * ev)1449*042d53a7SEvalZero ble_ll_scan_event_proc(struct ble_npl_event *ev)
1450*042d53a7SEvalZero {
1451*042d53a7SEvalZero os_sr_t sr;
1452*042d53a7SEvalZero int inside_window;
1453*042d53a7SEvalZero int start_scan;
1454*042d53a7SEvalZero uint32_t now;
1455*042d53a7SEvalZero uint32_t dt;
1456*042d53a7SEvalZero uint32_t win;
1457*042d53a7SEvalZero uint32_t win_start;
1458*042d53a7SEvalZero uint32_t scan_itvl;
1459*042d53a7SEvalZero uint32_t next_event_time;
1460*042d53a7SEvalZero #ifdef BLE_XCVR_RFCLK
1461*042d53a7SEvalZero uint32_t xtal_ticks;
1462*042d53a7SEvalZero int xtal_state;
1463*042d53a7SEvalZero #endif
1464*042d53a7SEvalZero struct ble_ll_scan_sm *scansm;
1465*042d53a7SEvalZero struct ble_ll_scan_params *scanphy;
1466*042d53a7SEvalZero
1467*042d53a7SEvalZero /*
1468*042d53a7SEvalZero * Get the scanning state machine. If not enabled (this is possible), just
1469*042d53a7SEvalZero * leave and do nothing (just make sure timer is stopped).
1470*042d53a7SEvalZero */
1471*042d53a7SEvalZero scansm = (struct ble_ll_scan_sm *)ble_npl_event_get_arg(ev);
1472*042d53a7SEvalZero scanphy = &scansm->phy_data[scansm->cur_phy];
1473*042d53a7SEvalZero
1474*042d53a7SEvalZero OS_ENTER_CRITICAL(sr);
1475*042d53a7SEvalZero if (!scansm->scan_enabled) {
1476*042d53a7SEvalZero os_cputime_timer_stop(&scansm->scan_timer);
1477*042d53a7SEvalZero OS_EXIT_CRITICAL(sr);
1478*042d53a7SEvalZero return;
1479*042d53a7SEvalZero }
1480*042d53a7SEvalZero
1481*042d53a7SEvalZero if (scansm->cur_aux_data) {
1482*042d53a7SEvalZero /* Aux scan in progress. Wait */
1483*042d53a7SEvalZero STATS_INC(ble_ll_stats, scan_timer_stopped);
1484*042d53a7SEvalZero scansm->restart_timer_needed = 1;
1485*042d53a7SEvalZero OS_EXIT_CRITICAL(sr);
1486*042d53a7SEvalZero return;
1487*042d53a7SEvalZero }
1488*042d53a7SEvalZero
1489*042d53a7SEvalZero /* Make sure the scan window start time and channel are up to date. */
1490*042d53a7SEvalZero now = os_cputime_get32();
1491*042d53a7SEvalZero win_start = ble_ll_scan_get_current_scan_win(scansm, now);
1492*042d53a7SEvalZero
1493*042d53a7SEvalZero /* Check if we are in scan window */
1494*042d53a7SEvalZero dt = now - win_start;
1495*042d53a7SEvalZero
1496*042d53a7SEvalZero if (scanphy->scan_window != scanphy->scan_itvl) {
1497*042d53a7SEvalZero win = os_cputime_usecs_to_ticks(scanphy->scan_window * BLE_HCI_SCAN_ITVL);
1498*042d53a7SEvalZero inside_window = dt < win ? 1 : 0;
1499*042d53a7SEvalZero } else {
1500*042d53a7SEvalZero win = 0;
1501*042d53a7SEvalZero /* In case continous scan lets assume we area always in the window*/
1502*042d53a7SEvalZero inside_window = 1;
1503*042d53a7SEvalZero }
1504*042d53a7SEvalZero
1505*042d53a7SEvalZero /* Determine on/off state based on scan window */
1506*042d53a7SEvalZero scan_itvl = os_cputime_usecs_to_ticks(scanphy->scan_itvl *
1507*042d53a7SEvalZero BLE_HCI_SCAN_ITVL);
1508*042d53a7SEvalZero
1509*042d53a7SEvalZero if (win != 0 && inside_window) {
1510*042d53a7SEvalZero next_event_time = win_start + win;
1511*042d53a7SEvalZero } else {
1512*042d53a7SEvalZero next_event_time = win_start + scan_itvl;
1513*042d53a7SEvalZero }
1514*042d53a7SEvalZero
1515*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
1516*042d53a7SEvalZero if (inside_window == 0 &&
1517*042d53a7SEvalZero ble_ll_scan_start_next_phy(scansm, &next_event_time)) {
1518*042d53a7SEvalZero /* Check if we should start next phy. If so let's say we are inside
1519*042d53a7SEvalZero * the window
1520*042d53a7SEvalZero */
1521*042d53a7SEvalZero inside_window = 1;
1522*042d53a7SEvalZero }
1523*042d53a7SEvalZero #endif
1524*042d53a7SEvalZero
1525*042d53a7SEvalZero /*
1526*042d53a7SEvalZero * If we are not in the standby state it means that the scheduled
1527*042d53a7SEvalZero * scanning event was overlapped in the schedule. In this case all we do
1528*042d53a7SEvalZero * is post the scan schedule end event.
1529*042d53a7SEvalZero */
1530*042d53a7SEvalZero start_scan = 1;
1531*042d53a7SEvalZero switch (ble_ll_state_get()) {
1532*042d53a7SEvalZero case BLE_LL_STATE_ADV:
1533*042d53a7SEvalZero case BLE_LL_STATE_CONNECTION:
1534*042d53a7SEvalZero start_scan = 0;
1535*042d53a7SEvalZero break;
1536*042d53a7SEvalZero case BLE_LL_STATE_INITIATING:
1537*042d53a7SEvalZero /* Must disable PHY since we will move to a new channel */
1538*042d53a7SEvalZero ble_phy_disable();
1539*042d53a7SEvalZero if (!inside_window) {
1540*042d53a7SEvalZero ble_ll_state_set(BLE_LL_STATE_STANDBY);
1541*042d53a7SEvalZero }
1542*042d53a7SEvalZero /* PHY is disabled - make sure we do not wait for AUX_CONNECT_RSP */
1543*042d53a7SEvalZero ble_ll_conn_reset_pending_aux_conn_rsp();
1544*042d53a7SEvalZero break;
1545*042d53a7SEvalZero case BLE_LL_STATE_SCANNING:
1546*042d53a7SEvalZero /* Must disable PHY since we will move to a new channel */
1547*042d53a7SEvalZero ble_phy_disable();
1548*042d53a7SEvalZero if (!inside_window) {
1549*042d53a7SEvalZero ble_ll_state_set(BLE_LL_STATE_STANDBY);
1550*042d53a7SEvalZero }
1551*042d53a7SEvalZero break;
1552*042d53a7SEvalZero case BLE_LL_STATE_STANDBY:
1553*042d53a7SEvalZero break;
1554*042d53a7SEvalZero default:
1555*042d53a7SEvalZero BLE_LL_ASSERT(0);
1556*042d53a7SEvalZero break;
1557*042d53a7SEvalZero }
1558*042d53a7SEvalZero
1559*042d53a7SEvalZero if (start_scan && inside_window) {
1560*042d53a7SEvalZero #ifdef BLE_XCVR_RFCLK
1561*042d53a7SEvalZero xtal_state = ble_ll_xcvr_rfclk_state();
1562*042d53a7SEvalZero if (xtal_state != BLE_RFCLK_STATE_SETTLED) {
1563*042d53a7SEvalZero if (xtal_state == BLE_RFCLK_STATE_OFF) {
1564*042d53a7SEvalZero xtal_ticks = g_ble_ll_data.ll_xtal_ticks;
1565*042d53a7SEvalZero } else {
1566*042d53a7SEvalZero xtal_ticks = ble_ll_xcvr_rfclk_time_till_settled();
1567*042d53a7SEvalZero }
1568*042d53a7SEvalZero
1569*042d53a7SEvalZero /*
1570*042d53a7SEvalZero * Only bother if we have enough time to receive anything
1571*042d53a7SEvalZero * here. The next event time will turn off the clock.
1572*042d53a7SEvalZero */
1573*042d53a7SEvalZero if (win != 0) {
1574*042d53a7SEvalZero if ((win - dt) <= xtal_ticks) {
1575*042d53a7SEvalZero goto done;
1576*042d53a7SEvalZero }
1577*042d53a7SEvalZero }
1578*042d53a7SEvalZero
1579*042d53a7SEvalZero /*
1580*042d53a7SEvalZero * If clock off, start clock. Set next event time to now plus
1581*042d53a7SEvalZero * the clock setting time.
1582*042d53a7SEvalZero */
1583*042d53a7SEvalZero if (xtal_state == BLE_RFCLK_STATE_OFF) {
1584*042d53a7SEvalZero ble_ll_xcvr_rfclk_start_now(now);
1585*042d53a7SEvalZero }
1586*042d53a7SEvalZero next_event_time = now + xtal_ticks;
1587*042d53a7SEvalZero goto done;
1588*042d53a7SEvalZero }
1589*042d53a7SEvalZero #endif
1590*042d53a7SEvalZero ble_ll_scan_start(scansm, NULL);
1591*042d53a7SEvalZero goto done;
1592*042d53a7SEvalZero }
1593*042d53a7SEvalZero
1594*042d53a7SEvalZero #ifdef BLE_XCVR_RFCLK
1595*042d53a7SEvalZero if (inside_window == 0) {
1596*042d53a7SEvalZero /*
1597*042d53a7SEvalZero * We need to wake up before we need to start scanning in order
1598*042d53a7SEvalZero * to make sure the rfclock is on. If we are close to being on,
1599*042d53a7SEvalZero * enable the rfclock. If not, set wakeup time.
1600*042d53a7SEvalZero */
1601*042d53a7SEvalZero if (dt >= (scan_itvl - g_ble_ll_data.ll_xtal_ticks)) {
1602*042d53a7SEvalZero /* Start the clock if necessary */
1603*042d53a7SEvalZero if (start_scan) {
1604*042d53a7SEvalZero if (ble_ll_xcvr_rfclk_state() == BLE_RFCLK_STATE_OFF) {
1605*042d53a7SEvalZero ble_ll_xcvr_rfclk_start_now(now);
1606*042d53a7SEvalZero next_event_time = now + g_ble_ll_data.ll_xtal_ticks;
1607*042d53a7SEvalZero }
1608*042d53a7SEvalZero }
1609*042d53a7SEvalZero } else {
1610*042d53a7SEvalZero next_event_time -= g_ble_ll_data.ll_xtal_ticks;
1611*042d53a7SEvalZero if (start_scan) {
1612*042d53a7SEvalZero ble_ll_scan_rfclk_chk_stop();
1613*042d53a7SEvalZero }
1614*042d53a7SEvalZero }
1615*042d53a7SEvalZero }
1616*042d53a7SEvalZero #endif
1617*042d53a7SEvalZero
1618*042d53a7SEvalZero done:
1619*042d53a7SEvalZero OS_EXIT_CRITICAL(sr);
1620*042d53a7SEvalZero os_cputime_timer_start(&scansm->scan_timer, next_event_time);
1621*042d53a7SEvalZero }
1622*042d53a7SEvalZero
1623*042d53a7SEvalZero /**
1624*042d53a7SEvalZero * ble ll scan rx pdu start
1625*042d53a7SEvalZero *
1626*042d53a7SEvalZero * Called when a PDU reception has started and the Link Layer is in the
1627*042d53a7SEvalZero * scanning state.
1628*042d53a7SEvalZero *
1629*042d53a7SEvalZero * Context: Interrupt
1630*042d53a7SEvalZero *
1631*042d53a7SEvalZero * @param pdu_type
1632*042d53a7SEvalZero * @param rxflags
1633*042d53a7SEvalZero *
1634*042d53a7SEvalZero * @return int
1635*042d53a7SEvalZero * 0: we will not attempt to reply to this frame
1636*042d53a7SEvalZero * 1: we may send a response to this frame.
1637*042d53a7SEvalZero */
1638*042d53a7SEvalZero int
ble_ll_scan_rx_isr_start(uint8_t pdu_type,uint16_t * rxflags)1639*042d53a7SEvalZero ble_ll_scan_rx_isr_start(uint8_t pdu_type, uint16_t *rxflags)
1640*042d53a7SEvalZero {
1641*042d53a7SEvalZero int rc;
1642*042d53a7SEvalZero struct ble_ll_scan_sm *scansm;
1643*042d53a7SEvalZero struct ble_ll_scan_params *scanphy;
1644*042d53a7SEvalZero
1645*042d53a7SEvalZero rc = 0;
1646*042d53a7SEvalZero scansm = &g_ble_ll_scan_sm;
1647*042d53a7SEvalZero scanphy = &scansm->phy_data[scansm->cur_phy];
1648*042d53a7SEvalZero
1649*042d53a7SEvalZero switch (scanphy->scan_type) {
1650*042d53a7SEvalZero case BLE_SCAN_TYPE_ACTIVE:
1651*042d53a7SEvalZero /* If adv ind or scan ind, we may send scan request */
1652*042d53a7SEvalZero if ((pdu_type == BLE_ADV_PDU_TYPE_ADV_IND) ||
1653*042d53a7SEvalZero (pdu_type == BLE_ADV_PDU_TYPE_ADV_SCAN_IND)) {
1654*042d53a7SEvalZero rc = 1;
1655*042d53a7SEvalZero }
1656*042d53a7SEvalZero
1657*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
1658*042d53a7SEvalZero if ((pdu_type == BLE_ADV_PDU_TYPE_ADV_EXT_IND && scansm->ext_scanning)) {
1659*042d53a7SEvalZero *rxflags |= BLE_MBUF_HDR_F_EXT_ADV;
1660*042d53a7SEvalZero rc = 1;
1661*042d53a7SEvalZero }
1662*042d53a7SEvalZero #endif
1663*042d53a7SEvalZero
1664*042d53a7SEvalZero /*
1665*042d53a7SEvalZero * If this is the first PDU after we sent the scan response (as
1666*042d53a7SEvalZero * denoted by the scan rsp pending flag), we set a bit in the ble
1667*042d53a7SEvalZero * header so the link layer can check to see if the scan request
1668*042d53a7SEvalZero * was successful. We do it this way to let the Link Layer do the
1669*042d53a7SEvalZero * work for successful scan requests. If failed, we do the work here.
1670*042d53a7SEvalZero */
1671*042d53a7SEvalZero if (scansm->scan_rsp_pending) {
1672*042d53a7SEvalZero if (pdu_type == BLE_ADV_PDU_TYPE_SCAN_RSP) {
1673*042d53a7SEvalZero *rxflags |= BLE_MBUF_HDR_F_SCAN_RSP_CHK;
1674*042d53a7SEvalZero } else if (pdu_type == BLE_ADV_PDU_TYPE_AUX_SCAN_RSP) {
1675*042d53a7SEvalZero *rxflags |= BLE_MBUF_HDR_F_SCAN_RSP_CHK;
1676*042d53a7SEvalZero } else {
1677*042d53a7SEvalZero ble_ll_scan_req_backoff(scansm, 0);
1678*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
1679*042d53a7SEvalZero ble_ll_aux_scan_rsp_failed();
1680*042d53a7SEvalZero #endif
1681*042d53a7SEvalZero }
1682*042d53a7SEvalZero }
1683*042d53a7SEvalZero
1684*042d53a7SEvalZero if (scansm->cur_aux_data && !scansm->scan_rsp_pending ) {
1685*042d53a7SEvalZero STATS_INC(ble_ll_stats, aux_received);
1686*042d53a7SEvalZero }
1687*042d53a7SEvalZero
1688*042d53a7SEvalZero /* Disable wfr if running */
1689*042d53a7SEvalZero ble_ll_wfr_disable();
1690*042d53a7SEvalZero break;
1691*042d53a7SEvalZero case BLE_SCAN_TYPE_PASSIVE:
1692*042d53a7SEvalZero default:
1693*042d53a7SEvalZero break;
1694*042d53a7SEvalZero }
1695*042d53a7SEvalZero
1696*042d53a7SEvalZero return rc;
1697*042d53a7SEvalZero }
1698*042d53a7SEvalZero
1699*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
1700*042d53a7SEvalZero static uint8_t
ble_ll_ext_adv_phy_mode_to_local_phy(uint8_t adv_phy_mode)1701*042d53a7SEvalZero ble_ll_ext_adv_phy_mode_to_local_phy(uint8_t adv_phy_mode)
1702*042d53a7SEvalZero {
1703*042d53a7SEvalZero switch (adv_phy_mode) {
1704*042d53a7SEvalZero case 0x00:
1705*042d53a7SEvalZero return BLE_PHY_1M;
1706*042d53a7SEvalZero case 0x01:
1707*042d53a7SEvalZero return BLE_PHY_2M;
1708*042d53a7SEvalZero case 0x02:
1709*042d53a7SEvalZero return BLE_PHY_CODED;
1710*042d53a7SEvalZero }
1711*042d53a7SEvalZero
1712*042d53a7SEvalZero return 0;
1713*042d53a7SEvalZero }
1714*042d53a7SEvalZero
1715*042d53a7SEvalZero static int
ble_ll_ext_scan_parse_aux_ptr(struct ble_ll_aux_data * aux_data,uint8_t * buf)1716*042d53a7SEvalZero ble_ll_ext_scan_parse_aux_ptr(struct ble_ll_aux_data *aux_data, uint8_t *buf)
1717*042d53a7SEvalZero {
1718*042d53a7SEvalZero uint32_t aux_ptr_field = get_le32(buf) & 0x00FFFFFF;
1719*042d53a7SEvalZero
1720*042d53a7SEvalZero aux_data->chan = (aux_ptr_field) & 0x3F;
1721*042d53a7SEvalZero if (aux_data->chan >= BLE_PHY_NUM_DATA_CHANS) {
1722*042d53a7SEvalZero return -1;
1723*042d53a7SEvalZero }
1724*042d53a7SEvalZero
1725*042d53a7SEvalZero /* TODO use CA aux_ptr_field >> 6 */
1726*042d53a7SEvalZero
1727*042d53a7SEvalZero aux_data->offset = 30 * ((aux_ptr_field >> 8) & 0x1FFF);
1728*042d53a7SEvalZero
1729*042d53a7SEvalZero if ((aux_ptr_field >> 7) & 0x01) {
1730*042d53a7SEvalZero aux_data->offset *= 10;
1731*042d53a7SEvalZero aux_data->offset_units = 1;
1732*042d53a7SEvalZero }
1733*042d53a7SEvalZero
1734*042d53a7SEvalZero if (aux_data->offset < BLE_LL_MAFS) {
1735*042d53a7SEvalZero return -1;
1736*042d53a7SEvalZero }
1737*042d53a7SEvalZero
1738*042d53a7SEvalZero aux_data->aux_phy =
1739*042d53a7SEvalZero ble_ll_ext_adv_phy_mode_to_local_phy((aux_ptr_field >> 21) & 0x07);
1740*042d53a7SEvalZero if (aux_data->aux_phy == 0) {
1741*042d53a7SEvalZero return -1;
1742*042d53a7SEvalZero }
1743*042d53a7SEvalZero
1744*042d53a7SEvalZero return 0;
1745*042d53a7SEvalZero }
1746*042d53a7SEvalZero
1747*042d53a7SEvalZero static void
ble_ll_ext_scan_parse_adv_info(struct ble_ll_scan_sm * scansm,struct ble_ll_ext_adv_report * evt,uint8_t * buf)1748*042d53a7SEvalZero ble_ll_ext_scan_parse_adv_info(struct ble_ll_scan_sm *scansm,
1749*042d53a7SEvalZero struct ble_ll_ext_adv_report *evt, uint8_t *buf)
1750*042d53a7SEvalZero {
1751*042d53a7SEvalZero uint16_t adv_info = get_le16(buf);
1752*042d53a7SEvalZero
1753*042d53a7SEvalZero /* TODO Use DID */
1754*042d53a7SEvalZero
1755*042d53a7SEvalZero evt->sid = (adv_info >> 12);
1756*042d53a7SEvalZero }
1757*042d53a7SEvalZero
1758*042d53a7SEvalZero /**
1759*042d53a7SEvalZero * ble_ll_scan_get_aux_data
1760*042d53a7SEvalZero *
1761*042d53a7SEvalZero * Get aux data pointer. It is new allocated data for beacon or currently
1762*042d53a7SEvalZero * processing aux data pointer. Aux data pointer will be attached to ble_hdr.rxinfo.user_data
1763*042d53a7SEvalZero *
1764*042d53a7SEvalZero * Context: Interrupt
1765*042d53a7SEvalZero *
1766*042d53a7SEvalZero * @param scansm
1767*042d53a7SEvalZero * @param ble_hdr
1768*042d53a7SEvalZero * @param rxbuf
1769*042d53a7SEvalZero * @param aux_data
1770*042d53a7SEvalZero *
1771*042d53a7SEvalZero * @return int
1772*042d53a7SEvalZero * 0: new allocated aux data
1773*042d53a7SEvalZero * 1: current processing aux data
1774*042d53a7SEvalZero * -1: error
1775*042d53a7SEvalZero */
1776*042d53a7SEvalZero int
ble_ll_scan_get_aux_data(struct ble_mbuf_hdr * ble_hdr,uint8_t * rxbuf)1777*042d53a7SEvalZero ble_ll_scan_get_aux_data(struct ble_mbuf_hdr *ble_hdr, uint8_t *rxbuf)
1778*042d53a7SEvalZero {
1779*042d53a7SEvalZero uint8_t ext_hdr_len;
1780*042d53a7SEvalZero uint8_t pdu_len;
1781*042d53a7SEvalZero uint8_t ext_hdr_flags;
1782*042d53a7SEvalZero uint8_t *ext_hdr;
1783*042d53a7SEvalZero uint8_t has_addr = 0;
1784*042d53a7SEvalZero uint8_t has_dir_addr = 0;
1785*042d53a7SEvalZero uint8_t has_adi = 0;
1786*042d53a7SEvalZero int i;
1787*042d53a7SEvalZero struct ble_ll_aux_data *current_aux = ble_hdr->rxinfo.user_data;
1788*042d53a7SEvalZero struct ble_ll_aux_data *new_aux = NULL;
1789*042d53a7SEvalZero struct ble_ll_aux_data tmp_aux_data = { 0 };
1790*042d53a7SEvalZero int rc;
1791*042d53a7SEvalZero
1792*042d53a7SEvalZero pdu_len = rxbuf[1];
1793*042d53a7SEvalZero if (pdu_len == 0) {
1794*042d53a7SEvalZero return -1;
1795*042d53a7SEvalZero }
1796*042d53a7SEvalZero
1797*042d53a7SEvalZero tmp_aux_data.mode = rxbuf[2] >> 6;
1798*042d53a7SEvalZero
1799*042d53a7SEvalZero ext_hdr_len = rxbuf[2] & 0x3F;
1800*042d53a7SEvalZero if (ext_hdr_len < BLE_LL_EXT_ADV_AUX_PTR_SIZE && !ble_hdr->rxinfo.user_data) {
1801*042d53a7SEvalZero return -1;
1802*042d53a7SEvalZero }
1803*042d53a7SEvalZero
1804*042d53a7SEvalZero ext_hdr_flags = rxbuf[3];
1805*042d53a7SEvalZero ext_hdr = &rxbuf[4];
1806*042d53a7SEvalZero
1807*042d53a7SEvalZero i = 0;
1808*042d53a7SEvalZero /* Just all until AUX PTR it for now*/
1809*042d53a7SEvalZero if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) {
1810*042d53a7SEvalZero memcpy(tmp_aux_data.addr, ext_hdr + i, 6);
1811*042d53a7SEvalZero tmp_aux_data.addr_type =
1812*042d53a7SEvalZero ble_ll_get_addr_type(rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK);
1813*042d53a7SEvalZero i += BLE_LL_EXT_ADV_ADVA_SIZE;
1814*042d53a7SEvalZero has_addr = 1;
1815*042d53a7SEvalZero }
1816*042d53a7SEvalZero
1817*042d53a7SEvalZero if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) {
1818*042d53a7SEvalZero memcpy(tmp_aux_data.dir_addr, ext_hdr + i, 6);
1819*042d53a7SEvalZero tmp_aux_data.dir_addr_type =
1820*042d53a7SEvalZero ble_ll_get_addr_type(rxbuf[0] & BLE_ADV_PDU_HDR_RXADD_MASK);
1821*042d53a7SEvalZero has_dir_addr = 1;
1822*042d53a7SEvalZero i += BLE_LL_EXT_ADV_TARGETA_SIZE;
1823*042d53a7SEvalZero }
1824*042d53a7SEvalZero
1825*042d53a7SEvalZero if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_RFU_BIT)) {
1826*042d53a7SEvalZero i += 1;
1827*042d53a7SEvalZero }
1828*042d53a7SEvalZero
1829*042d53a7SEvalZero if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) {
1830*042d53a7SEvalZero tmp_aux_data.adi = get_le16(ext_hdr + i);
1831*042d53a7SEvalZero i += BLE_LL_EXT_ADV_DATA_INFO_SIZE;
1832*042d53a7SEvalZero has_adi = 1;
1833*042d53a7SEvalZero }
1834*042d53a7SEvalZero
1835*042d53a7SEvalZero if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) {
1836*042d53a7SEvalZero
1837*042d53a7SEvalZero if (ble_ll_ext_scan_parse_aux_ptr(&tmp_aux_data, ext_hdr + i) < 0) {
1838*042d53a7SEvalZero return -1;
1839*042d53a7SEvalZero }
1840*042d53a7SEvalZero
1841*042d53a7SEvalZero if (current_aux) {
1842*042d53a7SEvalZero /* If we are here that means there is chain advertising. */
1843*042d53a7SEvalZero
1844*042d53a7SEvalZero /* Lets reuse old aux_data */
1845*042d53a7SEvalZero new_aux = current_aux;
1846*042d53a7SEvalZero
1847*042d53a7SEvalZero /* TODO Collision; Do smth smart when did does not match */
1848*042d53a7SEvalZero if (!(new_aux->evt_type & (BLE_HCI_ADV_SCAN_MASK))
1849*042d53a7SEvalZero && (tmp_aux_data.adi != new_aux->adi)) {
1850*042d53a7SEvalZero STATS_INC(ble_ll_stats, aux_chain_err);
1851*042d53a7SEvalZero new_aux->flags |= BLE_LL_AUX_INCOMPLETE_ERR_BIT;
1852*042d53a7SEvalZero }
1853*042d53a7SEvalZero
1854*042d53a7SEvalZero new_aux->flags |= BLE_LL_AUX_CHAIN_BIT;
1855*042d53a7SEvalZero new_aux->flags |= BLE_LL_AUX_INCOMPLETE_BIT;
1856*042d53a7SEvalZero } else {
1857*042d53a7SEvalZero if (ble_ll_scan_ext_adv_init(&new_aux) < 0) {
1858*042d53a7SEvalZero /* Out of memory */
1859*042d53a7SEvalZero return -1;
1860*042d53a7SEvalZero }
1861*042d53a7SEvalZero }
1862*042d53a7SEvalZero
1863*042d53a7SEvalZero new_aux->aux_phy = tmp_aux_data.aux_phy;
1864*042d53a7SEvalZero
1865*042d53a7SEvalZero if (!current_aux) {
1866*042d53a7SEvalZero /* Only for first ext adv we want to keep primary phy.*/
1867*042d53a7SEvalZero new_aux->aux_primary_phy = ble_hdr->rxinfo.phy;
1868*042d53a7SEvalZero }
1869*042d53a7SEvalZero
1870*042d53a7SEvalZero new_aux->chan = tmp_aux_data.chan;
1871*042d53a7SEvalZero new_aux->offset = tmp_aux_data.offset;
1872*042d53a7SEvalZero new_aux->mode = tmp_aux_data.mode;
1873*042d53a7SEvalZero
1874*042d53a7SEvalZero /* New aux_data or chaining */
1875*042d53a7SEvalZero rc = 0;
1876*042d53a7SEvalZero } else {
1877*042d53a7SEvalZero
1878*042d53a7SEvalZero /* So ext packet does not have aux ptr. It can be because
1879*042d53a7SEvalZero * a) it is empty beacon (no aux ptr at all)
1880*042d53a7SEvalZero * b) there is no chaining or chaining has just stopped. In this case we do hava aux_data */
1881*042d53a7SEvalZero
1882*042d53a7SEvalZero if (!current_aux) {
1883*042d53a7SEvalZero new_aux = NULL;
1884*042d53a7SEvalZero return 1;
1885*042d53a7SEvalZero }
1886*042d53a7SEvalZero
1887*042d53a7SEvalZero /*If there is no new aux ptr, just get current one */
1888*042d53a7SEvalZero new_aux = ble_hdr->rxinfo.user_data;
1889*042d53a7SEvalZero
1890*042d53a7SEvalZero /* Clear incomplete flag */
1891*042d53a7SEvalZero new_aux->flags &= ~BLE_LL_AUX_INCOMPLETE_BIT;
1892*042d53a7SEvalZero
1893*042d53a7SEvalZero /* Current processing aux_ptr */
1894*042d53a7SEvalZero rc = 1;
1895*042d53a7SEvalZero }
1896*042d53a7SEvalZero
1897*042d53a7SEvalZero if (has_adi) {
1898*042d53a7SEvalZero new_aux->adi = tmp_aux_data.adi;
1899*042d53a7SEvalZero BLE_LL_SET_AUX_FLAG(new_aux, BLE_LL_AUX_HAS_ADI);
1900*042d53a7SEvalZero }
1901*042d53a7SEvalZero
1902*042d53a7SEvalZero if (has_addr) {
1903*042d53a7SEvalZero memcpy(new_aux->addr, tmp_aux_data.addr, 6);
1904*042d53a7SEvalZero new_aux->addr_type = tmp_aux_data.addr_type;
1905*042d53a7SEvalZero new_aux->flags |= BLE_LL_AUX_HAS_ADDRA;
1906*042d53a7SEvalZero }
1907*042d53a7SEvalZero
1908*042d53a7SEvalZero if (has_dir_addr) {
1909*042d53a7SEvalZero memcpy(new_aux->dir_addr, tmp_aux_data.dir_addr, 6);
1910*042d53a7SEvalZero new_aux->dir_addr_type = tmp_aux_data.dir_addr_type;
1911*042d53a7SEvalZero new_aux->flags |= BLE_LL_AUX_HAS_DIR_ADDRA;
1912*042d53a7SEvalZero }
1913*042d53a7SEvalZero
1914*042d53a7SEvalZero ble_hdr->rxinfo.user_data = new_aux;
1915*042d53a7SEvalZero
1916*042d53a7SEvalZero return rc;
1917*042d53a7SEvalZero }
1918*042d53a7SEvalZero /**
1919*042d53a7SEvalZero * Called when a receive ADV_EXT PDU has ended.
1920*042d53a7SEvalZero *
1921*042d53a7SEvalZero * Context: Interrupt
1922*042d53a7SEvalZero *
1923*042d53a7SEvalZero * @return int
1924*042d53a7SEvalZero * < 0 Error
1925*042d53a7SEvalZero * >= 0: Success (number of bytes left in PDU)
1926*042d53a7SEvalZero *
1927*042d53a7SEvalZero */
1928*042d53a7SEvalZero int
ble_ll_scan_parse_ext_hdr(struct os_mbuf * om,uint8_t * adva,uint8_t adva_type,uint8_t * inita,uint8_t inita_type,struct ble_mbuf_hdr * ble_hdr,struct ble_ll_ext_adv_report * out_evt)1929*042d53a7SEvalZero ble_ll_scan_parse_ext_hdr(struct os_mbuf *om,
1930*042d53a7SEvalZero uint8_t *adva, uint8_t adva_type,
1931*042d53a7SEvalZero uint8_t *inita, uint8_t inita_type,
1932*042d53a7SEvalZero struct ble_mbuf_hdr *ble_hdr,
1933*042d53a7SEvalZero struct ble_ll_ext_adv_report *out_evt)
1934*042d53a7SEvalZero {
1935*042d53a7SEvalZero uint8_t pdu_len;
1936*042d53a7SEvalZero uint8_t ext_hdr_len;
1937*042d53a7SEvalZero uint8_t ext_hdr_flags;
1938*042d53a7SEvalZero uint8_t *ext_hdr;
1939*042d53a7SEvalZero uint8_t *rxbuf = om->om_data;
1940*042d53a7SEvalZero int i = 1;
1941*042d53a7SEvalZero struct ble_ll_scan_sm *scansm;
1942*042d53a7SEvalZero struct ble_ll_aux_data *aux_data = ble_hdr->rxinfo.user_data;
1943*042d53a7SEvalZero
1944*042d53a7SEvalZero if (!out_evt) {
1945*042d53a7SEvalZero return -1;
1946*042d53a7SEvalZero }
1947*042d53a7SEvalZero
1948*042d53a7SEvalZero scansm = &g_ble_ll_scan_sm;
1949*042d53a7SEvalZero
1950*042d53a7SEvalZero if (!scansm->ext_scanning) {
1951*042d53a7SEvalZero /* Ignore ext adv if host does not want it*/
1952*042d53a7SEvalZero return -1;
1953*042d53a7SEvalZero }
1954*042d53a7SEvalZero
1955*042d53a7SEvalZero pdu_len = rxbuf[1];
1956*042d53a7SEvalZero if (pdu_len == 0) {
1957*042d53a7SEvalZero return -1;
1958*042d53a7SEvalZero }
1959*042d53a7SEvalZero
1960*042d53a7SEvalZero out_evt->evt_type = rxbuf[2] >> 6;
1961*042d53a7SEvalZero if (out_evt->evt_type > BLE_LL_EXT_ADV_MODE_SCAN) {
1962*042d53a7SEvalZero return -1;
1963*042d53a7SEvalZero }
1964*042d53a7SEvalZero
1965*042d53a7SEvalZero if (BLE_MBUF_HDR_SCAN_RSP_RCV(ble_hdr)) {
1966*042d53a7SEvalZero out_evt->evt_type |= BLE_HCI_ADV_SCAN_RSP_MASK;
1967*042d53a7SEvalZero }
1968*042d53a7SEvalZero
1969*042d53a7SEvalZero ext_hdr_len = rxbuf[2] & 0x3F;
1970*042d53a7SEvalZero os_mbuf_adj(om, 3);
1971*042d53a7SEvalZero
1972*042d53a7SEvalZero ext_hdr_flags = rxbuf[3];
1973*042d53a7SEvalZero ext_hdr = &rxbuf[4];
1974*042d53a7SEvalZero
1975*042d53a7SEvalZero i = 0;
1976*042d53a7SEvalZero if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) {
1977*042d53a7SEvalZero i += BLE_LL_EXT_ADV_ADVA_SIZE;
1978*042d53a7SEvalZero }
1979*042d53a7SEvalZero
1980*042d53a7SEvalZero if (adva) {
1981*042d53a7SEvalZero memcpy(out_evt->addr, adva, 6);
1982*042d53a7SEvalZero out_evt->addr_type = adva_type;
1983*042d53a7SEvalZero }
1984*042d53a7SEvalZero
1985*042d53a7SEvalZero if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) {
1986*042d53a7SEvalZero i += BLE_LL_EXT_ADV_TARGETA_SIZE;
1987*042d53a7SEvalZero }
1988*042d53a7SEvalZero
1989*042d53a7SEvalZero if (inita) {
1990*042d53a7SEvalZero memcpy(out_evt->dir_addr, inita, 6);
1991*042d53a7SEvalZero out_evt->dir_addr_type = inita_type;
1992*042d53a7SEvalZero out_evt->evt_type |= BLE_HCI_ADV_DIRECT_MASK;
1993*042d53a7SEvalZero }
1994*042d53a7SEvalZero
1995*042d53a7SEvalZero if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_RFU_BIT)) {
1996*042d53a7SEvalZero /* Just skip it for now*/
1997*042d53a7SEvalZero i += 1;
1998*042d53a7SEvalZero }
1999*042d53a7SEvalZero
2000*042d53a7SEvalZero if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) {
2001*042d53a7SEvalZero ble_ll_ext_scan_parse_adv_info(scansm, out_evt, (ext_hdr + i));
2002*042d53a7SEvalZero i += BLE_LL_EXT_ADV_DATA_INFO_SIZE;
2003*042d53a7SEvalZero } else if (out_evt->evt_type & BLE_HCI_ADV_SCAN_RSP_MASK) {
2004*042d53a7SEvalZero out_evt->sid = (aux_data->adi >> 12);
2005*042d53a7SEvalZero }
2006*042d53a7SEvalZero
2007*042d53a7SEvalZero /* In this point of time we don't want to care about aux ptr */
2008*042d53a7SEvalZero if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) {
2009*042d53a7SEvalZero i += BLE_LL_EXT_ADV_AUX_PTR_SIZE;
2010*042d53a7SEvalZero }
2011*042d53a7SEvalZero
2012*042d53a7SEvalZero if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT)) {
2013*042d53a7SEvalZero /* TODO Handle periodic adv */
2014*042d53a7SEvalZero i += BLE_LL_EXT_ADV_SYNC_INFO_SIZE;
2015*042d53a7SEvalZero }
2016*042d53a7SEvalZero
2017*042d53a7SEvalZero if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_TX_POWER_BIT)) {
2018*042d53a7SEvalZero out_evt->tx_power = *(ext_hdr + i);
2019*042d53a7SEvalZero i += BLE_LL_EXT_ADV_TX_POWER_SIZE;
2020*042d53a7SEvalZero }
2021*042d53a7SEvalZero
2022*042d53a7SEvalZero /* Skip ADAC if it is there */
2023*042d53a7SEvalZero i = ext_hdr_len;
2024*042d53a7SEvalZero
2025*042d53a7SEvalZero /* In the event we need information on primary and secondary PHY used during
2026*042d53a7SEvalZero * advertising.
2027*042d53a7SEvalZero */
2028*042d53a7SEvalZero if (!aux_data) {
2029*042d53a7SEvalZero out_evt->prim_phy = ble_hdr->rxinfo.phy;
2030*042d53a7SEvalZero goto done;
2031*042d53a7SEvalZero }
2032*042d53a7SEvalZero
2033*042d53a7SEvalZero out_evt->sec_phy = aux_data->aux_phy;
2034*042d53a7SEvalZero out_evt->prim_phy = aux_data->aux_primary_phy;
2035*042d53a7SEvalZero
2036*042d53a7SEvalZero /* Adjust mbuf to contain advertising data only */
2037*042d53a7SEvalZero os_mbuf_adj(om, i);
2038*042d53a7SEvalZero
2039*042d53a7SEvalZero /* Let us first keep update event type in aux data.
2040*042d53a7SEvalZero * Note that in aux chain and aux scan response packets
2041*042d53a7SEvalZero * we do miss original event type, which we need for advertising report.
2042*042d53a7SEvalZero */
2043*042d53a7SEvalZero aux_data->evt_type |= out_evt->evt_type;
2044*042d53a7SEvalZero out_evt->evt_type = aux_data->evt_type;
2045*042d53a7SEvalZero
2046*042d53a7SEvalZero done:
2047*042d53a7SEvalZero return pdu_len - i - 1;
2048*042d53a7SEvalZero }
2049*042d53a7SEvalZero
2050*042d53a7SEvalZero static int
ble_ll_scan_get_addr_from_ext_adv(uint8_t * rxbuf,struct ble_mbuf_hdr * ble_hdr,uint8_t ** addr,uint8_t * addr_type,uint8_t ** inita,uint8_t * inita_type,int * ext_mode)2051*042d53a7SEvalZero ble_ll_scan_get_addr_from_ext_adv(uint8_t *rxbuf, struct ble_mbuf_hdr *ble_hdr,
2052*042d53a7SEvalZero uint8_t **addr, uint8_t *addr_type,
2053*042d53a7SEvalZero uint8_t **inita, uint8_t *inita_type,
2054*042d53a7SEvalZero int *ext_mode)
2055*042d53a7SEvalZero {
2056*042d53a7SEvalZero uint8_t pdu_len;
2057*042d53a7SEvalZero uint8_t ext_hdr_len;
2058*042d53a7SEvalZero uint8_t ext_hdr_flags;
2059*042d53a7SEvalZero uint8_t *ext_hdr;
2060*042d53a7SEvalZero int i;
2061*042d53a7SEvalZero struct ble_ll_aux_data *aux_data = ble_hdr->rxinfo.user_data;
2062*042d53a7SEvalZero
2063*042d53a7SEvalZero pdu_len = rxbuf[1];
2064*042d53a7SEvalZero if (pdu_len == 0) {
2065*042d53a7SEvalZero return -1;
2066*042d53a7SEvalZero }
2067*042d53a7SEvalZero
2068*042d53a7SEvalZero *ext_mode = rxbuf[2] >> 6;
2069*042d53a7SEvalZero if (*ext_mode > BLE_LL_EXT_ADV_MODE_SCAN) {
2070*042d53a7SEvalZero return -1;
2071*042d53a7SEvalZero }
2072*042d53a7SEvalZero
2073*042d53a7SEvalZero if (aux_data) {
2074*042d53a7SEvalZero /* If address has been provided, we do have it already in aux_data.*/
2075*042d53a7SEvalZero if (aux_data->flags & BLE_LL_AUX_HAS_ADDRA) {
2076*042d53a7SEvalZero *addr = aux_data->addr;
2077*042d53a7SEvalZero *addr_type = aux_data->addr_type;
2078*042d53a7SEvalZero }
2079*042d53a7SEvalZero
2080*042d53a7SEvalZero if (!inita) {
2081*042d53a7SEvalZero return 0;
2082*042d53a7SEvalZero }
2083*042d53a7SEvalZero
2084*042d53a7SEvalZero if (aux_data->flags & BLE_LL_AUX_HAS_DIR_ADDRA) {
2085*042d53a7SEvalZero *inita = aux_data->dir_addr;
2086*042d53a7SEvalZero *inita_type = aux_data->dir_addr_type;
2087*042d53a7SEvalZero }
2088*042d53a7SEvalZero
2089*042d53a7SEvalZero return 0;
2090*042d53a7SEvalZero }
2091*042d53a7SEvalZero
2092*042d53a7SEvalZero /* If this is just becon with no aux data, lets get address from the packet */
2093*042d53a7SEvalZero
2094*042d53a7SEvalZero ext_hdr_len = rxbuf[2] & 0x3F;
2095*042d53a7SEvalZero
2096*042d53a7SEvalZero ext_hdr_flags = rxbuf[3];
2097*042d53a7SEvalZero ext_hdr = &rxbuf[4];
2098*042d53a7SEvalZero
2099*042d53a7SEvalZero i = 0;
2100*042d53a7SEvalZero if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) {
2101*042d53a7SEvalZero if (ext_hdr_len < BLE_LL_EXT_ADV_ADVA_SIZE) {
2102*042d53a7SEvalZero return -1;
2103*042d53a7SEvalZero }
2104*042d53a7SEvalZero
2105*042d53a7SEvalZero *addr = ext_hdr + i;
2106*042d53a7SEvalZero *addr_type =
2107*042d53a7SEvalZero ble_ll_get_addr_type(rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK);
2108*042d53a7SEvalZero i += BLE_LL_EXT_ADV_ADVA_SIZE;
2109*042d53a7SEvalZero }
2110*042d53a7SEvalZero
2111*042d53a7SEvalZero if (!inita) {
2112*042d53a7SEvalZero return 0;
2113*042d53a7SEvalZero }
2114*042d53a7SEvalZero
2115*042d53a7SEvalZero if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) {
2116*042d53a7SEvalZero *inita = ext_hdr + i;
2117*042d53a7SEvalZero *inita_type =
2118*042d53a7SEvalZero ble_ll_get_addr_type(rxbuf[0] & BLE_ADV_PDU_HDR_RXADD_MASK);
2119*042d53a7SEvalZero i += BLE_LL_EXT_ADV_TARGETA_SIZE;
2120*042d53a7SEvalZero }
2121*042d53a7SEvalZero
2122*042d53a7SEvalZero return 0;
2123*042d53a7SEvalZero }
2124*042d53a7SEvalZero
2125*042d53a7SEvalZero static int
ble_ll_scan_get_adi(struct ble_ll_aux_data * aux_data,uint16_t * adi)2126*042d53a7SEvalZero ble_ll_scan_get_adi(struct ble_ll_aux_data *aux_data, uint16_t *adi)
2127*042d53a7SEvalZero {
2128*042d53a7SEvalZero if (!aux_data) {
2129*042d53a7SEvalZero return -1;
2130*042d53a7SEvalZero }
2131*042d53a7SEvalZero
2132*042d53a7SEvalZero if (!BLE_LL_CHECK_AUX_FLAG(aux_data, BLE_LL_AUX_HAS_ADI)) {
2133*042d53a7SEvalZero return -1;
2134*042d53a7SEvalZero }
2135*042d53a7SEvalZero
2136*042d53a7SEvalZero *adi = aux_data->adi;
2137*042d53a7SEvalZero
2138*042d53a7SEvalZero return 0;
2139*042d53a7SEvalZero }
2140*042d53a7SEvalZero #endif
2141*042d53a7SEvalZero
2142*042d53a7SEvalZero int
ble_ll_scan_adv_decode_addr(uint8_t pdu_type,uint8_t * rxbuf,struct ble_mbuf_hdr * ble_hdr,uint8_t ** addr,uint8_t * addr_type,uint8_t ** inita,uint8_t * inita_type,int * ext_mode)2143*042d53a7SEvalZero ble_ll_scan_adv_decode_addr(uint8_t pdu_type, uint8_t *rxbuf,
2144*042d53a7SEvalZero struct ble_mbuf_hdr *ble_hdr,
2145*042d53a7SEvalZero uint8_t **addr, uint8_t *addr_type,
2146*042d53a7SEvalZero uint8_t **inita, uint8_t *inita_type,
2147*042d53a7SEvalZero int *ext_mode)
2148*042d53a7SEvalZero {
2149*042d53a7SEvalZero if (pdu_type != BLE_ADV_PDU_TYPE_ADV_EXT_IND &&
2150*042d53a7SEvalZero pdu_type != BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP) {
2151*042d53a7SEvalZero /* Legacy advertising */
2152*042d53a7SEvalZero *addr_type = ble_ll_get_addr_type(rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK);
2153*042d53a7SEvalZero *addr = rxbuf + BLE_LL_PDU_HDR_LEN;
2154*042d53a7SEvalZero
2155*042d53a7SEvalZero if (!inita) {
2156*042d53a7SEvalZero return 0;
2157*042d53a7SEvalZero }
2158*042d53a7SEvalZero
2159*042d53a7SEvalZero if (pdu_type != BLE_ADV_PDU_TYPE_ADV_DIRECT_IND) {
2160*042d53a7SEvalZero *inita = NULL;
2161*042d53a7SEvalZero *inita_type = 0;
2162*042d53a7SEvalZero return 0;
2163*042d53a7SEvalZero }
2164*042d53a7SEvalZero
2165*042d53a7SEvalZero *inita = rxbuf + BLE_LL_PDU_HDR_LEN + BLE_DEV_ADDR_LEN;
2166*042d53a7SEvalZero *inita_type = ble_ll_get_addr_type(rxbuf[0] & BLE_ADV_PDU_HDR_RXADD_MASK);
2167*042d53a7SEvalZero
2168*042d53a7SEvalZero return 0;
2169*042d53a7SEvalZero }
2170*042d53a7SEvalZero
2171*042d53a7SEvalZero /* Extended advertising */
2172*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2173*042d53a7SEvalZero if (ble_ll_scan_get_addr_from_ext_adv(rxbuf, ble_hdr, addr, addr_type,
2174*042d53a7SEvalZero inita, inita_type, ext_mode)) {
2175*042d53a7SEvalZero return -1;
2176*042d53a7SEvalZero }
2177*042d53a7SEvalZero #else
2178*042d53a7SEvalZero return -1;
2179*042d53a7SEvalZero #endif
2180*042d53a7SEvalZero
2181*042d53a7SEvalZero return 0;
2182*042d53a7SEvalZero }
2183*042d53a7SEvalZero
2184*042d53a7SEvalZero /**
2185*042d53a7SEvalZero * Called when a receive PDU has ended.
2186*042d53a7SEvalZero *
2187*042d53a7SEvalZero * Context: Interrupt
2188*042d53a7SEvalZero *
2189*042d53a7SEvalZero * @param rxpdu
2190*042d53a7SEvalZero *
2191*042d53a7SEvalZero * @return int
2192*042d53a7SEvalZero * < 0: Disable the phy after reception.
2193*042d53a7SEvalZero * == 0: Success. Do not disable the PHY.
2194*042d53a7SEvalZero * > 0: Do not disable PHY as that has already been done.
2195*042d53a7SEvalZero */
2196*042d53a7SEvalZero int
ble_ll_scan_rx_isr_end(struct os_mbuf * rxpdu,uint8_t crcok)2197*042d53a7SEvalZero ble_ll_scan_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok)
2198*042d53a7SEvalZero {
2199*042d53a7SEvalZero int rc;
2200*042d53a7SEvalZero int chk_send_req;
2201*042d53a7SEvalZero int chk_wl;
2202*042d53a7SEvalZero int index;
2203*042d53a7SEvalZero int resolved;
2204*042d53a7SEvalZero uint8_t pdu_type;
2205*042d53a7SEvalZero uint8_t addr_type;
2206*042d53a7SEvalZero uint8_t peer_addr_type = 0;
2207*042d53a7SEvalZero uint8_t *adv_addr = NULL;
2208*042d53a7SEvalZero uint8_t *peer = NULL;
2209*042d53a7SEvalZero uint8_t *rxbuf;
2210*042d53a7SEvalZero struct ble_mbuf_hdr *ble_hdr;
2211*042d53a7SEvalZero struct ble_ll_scan_sm *scansm;
2212*042d53a7SEvalZero struct ble_ll_scan_params *scanphy;
2213*042d53a7SEvalZero int ext_adv_mode = -1;
2214*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2215*042d53a7SEvalZero uint8_t phy_mode;
2216*042d53a7SEvalZero uint16_t adi;
2217*042d53a7SEvalZero #endif
2218*042d53a7SEvalZero
2219*042d53a7SEvalZero /* Get scanning state machine */
2220*042d53a7SEvalZero scansm = &g_ble_ll_scan_sm;
2221*042d53a7SEvalZero scanphy = &scansm->phy_data[scansm->cur_phy];
2222*042d53a7SEvalZero
2223*042d53a7SEvalZero /*
2224*042d53a7SEvalZero * The reason we do something different here (as opposed to failed CRC) is
2225*042d53a7SEvalZero * that the received PDU will not be handed up in this case. So we have
2226*042d53a7SEvalZero * to restart scanning and handle a failed scan request. Note that we
2227*042d53a7SEvalZero * return 0 in this case because we dont want the phy disabled.
2228*042d53a7SEvalZero */
2229*042d53a7SEvalZero if (rxpdu == NULL) {
2230*042d53a7SEvalZero if (scansm->scan_rsp_pending) {
2231*042d53a7SEvalZero ble_ll_scan_req_backoff(scansm, 0);
2232*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2233*042d53a7SEvalZero ble_ll_aux_scan_rsp_failed();
2234*042d53a7SEvalZero #endif
2235*042d53a7SEvalZero }
2236*042d53a7SEvalZero ble_phy_restart_rx();
2237*042d53a7SEvalZero return 0;
2238*042d53a7SEvalZero }
2239*042d53a7SEvalZero
2240*042d53a7SEvalZero rc = -1;
2241*042d53a7SEvalZero
2242*042d53a7SEvalZero ble_hdr = BLE_MBUF_HDR_PTR(rxpdu);
2243*042d53a7SEvalZero
2244*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2245*042d53a7SEvalZero if (scansm->cur_aux_data) {
2246*042d53a7SEvalZero ble_hdr->rxinfo.user_data = scansm->cur_aux_data;
2247*042d53a7SEvalZero scansm->cur_aux_data = NULL;
2248*042d53a7SEvalZero if (ble_ll_scan_aux_data_unref(ble_hdr->rxinfo.user_data) == 0) {
2249*042d53a7SEvalZero ble_hdr->rxinfo.user_data = NULL;
2250*042d53a7SEvalZero ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_AUX_INVALID;
2251*042d53a7SEvalZero goto scan_rx_isr_exit;
2252*042d53a7SEvalZero }
2253*042d53a7SEvalZero }
2254*042d53a7SEvalZero #endif
2255*042d53a7SEvalZero
2256*042d53a7SEvalZero /* Just leave if the CRC is not OK. */
2257*042d53a7SEvalZero if (!crcok) {
2258*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2259*042d53a7SEvalZero ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_AUX_INVALID;
2260*042d53a7SEvalZero #endif
2261*042d53a7SEvalZero goto scan_rx_isr_exit;
2262*042d53a7SEvalZero }
2263*042d53a7SEvalZero
2264*042d53a7SEvalZero /* Get pdu type, pointer to address and address "type" */
2265*042d53a7SEvalZero rxbuf = rxpdu->om_data;
2266*042d53a7SEvalZero pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK;
2267*042d53a7SEvalZero
2268*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2269*042d53a7SEvalZero if (pdu_type == BLE_ADV_PDU_TYPE_ADV_EXT_IND) {
2270*042d53a7SEvalZero if (!scansm->ext_scanning) {
2271*042d53a7SEvalZero goto scan_rx_isr_exit;
2272*042d53a7SEvalZero }
2273*042d53a7SEvalZero /* Create new aux data for beacon or get current processing aux ptr */
2274*042d53a7SEvalZero rc = ble_ll_scan_get_aux_data(ble_hdr, rxbuf);
2275*042d53a7SEvalZero if (rc < 0) {
2276*042d53a7SEvalZero /* No memory or broken packet */
2277*042d53a7SEvalZero ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_AUX_INVALID;
2278*042d53a7SEvalZero
2279*042d53a7SEvalZero goto scan_rx_isr_exit;
2280*042d53a7SEvalZero }
2281*042d53a7SEvalZero if (rc == 0) {
2282*042d53a7SEvalZero /* Let's tell LL to schedule aux */
2283*042d53a7SEvalZero ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_AUX_PTR_WAIT;
2284*042d53a7SEvalZero }
2285*042d53a7SEvalZero
2286*042d53a7SEvalZero rc = -1;
2287*042d53a7SEvalZero }
2288*042d53a7SEvalZero #endif
2289*042d53a7SEvalZero
2290*042d53a7SEvalZero /* Lets get addresses from advertising report*/
2291*042d53a7SEvalZero if (ble_ll_scan_adv_decode_addr(pdu_type, rxbuf, ble_hdr,
2292*042d53a7SEvalZero &peer, &peer_addr_type,
2293*042d53a7SEvalZero NULL, NULL, &ext_adv_mode)) {
2294*042d53a7SEvalZero goto scan_rx_isr_exit;
2295*042d53a7SEvalZero }
2296*042d53a7SEvalZero
2297*042d53a7SEvalZero /* Determine if request may be sent and if whitelist needs to be checked */
2298*042d53a7SEvalZero chk_send_req = 0;
2299*042d53a7SEvalZero switch (pdu_type) {
2300*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2301*042d53a7SEvalZero case BLE_ADV_PDU_TYPE_ADV_EXT_IND:
2302*042d53a7SEvalZero if (!peer) {
2303*042d53a7SEvalZero /*Wait for AUX ptr */
2304*042d53a7SEvalZero goto scan_rx_isr_exit;
2305*042d53a7SEvalZero }
2306*042d53a7SEvalZero
2307*042d53a7SEvalZero if ((ext_adv_mode == BLE_LL_EXT_ADV_MODE_SCAN) &&
2308*042d53a7SEvalZero (scanphy->scan_type == BLE_SCAN_TYPE_ACTIVE)) {
2309*042d53a7SEvalZero chk_send_req = 1;
2310*042d53a7SEvalZero }
2311*042d53a7SEvalZero chk_wl = 1;
2312*042d53a7SEvalZero break;
2313*042d53a7SEvalZero #endif
2314*042d53a7SEvalZero case BLE_ADV_PDU_TYPE_ADV_IND:
2315*042d53a7SEvalZero case BLE_ADV_PDU_TYPE_ADV_SCAN_IND:
2316*042d53a7SEvalZero if (scanphy->scan_type == BLE_SCAN_TYPE_ACTIVE) {
2317*042d53a7SEvalZero chk_send_req = 1;
2318*042d53a7SEvalZero }
2319*042d53a7SEvalZero chk_wl = 1;
2320*042d53a7SEvalZero break;
2321*042d53a7SEvalZero case BLE_ADV_PDU_TYPE_ADV_NONCONN_IND:
2322*042d53a7SEvalZero case BLE_ADV_PDU_TYPE_ADV_DIRECT_IND:
2323*042d53a7SEvalZero chk_wl = 1;
2324*042d53a7SEvalZero break;
2325*042d53a7SEvalZero default:
2326*042d53a7SEvalZero chk_wl = 0;
2327*042d53a7SEvalZero break;
2328*042d53a7SEvalZero }
2329*042d53a7SEvalZero
2330*042d53a7SEvalZero /* Since peer might point to different address e.g. resolved one
2331*042d53a7SEvalZero * lets do a copy of pointers for scan request
2332*042d53a7SEvalZero */
2333*042d53a7SEvalZero adv_addr = peer;
2334*042d53a7SEvalZero addr_type = peer_addr_type;
2335*042d53a7SEvalZero
2336*042d53a7SEvalZero if ((scanphy->scan_filt_policy & 1) == 0) {
2337*042d53a7SEvalZero chk_wl = 0;
2338*042d53a7SEvalZero }
2339*042d53a7SEvalZero resolved = 0;
2340*042d53a7SEvalZero
2341*042d53a7SEvalZero index = -1;
2342*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
2343*042d53a7SEvalZero if (ble_ll_is_rpa(peer, peer_addr_type) && ble_ll_resolv_enabled()) {
2344*042d53a7SEvalZero index = ble_hw_resolv_list_match();
2345*042d53a7SEvalZero if (index >= 0) {
2346*042d53a7SEvalZero ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_RESOLVED;
2347*042d53a7SEvalZero peer = g_ble_ll_resolv_list[index].rl_identity_addr;
2348*042d53a7SEvalZero peer_addr_type = g_ble_ll_resolv_list[index].rl_addr_type;
2349*042d53a7SEvalZero resolved = 1;
2350*042d53a7SEvalZero } else {
2351*042d53a7SEvalZero if (chk_wl) {
2352*042d53a7SEvalZero goto scan_rx_isr_exit;
2353*042d53a7SEvalZero }
2354*042d53a7SEvalZero }
2355*042d53a7SEvalZero }
2356*042d53a7SEvalZero #endif
2357*042d53a7SEvalZero scansm->scan_rpa_index = index;
2358*042d53a7SEvalZero
2359*042d53a7SEvalZero /* If whitelist enabled, check to see if device is in the white list */
2360*042d53a7SEvalZero if (chk_wl && !ble_ll_whitelist_match(peer, peer_addr_type, resolved)) {
2361*042d53a7SEvalZero goto scan_rx_isr_exit;
2362*042d53a7SEvalZero }
2363*042d53a7SEvalZero ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_DEVMATCH;
2364*042d53a7SEvalZero
2365*042d53a7SEvalZero /* Should we send a scan request? */
2366*042d53a7SEvalZero if (chk_send_req) {
2367*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2368*042d53a7SEvalZero if (pdu_type == BLE_ADV_PDU_TYPE_ADV_EXT_IND) {
2369*042d53a7SEvalZero if (ble_ll_scan_get_adi(ble_hdr->rxinfo.user_data, &adi) < 0) {
2370*042d53a7SEvalZero /* There is not ADI in scannable packet? This must be some trash,
2371*042d53a7SEvalZero * ignore it
2372*042d53a7SEvalZero */
2373*042d53a7SEvalZero goto scan_rx_isr_exit;
2374*042d53a7SEvalZero }
2375*042d53a7SEvalZero if (ble_ll_scan_have_rxd_scan_rsp(peer, peer_addr_type, 1, adi)) {
2376*042d53a7SEvalZero goto scan_rx_isr_exit;
2377*042d53a7SEvalZero }
2378*042d53a7SEvalZero } else {
2379*042d53a7SEvalZero /* Dont send scan request if we have sent one to this advertiser */
2380*042d53a7SEvalZero if (ble_ll_scan_have_rxd_scan_rsp(peer, peer_addr_type, 0, 0)) {
2381*042d53a7SEvalZero goto scan_rx_isr_exit;
2382*042d53a7SEvalZero }
2383*042d53a7SEvalZero }
2384*042d53a7SEvalZero #else
2385*042d53a7SEvalZero /* Dont send scan request if we have sent one to this advertiser */
2386*042d53a7SEvalZero if (ble_ll_scan_have_rxd_scan_rsp(peer, peer_addr_type, 0, 0)) {
2387*042d53a7SEvalZero goto scan_rx_isr_exit;
2388*042d53a7SEvalZero }
2389*042d53a7SEvalZero #endif
2390*042d53a7SEvalZero /* Better not be a scan response pending */
2391*042d53a7SEvalZero BLE_LL_ASSERT(scansm->scan_rsp_pending == 0);
2392*042d53a7SEvalZero
2393*042d53a7SEvalZero /* We want to send a request. See if backoff allows us */
2394*042d53a7SEvalZero --scansm->backoff_count;
2395*042d53a7SEvalZero if (scansm->backoff_count == 0) {
2396*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2397*042d53a7SEvalZero phy_mode = ble_ll_phy_to_phy_mode(ble_hdr->rxinfo.phy,
2398*042d53a7SEvalZero BLE_HCI_LE_PHY_CODED_ANY);
2399*042d53a7SEvalZero if (ble_ll_sched_scan_req_over_aux_ptr(ble_hdr->rxinfo.channel,
2400*042d53a7SEvalZero phy_mode)) {
2401*042d53a7SEvalZero goto scan_rx_isr_exit;
2402*042d53a7SEvalZero }
2403*042d53a7SEvalZero #endif
2404*042d53a7SEvalZero /* XXX: TODO assume we are on correct phy */
2405*042d53a7SEvalZero ble_ll_scan_req_pdu_make(scansm, adv_addr, addr_type);
2406*042d53a7SEvalZero rc = ble_phy_tx(ble_ll_tx_mbuf_pducb, scansm->scan_req_pdu,
2407*042d53a7SEvalZero BLE_PHY_TRANSITION_TX_RX);
2408*042d53a7SEvalZero
2409*042d53a7SEvalZero if (rc == 0) {
2410*042d53a7SEvalZero /* Set "waiting for scan response" flag */
2411*042d53a7SEvalZero scansm->scan_rsp_pending = 1;
2412*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2413*042d53a7SEvalZero if (ble_hdr->rxinfo.channel < BLE_PHY_NUM_DATA_CHANS) {
2414*042d53a7SEvalZero /* Let's keep the aux ptr as a reference to scan rsp */
2415*042d53a7SEvalZero scansm->cur_aux_data = ble_hdr->rxinfo.user_data;
2416*042d53a7SEvalZero ble_ll_scan_aux_data_ref(scansm->cur_aux_data);
2417*042d53a7SEvalZero STATS_INC(ble_ll_stats, aux_scan_req_tx);
2418*042d53a7SEvalZero }
2419*042d53a7SEvalZero #endif
2420*042d53a7SEvalZero }
2421*042d53a7SEvalZero }
2422*042d53a7SEvalZero }
2423*042d53a7SEvalZero
2424*042d53a7SEvalZero scan_rx_isr_exit:
2425*042d53a7SEvalZero if (rc) {
2426*042d53a7SEvalZero ble_ll_state_set(BLE_LL_STATE_STANDBY);
2427*042d53a7SEvalZero }
2428*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2429*042d53a7SEvalZero /* On handover lets increase ref count */
2430*042d53a7SEvalZero if (ble_hdr->rxinfo.user_data) {
2431*042d53a7SEvalZero ble_ll_scan_aux_data_ref(ble_hdr->rxinfo.user_data);
2432*042d53a7SEvalZero }
2433*042d53a7SEvalZero #endif
2434*042d53a7SEvalZero return rc;
2435*042d53a7SEvalZero }
2436*042d53a7SEvalZero
2437*042d53a7SEvalZero /**
2438*042d53a7SEvalZero * Called to resume scanning. This is called after an advertising event or
2439*042d53a7SEvalZero * connection event has ended. It is also called if we receive a packet while
2440*042d53a7SEvalZero * in the initiating or scanning state.
2441*042d53a7SEvalZero *
2442*042d53a7SEvalZero * Context: Link Layer task
2443*042d53a7SEvalZero */
2444*042d53a7SEvalZero void
ble_ll_scan_chk_resume(void)2445*042d53a7SEvalZero ble_ll_scan_chk_resume(void)
2446*042d53a7SEvalZero {
2447*042d53a7SEvalZero os_sr_t sr;
2448*042d53a7SEvalZero struct ble_ll_scan_sm *scansm;
2449*042d53a7SEvalZero
2450*042d53a7SEvalZero scansm = &g_ble_ll_scan_sm;
2451*042d53a7SEvalZero if (scansm->scan_enabled) {
2452*042d53a7SEvalZero OS_ENTER_CRITICAL(sr);
2453*042d53a7SEvalZero if (scansm->restart_timer_needed) {
2454*042d53a7SEvalZero scansm->restart_timer_needed = 0;
2455*042d53a7SEvalZero ble_ll_event_send(&scansm->scan_sched_ev);
2456*042d53a7SEvalZero STATS_INC(ble_ll_stats, scan_timer_restarted);
2457*042d53a7SEvalZero OS_EXIT_CRITICAL(sr);
2458*042d53a7SEvalZero return;
2459*042d53a7SEvalZero }
2460*042d53a7SEvalZero
2461*042d53a7SEvalZero if (ble_ll_state_get() == BLE_LL_STATE_STANDBY &&
2462*042d53a7SEvalZero ble_ll_scan_window_chk(scansm, os_cputime_get32()) == 0) {
2463*042d53a7SEvalZero /* Turn on the receiver and set state */
2464*042d53a7SEvalZero ble_ll_scan_start(scansm, NULL);
2465*042d53a7SEvalZero }
2466*042d53a7SEvalZero OS_EXIT_CRITICAL(sr);
2467*042d53a7SEvalZero }
2468*042d53a7SEvalZero }
2469*042d53a7SEvalZero
2470*042d53a7SEvalZero /**
2471*042d53a7SEvalZero * Scan timer callback; means that the scan window timeout has been reached
2472*042d53a7SEvalZero * and we should perform the appropriate actions.
2473*042d53a7SEvalZero *
2474*042d53a7SEvalZero * Context: Interrupt (cputimer)
2475*042d53a7SEvalZero *
2476*042d53a7SEvalZero * @param arg Pointer to scan state machine.
2477*042d53a7SEvalZero */
2478*042d53a7SEvalZero void
ble_ll_scan_timer_cb(void * arg)2479*042d53a7SEvalZero ble_ll_scan_timer_cb(void *arg)
2480*042d53a7SEvalZero {
2481*042d53a7SEvalZero struct ble_ll_scan_sm *scansm;
2482*042d53a7SEvalZero
2483*042d53a7SEvalZero scansm = (struct ble_ll_scan_sm *)arg;
2484*042d53a7SEvalZero ble_ll_event_send(&scansm->scan_sched_ev);
2485*042d53a7SEvalZero }
2486*042d53a7SEvalZero
2487*042d53a7SEvalZero /**
2488*042d53a7SEvalZero * Called when the wait for response timer expires while in the scanning
2489*042d53a7SEvalZero * state.
2490*042d53a7SEvalZero *
2491*042d53a7SEvalZero * Context: Interrupt.
2492*042d53a7SEvalZero */
2493*042d53a7SEvalZero void
ble_ll_scan_wfr_timer_exp(void)2494*042d53a7SEvalZero ble_ll_scan_wfr_timer_exp(void)
2495*042d53a7SEvalZero {
2496*042d53a7SEvalZero struct ble_ll_scan_sm *scansm;
2497*042d53a7SEvalZero
2498*042d53a7SEvalZero /*
2499*042d53a7SEvalZero * If we timed out waiting for a response, the scan response pending
2500*042d53a7SEvalZero * flag should be set. Deal with scan backoff. Put device back into rx.
2501*042d53a7SEvalZero */
2502*042d53a7SEvalZero scansm = &g_ble_ll_scan_sm;
2503*042d53a7SEvalZero if (scansm->scan_rsp_pending) {
2504*042d53a7SEvalZero ble_ll_scan_req_backoff(scansm, 0);
2505*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2506*042d53a7SEvalZero ble_ll_aux_scan_rsp_failed();
2507*042d53a7SEvalZero ble_ll_scan_chk_resume();
2508*042d53a7SEvalZero #endif
2509*042d53a7SEvalZero }
2510*042d53a7SEvalZero
2511*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2512*042d53a7SEvalZero if (scansm->cur_aux_data) {
2513*042d53a7SEvalZero ble_ll_scan_end_adv_evt(scansm->cur_aux_data);
2514*042d53a7SEvalZero scansm->cur_aux_data = NULL;
2515*042d53a7SEvalZero STATS_INC(ble_ll_stats, aux_missed_adv);
2516*042d53a7SEvalZero ble_ll_scan_chk_resume();
2517*042d53a7SEvalZero }
2518*042d53a7SEvalZero #endif
2519*042d53a7SEvalZero
2520*042d53a7SEvalZero ble_phy_restart_rx();
2521*042d53a7SEvalZero }
2522*042d53a7SEvalZero
2523*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2524*042d53a7SEvalZero /*
2525*042d53a7SEvalZero * Send extended advertising report
2526*042d53a7SEvalZero *
2527*042d53a7SEvalZero * @return -1 on error (data truncated or other error)
2528*042d53a7SEvalZero * 0 on success (data status is "completed")
2529*042d53a7SEvalZero * 1 on success (data status is not "completed")
2530*042d53a7SEvalZero */
2531*042d53a7SEvalZero static int
ble_ll_hci_send_ext_adv_report(uint8_t ptype,uint8_t * adva,uint8_t adva_type,uint8_t * inita,uint8_t inita_type,struct os_mbuf * om,struct ble_mbuf_hdr * hdr)2532*042d53a7SEvalZero ble_ll_hci_send_ext_adv_report(uint8_t ptype, uint8_t *adva, uint8_t adva_type,
2533*042d53a7SEvalZero uint8_t *inita, uint8_t inita_type,
2534*042d53a7SEvalZero struct os_mbuf *om,
2535*042d53a7SEvalZero struct ble_mbuf_hdr *hdr)
2536*042d53a7SEvalZero {
2537*042d53a7SEvalZero struct ble_ll_aux_data *aux_data = hdr->rxinfo.user_data;
2538*042d53a7SEvalZero struct ble_ll_ext_adv_report *evt;
2539*042d53a7SEvalZero struct ble_ll_ext_adv_report *next_evt;
2540*042d53a7SEvalZero int offset;
2541*042d53a7SEvalZero int datalen;
2542*042d53a7SEvalZero int rc;
2543*042d53a7SEvalZero bool need_event;
2544*042d53a7SEvalZero uint8_t max_event_len;
2545*042d53a7SEvalZero
2546*042d53a7SEvalZero if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) {
2547*042d53a7SEvalZero rc = -1;
2548*042d53a7SEvalZero goto done;
2549*042d53a7SEvalZero }
2550*042d53a7SEvalZero
2551*042d53a7SEvalZero /*
2552*042d53a7SEvalZero * We keep one allocated event in aux_data to be able to truncate chain
2553*042d53a7SEvalZero * properly in case of error. If there is no event in aux_data it means this
2554*042d53a7SEvalZero * is the first event for this chain.
2555*042d53a7SEvalZero */
2556*042d53a7SEvalZero if (aux_data && aux_data->evt) {
2557*042d53a7SEvalZero evt = aux_data->evt;
2558*042d53a7SEvalZero aux_data->evt = NULL;
2559*042d53a7SEvalZero } else {
2560*042d53a7SEvalZero evt = ble_ll_scan_init_ext_adv_report(NULL);
2561*042d53a7SEvalZero if (!evt) {
2562*042d53a7SEvalZero rc = -1;
2563*042d53a7SEvalZero goto done;
2564*042d53a7SEvalZero }
2565*042d53a7SEvalZero }
2566*042d53a7SEvalZero
2567*042d53a7SEvalZero datalen = ble_ll_scan_parse_ext_hdr(om, adva, adva_type, inita, inita_type, hdr, evt);
2568*042d53a7SEvalZero if (datalen < 0) {
2569*042d53a7SEvalZero /* XXX what should we do here? send some trimmed event? */
2570*042d53a7SEvalZero ble_hci_trans_buf_free((uint8_t *)evt);
2571*042d53a7SEvalZero rc = -1;
2572*042d53a7SEvalZero goto done;
2573*042d53a7SEvalZero }
2574*042d53a7SEvalZero
2575*042d53a7SEvalZero offset = 0;
2576*042d53a7SEvalZero max_event_len = min(UINT8_MAX, BLE_LL_MAX_EVT_LEN);
2577*042d53a7SEvalZero
2578*042d53a7SEvalZero do {
2579*042d53a7SEvalZero need_event = false;
2580*042d53a7SEvalZero next_evt = NULL;
2581*042d53a7SEvalZero
2582*042d53a7SEvalZero evt->adv_data_len = min(max_event_len - sizeof(*evt),
2583*042d53a7SEvalZero datalen - offset);
2584*042d53a7SEvalZero /* Event len, should not contain event meta code and let itself */
2585*042d53a7SEvalZero evt->event_len = (sizeof(*evt) - BLE_HCI_EVENT_HDR_LEN) + evt->adv_data_len;
2586*042d53a7SEvalZero evt->rssi = hdr->rxinfo.rssi;
2587*042d53a7SEvalZero
2588*042d53a7SEvalZero os_mbuf_copydata(om, offset, evt->adv_data_len, evt->adv_data);
2589*042d53a7SEvalZero offset += evt->adv_data_len;
2590*042d53a7SEvalZero
2591*042d53a7SEvalZero
2592*042d53a7SEvalZero if (offset < datalen) {
2593*042d53a7SEvalZero /* Need another event for next fragment of this PDU */
2594*042d53a7SEvalZero need_event = true;
2595*042d53a7SEvalZero } else if (aux_data && BLE_LL_CHECK_AUX_FLAG(aux_data, BLE_LL_AUX_INCOMPLETE_ERR_BIT)) {
2596*042d53a7SEvalZero need_event = false;
2597*042d53a7SEvalZero } else if (aux_data && BLE_LL_CHECK_AUX_FLAG(aux_data, BLE_LL_AUX_INCOMPLETE_BIT)) {
2598*042d53a7SEvalZero /* Need another event for next PDU in chain */
2599*042d53a7SEvalZero need_event = true;
2600*042d53a7SEvalZero }
2601*042d53a7SEvalZero
2602*042d53a7SEvalZero /* Assume data status is not "completed" */
2603*042d53a7SEvalZero rc = 1;
2604*042d53a7SEvalZero
2605*042d53a7SEvalZero if (need_event) {
2606*042d53a7SEvalZero /*
2607*042d53a7SEvalZero * We will need another event so let's try to allocate one now. If
2608*042d53a7SEvalZero * we cannot do this, need to mark event as truncated.
2609*042d53a7SEvalZero */
2610*042d53a7SEvalZero next_evt = ble_ll_scan_init_ext_adv_report(evt);
2611*042d53a7SEvalZero
2612*042d53a7SEvalZero if (next_evt) {
2613*042d53a7SEvalZero evt->evt_type |= (BLE_HCI_ADV_DATA_STATUS_INCOMPLETE);
2614*042d53a7SEvalZero } else {
2615*042d53a7SEvalZero evt->evt_type |= (BLE_HCI_ADV_DATA_STATUS_TRUNCATED);
2616*042d53a7SEvalZero BLE_LL_SET_AUX_FLAG(aux_data, BLE_LL_AUX_TRUNCATED_SENT);
2617*042d53a7SEvalZero rc = -1;
2618*042d53a7SEvalZero }
2619*042d53a7SEvalZero } else if (aux_data ) {
2620*042d53a7SEvalZero if (BLE_LL_CHECK_AUX_FLAG(aux_data, BLE_LL_AUX_INCOMPLETE_ERR_BIT)) {
2621*042d53a7SEvalZero evt->evt_type |= (BLE_HCI_ADV_DATA_STATUS_TRUNCATED);
2622*042d53a7SEvalZero rc = -1;
2623*042d53a7SEvalZero } else if (BLE_LL_CHECK_AUX_FLAG(aux_data, BLE_LL_AUX_INCOMPLETE_BIT)) {
2624*042d53a7SEvalZero evt->evt_type |= (BLE_HCI_ADV_DATA_STATUS_INCOMPLETE);
2625*042d53a7SEvalZero } else {
2626*042d53a7SEvalZero rc = 0;
2627*042d53a7SEvalZero }
2628*042d53a7SEvalZero } else {
2629*042d53a7SEvalZero rc = 0;
2630*042d53a7SEvalZero }
2631*042d53a7SEvalZero
2632*042d53a7SEvalZero ble_ll_hci_event_send((uint8_t *)evt);
2633*042d53a7SEvalZero
2634*042d53a7SEvalZero evt = next_evt;
2635*042d53a7SEvalZero } while ((offset < datalen) && evt);
2636*042d53a7SEvalZero
2637*042d53a7SEvalZero BLE_LL_ASSERT(offset <= datalen);
2638*042d53a7SEvalZero
2639*042d53a7SEvalZero if (aux_data){
2640*042d53a7SEvalZero /* Store any event left for later use */
2641*042d53a7SEvalZero aux_data->evt = evt;
2642*042d53a7SEvalZero } else {
2643*042d53a7SEvalZero /* If it is empty beacon, evt shall be NULL */
2644*042d53a7SEvalZero BLE_LL_ASSERT(!evt);
2645*042d53a7SEvalZero }
2646*042d53a7SEvalZero
2647*042d53a7SEvalZero done:
2648*042d53a7SEvalZero /* If advertising event is completed or failed, we can drop the reference */
2649*042d53a7SEvalZero if (rc <= 0) {
2650*042d53a7SEvalZero if (aux_data){
2651*042d53a7SEvalZero if ((rc == 0) && (aux_data->evt_type & BLE_HCI_ADV_SCAN_RSP_MASK)) {
2652*042d53a7SEvalZero /* Scan response completed successfully */
2653*042d53a7SEvalZero ble_ll_scan_add_scan_rsp_adv(aux_data->addr, aux_data->addr_type,
2654*042d53a7SEvalZero 1, aux_data->adi);
2655*042d53a7SEvalZero }
2656*042d53a7SEvalZero ble_ll_scan_aux_data_unref(aux_data);
2657*042d53a7SEvalZero }
2658*042d53a7SEvalZero }
2659*042d53a7SEvalZero
2660*042d53a7SEvalZero return rc;
2661*042d53a7SEvalZero }
2662*042d53a7SEvalZero #endif
2663*042d53a7SEvalZero /**
2664*042d53a7SEvalZero * Process a received PDU while in the scanning state.
2665*042d53a7SEvalZero *
2666*042d53a7SEvalZero * Context: Link Layer task.
2667*042d53a7SEvalZero *
2668*042d53a7SEvalZero * @param pdu_type
2669*042d53a7SEvalZero * @param rxbuf
2670*042d53a7SEvalZero */
2671*042d53a7SEvalZero void
ble_ll_scan_rx_pkt_in(uint8_t ptype,struct os_mbuf * om,struct ble_mbuf_hdr * hdr)2672*042d53a7SEvalZero ble_ll_scan_rx_pkt_in(uint8_t ptype, struct os_mbuf *om, struct ble_mbuf_hdr *hdr)
2673*042d53a7SEvalZero {
2674*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
2675*042d53a7SEvalZero int index;
2676*042d53a7SEvalZero struct ble_ll_resolv_entry *rl;
2677*042d53a7SEvalZero #endif
2678*042d53a7SEvalZero uint8_t *rxbuf = om->om_data;
2679*042d53a7SEvalZero uint8_t *adv_addr = NULL;
2680*042d53a7SEvalZero uint8_t *adva;
2681*042d53a7SEvalZero uint8_t *ident_addr;
2682*042d53a7SEvalZero uint8_t ident_addr_type;
2683*042d53a7SEvalZero uint8_t *init_addr = NULL;
2684*042d53a7SEvalZero uint8_t init_addr_type = 0;
2685*042d53a7SEvalZero uint8_t txadd = 0;
2686*042d53a7SEvalZero uint8_t rxadd;
2687*042d53a7SEvalZero uint8_t scan_rsp_chk;
2688*042d53a7SEvalZero struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm;
2689*042d53a7SEvalZero struct ble_mbuf_hdr *ble_hdr;
2690*042d53a7SEvalZero int ext_adv_mode = -1;
2691*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2692*042d53a7SEvalZero struct ble_ll_aux_data *aux_data = hdr->rxinfo.user_data;
2693*042d53a7SEvalZero int rc;
2694*042d53a7SEvalZero uint8_t evt_possibly_truncated = 0;
2695*042d53a7SEvalZero #endif
2696*042d53a7SEvalZero
2697*042d53a7SEvalZero /* Set scan response check flag */
2698*042d53a7SEvalZero scan_rsp_chk = BLE_MBUF_HDR_SCAN_RSP_RCV(hdr);
2699*042d53a7SEvalZero
2700*042d53a7SEvalZero /* We dont care about scan requests or connect requests */
2701*042d53a7SEvalZero if (!BLE_MBUF_HDR_CRC_OK(hdr)) {
2702*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2703*042d53a7SEvalZero if (BLE_MBUF_HDR_AUX_INVALID(hdr)) {
2704*042d53a7SEvalZero evt_possibly_truncated = 1;
2705*042d53a7SEvalZero }
2706*042d53a7SEvalZero #endif
2707*042d53a7SEvalZero goto scan_continue;
2708*042d53a7SEvalZero }
2709*042d53a7SEvalZero
2710*042d53a7SEvalZero if ((ptype == BLE_ADV_PDU_TYPE_SCAN_REQ) || (ptype == BLE_ADV_PDU_TYPE_CONNECT_REQ)) {
2711*042d53a7SEvalZero goto scan_continue;
2712*042d53a7SEvalZero }
2713*042d53a7SEvalZero
2714*042d53a7SEvalZero if (ble_ll_scan_adv_decode_addr(ptype, rxbuf, hdr,
2715*042d53a7SEvalZero &adv_addr, &txadd,
2716*042d53a7SEvalZero &init_addr, &init_addr_type,
2717*042d53a7SEvalZero &ext_adv_mode)) {
2718*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2719*042d53a7SEvalZero evt_possibly_truncated = 1;
2720*042d53a7SEvalZero #endif
2721*042d53a7SEvalZero goto scan_continue;
2722*042d53a7SEvalZero }
2723*042d53a7SEvalZero
2724*042d53a7SEvalZero ident_addr = adv_addr;
2725*042d53a7SEvalZero ident_addr_type = txadd;
2726*042d53a7SEvalZero
2727*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
2728*042d53a7SEvalZero index = scansm->scan_rpa_index;
2729*042d53a7SEvalZero if (index >= 0) {
2730*042d53a7SEvalZero ident_addr = g_ble_ll_resolv_list[index].rl_identity_addr;
2731*042d53a7SEvalZero ident_addr_type = g_ble_ll_resolv_list[index].rl_addr_type;
2732*042d53a7SEvalZero
2733*042d53a7SEvalZero if (ble_ll_is_rpa(init_addr, init_addr_type)) {
2734*042d53a7SEvalZero /* Let's try resolve InitA. */
2735*042d53a7SEvalZero if (ble_ll_resolv_rpa(init_addr, g_ble_ll_resolv_list[index].rl_local_irk)) {
2736*042d53a7SEvalZero init_addr = ble_ll_get_our_devaddr(scansm->own_addr_type & 1);
2737*042d53a7SEvalZero init_addr_type = scansm->own_addr_type;
2738*042d53a7SEvalZero }
2739*042d53a7SEvalZero }
2740*042d53a7SEvalZero } else if (init_addr && ble_ll_resolv_enabled() && ble_ll_is_rpa(init_addr, init_addr_type)) {
2741*042d53a7SEvalZero /* If we are here it means AdvA is identity. Check if initA is RPA */
2742*042d53a7SEvalZero rl = ble_ll_resolv_list_find(ident_addr, ident_addr_type);
2743*042d53a7SEvalZero if (rl && ble_ll_resolv_rpa(init_addr, rl->rl_local_irk)) {
2744*042d53a7SEvalZero init_addr = ble_ll_get_our_devaddr(scansm->own_addr_type & 1);
2745*042d53a7SEvalZero init_addr_type = scansm->own_addr_type;
2746*042d53a7SEvalZero }
2747*042d53a7SEvalZero }
2748*042d53a7SEvalZero #endif
2749*042d53a7SEvalZero
2750*042d53a7SEvalZero /* Check the scanner filter policy */
2751*042d53a7SEvalZero if (ble_ll_scan_chk_filter_policy(ptype, adv_addr, txadd, init_addr,
2752*042d53a7SEvalZero init_addr_type,
2753*042d53a7SEvalZero BLE_MBUF_HDR_DEVMATCH(hdr))) {
2754*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2755*042d53a7SEvalZero ble_ll_scan_aux_data_unref(aux_data);
2756*042d53a7SEvalZero #endif
2757*042d53a7SEvalZero goto scan_continue;
2758*042d53a7SEvalZero }
2759*042d53a7SEvalZero
2760*042d53a7SEvalZero /*
2761*042d53a7SEvalZero * XXX: The BLE spec is a bit unclear here. What if we get a scan
2762*042d53a7SEvalZero * response from an advertiser that we did not send a request to?
2763*042d53a7SEvalZero * Do we send an advertising report? Do we add it to list of devices
2764*042d53a7SEvalZero * that we have heard a scan response from?
2765*042d53a7SEvalZero */
2766*042d53a7SEvalZero if (ptype == BLE_ADV_PDU_TYPE_SCAN_RSP) {
2767*042d53a7SEvalZero /*
2768*042d53a7SEvalZero * If this is a scan response in reply to a request we sent we need
2769*042d53a7SEvalZero * to store this advertiser's address so we dont send a request to it.
2770*042d53a7SEvalZero */
2771*042d53a7SEvalZero if (scansm->scan_rsp_pending && scan_rsp_chk) {
2772*042d53a7SEvalZero /*
2773*042d53a7SEvalZero * We could also check the timing of the scan reponse; make sure
2774*042d53a7SEvalZero * that it is relatively close to the end of the scan request but
2775*042d53a7SEvalZero * we wont for now.
2776*042d53a7SEvalZero */
2777*042d53a7SEvalZero ble_hdr = BLE_MBUF_HDR_PTR(scansm->scan_req_pdu);
2778*042d53a7SEvalZero rxadd = ble_hdr->txinfo.hdr_byte & BLE_ADV_PDU_HDR_RXADD_MASK;
2779*042d53a7SEvalZero adva = scansm->scan_req_pdu->om_data + BLE_DEV_ADDR_LEN;
2780*042d53a7SEvalZero if (((txadd && rxadd) || ((txadd + rxadd) == 0)) &&
2781*042d53a7SEvalZero !memcmp(adv_addr, adva, BLE_DEV_ADDR_LEN)) {
2782*042d53a7SEvalZero /* We have received a scan response. Add to list */
2783*042d53a7SEvalZero ble_ll_scan_add_scan_rsp_adv(ident_addr, ident_addr_type, 0, 0);
2784*042d53a7SEvalZero
2785*042d53a7SEvalZero /* Perform scan request backoff procedure */
2786*042d53a7SEvalZero ble_ll_scan_req_backoff(scansm, 1);
2787*042d53a7SEvalZero }
2788*042d53a7SEvalZero } else {
2789*042d53a7SEvalZero /* Ignore if this is not ours */
2790*042d53a7SEvalZero goto scan_continue;
2791*042d53a7SEvalZero }
2792*042d53a7SEvalZero }
2793*042d53a7SEvalZero
2794*042d53a7SEvalZero /* Filter duplicates */
2795*042d53a7SEvalZero if (scansm->scan_filt_dups) {
2796*042d53a7SEvalZero if (ble_ll_scan_is_dup_adv(ptype, ident_addr_type, ident_addr)) {
2797*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2798*042d53a7SEvalZero if (ptype == BLE_ADV_PDU_TYPE_ADV_EXT_IND) {
2799*042d53a7SEvalZero ble_ll_scan_aux_data_unref(aux_data);
2800*042d53a7SEvalZero }
2801*042d53a7SEvalZero #endif
2802*042d53a7SEvalZero goto scan_continue;
2803*042d53a7SEvalZero }
2804*042d53a7SEvalZero }
2805*042d53a7SEvalZero
2806*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2807*042d53a7SEvalZero if (ptype == BLE_ADV_PDU_TYPE_ADV_EXT_IND) {
2808*042d53a7SEvalZero if (!scansm->ext_scanning) {
2809*042d53a7SEvalZero ble_ll_scan_aux_data_unref(aux_data);
2810*042d53a7SEvalZero goto scan_continue;
2811*042d53a7SEvalZero }
2812*042d53a7SEvalZero
2813*042d53a7SEvalZero if (BLE_MBUF_HDR_AUX_INVALID(hdr)) {
2814*042d53a7SEvalZero evt_possibly_truncated = 1;
2815*042d53a7SEvalZero goto scan_continue;
2816*042d53a7SEvalZero }
2817*042d53a7SEvalZero
2818*042d53a7SEvalZero /* If it is ignore it means event is already truncated, just unref aux */
2819*042d53a7SEvalZero if (aux_data && BLE_LL_CHECK_AUX_FLAG(aux_data, BLE_LL_AUX_IGNORE_BIT)) {
2820*042d53a7SEvalZero ble_ll_scan_aux_data_unref(aux_data);
2821*042d53a7SEvalZero goto scan_continue;
2822*042d53a7SEvalZero }
2823*042d53a7SEvalZero
2824*042d53a7SEvalZero /* Let's see if that packet contains aux ptr*/
2825*042d53a7SEvalZero if (BLE_MBUF_HDR_WAIT_AUX(hdr)) {
2826*042d53a7SEvalZero BLE_LL_ASSERT(aux_data);
2827*042d53a7SEvalZero if (ble_ll_sched_aux_scan(hdr, scansm, hdr->rxinfo.user_data)) {
2828*042d53a7SEvalZero /* We are here when could not schedule the aux ptr */
2829*042d53a7SEvalZero hdr->rxinfo.flags &= ~BLE_MBUF_HDR_F_AUX_PTR_WAIT;
2830*042d53a7SEvalZero /* Mark that chain is trimmed */
2831*042d53a7SEvalZero aux_data->flags |= BLE_LL_AUX_INCOMPLETE_ERR_BIT;
2832*042d53a7SEvalZero /* Note: aux_data unref will be done when truncated is sent to the host or
2833*042d53a7SEvalZero * below if we failed to schedule for the very first aux packet.
2834*042d53a7SEvalZero */
2835*042d53a7SEvalZero } else {
2836*042d53a7SEvalZero /* We are here because successfully scheduled for next aux */
2837*042d53a7SEvalZero ble_ll_scan_aux_data_ref(aux_data);
2838*042d53a7SEvalZero }
2839*042d53a7SEvalZero
2840*042d53a7SEvalZero /*
2841*042d53a7SEvalZero * If this is ext adv, there is nothing to do here but just leave and wait
2842*042d53a7SEvalZero * for aux packet. However, if we was not able to schedule for first aux packet,
2843*042d53a7SEvalZero * make sure to unref aux_data here
2844*042d53a7SEvalZero */
2845*042d53a7SEvalZero if (!BLE_LL_CHECK_AUX_FLAG(aux_data, BLE_LL_AUX_CHAIN_BIT)) {
2846*042d53a7SEvalZero if (BLE_LL_CHECK_AUX_FLAG(aux_data, BLE_LL_AUX_INCOMPLETE_ERR_BIT)) {
2847*042d53a7SEvalZero ble_ll_scan_aux_data_unref(aux_data);
2848*042d53a7SEvalZero }
2849*042d53a7SEvalZero goto scan_continue;
2850*042d53a7SEvalZero }
2851*042d53a7SEvalZero
2852*042d53a7SEvalZero STATS_INC(ble_ll_stats, aux_chain_cnt);
2853*042d53a7SEvalZero }
2854*042d53a7SEvalZero
2855*042d53a7SEvalZero /* For the time when sending events up, lets increase ref count */
2856*042d53a7SEvalZero ble_ll_scan_aux_data_ref(aux_data);
2857*042d53a7SEvalZero rc = ble_ll_hci_send_ext_adv_report(ptype, ident_addr, ident_addr_type,
2858*042d53a7SEvalZero init_addr, init_addr_type, om, hdr);
2859*042d53a7SEvalZero if (rc < 0) {
2860*042d53a7SEvalZero /*
2861*042d53a7SEvalZero * Data were trimmed so no need to scan this chain anymore. Also
2862*042d53a7SEvalZero * make sure we do not send any more events for this chain, just in
2863*042d53a7SEvalZero * case we managed to scan something before events were processed.
2864*042d53a7SEvalZero */
2865*042d53a7SEvalZero if (BLE_MBUF_HDR_WAIT_AUX(hdr)) {
2866*042d53a7SEvalZero hdr->rxinfo.flags &= ~BLE_MBUF_HDR_F_AUX_PTR_WAIT;
2867*042d53a7SEvalZero if (ble_ll_sched_rmv_elem(&aux_data->sch) == 0) {
2868*042d53a7SEvalZero ble_ll_scan_aux_data_unref(aux_data);
2869*042d53a7SEvalZero }
2870*042d53a7SEvalZero }
2871*042d53a7SEvalZero aux_data->flags |= BLE_LL_AUX_IGNORE_BIT;
2872*042d53a7SEvalZero }
2873*042d53a7SEvalZero ble_ll_scan_aux_data_unref(aux_data);
2874*042d53a7SEvalZero
2875*042d53a7SEvalZero ble_ll_scan_switch_phy(scansm);
2876*042d53a7SEvalZero
2877*042d53a7SEvalZero if (scansm->scan_rsp_pending) {
2878*042d53a7SEvalZero if (!scan_rsp_chk) {
2879*042d53a7SEvalZero /* We are here because we sent SCAN_REQ and wait for SCAN_RSP.
2880*042d53a7SEvalZero * We do not drop reference here by purpose, because
2881*042d53a7SEvalZero * it was already dropped in ble_ll_hci_send_ext_adv_report() as
2882*042d53a7SEvalZero * very first advertising report for scannable report is "completed"
2883*042d53a7SEvalZero */
2884*042d53a7SEvalZero return;
2885*042d53a7SEvalZero }
2886*042d53a7SEvalZero
2887*042d53a7SEvalZero /* XXX: For now let us consider scan response as succeed in the backoff context,
2888*042d53a7SEvalZero * after first scan response packet is received.
2889*042d53a7SEvalZero * I guess we should marked it succeed after complete scan response is received,
2890*042d53a7SEvalZero * and failed when truncated, but then we need to analyze reason of truncation as it
2891*042d53a7SEvalZero * also might be issue of the resources on our side
2892*042d53a7SEvalZero */
2893*042d53a7SEvalZero ble_ll_scan_req_backoff(scansm, 1);
2894*042d53a7SEvalZero }
2895*042d53a7SEvalZero
2896*042d53a7SEvalZero goto scan_continue;
2897*042d53a7SEvalZero }
2898*042d53a7SEvalZero #endif
2899*042d53a7SEvalZero
2900*042d53a7SEvalZero /* Send the advertising report */
2901*042d53a7SEvalZero ble_ll_scan_send_adv_report(ptype, ident_addr, ident_addr_type,
2902*042d53a7SEvalZero init_addr, init_addr_type, om, hdr, scansm);
2903*042d53a7SEvalZero
2904*042d53a7SEvalZero scan_continue:
2905*042d53a7SEvalZero
2906*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2907*042d53a7SEvalZero if (aux_data) {
2908*042d53a7SEvalZero if (evt_possibly_truncated) {
2909*042d53a7SEvalZero ble_ll_scan_end_adv_evt(aux_data);
2910*042d53a7SEvalZero } else {
2911*042d53a7SEvalZero /* This is ref for handover to LL */
2912*042d53a7SEvalZero ble_ll_scan_aux_data_unref(aux_data);
2913*042d53a7SEvalZero }
2914*042d53a7SEvalZero }
2915*042d53a7SEvalZero #endif
2916*042d53a7SEvalZero /*
2917*042d53a7SEvalZero * If the scan response check bit is set and we are pending a response,
2918*042d53a7SEvalZero * we have failed the scan request (as we would have reset the scan rsp
2919*042d53a7SEvalZero * pending flag if we received a valid response
2920*042d53a7SEvalZero */
2921*042d53a7SEvalZero if (scansm->scan_rsp_pending && scan_rsp_chk) {
2922*042d53a7SEvalZero ble_ll_scan_req_backoff(scansm, 0);
2923*042d53a7SEvalZero }
2924*042d53a7SEvalZero
2925*042d53a7SEvalZero ble_ll_scan_chk_resume();
2926*042d53a7SEvalZero }
2927*042d53a7SEvalZero
2928*042d53a7SEvalZero int
ble_ll_scan_set_scan_params(uint8_t * cmd)2929*042d53a7SEvalZero ble_ll_scan_set_scan_params(uint8_t *cmd)
2930*042d53a7SEvalZero {
2931*042d53a7SEvalZero uint8_t scan_type;
2932*042d53a7SEvalZero uint8_t own_addr_type;
2933*042d53a7SEvalZero uint8_t filter_policy;
2934*042d53a7SEvalZero uint16_t scan_itvl;
2935*042d53a7SEvalZero uint16_t scan_window;
2936*042d53a7SEvalZero struct ble_ll_scan_sm *scansm;
2937*042d53a7SEvalZero struct ble_ll_scan_params *scanp;
2938*042d53a7SEvalZero
2939*042d53a7SEvalZero /* If already enabled, we return an error */
2940*042d53a7SEvalZero scansm = &g_ble_ll_scan_sm;
2941*042d53a7SEvalZero if (scansm->scan_enabled) {
2942*042d53a7SEvalZero return BLE_ERR_CMD_DISALLOWED;
2943*042d53a7SEvalZero }
2944*042d53a7SEvalZero
2945*042d53a7SEvalZero /* Get the scan interval and window */
2946*042d53a7SEvalZero scan_type = cmd[0];
2947*042d53a7SEvalZero scan_itvl = get_le16(cmd + 1);
2948*042d53a7SEvalZero scan_window = get_le16(cmd + 3);
2949*042d53a7SEvalZero own_addr_type = cmd[5];
2950*042d53a7SEvalZero filter_policy = cmd[6];
2951*042d53a7SEvalZero
2952*042d53a7SEvalZero /* Check scan type */
2953*042d53a7SEvalZero if ((scan_type != BLE_HCI_SCAN_TYPE_PASSIVE) &&
2954*042d53a7SEvalZero (scan_type != BLE_HCI_SCAN_TYPE_ACTIVE)) {
2955*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2956*042d53a7SEvalZero }
2957*042d53a7SEvalZero
2958*042d53a7SEvalZero /* Check interval and window */
2959*042d53a7SEvalZero if ((scan_itvl < BLE_HCI_SCAN_ITVL_MIN) ||
2960*042d53a7SEvalZero (scan_itvl > BLE_HCI_SCAN_ITVL_MAX) ||
2961*042d53a7SEvalZero (scan_window < BLE_HCI_SCAN_WINDOW_MIN) ||
2962*042d53a7SEvalZero (scan_window > BLE_HCI_SCAN_WINDOW_MAX) ||
2963*042d53a7SEvalZero (scan_itvl < scan_window)) {
2964*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2965*042d53a7SEvalZero }
2966*042d53a7SEvalZero
2967*042d53a7SEvalZero /* Check own addr type */
2968*042d53a7SEvalZero if (own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) {
2969*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2970*042d53a7SEvalZero }
2971*042d53a7SEvalZero
2972*042d53a7SEvalZero /* Check scanner filter policy */
2973*042d53a7SEvalZero if (filter_policy > BLE_HCI_SCAN_FILT_MAX) {
2974*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2975*042d53a7SEvalZero }
2976*042d53a7SEvalZero
2977*042d53a7SEvalZero /* Store scan parameters */
2978*042d53a7SEvalZero scanp = &g_ble_ll_scan_params[PHY_UNCODED];
2979*042d53a7SEvalZero scanp->configured = 1;
2980*042d53a7SEvalZero scanp->scan_type = scan_type;
2981*042d53a7SEvalZero scanp->scan_itvl = scan_itvl;
2982*042d53a7SEvalZero scanp->scan_window = scan_window;
2983*042d53a7SEvalZero scanp->scan_filt_policy = filter_policy;
2984*042d53a7SEvalZero scanp->own_addr_type = own_addr_type;
2985*042d53a7SEvalZero
2986*042d53a7SEvalZero #if (BLE_LL_SCAN_PHY_NUMBER == 2)
2987*042d53a7SEvalZero g_ble_ll_scan_params[PHY_CODED].configured = 0;
2988*042d53a7SEvalZero #endif
2989*042d53a7SEvalZero
2990*042d53a7SEvalZero return 0;
2991*042d53a7SEvalZero }
2992*042d53a7SEvalZero
2993*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2994*042d53a7SEvalZero static int
ble_ll_check_scan_params(uint8_t type,uint16_t itvl,uint16_t window)2995*042d53a7SEvalZero ble_ll_check_scan_params(uint8_t type, uint16_t itvl, uint16_t window)
2996*042d53a7SEvalZero {
2997*042d53a7SEvalZero /* Check scan type */
2998*042d53a7SEvalZero if ((type != BLE_HCI_SCAN_TYPE_PASSIVE) &&
2999*042d53a7SEvalZero (type != BLE_HCI_SCAN_TYPE_ACTIVE)) {
3000*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
3001*042d53a7SEvalZero }
3002*042d53a7SEvalZero
3003*042d53a7SEvalZero /* Check interval and window */
3004*042d53a7SEvalZero if ((itvl < BLE_HCI_SCAN_ITVL_MIN) ||
3005*042d53a7SEvalZero (itvl > BLE_HCI_SCAN_ITVL_MAX) ||
3006*042d53a7SEvalZero (window < BLE_HCI_SCAN_WINDOW_MIN) ||
3007*042d53a7SEvalZero (window > BLE_HCI_SCAN_WINDOW_MAX) ||
3008*042d53a7SEvalZero (itvl < window)) {
3009*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
3010*042d53a7SEvalZero }
3011*042d53a7SEvalZero
3012*042d53a7SEvalZero return 0;
3013*042d53a7SEvalZero }
3014*042d53a7SEvalZero
3015*042d53a7SEvalZero int
ble_ll_set_ext_scan_params(uint8_t * cmd,uint8_t cmdlen)3016*042d53a7SEvalZero ble_ll_set_ext_scan_params(uint8_t *cmd, uint8_t cmdlen)
3017*042d53a7SEvalZero {
3018*042d53a7SEvalZero struct ble_ll_scan_params new_params[BLE_LL_SCAN_PHY_NUMBER] = { };
3019*042d53a7SEvalZero struct ble_ll_scan_params *uncoded = &new_params[PHY_UNCODED];
3020*042d53a7SEvalZero struct ble_ll_scan_params *coded = &new_params[PHY_CODED];
3021*042d53a7SEvalZero uint8_t idx;
3022*042d53a7SEvalZero int rc;
3023*042d53a7SEvalZero
3024*042d53a7SEvalZero if (cmdlen < 3) {
3025*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
3026*042d53a7SEvalZero }
3027*042d53a7SEvalZero
3028*042d53a7SEvalZero /* If already enabled, we return an error */
3029*042d53a7SEvalZero if (g_ble_ll_scan_sm.scan_enabled) {
3030*042d53a7SEvalZero return BLE_ERR_CMD_DISALLOWED;
3031*042d53a7SEvalZero }
3032*042d53a7SEvalZero
3033*042d53a7SEvalZero /* Check own addr type */
3034*042d53a7SEvalZero if (cmd[0] > BLE_HCI_ADV_OWN_ADDR_MAX) {
3035*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
3036*042d53a7SEvalZero }
3037*042d53a7SEvalZero
3038*042d53a7SEvalZero coded->own_addr_type = cmd[0];
3039*042d53a7SEvalZero uncoded->own_addr_type = cmd[0];
3040*042d53a7SEvalZero
3041*042d53a7SEvalZero /* Check scanner filter policy */
3042*042d53a7SEvalZero if (cmd[1] > BLE_HCI_SCAN_FILT_MAX) {
3043*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
3044*042d53a7SEvalZero }
3045*042d53a7SEvalZero
3046*042d53a7SEvalZero coded->scan_filt_policy = cmd[1];
3047*042d53a7SEvalZero uncoded->scan_filt_policy = cmd[1];
3048*042d53a7SEvalZero
3049*042d53a7SEvalZero /* Check if no reserved bits in PHYS are set and that at least one valid PHY
3050*042d53a7SEvalZero * is set.
3051*042d53a7SEvalZero */
3052*042d53a7SEvalZero if (!(cmd[2] & ble_ll_valid_scan_phy_mask) ||
3053*042d53a7SEvalZero (cmd[2] & ~ble_ll_valid_scan_phy_mask)) {
3054*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
3055*042d53a7SEvalZero }
3056*042d53a7SEvalZero
3057*042d53a7SEvalZero idx = 3;
3058*042d53a7SEvalZero if (cmd[2] & BLE_HCI_LE_PHY_1M_PREF_MASK) {
3059*042d53a7SEvalZero if (cmdlen < idx + 5) {
3060*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
3061*042d53a7SEvalZero }
3062*042d53a7SEvalZero
3063*042d53a7SEvalZero uncoded->scan_type = cmd[idx];
3064*042d53a7SEvalZero idx++;
3065*042d53a7SEvalZero uncoded->scan_itvl = get_le16(cmd + idx);
3066*042d53a7SEvalZero idx += 2;
3067*042d53a7SEvalZero uncoded->scan_window = get_le16(cmd + idx);
3068*042d53a7SEvalZero idx += 2;
3069*042d53a7SEvalZero
3070*042d53a7SEvalZero rc = ble_ll_check_scan_params(uncoded->scan_type,
3071*042d53a7SEvalZero uncoded->scan_itvl,
3072*042d53a7SEvalZero uncoded->scan_window);
3073*042d53a7SEvalZero if (rc) {
3074*042d53a7SEvalZero return rc;
3075*042d53a7SEvalZero }
3076*042d53a7SEvalZero
3077*042d53a7SEvalZero /* That means user whats to use this PHY for scanning */
3078*042d53a7SEvalZero uncoded->configured = 1;
3079*042d53a7SEvalZero }
3080*042d53a7SEvalZero
3081*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
3082*042d53a7SEvalZero if (cmd[2] & BLE_HCI_LE_PHY_CODED_PREF_MASK) {
3083*042d53a7SEvalZero if (cmdlen < idx + 5) {
3084*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
3085*042d53a7SEvalZero }
3086*042d53a7SEvalZero
3087*042d53a7SEvalZero coded->scan_type = cmd[idx];
3088*042d53a7SEvalZero idx++;
3089*042d53a7SEvalZero coded->scan_itvl = get_le16(cmd + idx);
3090*042d53a7SEvalZero idx += 2;
3091*042d53a7SEvalZero coded->scan_window = get_le16(cmd + idx);
3092*042d53a7SEvalZero idx += 2;
3093*042d53a7SEvalZero
3094*042d53a7SEvalZero rc = ble_ll_check_scan_params(coded->scan_type,
3095*042d53a7SEvalZero coded->scan_itvl,
3096*042d53a7SEvalZero coded->scan_window);
3097*042d53a7SEvalZero if (rc) {
3098*042d53a7SEvalZero return rc;
3099*042d53a7SEvalZero }
3100*042d53a7SEvalZero
3101*042d53a7SEvalZero /* That means user whats to use this PHY for scanning */
3102*042d53a7SEvalZero coded->configured = 1;
3103*042d53a7SEvalZero }
3104*042d53a7SEvalZero #endif
3105*042d53a7SEvalZero
3106*042d53a7SEvalZero /* If host requests continuous scan for 2 PHYs, we double scan interval
3107*042d53a7SEvalZero * and split it for two equal scan windows between 2 PHYs
3108*042d53a7SEvalZero */
3109*042d53a7SEvalZero if ((coded->configured && uncoded->configured) &&
3110*042d53a7SEvalZero ((uncoded->scan_itvl == uncoded->scan_window) ||
3111*042d53a7SEvalZero (coded->scan_itvl == coded-> scan_window))) {
3112*042d53a7SEvalZero
3113*042d53a7SEvalZero uncoded->scan_itvl *= 2;
3114*042d53a7SEvalZero coded-> scan_itvl = uncoded->scan_itvl;
3115*042d53a7SEvalZero coded->scan_window = uncoded->scan_window;
3116*042d53a7SEvalZero }
3117*042d53a7SEvalZero
3118*042d53a7SEvalZero memcpy(g_ble_ll_scan_params, new_params, sizeof(new_params));
3119*042d53a7SEvalZero
3120*042d53a7SEvalZero return 0;
3121*042d53a7SEvalZero }
3122*042d53a7SEvalZero
3123*042d53a7SEvalZero #endif
3124*042d53a7SEvalZero
3125*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3126*042d53a7SEvalZero static void
ble_ll_scan_duration_period_timers_restart(struct ble_ll_scan_sm * scansm)3127*042d53a7SEvalZero ble_ll_scan_duration_period_timers_restart(struct ble_ll_scan_sm *scansm)
3128*042d53a7SEvalZero {
3129*042d53a7SEvalZero uint32_t now;
3130*042d53a7SEvalZero
3131*042d53a7SEvalZero now = os_cputime_get32();
3132*042d53a7SEvalZero
3133*042d53a7SEvalZero os_cputime_timer_stop(&scansm->duration_timer);
3134*042d53a7SEvalZero os_cputime_timer_stop(&scansm->period_timer);
3135*042d53a7SEvalZero
3136*042d53a7SEvalZero if (scansm->duration_ticks) {
3137*042d53a7SEvalZero os_cputime_timer_start(&scansm->duration_timer,
3138*042d53a7SEvalZero now + scansm->duration_ticks);
3139*042d53a7SEvalZero
3140*042d53a7SEvalZero if (scansm->period_ticks) {
3141*042d53a7SEvalZero os_cputime_timer_start(&scansm->period_timer,
3142*042d53a7SEvalZero now + scansm->period_ticks);
3143*042d53a7SEvalZero }
3144*042d53a7SEvalZero }
3145*042d53a7SEvalZero }
3146*042d53a7SEvalZero
3147*042d53a7SEvalZero static void
ble_ll_scan_duration_timer_cb(void * arg)3148*042d53a7SEvalZero ble_ll_scan_duration_timer_cb(void *arg)
3149*042d53a7SEvalZero {
3150*042d53a7SEvalZero struct ble_ll_scan_sm *scansm;
3151*042d53a7SEvalZero
3152*042d53a7SEvalZero scansm = (struct ble_ll_scan_sm *)arg;
3153*042d53a7SEvalZero
3154*042d53a7SEvalZero ble_ll_scan_sm_stop(2);
3155*042d53a7SEvalZero
3156*042d53a7SEvalZero /* if period is set both timers get started from period cb */
3157*042d53a7SEvalZero if (!scansm->period_ticks) {
3158*042d53a7SEvalZero ble_ll_hci_ev_send_scan_timeout();
3159*042d53a7SEvalZero }
3160*042d53a7SEvalZero }
3161*042d53a7SEvalZero
3162*042d53a7SEvalZero static void
ble_ll_scan_period_timer_cb(void * arg)3163*042d53a7SEvalZero ble_ll_scan_period_timer_cb(void *arg)
3164*042d53a7SEvalZero {
3165*042d53a7SEvalZero struct ble_ll_scan_sm *scansm = arg;
3166*042d53a7SEvalZero
3167*042d53a7SEvalZero ble_ll_scan_sm_start(scansm);
3168*042d53a7SEvalZero
3169*042d53a7SEvalZero /* always start timer regardless of ble_ll_scan_sm_start result
3170*042d53a7SEvalZero * if it failed will restart in next period
3171*042d53a7SEvalZero */
3172*042d53a7SEvalZero ble_ll_scan_duration_period_timers_restart(scansm);
3173*042d53a7SEvalZero }
3174*042d53a7SEvalZero #endif
3175*042d53a7SEvalZero
3176*042d53a7SEvalZero /**
3177*042d53a7SEvalZero * ble ll scan set enable
3178*042d53a7SEvalZero *
3179*042d53a7SEvalZero * HCI scan set enable command processing function
3180*042d53a7SEvalZero *
3181*042d53a7SEvalZero * Context: Link Layer task (HCI Command parser).
3182*042d53a7SEvalZero *
3183*042d53a7SEvalZero * @param cmd Pointer to command buffer
3184*042d53a7SEvalZero *
3185*042d53a7SEvalZero * @return int BLE error code.
3186*042d53a7SEvalZero */
3187*042d53a7SEvalZero int
ble_ll_scan_set_enable(uint8_t * cmd,uint8_t ext)3188*042d53a7SEvalZero ble_ll_scan_set_enable(uint8_t *cmd, uint8_t ext)
3189*042d53a7SEvalZero {
3190*042d53a7SEvalZero int rc;
3191*042d53a7SEvalZero uint8_t filter_dups;
3192*042d53a7SEvalZero uint8_t enable;
3193*042d53a7SEvalZero struct ble_ll_scan_sm *scansm;
3194*042d53a7SEvalZero struct ble_ll_scan_params *scanp;
3195*042d53a7SEvalZero struct ble_ll_scan_params *scanphy;
3196*042d53a7SEvalZero int i;
3197*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3198*042d53a7SEvalZero uint32_t period_ticks = 0;
3199*042d53a7SEvalZero uint32_t dur_ticks = 0;
3200*042d53a7SEvalZero uint16_t period;
3201*042d53a7SEvalZero uint16_t dur;
3202*042d53a7SEvalZero #endif
3203*042d53a7SEvalZero
3204*042d53a7SEvalZero /* Check for valid parameters */
3205*042d53a7SEvalZero enable = cmd[0];
3206*042d53a7SEvalZero filter_dups = cmd[1];
3207*042d53a7SEvalZero if ((filter_dups > 1) || (enable > 1)) {
3208*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
3209*042d53a7SEvalZero }
3210*042d53a7SEvalZero
3211*042d53a7SEvalZero scansm = &g_ble_ll_scan_sm;
3212*042d53a7SEvalZero
3213*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3214*042d53a7SEvalZero /* we can do that here since value will never change until reset */
3215*042d53a7SEvalZero scansm->ext_scanning = ext;
3216*042d53a7SEvalZero
3217*042d53a7SEvalZero if (ext) {
3218*042d53a7SEvalZero dur = get_le16(cmd + 2);
3219*042d53a7SEvalZero
3220*042d53a7SEvalZero /* Period parameter is ignored when the Duration parameter is zero */
3221*042d53a7SEvalZero if (dur) {
3222*042d53a7SEvalZero period = get_le16(cmd + 4);
3223*042d53a7SEvalZero } else {
3224*042d53a7SEvalZero period = 0;
3225*042d53a7SEvalZero }
3226*042d53a7SEvalZero
3227*042d53a7SEvalZero /* period is in 1.28 sec units
3228*042d53a7SEvalZero * TODO support full range, would require os_cputime milliseconds API
3229*042d53a7SEvalZero */
3230*042d53a7SEvalZero if (period > 3355) {
3231*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
3232*042d53a7SEvalZero }
3233*042d53a7SEvalZero period_ticks = os_cputime_usecs_to_ticks(period * 1280000);
3234*042d53a7SEvalZero
3235*042d53a7SEvalZero /* duration is in 10ms units */
3236*042d53a7SEvalZero dur_ticks = os_cputime_usecs_to_ticks(dur * 10000);
3237*042d53a7SEvalZero
3238*042d53a7SEvalZero if (dur_ticks && period_ticks && (dur_ticks >= period_ticks)) {
3239*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
3240*042d53a7SEvalZero }
3241*042d53a7SEvalZero }
3242*042d53a7SEvalZero #endif
3243*042d53a7SEvalZero
3244*042d53a7SEvalZero /* disable*/
3245*042d53a7SEvalZero if (!enable) {
3246*042d53a7SEvalZero if (scansm->scan_enabled) {
3247*042d53a7SEvalZero ble_ll_scan_sm_stop(1);
3248*042d53a7SEvalZero }
3249*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3250*042d53a7SEvalZero os_cputime_timer_stop(&scansm->duration_timer);
3251*042d53a7SEvalZero os_cputime_timer_stop(&scansm->period_timer);
3252*042d53a7SEvalZero #endif
3253*042d53a7SEvalZero
3254*042d53a7SEvalZero return BLE_ERR_SUCCESS;
3255*042d53a7SEvalZero }
3256*042d53a7SEvalZero
3257*042d53a7SEvalZero /* if already enable we just need to update parameters */
3258*042d53a7SEvalZero if (scansm->scan_enabled) {
3259*042d53a7SEvalZero /* Controller does not allow initiating and scanning.*/
3260*042d53a7SEvalZero for (i = 0; i < BLE_LL_SCAN_PHY_NUMBER; i++) {
3261*042d53a7SEvalZero scanphy = &scansm->phy_data[i];
3262*042d53a7SEvalZero if (scanphy->configured &&
3263*042d53a7SEvalZero scanphy->scan_type == BLE_SCAN_TYPE_INITIATE) {
3264*042d53a7SEvalZero return BLE_ERR_CMD_DISALLOWED;
3265*042d53a7SEvalZero }
3266*042d53a7SEvalZero }
3267*042d53a7SEvalZero
3268*042d53a7SEvalZero /* update filter policy */
3269*042d53a7SEvalZero scansm->scan_filt_dups = filter_dups;
3270*042d53a7SEvalZero
3271*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3272*042d53a7SEvalZero /* restart timers according to new settings */
3273*042d53a7SEvalZero scansm->duration_ticks = dur_ticks;
3274*042d53a7SEvalZero scansm->period_ticks = period_ticks;
3275*042d53a7SEvalZero ble_ll_scan_duration_period_timers_restart(scansm);
3276*042d53a7SEvalZero #endif
3277*042d53a7SEvalZero
3278*042d53a7SEvalZero return BLE_ERR_SUCCESS;
3279*042d53a7SEvalZero }
3280*042d53a7SEvalZero
3281*042d53a7SEvalZero /* we can store those upfront regardless of start scan result since scan is
3282*042d53a7SEvalZero * disabled now
3283*042d53a7SEvalZero */
3284*042d53a7SEvalZero
3285*042d53a7SEvalZero scansm->scan_filt_dups = filter_dups;
3286*042d53a7SEvalZero scansm->cur_phy = PHY_NOT_CONFIGURED;
3287*042d53a7SEvalZero scansm->next_phy = PHY_NOT_CONFIGURED;
3288*042d53a7SEvalZero
3289*042d53a7SEvalZero for (i = 0; i < BLE_LL_SCAN_PHY_NUMBER; i++) {
3290*042d53a7SEvalZero scanphy = &scansm->phy_data[i];
3291*042d53a7SEvalZero scanp = &g_ble_ll_scan_params[i];
3292*042d53a7SEvalZero
3293*042d53a7SEvalZero if (!scanp->configured) {
3294*042d53a7SEvalZero continue;
3295*042d53a7SEvalZero }
3296*042d53a7SEvalZero
3297*042d53a7SEvalZero scanphy->configured = scanp->configured;
3298*042d53a7SEvalZero scanphy->scan_type = scanp->scan_type;
3299*042d53a7SEvalZero scanphy->scan_itvl = scanp->scan_itvl;
3300*042d53a7SEvalZero scanphy->scan_window = scanp->scan_window;
3301*042d53a7SEvalZero scanphy->scan_filt_policy = scanp->scan_filt_policy;
3302*042d53a7SEvalZero scanphy->own_addr_type = scanp->own_addr_type;
3303*042d53a7SEvalZero
3304*042d53a7SEvalZero if (scansm->cur_phy == PHY_NOT_CONFIGURED) {
3305*042d53a7SEvalZero scansm->cur_phy = i;
3306*042d53a7SEvalZero /* Take own_addr_type from the first configured PHY.
3307*042d53a7SEvalZero * Note: All configured PHYs shall have the same own_addr_type
3308*042d53a7SEvalZero */
3309*042d53a7SEvalZero scansm->own_addr_type = scanphy->own_addr_type;
3310*042d53a7SEvalZero } else {
3311*042d53a7SEvalZero scansm->next_phy = i;
3312*042d53a7SEvalZero }
3313*042d53a7SEvalZero }
3314*042d53a7SEvalZero
3315*042d53a7SEvalZero rc = ble_ll_scan_sm_start(scansm);
3316*042d53a7SEvalZero
3317*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3318*042d53a7SEvalZero if (rc == BLE_ERR_SUCCESS) {
3319*042d53a7SEvalZero scansm->duration_ticks = dur_ticks;
3320*042d53a7SEvalZero scansm->period_ticks = period_ticks;
3321*042d53a7SEvalZero ble_ll_scan_duration_period_timers_restart(scansm);
3322*042d53a7SEvalZero }
3323*042d53a7SEvalZero #endif
3324*042d53a7SEvalZero
3325*042d53a7SEvalZero return rc;
3326*042d53a7SEvalZero }
3327*042d53a7SEvalZero
3328*042d53a7SEvalZero /**
3329*042d53a7SEvalZero * Checks if controller can change the whitelist. If scanning is enabled and
3330*042d53a7SEvalZero * using the whitelist the controller is not allowed to change the whitelist.
3331*042d53a7SEvalZero *
3332*042d53a7SEvalZero * @return int 0: not allowed to change whitelist; 1: change allowed.
3333*042d53a7SEvalZero */
3334*042d53a7SEvalZero int
ble_ll_scan_can_chg_whitelist(void)3335*042d53a7SEvalZero ble_ll_scan_can_chg_whitelist(void)
3336*042d53a7SEvalZero {
3337*042d53a7SEvalZero int rc;
3338*042d53a7SEvalZero struct ble_ll_scan_sm *scansm;
3339*042d53a7SEvalZero struct ble_ll_scan_params *params;
3340*042d53a7SEvalZero
3341*042d53a7SEvalZero scansm = &g_ble_ll_scan_sm;
3342*042d53a7SEvalZero params = &scansm->phy_data[scansm->cur_phy];
3343*042d53a7SEvalZero if (scansm->scan_enabled && (params->scan_filt_policy & 1)) {
3344*042d53a7SEvalZero rc = 0;
3345*042d53a7SEvalZero } else {
3346*042d53a7SEvalZero rc = 1;
3347*042d53a7SEvalZero }
3348*042d53a7SEvalZero
3349*042d53a7SEvalZero return rc;
3350*042d53a7SEvalZero }
3351*042d53a7SEvalZero
3352*042d53a7SEvalZero int
ble_ll_scan_initiator_start(struct hci_create_conn * hcc,struct ble_ll_scan_sm ** sm)3353*042d53a7SEvalZero ble_ll_scan_initiator_start(struct hci_create_conn *hcc,
3354*042d53a7SEvalZero struct ble_ll_scan_sm **sm)
3355*042d53a7SEvalZero {
3356*042d53a7SEvalZero struct ble_ll_scan_sm *scansm;
3357*042d53a7SEvalZero struct ble_ll_scan_params *scanphy;
3358*042d53a7SEvalZero int rc;
3359*042d53a7SEvalZero
3360*042d53a7SEvalZero scansm = &g_ble_ll_scan_sm;
3361*042d53a7SEvalZero scansm->own_addr_type = hcc->own_addr_type;
3362*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3363*042d53a7SEvalZero scansm->ext_scanning = 0;
3364*042d53a7SEvalZero #endif
3365*042d53a7SEvalZero scansm->cur_phy = PHY_UNCODED;
3366*042d53a7SEvalZero scansm->next_phy = PHY_NOT_CONFIGURED;
3367*042d53a7SEvalZero
3368*042d53a7SEvalZero scanphy = &scansm->phy_data[scansm->cur_phy];
3369*042d53a7SEvalZero scanphy->scan_filt_policy = hcc->filter_policy;
3370*042d53a7SEvalZero scanphy->scan_itvl = hcc->scan_itvl;
3371*042d53a7SEvalZero scanphy->scan_window = hcc->scan_window;
3372*042d53a7SEvalZero scanphy->scan_type = BLE_SCAN_TYPE_INITIATE;
3373*042d53a7SEvalZero
3374*042d53a7SEvalZero rc = ble_ll_scan_sm_start(scansm);
3375*042d53a7SEvalZero if (sm == NULL) {
3376*042d53a7SEvalZero return rc;
3377*042d53a7SEvalZero }
3378*042d53a7SEvalZero
3379*042d53a7SEvalZero if (rc == BLE_ERR_SUCCESS) {
3380*042d53a7SEvalZero *sm = scansm;
3381*042d53a7SEvalZero } else {
3382*042d53a7SEvalZero *sm = NULL;
3383*042d53a7SEvalZero }
3384*042d53a7SEvalZero
3385*042d53a7SEvalZero return rc;
3386*042d53a7SEvalZero }
3387*042d53a7SEvalZero
3388*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3389*042d53a7SEvalZero int
ble_ll_scan_ext_initiator_start(struct hci_ext_create_conn * hcc,struct ble_ll_scan_sm ** sm)3390*042d53a7SEvalZero ble_ll_scan_ext_initiator_start(struct hci_ext_create_conn *hcc,
3391*042d53a7SEvalZero struct ble_ll_scan_sm **sm)
3392*042d53a7SEvalZero {
3393*042d53a7SEvalZero struct ble_ll_scan_sm *scansm;
3394*042d53a7SEvalZero struct ble_ll_scan_params *uncoded;
3395*042d53a7SEvalZero struct ble_ll_scan_params *coded;
3396*042d53a7SEvalZero struct hci_ext_conn_params *params;
3397*042d53a7SEvalZero int rc;
3398*042d53a7SEvalZero
3399*042d53a7SEvalZero scansm = &g_ble_ll_scan_sm;
3400*042d53a7SEvalZero scansm->own_addr_type = hcc->own_addr_type;
3401*042d53a7SEvalZero scansm->cur_phy = PHY_NOT_CONFIGURED;
3402*042d53a7SEvalZero scansm->next_phy = PHY_NOT_CONFIGURED;
3403*042d53a7SEvalZero scansm->ext_scanning = 1;
3404*042d53a7SEvalZero
3405*042d53a7SEvalZero if (hcc->init_phy_mask & BLE_PHY_MASK_1M) {
3406*042d53a7SEvalZero params = &hcc->params[0];
3407*042d53a7SEvalZero uncoded = &scansm->phy_data[PHY_UNCODED];
3408*042d53a7SEvalZero
3409*042d53a7SEvalZero uncoded->scan_itvl = params->scan_itvl;
3410*042d53a7SEvalZero uncoded->scan_window = params->scan_window;
3411*042d53a7SEvalZero uncoded->scan_type = BLE_SCAN_TYPE_INITIATE;
3412*042d53a7SEvalZero uncoded->scan_filt_policy = hcc->filter_policy;
3413*042d53a7SEvalZero scansm->cur_phy = PHY_UNCODED;
3414*042d53a7SEvalZero }
3415*042d53a7SEvalZero
3416*042d53a7SEvalZero if (hcc->init_phy_mask & BLE_PHY_MASK_CODED) {
3417*042d53a7SEvalZero params = &hcc->params[2];
3418*042d53a7SEvalZero coded = &scansm->phy_data[PHY_CODED];
3419*042d53a7SEvalZero
3420*042d53a7SEvalZero coded->scan_itvl = params->scan_itvl;
3421*042d53a7SEvalZero coded->scan_window = params->scan_window;
3422*042d53a7SEvalZero coded->scan_type = BLE_SCAN_TYPE_INITIATE;
3423*042d53a7SEvalZero coded->scan_filt_policy = hcc->filter_policy;
3424*042d53a7SEvalZero if (scansm->cur_phy == PHY_NOT_CONFIGURED) {
3425*042d53a7SEvalZero scansm->cur_phy = PHY_CODED;
3426*042d53a7SEvalZero } else {
3427*042d53a7SEvalZero scansm->next_phy = PHY_CODED;
3428*042d53a7SEvalZero }
3429*042d53a7SEvalZero }
3430*042d53a7SEvalZero
3431*042d53a7SEvalZero /* If host request for continuous scan if 2 PHYs are requested, we split
3432*042d53a7SEvalZero * time on two
3433*042d53a7SEvalZero */
3434*042d53a7SEvalZero if ((scansm->next_phy != PHY_NOT_CONFIGURED) &&
3435*042d53a7SEvalZero ((uncoded->scan_itvl == uncoded->scan_window) ||
3436*042d53a7SEvalZero (coded->scan_itvl == coded-> scan_window))) {
3437*042d53a7SEvalZero
3438*042d53a7SEvalZero uncoded->scan_itvl *= 2;
3439*042d53a7SEvalZero coded-> scan_itvl = uncoded->scan_itvl;
3440*042d53a7SEvalZero coded->scan_window = uncoded->scan_window;
3441*042d53a7SEvalZero }
3442*042d53a7SEvalZero
3443*042d53a7SEvalZero rc = ble_ll_scan_sm_start(scansm);
3444*042d53a7SEvalZero if (sm == NULL) {
3445*042d53a7SEvalZero return rc;
3446*042d53a7SEvalZero }
3447*042d53a7SEvalZero
3448*042d53a7SEvalZero if (rc == BLE_ERR_SUCCESS) {
3449*042d53a7SEvalZero *sm = scansm;
3450*042d53a7SEvalZero } else {
3451*042d53a7SEvalZero *sm = NULL;
3452*042d53a7SEvalZero }
3453*042d53a7SEvalZero
3454*042d53a7SEvalZero return rc;
3455*042d53a7SEvalZero }
3456*042d53a7SEvalZero #endif
3457*042d53a7SEvalZero
3458*042d53a7SEvalZero /**
3459*042d53a7SEvalZero * Checks to see if the scanner is enabled.
3460*042d53a7SEvalZero *
3461*042d53a7SEvalZero * @return int 0: not enabled; enabled otherwise
3462*042d53a7SEvalZero */
3463*042d53a7SEvalZero int
ble_ll_scan_enabled(void)3464*042d53a7SEvalZero ble_ll_scan_enabled(void)
3465*042d53a7SEvalZero {
3466*042d53a7SEvalZero return (int)g_ble_ll_scan_sm.scan_enabled;
3467*042d53a7SEvalZero }
3468*042d53a7SEvalZero
3469*042d53a7SEvalZero /**
3470*042d53a7SEvalZero * Returns the peer resolvable private address of last device connecting to us
3471*042d53a7SEvalZero *
3472*042d53a7SEvalZero * @return uint8_t*
3473*042d53a7SEvalZero */
3474*042d53a7SEvalZero uint8_t *
ble_ll_scan_get_peer_rpa(void)3475*042d53a7SEvalZero ble_ll_scan_get_peer_rpa(void)
3476*042d53a7SEvalZero {
3477*042d53a7SEvalZero struct ble_ll_scan_sm *scansm;
3478*042d53a7SEvalZero
3479*042d53a7SEvalZero /* XXX: should this go into IRK list or connection? */
3480*042d53a7SEvalZero scansm = &g_ble_ll_scan_sm;
3481*042d53a7SEvalZero return scansm->scan_peer_rpa;
3482*042d53a7SEvalZero }
3483*042d53a7SEvalZero
3484*042d53a7SEvalZero /**
3485*042d53a7SEvalZero * Returns the local resolvable private address currently being using by
3486*042d53a7SEvalZero * the scanner/initiator
3487*042d53a7SEvalZero *
3488*042d53a7SEvalZero * @return uint8_t*
3489*042d53a7SEvalZero */
3490*042d53a7SEvalZero uint8_t *
ble_ll_scan_get_local_rpa(void)3491*042d53a7SEvalZero ble_ll_scan_get_local_rpa(void)
3492*042d53a7SEvalZero {
3493*042d53a7SEvalZero uint8_t *rpa;
3494*042d53a7SEvalZero struct ble_ll_scan_sm *scansm;
3495*042d53a7SEvalZero
3496*042d53a7SEvalZero scansm = &g_ble_ll_scan_sm;
3497*042d53a7SEvalZero
3498*042d53a7SEvalZero /*
3499*042d53a7SEvalZero * The RPA we used is in connect request or scan request and is the
3500*042d53a7SEvalZero * first address in the packet
3501*042d53a7SEvalZero */
3502*042d53a7SEvalZero rpa = scansm->scan_req_pdu->om_data;
3503*042d53a7SEvalZero
3504*042d53a7SEvalZero return rpa;
3505*042d53a7SEvalZero }
3506*042d53a7SEvalZero
3507*042d53a7SEvalZero /**
3508*042d53a7SEvalZero * Set the Resolvable Private Address in the scanning (or initiating) state
3509*042d53a7SEvalZero * machine.
3510*042d53a7SEvalZero *
3511*042d53a7SEvalZero * XXX: should this go into IRK list or connection?
3512*042d53a7SEvalZero *
3513*042d53a7SEvalZero * @param rpa
3514*042d53a7SEvalZero */
3515*042d53a7SEvalZero void
ble_ll_scan_set_peer_rpa(uint8_t * rpa)3516*042d53a7SEvalZero ble_ll_scan_set_peer_rpa(uint8_t *rpa)
3517*042d53a7SEvalZero {
3518*042d53a7SEvalZero struct ble_ll_scan_sm *scansm;
3519*042d53a7SEvalZero
3520*042d53a7SEvalZero scansm = &g_ble_ll_scan_sm;
3521*042d53a7SEvalZero memcpy(scansm->scan_peer_rpa, rpa, BLE_DEV_ADDR_LEN);
3522*042d53a7SEvalZero }
3523*042d53a7SEvalZero
3524*042d53a7SEvalZero /* Returns the PDU allocated by the scanner */
3525*042d53a7SEvalZero struct os_mbuf *
ble_ll_scan_get_pdu(void)3526*042d53a7SEvalZero ble_ll_scan_get_pdu(void)
3527*042d53a7SEvalZero {
3528*042d53a7SEvalZero return g_ble_ll_scan_sm.scan_req_pdu;
3529*042d53a7SEvalZero }
3530*042d53a7SEvalZero
3531*042d53a7SEvalZero /* Returns true if whitelist is enabled for scanning */
3532*042d53a7SEvalZero int
ble_ll_scan_whitelist_enabled(void)3533*042d53a7SEvalZero ble_ll_scan_whitelist_enabled(void)
3534*042d53a7SEvalZero {
3535*042d53a7SEvalZero struct ble_ll_scan_params *params;
3536*042d53a7SEvalZero
3537*042d53a7SEvalZero params = &g_ble_ll_scan_sm.phy_data[g_ble_ll_scan_sm.cur_phy];
3538*042d53a7SEvalZero return params->scan_filt_policy & 1;
3539*042d53a7SEvalZero }
3540*042d53a7SEvalZero
3541*042d53a7SEvalZero static void
ble_ll_scan_common_init(void)3542*042d53a7SEvalZero ble_ll_scan_common_init(void)
3543*042d53a7SEvalZero {
3544*042d53a7SEvalZero struct ble_ll_scan_sm *scansm;
3545*042d53a7SEvalZero struct ble_ll_scan_params *scanp;
3546*042d53a7SEvalZero int i;
3547*042d53a7SEvalZero
3548*042d53a7SEvalZero /* Clear state machine in case re-initialized */
3549*042d53a7SEvalZero scansm = &g_ble_ll_scan_sm;
3550*042d53a7SEvalZero memset(scansm, 0, sizeof(struct ble_ll_scan_sm));
3551*042d53a7SEvalZero
3552*042d53a7SEvalZero /* Clear scan parameters in case re-initialized */
3553*042d53a7SEvalZero memset(g_ble_ll_scan_params, 0, sizeof(g_ble_ll_scan_params));
3554*042d53a7SEvalZero
3555*042d53a7SEvalZero /* Initialize scanning window end event */
3556*042d53a7SEvalZero ble_npl_event_init(&scansm->scan_sched_ev, ble_ll_scan_event_proc, scansm);
3557*042d53a7SEvalZero
3558*042d53a7SEvalZero for (i = 0; i < BLE_LL_SCAN_PHY_NUMBER; i++) {
3559*042d53a7SEvalZero /* Set all non-zero default parameters */
3560*042d53a7SEvalZero scanp = &g_ble_ll_scan_params[i];
3561*042d53a7SEvalZero scanp->scan_itvl = BLE_HCI_SCAN_ITVL_DEF;
3562*042d53a7SEvalZero scanp->scan_window = BLE_HCI_SCAN_WINDOW_DEF;
3563*042d53a7SEvalZero }
3564*042d53a7SEvalZero
3565*042d53a7SEvalZero scansm->phy_data[PHY_UNCODED].phy = BLE_PHY_1M;
3566*042d53a7SEvalZero #if (BLE_LL_SCAN_PHY_NUMBER == 2)
3567*042d53a7SEvalZero scansm->phy_data[PHY_CODED].phy = BLE_PHY_CODED;
3568*042d53a7SEvalZero #endif
3569*042d53a7SEvalZero
3570*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
3571*042d53a7SEvalZero /* Make sure we'll generate new NRPA if necessary */
3572*042d53a7SEvalZero scansm->scan_nrpa_timer = ble_npl_time_get();
3573*042d53a7SEvalZero #endif
3574*042d53a7SEvalZero
3575*042d53a7SEvalZero /* Initialize scanning timer */
3576*042d53a7SEvalZero os_cputime_timer_init(&scansm->scan_timer, ble_ll_scan_timer_cb, scansm);
3577*042d53a7SEvalZero
3578*042d53a7SEvalZero /* Initialize extended scan timers */
3579*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3580*042d53a7SEvalZero os_cputime_timer_init(&scansm->duration_timer,
3581*042d53a7SEvalZero ble_ll_scan_duration_timer_cb, scansm);
3582*042d53a7SEvalZero os_cputime_timer_init(&scansm->period_timer, ble_ll_scan_period_timer_cb,
3583*042d53a7SEvalZero scansm);
3584*042d53a7SEvalZero #endif
3585*042d53a7SEvalZero
3586*042d53a7SEvalZero /* Get a scan request mbuf (packet header) and attach to state machine */
3587*042d53a7SEvalZero scansm->scan_req_pdu = os_msys_get_pkthdr(BLE_SCAN_LEGACY_MAX_PKT_LEN,
3588*042d53a7SEvalZero sizeof(struct ble_mbuf_hdr));
3589*042d53a7SEvalZero BLE_LL_ASSERT(scansm->scan_req_pdu != NULL);
3590*042d53a7SEvalZero }
3591*042d53a7SEvalZero
3592*042d53a7SEvalZero /**
3593*042d53a7SEvalZero * Called when the controller receives the reset command. Resets the
3594*042d53a7SEvalZero * scanning state machine to its initial state.
3595*042d53a7SEvalZero *
3596*042d53a7SEvalZero * @return int
3597*042d53a7SEvalZero */
3598*042d53a7SEvalZero void
ble_ll_scan_reset(void)3599*042d53a7SEvalZero ble_ll_scan_reset(void)
3600*042d53a7SEvalZero {
3601*042d53a7SEvalZero struct ble_ll_scan_sm *scansm;
3602*042d53a7SEvalZero
3603*042d53a7SEvalZero scansm = &g_ble_ll_scan_sm;
3604*042d53a7SEvalZero
3605*042d53a7SEvalZero /* If enabled, stop it. */
3606*042d53a7SEvalZero if (scansm->scan_enabled) {
3607*042d53a7SEvalZero ble_ll_scan_sm_stop(0);
3608*042d53a7SEvalZero }
3609*042d53a7SEvalZero
3610*042d53a7SEvalZero /* stop extended scan timers */
3611*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3612*042d53a7SEvalZero os_cputime_timer_stop(&scansm->duration_timer);
3613*042d53a7SEvalZero os_cputime_timer_stop(&scansm->period_timer);
3614*042d53a7SEvalZero #endif
3615*042d53a7SEvalZero
3616*042d53a7SEvalZero /* Free the scan request pdu */
3617*042d53a7SEvalZero os_mbuf_free_chain(scansm->scan_req_pdu);
3618*042d53a7SEvalZero
3619*042d53a7SEvalZero /* Reset duplicate advertisers and those from which we rxd a response */
3620*042d53a7SEvalZero g_ble_ll_scan_num_rsp_advs = 0;
3621*042d53a7SEvalZero memset(&g_ble_ll_scan_rsp_advs[0], 0, sizeof(g_ble_ll_scan_rsp_advs));
3622*042d53a7SEvalZero
3623*042d53a7SEvalZero g_ble_ll_scan_num_dup_advs = 0;
3624*042d53a7SEvalZero memset(&g_ble_ll_scan_dup_advs[0], 0, sizeof(g_ble_ll_scan_dup_advs));
3625*042d53a7SEvalZero
3626*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3627*042d53a7SEvalZero /* clear memory pool for AUX scan results */
3628*042d53a7SEvalZero os_mempool_clear(&ext_adv_pool);
3629*042d53a7SEvalZero #endif
3630*042d53a7SEvalZero
3631*042d53a7SEvalZero /* Call the common init function again */
3632*042d53a7SEvalZero ble_ll_scan_common_init();
3633*042d53a7SEvalZero }
3634*042d53a7SEvalZero
3635*042d53a7SEvalZero /**
3636*042d53a7SEvalZero * ble ll scan init
3637*042d53a7SEvalZero *
3638*042d53a7SEvalZero * Initialize a scanner. Must be called before scanning can be started.
3639*042d53a7SEvalZero * Expected to be called with a un-initialized scanning state machine.
3640*042d53a7SEvalZero */
3641*042d53a7SEvalZero void
ble_ll_scan_init(void)3642*042d53a7SEvalZero ble_ll_scan_init(void)
3643*042d53a7SEvalZero {
3644*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3645*042d53a7SEvalZero os_error_t err;
3646*042d53a7SEvalZero
3647*042d53a7SEvalZero err = os_mempool_init(&ext_adv_pool,
3648*042d53a7SEvalZero MYNEWT_VAL(BLE_LL_EXT_ADV_AUX_PTR_CNT),
3649*042d53a7SEvalZero sizeof (struct ble_ll_aux_data),
3650*042d53a7SEvalZero ext_adv_mem,
3651*042d53a7SEvalZero "ble_ll_aux_scan_pool");
3652*042d53a7SEvalZero BLE_LL_ASSERT(err == 0);
3653*042d53a7SEvalZero #endif
3654*042d53a7SEvalZero
3655*042d53a7SEvalZero ble_ll_scan_common_init();
3656*042d53a7SEvalZero }
3657