1*042d53a7SEvalZero /*
2*042d53a7SEvalZero * Licensed to the Apache Software Foundation (ASF) under one
3*042d53a7SEvalZero * or more contributor license agreements. See the NOTICE file
4*042d53a7SEvalZero * distributed with this work for additional information
5*042d53a7SEvalZero * regarding copyright ownership. The ASF licenses this file
6*042d53a7SEvalZero * to you under the Apache License, Version 2.0 (the
7*042d53a7SEvalZero * "License"); you may not use this file except in compliance
8*042d53a7SEvalZero * with the License. You may obtain a copy of the License at
9*042d53a7SEvalZero *
10*042d53a7SEvalZero * http://www.apache.org/licenses/LICENSE-2.0
11*042d53a7SEvalZero *
12*042d53a7SEvalZero * Unless required by applicable law or agreed to in writing,
13*042d53a7SEvalZero * software distributed under the License is distributed on an
14*042d53a7SEvalZero * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15*042d53a7SEvalZero * KIND, either express or implied. See the License for the
16*042d53a7SEvalZero * specific language governing permissions and limitations
17*042d53a7SEvalZero * under the License.
18*042d53a7SEvalZero */
19*042d53a7SEvalZero #include <stdint.h>
20*042d53a7SEvalZero #include <stdlib.h>
21*042d53a7SEvalZero #include <string.h>
22*042d53a7SEvalZero #include <assert.h>
23*042d53a7SEvalZero #include "syscfg/syscfg.h"
24*042d53a7SEvalZero #include "os/os.h"
25*042d53a7SEvalZero #include "os/os_cputime.h"
26*042d53a7SEvalZero #include "ble/xcvr.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_hci.h"
35*042d53a7SEvalZero #include "controller/ble_ll_adv.h"
36*042d53a7SEvalZero #include "controller/ble_ll_sched.h"
37*042d53a7SEvalZero #include "controller/ble_ll_scan.h"
38*042d53a7SEvalZero #include "controller/ble_ll_whitelist.h"
39*042d53a7SEvalZero #include "controller/ble_ll_resolv.h"
40*042d53a7SEvalZero #include "controller/ble_ll_trace.h"
41*042d53a7SEvalZero #include "ble_ll_conn_priv.h"
42*042d53a7SEvalZero
43*042d53a7SEvalZero /* XXX: TODO
44*042d53a7SEvalZero * 1) Need to look at advertising and scan request PDUs. Do I allocate these
45*042d53a7SEvalZero * once? Do I use a different pool for smaller ones? Do I statically declare
46*042d53a7SEvalZero * them?
47*042d53a7SEvalZero * 3) How do features get supported? What happens if device does not support
48*042d53a7SEvalZero * advertising? (for example)
49*042d53a7SEvalZero * 4) How to determine the advertising interval we will actually use. As of
50*042d53a7SEvalZero * now, we set it to max.
51*042d53a7SEvalZero * 5) How does the advertising channel tx power get set? I dont implement
52*042d53a7SEvalZero * that currently.
53*042d53a7SEvalZero */
54*042d53a7SEvalZero
55*042d53a7SEvalZero /* Scheduling data for secondary channel */
56*042d53a7SEvalZero struct ble_ll_adv_aux {
57*042d53a7SEvalZero struct ble_ll_sched_item sch;
58*042d53a7SEvalZero uint32_t start_time;
59*042d53a7SEvalZero uint16_t aux_data_offset;
60*042d53a7SEvalZero uint8_t ext_hdr;
61*042d53a7SEvalZero uint8_t aux_data_len;
62*042d53a7SEvalZero uint8_t payload_len;
63*042d53a7SEvalZero };
64*042d53a7SEvalZero
65*042d53a7SEvalZero /*
66*042d53a7SEvalZero * Advertising state machine
67*042d53a7SEvalZero *
68*042d53a7SEvalZero * The advertising state machine data structure.
69*042d53a7SEvalZero *
70*042d53a7SEvalZero * adv_pdu_len
71*042d53a7SEvalZero * The length of the advertising PDU that will be sent. This does not
72*042d53a7SEvalZero * include the preamble, access address and CRC.
73*042d53a7SEvalZero *
74*042d53a7SEvalZero * initiator_addr:
75*042d53a7SEvalZero * This is the address that we send in directed advertisements (the
76*042d53a7SEvalZero * INITA field). If we are using Privacy this is a RPA that we need to
77*042d53a7SEvalZero * generate. We reserve space in the advsm to save time when creating
78*042d53a7SEvalZero * the ADV_DIRECT_IND. If own address type is not 2 or 3, this is simply
79*042d53a7SEvalZero * the peer address from the set advertising parameters.
80*042d53a7SEvalZero */
81*042d53a7SEvalZero struct ble_ll_adv_sm
82*042d53a7SEvalZero {
83*042d53a7SEvalZero uint8_t adv_enabled;
84*042d53a7SEvalZero uint8_t adv_instance;
85*042d53a7SEvalZero uint8_t adv_chanmask;
86*042d53a7SEvalZero uint8_t adv_filter_policy;
87*042d53a7SEvalZero uint8_t own_addr_type;
88*042d53a7SEvalZero uint8_t peer_addr_type;
89*042d53a7SEvalZero uint8_t adv_chan;
90*042d53a7SEvalZero uint8_t adv_pdu_len;
91*042d53a7SEvalZero int8_t adv_rpa_index;
92*042d53a7SEvalZero int8_t adv_txpwr;
93*042d53a7SEvalZero uint16_t flags;
94*042d53a7SEvalZero uint16_t props;
95*042d53a7SEvalZero uint16_t adv_itvl_min;
96*042d53a7SEvalZero uint16_t adv_itvl_max;
97*042d53a7SEvalZero uint32_t adv_itvl_usecs;
98*042d53a7SEvalZero uint32_t adv_event_start_time;
99*042d53a7SEvalZero uint32_t adv_pdu_start_time;
100*042d53a7SEvalZero uint32_t adv_end_time;
101*042d53a7SEvalZero uint32_t adv_rpa_timer;
102*042d53a7SEvalZero uint8_t adva[BLE_DEV_ADDR_LEN];
103*042d53a7SEvalZero uint8_t adv_rpa[BLE_DEV_ADDR_LEN];
104*042d53a7SEvalZero uint8_t peer_addr[BLE_DEV_ADDR_LEN];
105*042d53a7SEvalZero uint8_t initiator_addr[BLE_DEV_ADDR_LEN];
106*042d53a7SEvalZero struct os_mbuf *adv_data;
107*042d53a7SEvalZero struct os_mbuf *scan_rsp_data;
108*042d53a7SEvalZero uint8_t *conn_comp_ev;
109*042d53a7SEvalZero struct ble_npl_event adv_txdone_ev;
110*042d53a7SEvalZero struct ble_ll_sched_item adv_sch;
111*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
112*042d53a7SEvalZero uint8_t aux_active : 1;
113*042d53a7SEvalZero uint8_t aux_index : 1;
114*042d53a7SEvalZero uint8_t aux_first_pdu : 1;
115*042d53a7SEvalZero uint8_t aux_not_scanned : 1;
116*042d53a7SEvalZero struct ble_mbuf_hdr *rx_ble_hdr;
117*042d53a7SEvalZero struct os_mbuf **aux_data;
118*042d53a7SEvalZero struct ble_ll_adv_aux aux[2];
119*042d53a7SEvalZero struct ble_npl_event adv_sec_txdone_ev;
120*042d53a7SEvalZero uint16_t duration;
121*042d53a7SEvalZero uint16_t adi;
122*042d53a7SEvalZero uint8_t adv_secondary_chan;
123*042d53a7SEvalZero uint8_t adv_random_addr[BLE_DEV_ADDR_LEN];
124*042d53a7SEvalZero uint8_t events_max;
125*042d53a7SEvalZero uint8_t events;
126*042d53a7SEvalZero uint8_t pri_phy;
127*042d53a7SEvalZero uint8_t sec_phy;
128*042d53a7SEvalZero #endif
129*042d53a7SEvalZero };
130*042d53a7SEvalZero
131*042d53a7SEvalZero #define BLE_LL_ADV_SM_FLAG_TX_ADD 0x0001
132*042d53a7SEvalZero #define BLE_LL_ADV_SM_FLAG_RX_ADD 0x0002
133*042d53a7SEvalZero #define BLE_LL_ADV_SM_FLAG_SCAN_REQ_NOTIF 0x0004
134*042d53a7SEvalZero #define BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD 0x0008
135*042d53a7SEvalZero #define BLE_LL_ADV_SM_FLAG_ACTIVE_CHANSET_MASK 0x0030 /* use helpers! */
136*042d53a7SEvalZero #define BLE_LL_ADV_SM_FLAG_ADV_DATA_INCOMPLETE 0x0040
137*042d53a7SEvalZero #define BLE_LL_ADV_SM_FLAG_CONFIGURED 0x0080
138*042d53a7SEvalZero #define BLE_LL_ADV_SM_FLAG_ADV_RPA_TMO 0x0100
139*042d53a7SEvalZero
140*042d53a7SEvalZero #define ADV_DATA_LEN(_advsm) \
141*042d53a7SEvalZero ((_advsm->adv_data) ? OS_MBUF_PKTLEN(advsm->adv_data) : 0)
142*042d53a7SEvalZero #define SCAN_RSP_DATA_LEN(_advsm) \
143*042d53a7SEvalZero ((_advsm->scan_rsp_data) ? OS_MBUF_PKTLEN(advsm->scan_rsp_data) : 0)
144*042d53a7SEvalZero #define AUX_DATA_LEN(_advsm) \
145*042d53a7SEvalZero (*(_advsm->aux_data) ? OS_MBUF_PKTLEN(*advsm->aux_data) : 0)
146*042d53a7SEvalZero
147*042d53a7SEvalZero #define AUX_CURRENT(_advsm) (&(_advsm->aux[_advsm->aux_index]))
148*042d53a7SEvalZero #define AUX_NEXT(_advsm) (&(_advsm->aux[_advsm->aux_index ^ 1]))
149*042d53a7SEvalZero
150*042d53a7SEvalZero static inline int
ble_ll_adv_active_chanset_is_pri(struct ble_ll_adv_sm * advsm)151*042d53a7SEvalZero ble_ll_adv_active_chanset_is_pri(struct ble_ll_adv_sm *advsm)
152*042d53a7SEvalZero {
153*042d53a7SEvalZero return (advsm->flags & BLE_LL_ADV_SM_FLAG_ACTIVE_CHANSET_MASK) == 0x10;
154*042d53a7SEvalZero }
155*042d53a7SEvalZero
156*042d53a7SEvalZero static inline int
ble_ll_adv_active_chanset_is_sec(struct ble_ll_adv_sm * advsm)157*042d53a7SEvalZero ble_ll_adv_active_chanset_is_sec(struct ble_ll_adv_sm *advsm)
158*042d53a7SEvalZero {
159*042d53a7SEvalZero return (advsm->flags & BLE_LL_ADV_SM_FLAG_ACTIVE_CHANSET_MASK) == 0x20;
160*042d53a7SEvalZero }
161*042d53a7SEvalZero
162*042d53a7SEvalZero static inline void
ble_ll_adv_active_chanset_clear(struct ble_ll_adv_sm * advsm)163*042d53a7SEvalZero ble_ll_adv_active_chanset_clear(struct ble_ll_adv_sm *advsm)
164*042d53a7SEvalZero {
165*042d53a7SEvalZero advsm->flags &= ~BLE_LL_ADV_SM_FLAG_ACTIVE_CHANSET_MASK;
166*042d53a7SEvalZero }
167*042d53a7SEvalZero
168*042d53a7SEvalZero static inline void
ble_ll_adv_active_chanset_set_pri(struct ble_ll_adv_sm * advsm)169*042d53a7SEvalZero ble_ll_adv_active_chanset_set_pri(struct ble_ll_adv_sm *advsm)
170*042d53a7SEvalZero {
171*042d53a7SEvalZero assert((advsm->flags & BLE_LL_ADV_SM_FLAG_ACTIVE_CHANSET_MASK) == 0);
172*042d53a7SEvalZero advsm->flags &= ~BLE_LL_ADV_SM_FLAG_ACTIVE_CHANSET_MASK;
173*042d53a7SEvalZero advsm->flags |= 0x10;
174*042d53a7SEvalZero }
175*042d53a7SEvalZero
176*042d53a7SEvalZero static inline void
ble_ll_adv_active_chanset_set_sec(struct ble_ll_adv_sm * advsm)177*042d53a7SEvalZero ble_ll_adv_active_chanset_set_sec(struct ble_ll_adv_sm *advsm)
178*042d53a7SEvalZero {
179*042d53a7SEvalZero assert((advsm->flags & BLE_LL_ADV_SM_FLAG_ACTIVE_CHANSET_MASK) == 0);
180*042d53a7SEvalZero advsm->flags &= ~BLE_LL_ADV_SM_FLAG_ACTIVE_CHANSET_MASK;
181*042d53a7SEvalZero advsm->flags |= 0x20;
182*042d53a7SEvalZero }
183*042d53a7SEvalZero
184*042d53a7SEvalZero /* The advertising state machine global object */
185*042d53a7SEvalZero struct ble_ll_adv_sm g_ble_ll_adv_sm[BLE_ADV_INSTANCES];
186*042d53a7SEvalZero struct ble_ll_adv_sm *g_ble_ll_cur_adv_sm;
187*042d53a7SEvalZero
188*042d53a7SEvalZero static void ble_ll_adv_make_done(struct ble_ll_adv_sm *advsm, struct ble_mbuf_hdr *hdr);
189*042d53a7SEvalZero static void ble_ll_adv_sm_init(struct ble_ll_adv_sm *advsm);
190*042d53a7SEvalZero static void ble_ll_adv_sm_stop_timeout(struct ble_ll_adv_sm *advsm);
191*042d53a7SEvalZero
192*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
193*042d53a7SEvalZero static void
ble_ll_adv_rpa_update(struct ble_ll_adv_sm * advsm)194*042d53a7SEvalZero ble_ll_adv_rpa_update(struct ble_ll_adv_sm *advsm)
195*042d53a7SEvalZero {
196*042d53a7SEvalZero if (ble_ll_resolv_gen_rpa(advsm->peer_addr, advsm->peer_addr_type,
197*042d53a7SEvalZero advsm->adva, 1)) {
198*042d53a7SEvalZero advsm->flags |= BLE_LL_ADV_SM_FLAG_TX_ADD;
199*042d53a7SEvalZero } else {
200*042d53a7SEvalZero if (advsm->own_addr_type & 1) {
201*042d53a7SEvalZero advsm->flags |= BLE_LL_ADV_SM_FLAG_TX_ADD;
202*042d53a7SEvalZero } else {
203*042d53a7SEvalZero advsm->flags &= ~BLE_LL_ADV_SM_FLAG_TX_ADD;
204*042d53a7SEvalZero }
205*042d53a7SEvalZero }
206*042d53a7SEvalZero
207*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) {
208*042d53a7SEvalZero if (ble_ll_resolv_gen_rpa(advsm->peer_addr, advsm->peer_addr_type,
209*042d53a7SEvalZero advsm->initiator_addr, 0)) {
210*042d53a7SEvalZero advsm->flags |= BLE_LL_ADV_SM_FLAG_RX_ADD;
211*042d53a7SEvalZero } else {
212*042d53a7SEvalZero if (advsm->peer_addr_type & 1) {
213*042d53a7SEvalZero advsm->flags |= BLE_LL_ADV_SM_FLAG_RX_ADD;
214*042d53a7SEvalZero } else {
215*042d53a7SEvalZero advsm->flags &= ~BLE_LL_ADV_SM_FLAG_RX_ADD;
216*042d53a7SEvalZero }
217*042d53a7SEvalZero }
218*042d53a7SEvalZero }
219*042d53a7SEvalZero }
220*042d53a7SEvalZero
221*042d53a7SEvalZero /**
222*042d53a7SEvalZero * Called to change advertisers ADVA and INITA (for directed advertisements)
223*042d53a7SEvalZero * as an advertiser needs to adhere to the resolvable private address generation
224*042d53a7SEvalZero * timer.
225*042d53a7SEvalZero *
226*042d53a7SEvalZero * NOTE: the resolvable private address code uses its own timer to regenerate
227*042d53a7SEvalZero * local resolvable private addresses. The advertising code uses its own
228*042d53a7SEvalZero * timer to reset the INITA (for directed advertisements). This code also sets
229*042d53a7SEvalZero * the appropriate txadd and rxadd bits that will go into the advertisement.
230*042d53a7SEvalZero *
231*042d53a7SEvalZero * Another thing to note: it is possible that an IRK is all zeroes in the
232*042d53a7SEvalZero * resolving list. That is why we need to check if the generated address is
233*042d53a7SEvalZero * in fact a RPA as a resolving list entry with all zeroes will use the
234*042d53a7SEvalZero * identity address (which may be a private address or public).
235*042d53a7SEvalZero *
236*042d53a7SEvalZero * @param advsm
237*042d53a7SEvalZero */
238*042d53a7SEvalZero void
ble_ll_adv_chk_rpa_timeout(struct ble_ll_adv_sm * advsm)239*042d53a7SEvalZero ble_ll_adv_chk_rpa_timeout(struct ble_ll_adv_sm *advsm)
240*042d53a7SEvalZero {
241*042d53a7SEvalZero if (advsm->own_addr_type < BLE_HCI_ADV_OWN_ADDR_PRIV_PUB) {
242*042d53a7SEvalZero return;
243*042d53a7SEvalZero }
244*042d53a7SEvalZero
245*042d53a7SEvalZero if (advsm->flags & BLE_LL_ADV_SM_FLAG_ADV_RPA_TMO) {
246*042d53a7SEvalZero ble_ll_adv_rpa_update(advsm);
247*042d53a7SEvalZero advsm->flags &= ~BLE_LL_ADV_SM_FLAG_ADV_RPA_TMO;
248*042d53a7SEvalZero }
249*042d53a7SEvalZero }
250*042d53a7SEvalZero
251*042d53a7SEvalZero void
ble_ll_adv_rpa_timeout(void)252*042d53a7SEvalZero ble_ll_adv_rpa_timeout(void)
253*042d53a7SEvalZero {
254*042d53a7SEvalZero struct ble_ll_adv_sm *advsm;
255*042d53a7SEvalZero int i;
256*042d53a7SEvalZero
257*042d53a7SEvalZero for (i = 0; i < BLE_ADV_INSTANCES; i++) {
258*042d53a7SEvalZero advsm = &g_ble_ll_adv_sm[i];
259*042d53a7SEvalZero
260*042d53a7SEvalZero if (advsm->adv_enabled &&
261*042d53a7SEvalZero advsm->own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) {
262*042d53a7SEvalZero /* Mark RPA as timed out so we get a new RPA */
263*042d53a7SEvalZero advsm->flags |= BLE_LL_ADV_SM_FLAG_ADV_RPA_TMO;
264*042d53a7SEvalZero }
265*042d53a7SEvalZero }
266*042d53a7SEvalZero }
267*042d53a7SEvalZero #endif
268*042d53a7SEvalZero
269*042d53a7SEvalZero /**
270*042d53a7SEvalZero * Calculate the first channel that we should advertise upon when we start
271*042d53a7SEvalZero * an advertising event.
272*042d53a7SEvalZero *
273*042d53a7SEvalZero * @param advsm
274*042d53a7SEvalZero *
275*042d53a7SEvalZero * @return uint8_t The number of the first channel usable for advertising.
276*042d53a7SEvalZero */
277*042d53a7SEvalZero static uint8_t
ble_ll_adv_first_chan(struct ble_ll_adv_sm * advsm)278*042d53a7SEvalZero ble_ll_adv_first_chan(struct ble_ll_adv_sm *advsm)
279*042d53a7SEvalZero {
280*042d53a7SEvalZero uint8_t adv_chan;
281*042d53a7SEvalZero
282*042d53a7SEvalZero /* Set first advertising channel */
283*042d53a7SEvalZero if (advsm->adv_chanmask & 0x01) {
284*042d53a7SEvalZero adv_chan = BLE_PHY_ADV_CHAN_START;
285*042d53a7SEvalZero } else if (advsm->adv_chanmask & 0x02) {
286*042d53a7SEvalZero adv_chan = BLE_PHY_ADV_CHAN_START + 1;
287*042d53a7SEvalZero } else {
288*042d53a7SEvalZero adv_chan = BLE_PHY_ADV_CHAN_START + 2;
289*042d53a7SEvalZero }
290*042d53a7SEvalZero
291*042d53a7SEvalZero return adv_chan;
292*042d53a7SEvalZero }
293*042d53a7SEvalZero
294*042d53a7SEvalZero /**
295*042d53a7SEvalZero * Calculate the final channel that we should advertise upon when we start
296*042d53a7SEvalZero * an advertising event.
297*042d53a7SEvalZero *
298*042d53a7SEvalZero * @param advsm
299*042d53a7SEvalZero *
300*042d53a7SEvalZero * @return uint8_t The number of the final channel usable for advertising.
301*042d53a7SEvalZero */
302*042d53a7SEvalZero static uint8_t
ble_ll_adv_final_chan(struct ble_ll_adv_sm * advsm)303*042d53a7SEvalZero ble_ll_adv_final_chan(struct ble_ll_adv_sm *advsm)
304*042d53a7SEvalZero {
305*042d53a7SEvalZero uint8_t adv_chan;
306*042d53a7SEvalZero
307*042d53a7SEvalZero if (advsm->adv_chanmask & 0x04) {
308*042d53a7SEvalZero adv_chan = BLE_PHY_ADV_CHAN_START + 2;
309*042d53a7SEvalZero } else if (advsm->adv_chanmask & 0x02) {
310*042d53a7SEvalZero adv_chan = BLE_PHY_ADV_CHAN_START + 1;
311*042d53a7SEvalZero } else {
312*042d53a7SEvalZero adv_chan = BLE_PHY_ADV_CHAN_START;
313*042d53a7SEvalZero }
314*042d53a7SEvalZero
315*042d53a7SEvalZero return adv_chan;
316*042d53a7SEvalZero }
317*042d53a7SEvalZero
318*042d53a7SEvalZero /**
319*042d53a7SEvalZero * Create the advertising legacy PDU
320*042d53a7SEvalZero *
321*042d53a7SEvalZero * @param advsm Pointer to advertisement state machine
322*042d53a7SEvalZero */
323*042d53a7SEvalZero static uint8_t
ble_ll_adv_legacy_pdu_make(uint8_t * dptr,void * pducb_arg,uint8_t * hdr_byte)324*042d53a7SEvalZero ble_ll_adv_legacy_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte)
325*042d53a7SEvalZero {
326*042d53a7SEvalZero struct ble_ll_adv_sm *advsm;
327*042d53a7SEvalZero uint8_t adv_data_len;
328*042d53a7SEvalZero uint8_t pdulen;
329*042d53a7SEvalZero uint8_t pdu_type;
330*042d53a7SEvalZero
331*042d53a7SEvalZero advsm = pducb_arg;
332*042d53a7SEvalZero
333*042d53a7SEvalZero /* assume this is not a direct ind */
334*042d53a7SEvalZero adv_data_len = ADV_DATA_LEN(advsm);
335*042d53a7SEvalZero pdulen = BLE_DEV_ADDR_LEN + adv_data_len;
336*042d53a7SEvalZero
337*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) {
338*042d53a7SEvalZero pdu_type = BLE_ADV_PDU_TYPE_ADV_DIRECT_IND;
339*042d53a7SEvalZero
340*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) == 1)
341*042d53a7SEvalZero pdu_type |= BLE_ADV_PDU_HDR_CHSEL;
342*042d53a7SEvalZero #endif
343*042d53a7SEvalZero
344*042d53a7SEvalZero if (advsm->flags & BLE_LL_ADV_SM_FLAG_RX_ADD) {
345*042d53a7SEvalZero pdu_type |= BLE_ADV_PDU_HDR_RXADD_RAND;
346*042d53a7SEvalZero }
347*042d53a7SEvalZero
348*042d53a7SEvalZero adv_data_len = 0;
349*042d53a7SEvalZero pdulen = BLE_ADV_DIRECT_IND_LEN;
350*042d53a7SEvalZero } else if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) {
351*042d53a7SEvalZero pdu_type = BLE_ADV_PDU_TYPE_ADV_IND;
352*042d53a7SEvalZero
353*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) == 1)
354*042d53a7SEvalZero pdu_type |= BLE_ADV_PDU_HDR_CHSEL;
355*042d53a7SEvalZero #endif
356*042d53a7SEvalZero } else if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE) {
357*042d53a7SEvalZero pdu_type = BLE_ADV_PDU_TYPE_ADV_SCAN_IND;
358*042d53a7SEvalZero } else {
359*042d53a7SEvalZero pdu_type = BLE_ADV_PDU_TYPE_ADV_NONCONN_IND;
360*042d53a7SEvalZero }
361*042d53a7SEvalZero
362*042d53a7SEvalZero /* An invalid advertising data length indicates a memory overwrite */
363*042d53a7SEvalZero assert(adv_data_len <= BLE_ADV_LEGACY_DATA_MAX_LEN);
364*042d53a7SEvalZero
365*042d53a7SEvalZero /* Set the PDU length in the state machine (includes header) */
366*042d53a7SEvalZero advsm->adv_pdu_len = pdulen + BLE_LL_PDU_HDR_LEN;
367*042d53a7SEvalZero
368*042d53a7SEvalZero /* Set TxAdd to random if needed. */
369*042d53a7SEvalZero if (advsm->flags & BLE_LL_ADV_SM_FLAG_TX_ADD) {
370*042d53a7SEvalZero pdu_type |= BLE_ADV_PDU_HDR_TXADD_RAND;
371*042d53a7SEvalZero }
372*042d53a7SEvalZero
373*042d53a7SEvalZero *hdr_byte = pdu_type;
374*042d53a7SEvalZero
375*042d53a7SEvalZero /* Construct advertisement */
376*042d53a7SEvalZero memcpy(dptr, advsm->adva, BLE_DEV_ADDR_LEN);
377*042d53a7SEvalZero dptr += BLE_DEV_ADDR_LEN;
378*042d53a7SEvalZero
379*042d53a7SEvalZero /* For ADV_DIRECT_IND add inita */
380*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) {
381*042d53a7SEvalZero memcpy(dptr, advsm->initiator_addr, BLE_DEV_ADDR_LEN);
382*042d53a7SEvalZero }
383*042d53a7SEvalZero
384*042d53a7SEvalZero /* Copy in advertising data, if any */
385*042d53a7SEvalZero if (adv_data_len != 0) {
386*042d53a7SEvalZero os_mbuf_copydata(advsm->adv_data, 0, adv_data_len, dptr);
387*042d53a7SEvalZero }
388*042d53a7SEvalZero
389*042d53a7SEvalZero return pdulen;
390*042d53a7SEvalZero }
391*042d53a7SEvalZero
392*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
393*042d53a7SEvalZero static void
ble_ll_adv_put_aux_ptr(struct ble_ll_adv_sm * advsm,uint32_t offset,uint8_t * dptr)394*042d53a7SEvalZero ble_ll_adv_put_aux_ptr(struct ble_ll_adv_sm *advsm, uint32_t offset,
395*042d53a7SEvalZero uint8_t *dptr)
396*042d53a7SEvalZero {
397*042d53a7SEvalZero dptr[0] = advsm->adv_secondary_chan;
398*042d53a7SEvalZero
399*042d53a7SEvalZero if (offset > 245700) {
400*042d53a7SEvalZero dptr[0] |= 0x80;
401*042d53a7SEvalZero offset = offset / 300;
402*042d53a7SEvalZero } else {
403*042d53a7SEvalZero offset = offset / 30;
404*042d53a7SEvalZero }
405*042d53a7SEvalZero
406*042d53a7SEvalZero dptr[1] = (offset & 0x000000ff);
407*042d53a7SEvalZero dptr[2] = ((offset >> 8) & 0x0000001f) | (advsm->sec_phy - 1) << 5; //TODO;
408*042d53a7SEvalZero }
409*042d53a7SEvalZero
410*042d53a7SEvalZero /**
411*042d53a7SEvalZero * Create the advertising PDU
412*042d53a7SEvalZero */
413*042d53a7SEvalZero static uint8_t
ble_ll_adv_pdu_make(uint8_t * dptr,void * pducb_arg,uint8_t * hdr_byte)414*042d53a7SEvalZero ble_ll_adv_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte)
415*042d53a7SEvalZero {
416*042d53a7SEvalZero struct ble_ll_adv_sm *advsm;
417*042d53a7SEvalZero uint8_t pdu_type;
418*042d53a7SEvalZero uint8_t adv_mode;
419*042d53a7SEvalZero uint8_t ext_hdr_len;
420*042d53a7SEvalZero uint8_t ext_hdr_flags;
421*042d53a7SEvalZero uint32_t offset;
422*042d53a7SEvalZero
423*042d53a7SEvalZero advsm = pducb_arg;
424*042d53a7SEvalZero
425*042d53a7SEvalZero assert(ble_ll_adv_active_chanset_is_pri(advsm));
426*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) {
427*042d53a7SEvalZero return ble_ll_adv_legacy_pdu_make(dptr, advsm, hdr_byte);
428*042d53a7SEvalZero }
429*042d53a7SEvalZero
430*042d53a7SEvalZero /* only ADV_EXT_IND goes on primary advertising channels */
431*042d53a7SEvalZero pdu_type = BLE_ADV_PDU_TYPE_ADV_EXT_IND;
432*042d53a7SEvalZero
433*042d53a7SEvalZero /* Set TxAdd to random if needed. */
434*042d53a7SEvalZero if (advsm->flags & BLE_LL_ADV_SM_FLAG_TX_ADD) {
435*042d53a7SEvalZero pdu_type |= BLE_ADV_PDU_HDR_TXADD_RAND;
436*042d53a7SEvalZero }
437*042d53a7SEvalZero
438*042d53a7SEvalZero *hdr_byte = pdu_type;
439*042d53a7SEvalZero
440*042d53a7SEvalZero adv_mode = 0;
441*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) {
442*042d53a7SEvalZero adv_mode |= BLE_LL_EXT_ADV_MODE_CONN;
443*042d53a7SEvalZero }
444*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE) {
445*042d53a7SEvalZero adv_mode |= BLE_LL_EXT_ADV_MODE_SCAN;
446*042d53a7SEvalZero }
447*042d53a7SEvalZero
448*042d53a7SEvalZero ext_hdr_len = BLE_LL_EXT_ADV_FLAGS_SIZE + BLE_LL_EXT_ADV_DATA_INFO_SIZE +
449*042d53a7SEvalZero BLE_LL_EXT_ADV_AUX_PTR_SIZE;
450*042d53a7SEvalZero ext_hdr_flags = (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT) |
451*042d53a7SEvalZero (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT);
452*042d53a7SEvalZero
453*042d53a7SEvalZero /* ext hdr len and adv mode */
454*042d53a7SEvalZero dptr[0] = ext_hdr_len | (adv_mode << 6);
455*042d53a7SEvalZero dptr += 1;
456*042d53a7SEvalZero
457*042d53a7SEvalZero /* ext hdr flags */
458*042d53a7SEvalZero dptr[0] = ext_hdr_flags;
459*042d53a7SEvalZero dptr += 1;
460*042d53a7SEvalZero
461*042d53a7SEvalZero /* ADI */
462*042d53a7SEvalZero dptr[0] = advsm->adi & 0x00ff;
463*042d53a7SEvalZero dptr[1] = advsm->adi >> 8;
464*042d53a7SEvalZero dptr += BLE_LL_EXT_ADV_DATA_INFO_SIZE;
465*042d53a7SEvalZero
466*042d53a7SEvalZero /* AuxPtr */
467*042d53a7SEvalZero if (AUX_CURRENT(advsm)->sch.enqueued) {
468*042d53a7SEvalZero offset = os_cputime_ticks_to_usecs(AUX_CURRENT(advsm)->start_time - advsm->adv_pdu_start_time);
469*042d53a7SEvalZero } else {
470*042d53a7SEvalZero offset = 0;
471*042d53a7SEvalZero }
472*042d53a7SEvalZero ble_ll_adv_put_aux_ptr(advsm, offset, dptr);
473*042d53a7SEvalZero
474*042d53a7SEvalZero return BLE_LL_EXT_ADV_HDR_LEN + ext_hdr_len;
475*042d53a7SEvalZero }
476*042d53a7SEvalZero
477*042d53a7SEvalZero /**
478*042d53a7SEvalZero * Create the AUX PDU
479*042d53a7SEvalZero */
480*042d53a7SEvalZero static uint8_t
ble_ll_adv_aux_pdu_make(uint8_t * dptr,void * pducb_arg,uint8_t * hdr_byte)481*042d53a7SEvalZero ble_ll_adv_aux_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte)
482*042d53a7SEvalZero {
483*042d53a7SEvalZero struct ble_ll_adv_sm *advsm;
484*042d53a7SEvalZero struct ble_ll_adv_aux *aux;
485*042d53a7SEvalZero uint8_t adv_mode;
486*042d53a7SEvalZero uint8_t pdu_type;
487*042d53a7SEvalZero uint8_t ext_hdr_len;
488*042d53a7SEvalZero uint32_t offset;
489*042d53a7SEvalZero
490*042d53a7SEvalZero advsm = pducb_arg;
491*042d53a7SEvalZero aux = AUX_CURRENT(advsm);
492*042d53a7SEvalZero
493*042d53a7SEvalZero assert(!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY));
494*042d53a7SEvalZero assert(ble_ll_adv_active_chanset_is_sec(advsm));
495*042d53a7SEvalZero
496*042d53a7SEvalZero /* It's the same for AUX_ADV_IND and AUX_CHAIN_IND */
497*042d53a7SEvalZero pdu_type = BLE_ADV_PDU_TYPE_AUX_ADV_IND;
498*042d53a7SEvalZero
499*042d53a7SEvalZero /* Set TxAdd to random if needed. */
500*042d53a7SEvalZero if (advsm->flags & BLE_LL_ADV_SM_FLAG_TX_ADD) {
501*042d53a7SEvalZero pdu_type |= BLE_ADV_PDU_HDR_TXADD_RAND;
502*042d53a7SEvalZero }
503*042d53a7SEvalZero
504*042d53a7SEvalZero /* We do not create scannable PDUs here - this is handled separately */
505*042d53a7SEvalZero adv_mode = 0;
506*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) {
507*042d53a7SEvalZero adv_mode |= BLE_LL_EXT_ADV_MODE_CONN;
508*042d53a7SEvalZero }
509*042d53a7SEvalZero
510*042d53a7SEvalZero ext_hdr_len = aux->payload_len - BLE_LL_EXT_ADV_HDR_LEN - aux->aux_data_len;
511*042d53a7SEvalZero dptr[0] = (adv_mode << 6) | ext_hdr_len;
512*042d53a7SEvalZero dptr += 1;
513*042d53a7SEvalZero
514*042d53a7SEvalZero dptr[0] = aux->ext_hdr;
515*042d53a7SEvalZero dptr += 1;
516*042d53a7SEvalZero
517*042d53a7SEvalZero if (aux->ext_hdr & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) {
518*042d53a7SEvalZero memcpy(dptr, advsm->adva, BLE_LL_EXT_ADV_ADVA_SIZE);
519*042d53a7SEvalZero dptr += BLE_LL_EXT_ADV_ADVA_SIZE;
520*042d53a7SEvalZero }
521*042d53a7SEvalZero
522*042d53a7SEvalZero if (aux->ext_hdr & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) {
523*042d53a7SEvalZero memcpy(dptr, advsm->initiator_addr, BLE_LL_EXT_ADV_TARGETA_SIZE);
524*042d53a7SEvalZero dptr += BLE_LL_EXT_ADV_TARGETA_SIZE;
525*042d53a7SEvalZero
526*042d53a7SEvalZero /* Set RxAdd to random if needed. */
527*042d53a7SEvalZero if (advsm->flags & BLE_LL_ADV_SM_FLAG_RX_ADD) {
528*042d53a7SEvalZero pdu_type |= BLE_ADV_PDU_HDR_RXADD_RAND;
529*042d53a7SEvalZero }
530*042d53a7SEvalZero }
531*042d53a7SEvalZero
532*042d53a7SEvalZero if (aux->ext_hdr & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) {
533*042d53a7SEvalZero dptr[0] = advsm->adi & 0x00ff;
534*042d53a7SEvalZero dptr[1] = advsm->adi >> 8;
535*042d53a7SEvalZero dptr += BLE_LL_EXT_ADV_DATA_INFO_SIZE;
536*042d53a7SEvalZero }
537*042d53a7SEvalZero
538*042d53a7SEvalZero if (aux->ext_hdr & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) {
539*042d53a7SEvalZero if (!AUX_NEXT(advsm)->sch.enqueued) {
540*042d53a7SEvalZero /*
541*042d53a7SEvalZero * Trim data here in case we do not have next aux scheduled. This
542*042d53a7SEvalZero * can happen if next aux was outside advertising set period and
543*042d53a7SEvalZero * was removed from scheduler.
544*042d53a7SEvalZero */
545*042d53a7SEvalZero offset = 0;
546*042d53a7SEvalZero } else if (advsm->rx_ble_hdr) {
547*042d53a7SEvalZero offset = os_cputime_ticks_to_usecs(AUX_NEXT(advsm)->start_time - advsm->rx_ble_hdr->beg_cputime);
548*042d53a7SEvalZero offset -= (advsm->rx_ble_hdr->rem_usecs + ble_ll_pdu_tx_time_get(12, advsm->sec_phy) + BLE_LL_IFS);
549*042d53a7SEvalZero } else {
550*042d53a7SEvalZero offset = os_cputime_ticks_to_usecs(AUX_NEXT(advsm)->start_time - aux->start_time);
551*042d53a7SEvalZero }
552*042d53a7SEvalZero
553*042d53a7SEvalZero ble_ll_adv_put_aux_ptr(advsm, offset, dptr);
554*042d53a7SEvalZero
555*042d53a7SEvalZero dptr += BLE_LL_EXT_ADV_AUX_PTR_SIZE;
556*042d53a7SEvalZero }
557*042d53a7SEvalZero
558*042d53a7SEvalZero if (aux->ext_hdr & (1 << BLE_LL_EXT_ADV_TX_POWER_BIT)) {
559*042d53a7SEvalZero dptr[0] = advsm->adv_txpwr;
560*042d53a7SEvalZero dptr += BLE_LL_EXT_ADV_TX_POWER_SIZE;
561*042d53a7SEvalZero }
562*042d53a7SEvalZero
563*042d53a7SEvalZero if (aux->aux_data_len) {
564*042d53a7SEvalZero os_mbuf_copydata(*advsm->aux_data, aux->aux_data_offset,
565*042d53a7SEvalZero aux->aux_data_len, dptr);
566*042d53a7SEvalZero }
567*042d53a7SEvalZero
568*042d53a7SEvalZero *hdr_byte = pdu_type;
569*042d53a7SEvalZero
570*042d53a7SEvalZero return aux->payload_len;
571*042d53a7SEvalZero }
572*042d53a7SEvalZero
573*042d53a7SEvalZero static uint8_t
ble_ll_adv_aux_scannable_pdu_make(uint8_t * dptr,void * pducb_arg,uint8_t * hdr_byte)574*042d53a7SEvalZero ble_ll_adv_aux_scannable_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte)
575*042d53a7SEvalZero {
576*042d53a7SEvalZero struct ble_ll_adv_sm *advsm;
577*042d53a7SEvalZero uint8_t pdu_type;
578*042d53a7SEvalZero uint8_t *ext_hdr_len;
579*042d53a7SEvalZero uint8_t *ext_hdr;
580*042d53a7SEvalZero uint8_t pdulen;
581*042d53a7SEvalZero
582*042d53a7SEvalZero advsm = pducb_arg;
583*042d53a7SEvalZero
584*042d53a7SEvalZero assert(!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY));
585*042d53a7SEvalZero assert(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE);
586*042d53a7SEvalZero assert(advsm->aux_first_pdu);
587*042d53a7SEvalZero assert(ble_ll_adv_active_chanset_is_sec(advsm));
588*042d53a7SEvalZero
589*042d53a7SEvalZero pdu_type = BLE_ADV_PDU_TYPE_AUX_ADV_IND;
590*042d53a7SEvalZero
591*042d53a7SEvalZero /* Set TxAdd to random if needed. */
592*042d53a7SEvalZero if (advsm->flags & BLE_LL_ADV_SM_FLAG_TX_ADD) {
593*042d53a7SEvalZero pdu_type |= BLE_ADV_PDU_HDR_TXADD_RAND;
594*042d53a7SEvalZero }
595*042d53a7SEvalZero
596*042d53a7SEvalZero ext_hdr_len = &dptr[0];
597*042d53a7SEvalZero ext_hdr = &dptr[1];
598*042d53a7SEvalZero dptr += 2;
599*042d53a7SEvalZero
600*042d53a7SEvalZero /* Flags always */
601*042d53a7SEvalZero *ext_hdr_len = BLE_LL_EXT_ADV_FLAGS_SIZE;
602*042d53a7SEvalZero *ext_hdr = 0;
603*042d53a7SEvalZero
604*042d53a7SEvalZero /* AdvA always */
605*042d53a7SEvalZero *ext_hdr_len += BLE_LL_EXT_ADV_ADVA_SIZE;
606*042d53a7SEvalZero *ext_hdr |= (1 << BLE_LL_EXT_ADV_ADVA_BIT);
607*042d53a7SEvalZero memcpy(dptr, advsm->adva, BLE_LL_EXT_ADV_ADVA_SIZE);
608*042d53a7SEvalZero dptr += BLE_LL_EXT_ADV_ADVA_SIZE;
609*042d53a7SEvalZero
610*042d53a7SEvalZero /* TargetA only for directed */
611*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) {
612*042d53a7SEvalZero *ext_hdr_len += BLE_LL_EXT_ADV_TARGETA_SIZE;
613*042d53a7SEvalZero *ext_hdr |= (1 << BLE_LL_EXT_ADV_TARGETA_BIT);
614*042d53a7SEvalZero memcpy(dptr, advsm->initiator_addr, BLE_LL_EXT_ADV_TARGETA_SIZE);
615*042d53a7SEvalZero dptr += BLE_LL_EXT_ADV_TARGETA_SIZE;
616*042d53a7SEvalZero
617*042d53a7SEvalZero /* Set RxAdd to random if needed. */
618*042d53a7SEvalZero if (advsm->flags & BLE_LL_ADV_SM_FLAG_RX_ADD) {
619*042d53a7SEvalZero pdu_type |= BLE_ADV_PDU_HDR_RXADD_RAND;
620*042d53a7SEvalZero }
621*042d53a7SEvalZero }
622*042d53a7SEvalZero
623*042d53a7SEvalZero /* ADI always */
624*042d53a7SEvalZero *ext_hdr_len += BLE_LL_EXT_ADV_DATA_INFO_SIZE;
625*042d53a7SEvalZero *ext_hdr |= (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT);
626*042d53a7SEvalZero dptr[0] = advsm->adi & 0x00ff;
627*042d53a7SEvalZero dptr[1] = advsm->adi >> 8;
628*042d53a7SEvalZero dptr += BLE_LL_EXT_ADV_DATA_INFO_SIZE;
629*042d53a7SEvalZero
630*042d53a7SEvalZero /* TxPower if configured */
631*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_INC_TX_PWR) {
632*042d53a7SEvalZero *ext_hdr_len += BLE_LL_EXT_ADV_TX_POWER_SIZE;
633*042d53a7SEvalZero *ext_hdr |= (1 << BLE_LL_EXT_ADV_TX_POWER_BIT);
634*042d53a7SEvalZero dptr[0] = advsm->adv_txpwr;
635*042d53a7SEvalZero dptr += BLE_LL_EXT_ADV_TX_POWER_SIZE;
636*042d53a7SEvalZero }
637*042d53a7SEvalZero
638*042d53a7SEvalZero pdulen = BLE_LL_EXT_ADV_HDR_LEN + *ext_hdr_len;
639*042d53a7SEvalZero
640*042d53a7SEvalZero *hdr_byte = pdu_type;
641*042d53a7SEvalZero *ext_hdr_len |= (BLE_LL_EXT_ADV_MODE_SCAN << 6);
642*042d53a7SEvalZero
643*042d53a7SEvalZero return pdulen;
644*042d53a7SEvalZero }
645*042d53a7SEvalZero #endif
646*042d53a7SEvalZero
647*042d53a7SEvalZero static uint8_t
ble_ll_adv_scan_rsp_legacy_pdu_make(uint8_t * dptr,void * pducb_arg,uint8_t * hdr_byte)648*042d53a7SEvalZero ble_ll_adv_scan_rsp_legacy_pdu_make(uint8_t *dptr, void *pducb_arg,
649*042d53a7SEvalZero uint8_t *hdr_byte)
650*042d53a7SEvalZero {
651*042d53a7SEvalZero struct ble_ll_adv_sm *advsm;
652*042d53a7SEvalZero uint8_t scan_rsp_len;
653*042d53a7SEvalZero uint8_t pdulen;
654*042d53a7SEvalZero uint8_t hdr;
655*042d53a7SEvalZero
656*042d53a7SEvalZero advsm = pducb_arg;
657*042d53a7SEvalZero
658*042d53a7SEvalZero /* Make sure that the length is valid */
659*042d53a7SEvalZero scan_rsp_len = SCAN_RSP_DATA_LEN(advsm);
660*042d53a7SEvalZero assert(scan_rsp_len <= BLE_SCAN_RSP_LEGACY_DATA_MAX_LEN);
661*042d53a7SEvalZero
662*042d53a7SEvalZero /* Set BLE transmit header */
663*042d53a7SEvalZero pdulen = BLE_DEV_ADDR_LEN + scan_rsp_len;
664*042d53a7SEvalZero hdr = BLE_ADV_PDU_TYPE_SCAN_RSP;
665*042d53a7SEvalZero if (advsm->flags & BLE_LL_ADV_SM_FLAG_TX_ADD) {
666*042d53a7SEvalZero hdr |= BLE_ADV_PDU_HDR_TXADD_RAND;
667*042d53a7SEvalZero }
668*042d53a7SEvalZero
669*042d53a7SEvalZero *hdr_byte = hdr;
670*042d53a7SEvalZero
671*042d53a7SEvalZero /*
672*042d53a7SEvalZero * The adva in this packet will be the same one that was being advertised
673*042d53a7SEvalZero * and is based on the peer identity address in the set advertising
674*042d53a7SEvalZero * parameters. If a different peer sends us a scan request (for some reason)
675*042d53a7SEvalZero * we will reply with an adva that was not generated based on the local irk
676*042d53a7SEvalZero * of the peer sending the scan request.
677*042d53a7SEvalZero */
678*042d53a7SEvalZero
679*042d53a7SEvalZero /* Construct scan response */
680*042d53a7SEvalZero memcpy(dptr, advsm->adva, BLE_DEV_ADDR_LEN);
681*042d53a7SEvalZero if (scan_rsp_len != 0) {
682*042d53a7SEvalZero os_mbuf_copydata(advsm->scan_rsp_data, 0, scan_rsp_len,
683*042d53a7SEvalZero dptr + BLE_DEV_ADDR_LEN);
684*042d53a7SEvalZero }
685*042d53a7SEvalZero
686*042d53a7SEvalZero return pdulen;
687*042d53a7SEvalZero }
688*042d53a7SEvalZero
689*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
690*042d53a7SEvalZero /**
691*042d53a7SEvalZero * Create a scan response PDU
692*042d53a7SEvalZero *
693*042d53a7SEvalZero * @param advsm
694*042d53a7SEvalZero */
695*042d53a7SEvalZero static uint8_t
ble_ll_adv_scan_rsp_pdu_make(uint8_t * dptr,void * pducb_arg,uint8_t * hdr_byte)696*042d53a7SEvalZero ble_ll_adv_scan_rsp_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte)
697*042d53a7SEvalZero {
698*042d53a7SEvalZero struct ble_ll_adv_sm *advsm;
699*042d53a7SEvalZero
700*042d53a7SEvalZero advsm = pducb_arg;
701*042d53a7SEvalZero
702*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) {
703*042d53a7SEvalZero return ble_ll_adv_scan_rsp_legacy_pdu_make(dptr, pducb_arg, hdr_byte);
704*042d53a7SEvalZero }
705*042d53a7SEvalZero
706*042d53a7SEvalZero return ble_ll_adv_aux_pdu_make(dptr, pducb_arg, hdr_byte);
707*042d53a7SEvalZero }
708*042d53a7SEvalZero
709*042d53a7SEvalZero struct aux_conn_rsp_data {
710*042d53a7SEvalZero struct ble_ll_adv_sm *advsm;
711*042d53a7SEvalZero uint8_t *peer;
712*042d53a7SEvalZero uint8_t rxadd;
713*042d53a7SEvalZero };
714*042d53a7SEvalZero
715*042d53a7SEvalZero /**
716*042d53a7SEvalZero * Create a AUX connect response PDU
717*042d53a7SEvalZero *
718*042d53a7SEvalZero * @param advsm
719*042d53a7SEvalZero */
720*042d53a7SEvalZero static uint8_t
ble_ll_adv_aux_conn_rsp_pdu_make(uint8_t * dptr,void * pducb_arg,uint8_t * hdr_byte)721*042d53a7SEvalZero ble_ll_adv_aux_conn_rsp_pdu_make(uint8_t *dptr, void *pducb_arg,
722*042d53a7SEvalZero uint8_t *hdr_byte)
723*042d53a7SEvalZero {
724*042d53a7SEvalZero struct aux_conn_rsp_data *rsp_data;
725*042d53a7SEvalZero uint8_t pdulen;
726*042d53a7SEvalZero uint8_t ext_hdr_len;
727*042d53a7SEvalZero uint8_t ext_hdr_flags;
728*042d53a7SEvalZero uint8_t hdr;
729*042d53a7SEvalZero
730*042d53a7SEvalZero rsp_data = pducb_arg;
731*042d53a7SEvalZero
732*042d53a7SEvalZero /* flags,AdvA and TargetA */
733*042d53a7SEvalZero ext_hdr_len = BLE_LL_EXT_ADV_FLAGS_SIZE + BLE_LL_EXT_ADV_ADVA_SIZE +
734*042d53a7SEvalZero BLE_LL_EXT_ADV_TARGETA_SIZE;
735*042d53a7SEvalZero ext_hdr_flags = (1 << BLE_LL_EXT_ADV_ADVA_BIT);
736*042d53a7SEvalZero ext_hdr_flags |= (1 << BLE_LL_EXT_ADV_TARGETA_BIT);
737*042d53a7SEvalZero
738*042d53a7SEvalZero pdulen = BLE_LL_EXT_ADV_HDR_LEN + ext_hdr_len;
739*042d53a7SEvalZero
740*042d53a7SEvalZero /* Set BLE transmit header */
741*042d53a7SEvalZero hdr = BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP;
742*042d53a7SEvalZero if (rsp_data->rxadd) {
743*042d53a7SEvalZero hdr |= BLE_ADV_PDU_HDR_RXADD_MASK;
744*042d53a7SEvalZero }
745*042d53a7SEvalZero if (rsp_data->advsm->flags & BLE_LL_ADV_SM_FLAG_TX_ADD) {
746*042d53a7SEvalZero hdr |= BLE_ADV_PDU_HDR_TXADD_MASK;
747*042d53a7SEvalZero }
748*042d53a7SEvalZero
749*042d53a7SEvalZero *hdr_byte = hdr;
750*042d53a7SEvalZero
751*042d53a7SEvalZero /* ext hdr len and adv mode (00b) */
752*042d53a7SEvalZero dptr[0] = ext_hdr_len;
753*042d53a7SEvalZero dptr += 1;
754*042d53a7SEvalZero
755*042d53a7SEvalZero /* ext hdr flags */
756*042d53a7SEvalZero dptr[0] = ext_hdr_flags;
757*042d53a7SEvalZero dptr += 1;
758*042d53a7SEvalZero
759*042d53a7SEvalZero memcpy(dptr, rsp_data->advsm->adva, BLE_LL_EXT_ADV_ADVA_SIZE);
760*042d53a7SEvalZero dptr += BLE_LL_EXT_ADV_ADVA_SIZE;
761*042d53a7SEvalZero
762*042d53a7SEvalZero memcpy(dptr, rsp_data->peer, BLE_LL_EXT_ADV_TARGETA_SIZE);
763*042d53a7SEvalZero dptr += BLE_LL_EXT_ADV_ADVA_SIZE;
764*042d53a7SEvalZero
765*042d53a7SEvalZero return pdulen;
766*042d53a7SEvalZero }
767*042d53a7SEvalZero #endif
768*042d53a7SEvalZero
769*042d53a7SEvalZero /**
770*042d53a7SEvalZero * Called to indicate the advertising event is over.
771*042d53a7SEvalZero *
772*042d53a7SEvalZero * Context: Interrupt
773*042d53a7SEvalZero *
774*042d53a7SEvalZero * @param advsm
775*042d53a7SEvalZero *
776*042d53a7SEvalZero */
777*042d53a7SEvalZero static void
ble_ll_adv_tx_done(void * arg)778*042d53a7SEvalZero ble_ll_adv_tx_done(void *arg)
779*042d53a7SEvalZero {
780*042d53a7SEvalZero struct ble_ll_adv_sm *advsm;
781*042d53a7SEvalZero
782*042d53a7SEvalZero /* XXX: for now, reset power to max after advertising */
783*042d53a7SEvalZero ble_phy_txpwr_set(MYNEWT_VAL(BLE_LL_TX_PWR_DBM));
784*042d53a7SEvalZero
785*042d53a7SEvalZero advsm = (struct ble_ll_adv_sm *)arg;
786*042d53a7SEvalZero
787*042d53a7SEvalZero ble_ll_trace_u32x2(BLE_LL_TRACE_ID_ADV_TXDONE, advsm->adv_instance,
788*042d53a7SEvalZero advsm->flags & BLE_LL_ADV_SM_FLAG_ACTIVE_CHANSET_MASK);
789*042d53a7SEvalZero
790*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
791*042d53a7SEvalZero if (ble_ll_adv_active_chanset_is_pri(advsm)) {
792*042d53a7SEvalZero ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev);
793*042d53a7SEvalZero } else if (ble_ll_adv_active_chanset_is_sec(advsm)) {
794*042d53a7SEvalZero ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_sec_txdone_ev);
795*042d53a7SEvalZero } else {
796*042d53a7SEvalZero assert(0);
797*042d53a7SEvalZero }
798*042d53a7SEvalZero #else
799*042d53a7SEvalZero assert(ble_ll_adv_active_chanset_is_pri(advsm));
800*042d53a7SEvalZero ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev);
801*042d53a7SEvalZero #endif
802*042d53a7SEvalZero
803*042d53a7SEvalZero ble_ll_state_set(BLE_LL_STATE_STANDBY);
804*042d53a7SEvalZero
805*042d53a7SEvalZero ble_ll_adv_active_chanset_clear(advsm);
806*042d53a7SEvalZero
807*042d53a7SEvalZero /* We no longer have a current state machine */
808*042d53a7SEvalZero g_ble_ll_cur_adv_sm = NULL;
809*042d53a7SEvalZero }
810*042d53a7SEvalZero
811*042d53a7SEvalZero /*
812*042d53a7SEvalZero * Called when an advertising event has been removed from the scheduler
813*042d53a7SEvalZero * without being run.
814*042d53a7SEvalZero */
815*042d53a7SEvalZero void
ble_ll_adv_event_rmvd_from_sched(struct ble_ll_adv_sm * advsm)816*042d53a7SEvalZero ble_ll_adv_event_rmvd_from_sched(struct ble_ll_adv_sm *advsm)
817*042d53a7SEvalZero {
818*042d53a7SEvalZero /*
819*042d53a7SEvalZero * Need to set advertising channel to final chan so new event gets
820*042d53a7SEvalZero * scheduled.
821*042d53a7SEvalZero */
822*042d53a7SEvalZero advsm->adv_chan = ble_ll_adv_final_chan(advsm);
823*042d53a7SEvalZero ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev);
824*042d53a7SEvalZero }
825*042d53a7SEvalZero
826*042d53a7SEvalZero /**
827*042d53a7SEvalZero * This is the scheduler callback (called from interrupt context) which
828*042d53a7SEvalZero * transmits an advertisement.
829*042d53a7SEvalZero *
830*042d53a7SEvalZero * Context: Interrupt (scheduler)
831*042d53a7SEvalZero *
832*042d53a7SEvalZero * @param sch
833*042d53a7SEvalZero *
834*042d53a7SEvalZero * @return int
835*042d53a7SEvalZero */
836*042d53a7SEvalZero static int
ble_ll_adv_tx_start_cb(struct ble_ll_sched_item * sch)837*042d53a7SEvalZero ble_ll_adv_tx_start_cb(struct ble_ll_sched_item *sch)
838*042d53a7SEvalZero {
839*042d53a7SEvalZero int rc;
840*042d53a7SEvalZero uint8_t end_trans;
841*042d53a7SEvalZero uint32_t txstart;
842*042d53a7SEvalZero struct ble_ll_adv_sm *advsm;
843*042d53a7SEvalZero
844*042d53a7SEvalZero /* Get the state machine for the event */
845*042d53a7SEvalZero advsm = (struct ble_ll_adv_sm *)sch->cb_arg;
846*042d53a7SEvalZero
847*042d53a7SEvalZero /* Set the current advertiser */
848*042d53a7SEvalZero g_ble_ll_cur_adv_sm = advsm;
849*042d53a7SEvalZero
850*042d53a7SEvalZero ble_ll_adv_active_chanset_set_pri(advsm);
851*042d53a7SEvalZero
852*042d53a7SEvalZero /* Set the power */
853*042d53a7SEvalZero ble_phy_txpwr_set(advsm->adv_txpwr);
854*042d53a7SEvalZero
855*042d53a7SEvalZero /* Set channel */
856*042d53a7SEvalZero rc = ble_phy_setchan(advsm->adv_chan, BLE_ACCESS_ADDR_ADV, BLE_LL_CRCINIT_ADV);
857*042d53a7SEvalZero assert(rc == 0);
858*042d53a7SEvalZero
859*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
860*042d53a7SEvalZero /* Set phy mode */
861*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
862*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) {
863*042d53a7SEvalZero ble_phy_mode_set(BLE_PHY_MODE_1M, BLE_PHY_MODE_1M);
864*042d53a7SEvalZero } else {
865*042d53a7SEvalZero ble_phy_mode_set(advsm->pri_phy, advsm->pri_phy);
866*042d53a7SEvalZero }
867*042d53a7SEvalZero #else
868*042d53a7SEvalZero ble_phy_mode_set(BLE_PHY_MODE_1M, BLE_PHY_MODE_1M);
869*042d53a7SEvalZero #endif
870*042d53a7SEvalZero #endif
871*042d53a7SEvalZero
872*042d53a7SEvalZero /* Set transmit start time. */
873*042d53a7SEvalZero txstart = sch->start_time + g_ble_ll_sched_offset_ticks;
874*042d53a7SEvalZero rc = ble_phy_tx_set_start_time(txstart, sch->remainder);
875*042d53a7SEvalZero if (rc) {
876*042d53a7SEvalZero STATS_INC(ble_ll_stats, adv_late_starts);
877*042d53a7SEvalZero goto adv_tx_done;
878*042d53a7SEvalZero }
879*042d53a7SEvalZero
880*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
881*042d53a7SEvalZero /* XXX: automatically do this in the phy based on channel? */
882*042d53a7SEvalZero ble_phy_encrypt_disable();
883*042d53a7SEvalZero #endif
884*042d53a7SEvalZero
885*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
886*042d53a7SEvalZero advsm->adv_rpa_index = -1;
887*042d53a7SEvalZero if (ble_ll_resolv_enabled()) {
888*042d53a7SEvalZero ble_phy_resolv_list_enable();
889*042d53a7SEvalZero } else {
890*042d53a7SEvalZero ble_phy_resolv_list_disable();
891*042d53a7SEvalZero }
892*042d53a7SEvalZero #endif
893*042d53a7SEvalZero
894*042d53a7SEvalZero /* We switch to RX after connectable or scannable legacy packets. */
895*042d53a7SEvalZero if ((advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) &&
896*042d53a7SEvalZero ((advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) ||
897*042d53a7SEvalZero (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE))) {
898*042d53a7SEvalZero end_trans = BLE_PHY_TRANSITION_TX_RX;
899*042d53a7SEvalZero ble_phy_set_txend_cb(NULL, NULL);
900*042d53a7SEvalZero } else {
901*042d53a7SEvalZero end_trans = BLE_PHY_TRANSITION_NONE;
902*042d53a7SEvalZero ble_phy_set_txend_cb(ble_ll_adv_tx_done, advsm);
903*042d53a7SEvalZero }
904*042d53a7SEvalZero
905*042d53a7SEvalZero /* Transmit advertisement */
906*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
907*042d53a7SEvalZero rc = ble_phy_tx(ble_ll_adv_pdu_make, advsm, end_trans);
908*042d53a7SEvalZero #else
909*042d53a7SEvalZero rc = ble_phy_tx(ble_ll_adv_legacy_pdu_make, advsm, end_trans);
910*042d53a7SEvalZero #endif
911*042d53a7SEvalZero if (rc) {
912*042d53a7SEvalZero goto adv_tx_done;
913*042d53a7SEvalZero }
914*042d53a7SEvalZero
915*042d53a7SEvalZero /* Enable/disable whitelisting based on filter policy */
916*042d53a7SEvalZero if (advsm->adv_filter_policy != BLE_HCI_ADV_FILT_NONE) {
917*042d53a7SEvalZero ble_ll_whitelist_enable();
918*042d53a7SEvalZero } else {
919*042d53a7SEvalZero ble_ll_whitelist_disable();
920*042d53a7SEvalZero }
921*042d53a7SEvalZero
922*042d53a7SEvalZero /* Set link layer state to advertising */
923*042d53a7SEvalZero ble_ll_state_set(BLE_LL_STATE_ADV);
924*042d53a7SEvalZero
925*042d53a7SEvalZero /* Count # of adv. sent */
926*042d53a7SEvalZero STATS_INC(ble_ll_stats, adv_txg);
927*042d53a7SEvalZero
928*042d53a7SEvalZero return BLE_LL_SCHED_STATE_RUNNING;
929*042d53a7SEvalZero
930*042d53a7SEvalZero adv_tx_done:
931*042d53a7SEvalZero ble_ll_adv_tx_done(advsm);
932*042d53a7SEvalZero return BLE_LL_SCHED_STATE_DONE;
933*042d53a7SEvalZero }
934*042d53a7SEvalZero
935*042d53a7SEvalZero static void
ble_ll_adv_set_sched(struct ble_ll_adv_sm * advsm)936*042d53a7SEvalZero ble_ll_adv_set_sched(struct ble_ll_adv_sm *advsm)
937*042d53a7SEvalZero {
938*042d53a7SEvalZero uint32_t max_usecs;
939*042d53a7SEvalZero struct ble_ll_sched_item *sch;
940*042d53a7SEvalZero
941*042d53a7SEvalZero sch = &advsm->adv_sch;
942*042d53a7SEvalZero sch->cb_arg = advsm;
943*042d53a7SEvalZero sch->sched_cb = ble_ll_adv_tx_start_cb;
944*042d53a7SEvalZero sch->sched_type = BLE_LL_SCHED_TYPE_ADV;
945*042d53a7SEvalZero
946*042d53a7SEvalZero /* Set end time to maximum time this schedule item may take */
947*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
948*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) {
949*042d53a7SEvalZero max_usecs = ble_ll_pdu_tx_time_get(advsm->adv_pdu_len, BLE_PHY_MODE_1M);
950*042d53a7SEvalZero
951*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) {
952*042d53a7SEvalZero max_usecs += BLE_LL_SCHED_DIRECT_ADV_MAX_USECS;
953*042d53a7SEvalZero } else if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) {
954*042d53a7SEvalZero max_usecs += BLE_LL_SCHED_ADV_MAX_USECS;
955*042d53a7SEvalZero }
956*042d53a7SEvalZero } else {
957*042d53a7SEvalZero /*
958*042d53a7SEvalZero * In ADV_EXT_IND we always set only ADI and AUX so the payload length
959*042d53a7SEvalZero * is always 7 bytes.
960*042d53a7SEvalZero */
961*042d53a7SEvalZero max_usecs = ble_ll_pdu_tx_time_get(7, advsm->pri_phy);
962*042d53a7SEvalZero }
963*042d53a7SEvalZero #else
964*042d53a7SEvalZero max_usecs = ble_ll_pdu_tx_time_get(advsm->adv_pdu_len, BLE_PHY_MODE_1M);
965*042d53a7SEvalZero
966*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) {
967*042d53a7SEvalZero max_usecs += BLE_LL_SCHED_DIRECT_ADV_MAX_USECS;
968*042d53a7SEvalZero } else if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) {
969*042d53a7SEvalZero max_usecs += BLE_LL_SCHED_ADV_MAX_USECS;
970*042d53a7SEvalZero }
971*042d53a7SEvalZero #endif
972*042d53a7SEvalZero
973*042d53a7SEvalZero sch->start_time = advsm->adv_pdu_start_time - g_ble_ll_sched_offset_ticks;
974*042d53a7SEvalZero sch->remainder = 0;
975*042d53a7SEvalZero sch->end_time = advsm->adv_pdu_start_time +
976*042d53a7SEvalZero ble_ll_usecs_to_ticks_round_up(max_usecs);
977*042d53a7SEvalZero }
978*042d53a7SEvalZero
979*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
980*042d53a7SEvalZero static int
ble_ll_adv_secondary_tx_start_cb(struct ble_ll_sched_item * sch)981*042d53a7SEvalZero ble_ll_adv_secondary_tx_start_cb(struct ble_ll_sched_item *sch)
982*042d53a7SEvalZero {
983*042d53a7SEvalZero int rc;
984*042d53a7SEvalZero uint8_t end_trans;
985*042d53a7SEvalZero uint32_t txstart;
986*042d53a7SEvalZero struct ble_ll_adv_sm *advsm;
987*042d53a7SEvalZero ble_phy_tx_pducb_t pducb;
988*042d53a7SEvalZero
989*042d53a7SEvalZero /* Get the state machine for the event */
990*042d53a7SEvalZero advsm = (struct ble_ll_adv_sm *)sch->cb_arg;
991*042d53a7SEvalZero
992*042d53a7SEvalZero /* Set the current advertiser */
993*042d53a7SEvalZero g_ble_ll_cur_adv_sm = advsm;
994*042d53a7SEvalZero
995*042d53a7SEvalZero ble_ll_adv_active_chanset_set_sec(advsm);
996*042d53a7SEvalZero
997*042d53a7SEvalZero /* Set the power */
998*042d53a7SEvalZero ble_phy_txpwr_set(advsm->adv_txpwr);
999*042d53a7SEvalZero
1000*042d53a7SEvalZero /* Set channel */
1001*042d53a7SEvalZero rc = ble_phy_setchan(advsm->adv_secondary_chan, BLE_ACCESS_ADDR_ADV,
1002*042d53a7SEvalZero BLE_LL_CRCINIT_ADV);
1003*042d53a7SEvalZero assert(rc == 0);
1004*042d53a7SEvalZero
1005*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
1006*042d53a7SEvalZero /* Set phy mode */
1007*042d53a7SEvalZero ble_phy_mode_set(advsm->sec_phy, advsm->sec_phy);
1008*042d53a7SEvalZero #endif
1009*042d53a7SEvalZero
1010*042d53a7SEvalZero /* Set transmit start time. */
1011*042d53a7SEvalZero txstart = sch->start_time + g_ble_ll_sched_offset_ticks;
1012*042d53a7SEvalZero rc = ble_phy_tx_set_start_time(txstart, sch->remainder);
1013*042d53a7SEvalZero if (rc) {
1014*042d53a7SEvalZero STATS_INC(ble_ll_stats, adv_late_starts);
1015*042d53a7SEvalZero goto adv_tx_done;
1016*042d53a7SEvalZero }
1017*042d53a7SEvalZero
1018*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
1019*042d53a7SEvalZero ble_phy_encrypt_disable();
1020*042d53a7SEvalZero #endif
1021*042d53a7SEvalZero
1022*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
1023*042d53a7SEvalZero advsm->adv_rpa_index = -1;
1024*042d53a7SEvalZero if (ble_ll_resolv_enabled()) {
1025*042d53a7SEvalZero ble_phy_resolv_list_enable();
1026*042d53a7SEvalZero } else {
1027*042d53a7SEvalZero ble_phy_resolv_list_disable();
1028*042d53a7SEvalZero }
1029*042d53a7SEvalZero #endif
1030*042d53a7SEvalZero
1031*042d53a7SEvalZero /* Set phy mode based on type of advertisement */
1032*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) {
1033*042d53a7SEvalZero end_trans = BLE_PHY_TRANSITION_TX_RX;
1034*042d53a7SEvalZero ble_phy_set_txend_cb(NULL, NULL);
1035*042d53a7SEvalZero pducb = ble_ll_adv_aux_pdu_make;
1036*042d53a7SEvalZero } else if ((advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE) &&
1037*042d53a7SEvalZero advsm->aux_first_pdu) {
1038*042d53a7SEvalZero end_trans = BLE_PHY_TRANSITION_TX_RX;
1039*042d53a7SEvalZero ble_phy_set_txend_cb(NULL, NULL);
1040*042d53a7SEvalZero pducb = ble_ll_adv_aux_scannable_pdu_make;
1041*042d53a7SEvalZero } else {
1042*042d53a7SEvalZero end_trans = BLE_PHY_TRANSITION_NONE;
1043*042d53a7SEvalZero ble_phy_set_txend_cb(ble_ll_adv_tx_done, advsm);
1044*042d53a7SEvalZero pducb = ble_ll_adv_aux_pdu_make;
1045*042d53a7SEvalZero }
1046*042d53a7SEvalZero
1047*042d53a7SEvalZero /* Transmit advertisement */
1048*042d53a7SEvalZero rc = ble_phy_tx(pducb, advsm, end_trans);
1049*042d53a7SEvalZero if (rc) {
1050*042d53a7SEvalZero goto adv_tx_done;
1051*042d53a7SEvalZero }
1052*042d53a7SEvalZero
1053*042d53a7SEvalZero /* Enable/disable whitelisting based on filter policy */
1054*042d53a7SEvalZero if (advsm->adv_filter_policy != BLE_HCI_ADV_FILT_NONE) {
1055*042d53a7SEvalZero ble_ll_whitelist_enable();
1056*042d53a7SEvalZero } else {
1057*042d53a7SEvalZero ble_ll_whitelist_disable();
1058*042d53a7SEvalZero }
1059*042d53a7SEvalZero
1060*042d53a7SEvalZero /* Set link layer state to advertising */
1061*042d53a7SEvalZero ble_ll_state_set(BLE_LL_STATE_ADV);
1062*042d53a7SEvalZero
1063*042d53a7SEvalZero /* Count # of adv. sent */
1064*042d53a7SEvalZero STATS_INC(ble_ll_stats, adv_txg);
1065*042d53a7SEvalZero
1066*042d53a7SEvalZero return BLE_LL_SCHED_STATE_RUNNING;
1067*042d53a7SEvalZero
1068*042d53a7SEvalZero adv_tx_done:
1069*042d53a7SEvalZero ble_ll_adv_tx_done(advsm);
1070*042d53a7SEvalZero return BLE_LL_SCHED_STATE_DONE;
1071*042d53a7SEvalZero }
1072*042d53a7SEvalZero
1073*042d53a7SEvalZero static uint8_t
ble_ll_adv_aux_scannable_pdu_payload_len(struct ble_ll_adv_sm * advsm)1074*042d53a7SEvalZero ble_ll_adv_aux_scannable_pdu_payload_len(struct ble_ll_adv_sm *advsm)
1075*042d53a7SEvalZero {
1076*042d53a7SEvalZero uint8_t len;
1077*042d53a7SEvalZero
1078*042d53a7SEvalZero /* Flags, AdvA and ADI always */
1079*042d53a7SEvalZero len = BLE_LL_EXT_ADV_HDR_LEN + BLE_LL_EXT_ADV_FLAGS_SIZE +
1080*042d53a7SEvalZero BLE_LL_EXT_ADV_ADVA_SIZE + BLE_LL_EXT_ADV_DATA_INFO_SIZE;
1081*042d53a7SEvalZero
1082*042d53a7SEvalZero /* TargetA only for directed */
1083*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) {
1084*042d53a7SEvalZero len += BLE_LL_EXT_ADV_TARGETA_SIZE;
1085*042d53a7SEvalZero }
1086*042d53a7SEvalZero
1087*042d53a7SEvalZero /* TxPower if configured */
1088*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_INC_TX_PWR) {
1089*042d53a7SEvalZero len += BLE_LL_EXT_ADV_TX_POWER_SIZE;
1090*042d53a7SEvalZero }
1091*042d53a7SEvalZero
1092*042d53a7SEvalZero return len;
1093*042d53a7SEvalZero }
1094*042d53a7SEvalZero
1095*042d53a7SEvalZero static void
ble_ll_adv_aux_calculate(struct ble_ll_adv_sm * advsm,struct ble_ll_adv_aux * aux,uint16_t aux_data_offset)1096*042d53a7SEvalZero ble_ll_adv_aux_calculate(struct ble_ll_adv_sm *advsm,
1097*042d53a7SEvalZero struct ble_ll_adv_aux *aux, uint16_t aux_data_offset)
1098*042d53a7SEvalZero {
1099*042d53a7SEvalZero uint16_t rem_aux_data_len;
1100*042d53a7SEvalZero uint8_t hdr_len;
1101*042d53a7SEvalZero bool chainable;
1102*042d53a7SEvalZero
1103*042d53a7SEvalZero assert(!aux->sch.enqueued);
1104*042d53a7SEvalZero assert((AUX_DATA_LEN(advsm) > aux_data_offset) ||
1105*042d53a7SEvalZero (AUX_DATA_LEN(advsm) == 0 && aux_data_offset == 0));
1106*042d53a7SEvalZero
1107*042d53a7SEvalZero aux->aux_data_offset = aux_data_offset;
1108*042d53a7SEvalZero aux->aux_data_len = 0;
1109*042d53a7SEvalZero aux->payload_len = 0;
1110*042d53a7SEvalZero aux->ext_hdr = 0;
1111*042d53a7SEvalZero
1112*042d53a7SEvalZero rem_aux_data_len = AUX_DATA_LEN(advsm) - aux_data_offset;
1113*042d53a7SEvalZero chainable = !(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE);
1114*042d53a7SEvalZero
1115*042d53a7SEvalZero hdr_len = BLE_LL_EXT_ADV_HDR_LEN + BLE_LL_EXT_ADV_FLAGS_SIZE;
1116*042d53a7SEvalZero
1117*042d53a7SEvalZero if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE)) {
1118*042d53a7SEvalZero /* Flags and ADI */
1119*042d53a7SEvalZero aux->ext_hdr |= (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT);
1120*042d53a7SEvalZero hdr_len += BLE_LL_EXT_ADV_DATA_INFO_SIZE;
1121*042d53a7SEvalZero }
1122*042d53a7SEvalZero
1123*042d53a7SEvalZero /* AdvA for 1st PDU in chain (i.e. AUX_ADV_IND or AUX_SCAN_RSP) */
1124*042d53a7SEvalZero if (aux_data_offset == 0) {
1125*042d53a7SEvalZero aux->ext_hdr |= (1 << BLE_LL_EXT_ADV_ADVA_BIT);
1126*042d53a7SEvalZero hdr_len += BLE_LL_EXT_ADV_ADVA_SIZE;
1127*042d53a7SEvalZero }
1128*042d53a7SEvalZero
1129*042d53a7SEvalZero /* TargetA for directed connectable */
1130*042d53a7SEvalZero if ((advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) &&
1131*042d53a7SEvalZero (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE)) {
1132*042d53a7SEvalZero aux->ext_hdr |= (1 << BLE_LL_EXT_ADV_TARGETA_BIT);
1133*042d53a7SEvalZero hdr_len += BLE_LL_EXT_ADV_TARGETA_SIZE;
1134*042d53a7SEvalZero }
1135*042d53a7SEvalZero
1136*042d53a7SEvalZero /* TxPower if configured */
1137*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_INC_TX_PWR) {
1138*042d53a7SEvalZero aux->ext_hdr |= (1 << BLE_LL_EXT_ADV_TX_POWER_BIT);
1139*042d53a7SEvalZero hdr_len += BLE_LL_EXT_ADV_TX_POWER_SIZE;
1140*042d53a7SEvalZero }
1141*042d53a7SEvalZero
1142*042d53a7SEvalZero /* AdvData always */
1143*042d53a7SEvalZero aux->aux_data_len = min(BLE_LL_MAX_PAYLOAD_LEN - hdr_len, rem_aux_data_len);
1144*042d53a7SEvalZero
1145*042d53a7SEvalZero /* AuxPtr if there are more AdvData remaining that we can fit here */
1146*042d53a7SEvalZero if (chainable && (rem_aux_data_len > aux->aux_data_len)) {
1147*042d53a7SEvalZero aux->ext_hdr |= (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT);
1148*042d53a7SEvalZero hdr_len += BLE_LL_EXT_ADV_AUX_PTR_SIZE;
1149*042d53a7SEvalZero aux->aux_data_len -= BLE_LL_EXT_ADV_AUX_PTR_SIZE;
1150*042d53a7SEvalZero
1151*042d53a7SEvalZero /* PDU payload should be full if chained */
1152*042d53a7SEvalZero assert(hdr_len + aux->aux_data_len == BLE_LL_MAX_PAYLOAD_LEN);
1153*042d53a7SEvalZero }
1154*042d53a7SEvalZero
1155*042d53a7SEvalZero aux->payload_len = hdr_len + aux->aux_data_len;
1156*042d53a7SEvalZero }
1157*042d53a7SEvalZero
1158*042d53a7SEvalZero static void
ble_ll_adv_aux_scheduled(struct ble_ll_adv_sm * advsm,uint32_t sch_start,void * arg)1159*042d53a7SEvalZero ble_ll_adv_aux_scheduled(struct ble_ll_adv_sm *advsm, uint32_t sch_start,
1160*042d53a7SEvalZero void *arg)
1161*042d53a7SEvalZero {
1162*042d53a7SEvalZero struct ble_ll_adv_aux *aux = arg;
1163*042d53a7SEvalZero
1164*042d53a7SEvalZero aux->start_time = sch_start + g_ble_ll_sched_offset_ticks;
1165*042d53a7SEvalZero }
1166*042d53a7SEvalZero
1167*042d53a7SEvalZero static void
ble_ll_adv_aux_schedule_next(struct ble_ll_adv_sm * advsm)1168*042d53a7SEvalZero ble_ll_adv_aux_schedule_next(struct ble_ll_adv_sm *advsm)
1169*042d53a7SEvalZero {
1170*042d53a7SEvalZero struct ble_ll_adv_aux *aux;
1171*042d53a7SEvalZero struct ble_ll_adv_aux *aux_next;
1172*042d53a7SEvalZero struct ble_ll_sched_item *sch;
1173*042d53a7SEvalZero uint16_t rem_aux_data_len;
1174*042d53a7SEvalZero uint16_t next_aux_data_offset;
1175*042d53a7SEvalZero uint32_t max_usecs;
1176*042d53a7SEvalZero
1177*042d53a7SEvalZero assert(advsm->aux_active);
1178*042d53a7SEvalZero
1179*042d53a7SEvalZero aux = AUX_CURRENT(advsm);
1180*042d53a7SEvalZero aux_next = AUX_NEXT(advsm);
1181*042d53a7SEvalZero
1182*042d53a7SEvalZero assert(!aux_next->sch.enqueued);
1183*042d53a7SEvalZero
1184*042d53a7SEvalZero /*
1185*042d53a7SEvalZero * Do not schedule next aux if current aux is no longer scheduled since we
1186*042d53a7SEvalZero * do not have reference time for scheduling.
1187*042d53a7SEvalZero */
1188*042d53a7SEvalZero if (!aux->sch.enqueued) {
1189*042d53a7SEvalZero return;
1190*042d53a7SEvalZero }
1191*042d53a7SEvalZero
1192*042d53a7SEvalZero /*
1193*042d53a7SEvalZero * Do not schedule next aux if current aux does not have AuxPtr in extended
1194*042d53a7SEvalZero * header as this means we do not need subsequent ADV_CHAIN_IND to be sent.
1195*042d53a7SEvalZero */
1196*042d53a7SEvalZero if (!(aux->ext_hdr & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT))) {
1197*042d53a7SEvalZero return;
1198*042d53a7SEvalZero }
1199*042d53a7SEvalZero
1200*042d53a7SEvalZero next_aux_data_offset = aux->aux_data_offset + aux->aux_data_len;
1201*042d53a7SEvalZero
1202*042d53a7SEvalZero assert(AUX_DATA_LEN(advsm) >= next_aux_data_offset);
1203*042d53a7SEvalZero
1204*042d53a7SEvalZero rem_aux_data_len = AUX_DATA_LEN(advsm) - next_aux_data_offset;
1205*042d53a7SEvalZero assert(rem_aux_data_len > 0);
1206*042d53a7SEvalZero
1207*042d53a7SEvalZero ble_ll_adv_aux_calculate(advsm, aux_next, next_aux_data_offset);
1208*042d53a7SEvalZero max_usecs = ble_ll_pdu_tx_time_get(aux_next->payload_len, advsm->sec_phy);
1209*042d53a7SEvalZero
1210*042d53a7SEvalZero aux_next->start_time = aux->sch.end_time +
1211*042d53a7SEvalZero ble_ll_usecs_to_ticks_round_up(BLE_LL_MAFS);
1212*042d53a7SEvalZero
1213*042d53a7SEvalZero sch = &aux_next->sch;
1214*042d53a7SEvalZero sch->start_time = aux_next->start_time - g_ble_ll_sched_offset_ticks;
1215*042d53a7SEvalZero sch->remainder = 0;
1216*042d53a7SEvalZero sch->end_time = aux_next->start_time +
1217*042d53a7SEvalZero ble_ll_usecs_to_ticks_round_up(max_usecs);
1218*042d53a7SEvalZero ble_ll_sched_adv_new(&aux_next->sch, ble_ll_adv_aux_scheduled, aux_next);
1219*042d53a7SEvalZero
1220*042d53a7SEvalZero /*
1221*042d53a7SEvalZero * In case duration is set for advertising set we need to check if newly
1222*042d53a7SEvalZero * scheduled aux will fit inside duration. If not, remove it from scheduler
1223*042d53a7SEvalZero * so advertising will stop after current aux.
1224*042d53a7SEvalZero */
1225*042d53a7SEvalZero if (advsm->duration && (aux_next->sch.end_time > advsm->adv_end_time)) {
1226*042d53a7SEvalZero ble_ll_sched_rmv_elem(&aux_next->sch);
1227*042d53a7SEvalZero }
1228*042d53a7SEvalZero }
1229*042d53a7SEvalZero
1230*042d53a7SEvalZero static void
ble_ll_adv_aux_schedule_first(struct ble_ll_adv_sm * advsm)1231*042d53a7SEvalZero ble_ll_adv_aux_schedule_first(struct ble_ll_adv_sm *advsm)
1232*042d53a7SEvalZero {
1233*042d53a7SEvalZero struct ble_ll_adv_aux *aux;
1234*042d53a7SEvalZero struct ble_ll_sched_item *sch;
1235*042d53a7SEvalZero uint32_t max_usecs;
1236*042d53a7SEvalZero
1237*042d53a7SEvalZero assert(!advsm->aux_active);
1238*042d53a7SEvalZero assert(!advsm->aux[0].sch.enqueued);
1239*042d53a7SEvalZero assert(!advsm->aux[1].sch.enqueued);
1240*042d53a7SEvalZero
1241*042d53a7SEvalZero advsm->aux_active = 1;
1242*042d53a7SEvalZero advsm->aux_index = 0;
1243*042d53a7SEvalZero advsm->aux_first_pdu = 1;
1244*042d53a7SEvalZero advsm->aux_not_scanned = 0;
1245*042d53a7SEvalZero
1246*042d53a7SEvalZero aux = AUX_CURRENT(advsm);
1247*042d53a7SEvalZero ble_ll_adv_aux_calculate(advsm, aux, 0);
1248*042d53a7SEvalZero
1249*042d53a7SEvalZero /* TODO we could use CSA2 for this
1250*042d53a7SEvalZero * (will be needed for periodic advertising anyway)
1251*042d53a7SEvalZero */
1252*042d53a7SEvalZero advsm->adv_secondary_chan = rand() % BLE_PHY_NUM_DATA_CHANS;
1253*042d53a7SEvalZero
1254*042d53a7SEvalZero /* Set end time to maximum time this schedule item may take */
1255*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) {
1256*042d53a7SEvalZero max_usecs = ble_ll_pdu_tx_time_get(aux->payload_len, advsm->sec_phy) +
1257*042d53a7SEvalZero BLE_LL_IFS +
1258*042d53a7SEvalZero /* AUX_CONN_REQ */
1259*042d53a7SEvalZero ble_ll_pdu_tx_time_get(34 + 14, advsm->sec_phy) +
1260*042d53a7SEvalZero BLE_LL_IFS +
1261*042d53a7SEvalZero /* AUX_CONN_RSP */
1262*042d53a7SEvalZero ble_ll_pdu_tx_time_get(14, advsm->sec_phy);
1263*042d53a7SEvalZero } else if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE) {
1264*042d53a7SEvalZero /* Scheduled aux is calculated for AUX_SCAN_RSP, 1st aux is created separately */
1265*042d53a7SEvalZero max_usecs = ble_ll_pdu_tx_time_get(ble_ll_adv_aux_scannable_pdu_payload_len(advsm),
1266*042d53a7SEvalZero advsm->sec_phy) +
1267*042d53a7SEvalZero BLE_LL_IFS +
1268*042d53a7SEvalZero /* AUX_SCAN_REQ */
1269*042d53a7SEvalZero ble_ll_pdu_tx_time_get(12, advsm->sec_phy) +
1270*042d53a7SEvalZero BLE_LL_IFS +
1271*042d53a7SEvalZero /* AUX_SCAN_RSP */
1272*042d53a7SEvalZero ble_ll_pdu_tx_time_get(aux->payload_len, advsm->sec_phy);
1273*042d53a7SEvalZero } else {
1274*042d53a7SEvalZero max_usecs = ble_ll_pdu_tx_time_get(aux->payload_len, advsm->sec_phy);
1275*042d53a7SEvalZero }
1276*042d53a7SEvalZero
1277*042d53a7SEvalZero sch = &aux->sch;
1278*042d53a7SEvalZero sch->start_time = aux->start_time - g_ble_ll_sched_offset_ticks;
1279*042d53a7SEvalZero sch->remainder = 0;
1280*042d53a7SEvalZero sch->end_time = aux->start_time + ble_ll_usecs_to_ticks_round_up(max_usecs);
1281*042d53a7SEvalZero ble_ll_sched_adv_new(sch, ble_ll_adv_aux_scheduled, aux);
1282*042d53a7SEvalZero
1283*042d53a7SEvalZero }
1284*042d53a7SEvalZero
1285*042d53a7SEvalZero static void
ble_ll_adv_aux_set_start_time(struct ble_ll_adv_sm * advsm)1286*042d53a7SEvalZero ble_ll_adv_aux_set_start_time(struct ble_ll_adv_sm *advsm)
1287*042d53a7SEvalZero {
1288*042d53a7SEvalZero static const uint8_t bits[8] = {0, 1, 1, 2, 1, 2, 2, 3};
1289*042d53a7SEvalZero struct ble_ll_sched_item *sched = &advsm->adv_sch;
1290*042d53a7SEvalZero uint32_t adv_pdu_dur;
1291*042d53a7SEvalZero uint32_t adv_event_dur;
1292*042d53a7SEvalZero uint8_t chans;
1293*042d53a7SEvalZero
1294*042d53a7SEvalZero assert(!advsm->aux_active);
1295*042d53a7SEvalZero assert(!advsm->aux[0].sch.enqueued);
1296*042d53a7SEvalZero assert(!advsm->aux[1].sch.enqueued);
1297*042d53a7SEvalZero
1298*042d53a7SEvalZero assert(advsm->adv_chanmask > 0 &&
1299*042d53a7SEvalZero advsm->adv_chanmask <= BLE_HCI_ADV_CHANMASK_DEF);
1300*042d53a7SEvalZero
1301*042d53a7SEvalZero chans = bits[advsm->adv_chanmask];
1302*042d53a7SEvalZero
1303*042d53a7SEvalZero /*
1304*042d53a7SEvalZero * We want to schedule auxiliary packet as soon as possible after the end
1305*042d53a7SEvalZero * of advertising event, but no sooner than T_MAFS. The interval between
1306*042d53a7SEvalZero * advertising packets is 250 usecs (8.19 ticks) on LE Coded and a bit less
1307*042d53a7SEvalZero * on 1M, but it can vary a bit due to scheduling which we can't really
1308*042d53a7SEvalZero * control. Since we round ticks up for both interval and T_MAFS, we still
1309*042d53a7SEvalZero * have some margin here. The worst thing that can happen is that we skip
1310*042d53a7SEvalZero * last advertising packet which is not a bit problem so leave it as-is, no
1311*042d53a7SEvalZero * need to make code more complicated.
1312*042d53a7SEvalZero */
1313*042d53a7SEvalZero
1314*042d53a7SEvalZero /*
1315*042d53a7SEvalZero * XXX: this could be improved if phy has TX-TX transition with controlled
1316*042d53a7SEvalZero * or predefined interval, but since it makes advertising code even
1317*042d53a7SEvalZero * more complicated let's skip it for now...
1318*042d53a7SEvalZero */
1319*042d53a7SEvalZero
1320*042d53a7SEvalZero adv_pdu_dur = (int32_t)(sched->end_time - sched->start_time) -
1321*042d53a7SEvalZero g_ble_ll_sched_offset_ticks;
1322*042d53a7SEvalZero
1323*042d53a7SEvalZero /* 9 is 8.19 ticks rounded up - see comment above */
1324*042d53a7SEvalZero adv_event_dur = (adv_pdu_dur * chans) + (9 * (chans - 1));
1325*042d53a7SEvalZero
1326*042d53a7SEvalZero advsm->aux[0].start_time = advsm->adv_event_start_time + adv_event_dur +
1327*042d53a7SEvalZero ble_ll_usecs_to_ticks_round_up(BLE_LL_MAFS);
1328*042d53a7SEvalZero }
1329*042d53a7SEvalZero
1330*042d53a7SEvalZero static void
ble_ll_adv_aux_schedule(struct ble_ll_adv_sm * advsm)1331*042d53a7SEvalZero ble_ll_adv_aux_schedule(struct ble_ll_adv_sm *advsm)
1332*042d53a7SEvalZero {
1333*042d53a7SEvalZero /*
1334*042d53a7SEvalZero * For secondary channel we always start by scheduling two consecutive
1335*042d53a7SEvalZero * auxiliary packets at once. Then, after sending one packet we try to
1336*042d53a7SEvalZero * schedule another one as long as there are some data left to send. This
1337*042d53a7SEvalZero * is to make sure we can always calculate AuxPtr to subsequent packet
1338*042d53a7SEvalZero * without need to scheduled it in an interrupt.
1339*042d53a7SEvalZero */
1340*042d53a7SEvalZero
1341*042d53a7SEvalZero ble_ll_adv_aux_set_start_time(advsm);
1342*042d53a7SEvalZero ble_ll_adv_aux_schedule_first(advsm);
1343*042d53a7SEvalZero ble_ll_adv_aux_schedule_next(advsm);
1344*042d53a7SEvalZero
1345*042d53a7SEvalZero /*
1346*042d53a7SEvalZero * In case duration is set for advertising set we need to check if at least
1347*042d53a7SEvalZero * 1st aux will fit inside duration. If not, stop advertising now so we do
1348*042d53a7SEvalZero * not start extended advertising event which we cannot finish in time.
1349*042d53a7SEvalZero */
1350*042d53a7SEvalZero if (advsm->duration &&
1351*042d53a7SEvalZero (AUX_CURRENT(advsm)->sch.end_time > advsm->adv_end_time)) {
1352*042d53a7SEvalZero ble_ll_adv_sm_stop_timeout(advsm);
1353*042d53a7SEvalZero }
1354*042d53a7SEvalZero }
1355*042d53a7SEvalZero #endif
1356*042d53a7SEvalZero
1357*042d53a7SEvalZero /**
1358*042d53a7SEvalZero * Called when advertising need to be halted. This normally should not be called
1359*042d53a7SEvalZero * and is only called when a scheduled item executes but advertising is still
1360*042d53a7SEvalZero * running.
1361*042d53a7SEvalZero *
1362*042d53a7SEvalZero * Context: Interrupt
1363*042d53a7SEvalZero */
1364*042d53a7SEvalZero void
ble_ll_adv_halt(void)1365*042d53a7SEvalZero ble_ll_adv_halt(void)
1366*042d53a7SEvalZero {
1367*042d53a7SEvalZero struct ble_ll_adv_sm *advsm;
1368*042d53a7SEvalZero
1369*042d53a7SEvalZero if (g_ble_ll_cur_adv_sm != NULL) {
1370*042d53a7SEvalZero advsm = g_ble_ll_cur_adv_sm;
1371*042d53a7SEvalZero
1372*042d53a7SEvalZero ble_ll_trace_u32(BLE_LL_TRACE_ID_ADV_HALT, advsm->adv_instance);
1373*042d53a7SEvalZero
1374*042d53a7SEvalZero ble_phy_txpwr_set(MYNEWT_VAL(BLE_LL_TX_PWR_DBM));
1375*042d53a7SEvalZero
1376*042d53a7SEvalZero ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev);
1377*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
1378*042d53a7SEvalZero if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)) {
1379*042d53a7SEvalZero ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_sec_txdone_ev);
1380*042d53a7SEvalZero }
1381*042d53a7SEvalZero #endif
1382*042d53a7SEvalZero
1383*042d53a7SEvalZero ble_ll_state_set(BLE_LL_STATE_STANDBY);
1384*042d53a7SEvalZero ble_ll_adv_active_chanset_clear(g_ble_ll_cur_adv_sm);
1385*042d53a7SEvalZero g_ble_ll_cur_adv_sm = NULL;
1386*042d53a7SEvalZero } else {
1387*042d53a7SEvalZero ble_ll_trace_u32(BLE_LL_TRACE_ID_ADV_HALT, UINT32_MAX);
1388*042d53a7SEvalZero }
1389*042d53a7SEvalZero }
1390*042d53a7SEvalZero
1391*042d53a7SEvalZero /**
1392*042d53a7SEvalZero * Called by the HCI command parser when a set advertising parameters command
1393*042d53a7SEvalZero * has been received.
1394*042d53a7SEvalZero *
1395*042d53a7SEvalZero * Context: Link Layer task (HCI command parser)
1396*042d53a7SEvalZero *
1397*042d53a7SEvalZero * @param cmd
1398*042d53a7SEvalZero *
1399*042d53a7SEvalZero * @return int
1400*042d53a7SEvalZero */
1401*042d53a7SEvalZero int
ble_ll_adv_set_adv_params(uint8_t * cmd)1402*042d53a7SEvalZero ble_ll_adv_set_adv_params(uint8_t *cmd)
1403*042d53a7SEvalZero {
1404*042d53a7SEvalZero uint8_t adv_type;
1405*042d53a7SEvalZero uint8_t adv_filter_policy;
1406*042d53a7SEvalZero uint8_t adv_chanmask;
1407*042d53a7SEvalZero uint8_t own_addr_type;
1408*042d53a7SEvalZero uint8_t peer_addr_type;
1409*042d53a7SEvalZero uint16_t adv_itvl_min;
1410*042d53a7SEvalZero uint16_t adv_itvl_max;
1411*042d53a7SEvalZero struct ble_ll_adv_sm *advsm;
1412*042d53a7SEvalZero uint16_t props;
1413*042d53a7SEvalZero
1414*042d53a7SEvalZero advsm = &g_ble_ll_adv_sm[0];
1415*042d53a7SEvalZero if (advsm->adv_enabled) {
1416*042d53a7SEvalZero return BLE_ERR_CMD_DISALLOWED;
1417*042d53a7SEvalZero }
1418*042d53a7SEvalZero
1419*042d53a7SEvalZero /* Make sure intervals are OK (along with advertising type */
1420*042d53a7SEvalZero adv_itvl_min = get_le16(cmd);
1421*042d53a7SEvalZero adv_itvl_max = get_le16(cmd + 2);
1422*042d53a7SEvalZero adv_type = cmd[4];
1423*042d53a7SEvalZero
1424*042d53a7SEvalZero /*
1425*042d53a7SEvalZero * Get the filter policy now since we will ignore it if we are doing
1426*042d53a7SEvalZero * directed advertising
1427*042d53a7SEvalZero */
1428*042d53a7SEvalZero adv_filter_policy = cmd[14];
1429*042d53a7SEvalZero
1430*042d53a7SEvalZero switch (adv_type) {
1431*042d53a7SEvalZero case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD:
1432*042d53a7SEvalZero adv_filter_policy = BLE_HCI_ADV_FILT_NONE;
1433*042d53a7SEvalZero memcpy(advsm->peer_addr, cmd + 7, BLE_DEV_ADDR_LEN);
1434*042d53a7SEvalZero
1435*042d53a7SEvalZero /* Ignore min/max interval */
1436*042d53a7SEvalZero adv_itvl_min = 0;
1437*042d53a7SEvalZero adv_itvl_max = 0;
1438*042d53a7SEvalZero
1439*042d53a7SEvalZero props = BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_HD_DIR ;
1440*042d53a7SEvalZero break;
1441*042d53a7SEvalZero case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD:
1442*042d53a7SEvalZero adv_filter_policy = BLE_HCI_ADV_FILT_NONE;
1443*042d53a7SEvalZero memcpy(advsm->peer_addr, cmd + 7, BLE_DEV_ADDR_LEN);
1444*042d53a7SEvalZero
1445*042d53a7SEvalZero props = BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_LD_DIR ;
1446*042d53a7SEvalZero break;
1447*042d53a7SEvalZero case BLE_HCI_ADV_TYPE_ADV_IND:
1448*042d53a7SEvalZero props = BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_IND;
1449*042d53a7SEvalZero break;
1450*042d53a7SEvalZero case BLE_HCI_ADV_TYPE_ADV_NONCONN_IND:
1451*042d53a7SEvalZero props = BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_NONCONN;
1452*042d53a7SEvalZero break;
1453*042d53a7SEvalZero case BLE_HCI_ADV_TYPE_ADV_SCAN_IND:
1454*042d53a7SEvalZero props = BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_SCAN;
1455*042d53a7SEvalZero break;
1456*042d53a7SEvalZero default:
1457*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
1458*042d53a7SEvalZero }
1459*042d53a7SEvalZero
1460*042d53a7SEvalZero /* Make sure intervals values are valid
1461*042d53a7SEvalZero * (HD directed advertising ignores those parameters)
1462*042d53a7SEvalZero */
1463*042d53a7SEvalZero if (!(props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED)) {
1464*042d53a7SEvalZero if ((adv_itvl_min > adv_itvl_max) ||
1465*042d53a7SEvalZero (adv_itvl_min < BLE_HCI_ADV_ITVL_MIN) ||
1466*042d53a7SEvalZero (adv_itvl_min > BLE_HCI_ADV_ITVL_MAX) ||
1467*042d53a7SEvalZero (adv_itvl_max < BLE_HCI_ADV_ITVL_MIN) ||
1468*042d53a7SEvalZero (adv_itvl_max > BLE_HCI_ADV_ITVL_MAX)) {
1469*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
1470*042d53a7SEvalZero }
1471*042d53a7SEvalZero }
1472*042d53a7SEvalZero
1473*042d53a7SEvalZero /* Check own and peer address type */
1474*042d53a7SEvalZero own_addr_type = cmd[5];
1475*042d53a7SEvalZero peer_addr_type = cmd[6];
1476*042d53a7SEvalZero
1477*042d53a7SEvalZero if ((own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) ||
1478*042d53a7SEvalZero (peer_addr_type > BLE_HCI_ADV_PEER_ADDR_MAX)) {
1479*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
1480*042d53a7SEvalZero }
1481*042d53a7SEvalZero
1482*042d53a7SEvalZero advsm->adv_txpwr = MYNEWT_VAL(BLE_LL_TX_PWR_DBM);
1483*042d53a7SEvalZero
1484*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
1485*042d53a7SEvalZero if (own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) {
1486*042d53a7SEvalZero /* Copy peer address */
1487*042d53a7SEvalZero memcpy(advsm->peer_addr, cmd + 7, BLE_DEV_ADDR_LEN);
1488*042d53a7SEvalZero }
1489*042d53a7SEvalZero #else
1490*042d53a7SEvalZero /* If we dont support privacy some address types wont work */
1491*042d53a7SEvalZero if (own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) {
1492*042d53a7SEvalZero return BLE_ERR_UNSUPPORTED;
1493*042d53a7SEvalZero }
1494*042d53a7SEvalZero #endif
1495*042d53a7SEvalZero
1496*042d53a7SEvalZero /* There are only three adv channels, so check for any outside the range */
1497*042d53a7SEvalZero adv_chanmask = cmd[13];
1498*042d53a7SEvalZero if (((adv_chanmask & 0xF8) != 0) || (adv_chanmask == 0)) {
1499*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
1500*042d53a7SEvalZero }
1501*042d53a7SEvalZero
1502*042d53a7SEvalZero /* Check for valid filter policy */
1503*042d53a7SEvalZero if (adv_filter_policy > BLE_HCI_ADV_FILT_MAX) {
1504*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
1505*042d53a7SEvalZero }
1506*042d53a7SEvalZero
1507*042d53a7SEvalZero /* Fill out rest of advertising state machine */
1508*042d53a7SEvalZero advsm->own_addr_type = own_addr_type;
1509*042d53a7SEvalZero advsm->peer_addr_type = peer_addr_type;
1510*042d53a7SEvalZero advsm->adv_filter_policy = adv_filter_policy;
1511*042d53a7SEvalZero advsm->adv_chanmask = adv_chanmask;
1512*042d53a7SEvalZero advsm->adv_itvl_min = adv_itvl_min;
1513*042d53a7SEvalZero advsm->adv_itvl_max = adv_itvl_max;
1514*042d53a7SEvalZero advsm->props = props;
1515*042d53a7SEvalZero
1516*042d53a7SEvalZero return 0;
1517*042d53a7SEvalZero }
1518*042d53a7SEvalZero
1519*042d53a7SEvalZero /**
1520*042d53a7SEvalZero * Stop advertising state machine
1521*042d53a7SEvalZero *
1522*042d53a7SEvalZero * Context: Link Layer task.
1523*042d53a7SEvalZero *
1524*042d53a7SEvalZero * @param advsm
1525*042d53a7SEvalZero */
1526*042d53a7SEvalZero static void
ble_ll_adv_sm_stop(struct ble_ll_adv_sm * advsm)1527*042d53a7SEvalZero ble_ll_adv_sm_stop(struct ble_ll_adv_sm *advsm)
1528*042d53a7SEvalZero {
1529*042d53a7SEvalZero os_sr_t sr;
1530*042d53a7SEvalZero
1531*042d53a7SEvalZero if (advsm->adv_enabled) {
1532*042d53a7SEvalZero /* Remove any scheduled advertising items */
1533*042d53a7SEvalZero ble_ll_sched_rmv_elem(&advsm->adv_sch);
1534*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
1535*042d53a7SEvalZero advsm->aux_active = 0;
1536*042d53a7SEvalZero ble_ll_sched_rmv_elem(&advsm->aux[0].sch);
1537*042d53a7SEvalZero ble_ll_sched_rmv_elem(&advsm->aux[1].sch);
1538*042d53a7SEvalZero #endif
1539*042d53a7SEvalZero
1540*042d53a7SEvalZero /* Set to standby if we are no longer advertising */
1541*042d53a7SEvalZero OS_ENTER_CRITICAL(sr);
1542*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
1543*042d53a7SEvalZero if (g_ble_ll_cur_adv_sm == advsm) {
1544*042d53a7SEvalZero ble_phy_disable();
1545*042d53a7SEvalZero ble_ll_wfr_disable();
1546*042d53a7SEvalZero ble_ll_state_set(BLE_LL_STATE_STANDBY);
1547*042d53a7SEvalZero g_ble_ll_cur_adv_sm = NULL;
1548*042d53a7SEvalZero ble_ll_scan_chk_resume();
1549*042d53a7SEvalZero }
1550*042d53a7SEvalZero #else
1551*042d53a7SEvalZero if (ble_ll_state_get() == BLE_LL_STATE_ADV) {
1552*042d53a7SEvalZero ble_phy_disable();
1553*042d53a7SEvalZero ble_ll_wfr_disable();
1554*042d53a7SEvalZero ble_ll_state_set(BLE_LL_STATE_STANDBY);
1555*042d53a7SEvalZero g_ble_ll_cur_adv_sm = NULL;
1556*042d53a7SEvalZero ble_ll_scan_chk_resume();
1557*042d53a7SEvalZero }
1558*042d53a7SEvalZero #endif
1559*042d53a7SEvalZero #ifdef BLE_XCVR_RFCLK
1560*042d53a7SEvalZero ble_ll_sched_rfclk_chk_restart();
1561*042d53a7SEvalZero #endif
1562*042d53a7SEvalZero OS_EXIT_CRITICAL(sr);
1563*042d53a7SEvalZero
1564*042d53a7SEvalZero ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev);
1565*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
1566*042d53a7SEvalZero ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_sec_txdone_ev);
1567*042d53a7SEvalZero #endif
1568*042d53a7SEvalZero
1569*042d53a7SEvalZero /* If there is an event buf we need to free it */
1570*042d53a7SEvalZero if (advsm->conn_comp_ev) {
1571*042d53a7SEvalZero ble_hci_trans_buf_free(advsm->conn_comp_ev);
1572*042d53a7SEvalZero advsm->conn_comp_ev = NULL;
1573*042d53a7SEvalZero }
1574*042d53a7SEvalZero
1575*042d53a7SEvalZero ble_ll_adv_active_chanset_clear(advsm);
1576*042d53a7SEvalZero
1577*042d53a7SEvalZero /* Disable advertising */
1578*042d53a7SEvalZero advsm->adv_enabled = 0;
1579*042d53a7SEvalZero }
1580*042d53a7SEvalZero }
1581*042d53a7SEvalZero
1582*042d53a7SEvalZero static void
ble_ll_adv_sm_stop_timeout(struct ble_ll_adv_sm * advsm)1583*042d53a7SEvalZero ble_ll_adv_sm_stop_timeout(struct ble_ll_adv_sm *advsm)
1584*042d53a7SEvalZero {
1585*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
1586*042d53a7SEvalZero if (ble_ll_hci_adv_mode_ext()) {
1587*042d53a7SEvalZero ble_ll_hci_ev_send_adv_set_terminated(BLE_ERR_DIR_ADV_TMO,
1588*042d53a7SEvalZero advsm->adv_instance, 0,
1589*042d53a7SEvalZero advsm->events);
1590*042d53a7SEvalZero }
1591*042d53a7SEvalZero #endif
1592*042d53a7SEvalZero
1593*042d53a7SEvalZero /*
1594*042d53a7SEvalZero * For high duty directed advertising we need to send connection
1595*042d53a7SEvalZero * complete event with proper status
1596*042d53a7SEvalZero */
1597*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) {
1598*042d53a7SEvalZero ble_ll_conn_comp_event_send(NULL, BLE_ERR_DIR_ADV_TMO,
1599*042d53a7SEvalZero advsm->conn_comp_ev, advsm);
1600*042d53a7SEvalZero advsm->conn_comp_ev = NULL;
1601*042d53a7SEvalZero }
1602*042d53a7SEvalZero
1603*042d53a7SEvalZero /* Disable advertising */
1604*042d53a7SEvalZero ble_ll_adv_sm_stop(advsm);
1605*042d53a7SEvalZero }
1606*042d53a7SEvalZero
1607*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
1608*042d53a7SEvalZero static void
ble_ll_adv_sm_stop_limit_reached(struct ble_ll_adv_sm * advsm)1609*042d53a7SEvalZero ble_ll_adv_sm_stop_limit_reached(struct ble_ll_adv_sm *advsm)
1610*042d53a7SEvalZero {
1611*042d53a7SEvalZero ble_ll_hci_ev_send_adv_set_terminated(BLE_RR_LIMIT_REACHED,
1612*042d53a7SEvalZero advsm->adv_instance, 0,
1613*042d53a7SEvalZero advsm->events);
1614*042d53a7SEvalZero
1615*042d53a7SEvalZero /*
1616*042d53a7SEvalZero * For high duty directed advertising we need to send connection
1617*042d53a7SEvalZero * complete event with proper status
1618*042d53a7SEvalZero *
1619*042d53a7SEvalZero * Spec is a bit unambiguous here since it doesn't define what code should
1620*042d53a7SEvalZero * be used if HD directed advertising was terminated before timeout due to
1621*042d53a7SEvalZero * events count limit. For now just use same code as with duration timeout.
1622*042d53a7SEvalZero */
1623*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) {
1624*042d53a7SEvalZero ble_ll_conn_comp_event_send(NULL, BLE_ERR_DIR_ADV_TMO,
1625*042d53a7SEvalZero advsm->conn_comp_ev, advsm);
1626*042d53a7SEvalZero advsm->conn_comp_ev = NULL;
1627*042d53a7SEvalZero }
1628*042d53a7SEvalZero
1629*042d53a7SEvalZero /* Disable advertising */
1630*042d53a7SEvalZero ble_ll_adv_sm_stop(advsm);
1631*042d53a7SEvalZero }
1632*042d53a7SEvalZero #endif
1633*042d53a7SEvalZero
1634*042d53a7SEvalZero static void
ble_ll_adv_scheduled(struct ble_ll_adv_sm * advsm,uint32_t sch_start,void * arg)1635*042d53a7SEvalZero ble_ll_adv_scheduled(struct ble_ll_adv_sm *advsm, uint32_t sch_start, void *arg)
1636*042d53a7SEvalZero {
1637*042d53a7SEvalZero /* The event start time is when we start transmission of the adv PDU */
1638*042d53a7SEvalZero advsm->adv_event_start_time = sch_start + g_ble_ll_sched_offset_ticks;
1639*042d53a7SEvalZero advsm->adv_pdu_start_time = advsm->adv_event_start_time;
1640*042d53a7SEvalZero
1641*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
1642*042d53a7SEvalZero /* this is validated for HD adv so no need to do additional checks here
1643*042d53a7SEvalZero * duration is in 10ms units
1644*042d53a7SEvalZero */
1645*042d53a7SEvalZero if (advsm->duration) {
1646*042d53a7SEvalZero advsm->adv_end_time = advsm->adv_event_start_time +
1647*042d53a7SEvalZero os_cputime_usecs_to_ticks(advsm->duration * 10000);
1648*042d53a7SEvalZero }
1649*042d53a7SEvalZero #else
1650*042d53a7SEvalZero /* Set the time at which we must end directed, high-duty cycle advertising.
1651*042d53a7SEvalZero */
1652*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) {
1653*042d53a7SEvalZero advsm->adv_end_time = advsm->adv_event_start_time +
1654*042d53a7SEvalZero os_cputime_usecs_to_ticks(BLE_LL_ADV_STATE_HD_MAX * 1000);
1655*042d53a7SEvalZero }
1656*042d53a7SEvalZero #endif
1657*042d53a7SEvalZero }
1658*042d53a7SEvalZero
1659*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
1660*042d53a7SEvalZero #endif
1661*042d53a7SEvalZero
1662*042d53a7SEvalZero /**
1663*042d53a7SEvalZero * Start the advertising state machine. This is called when the host sends
1664*042d53a7SEvalZero * the "enable advertising" command and is not called again while in the
1665*042d53a7SEvalZero * advertising state.
1666*042d53a7SEvalZero *
1667*042d53a7SEvalZero * Context: Link-layer task.
1668*042d53a7SEvalZero *
1669*042d53a7SEvalZero * @param advsm Pointer to advertising state machine
1670*042d53a7SEvalZero *
1671*042d53a7SEvalZero * @return int
1672*042d53a7SEvalZero */
1673*042d53a7SEvalZero static int
ble_ll_adv_sm_start(struct ble_ll_adv_sm * advsm)1674*042d53a7SEvalZero ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm)
1675*042d53a7SEvalZero {
1676*042d53a7SEvalZero uint8_t adv_chan;
1677*042d53a7SEvalZero uint8_t *addr;
1678*042d53a7SEvalZero uint8_t *evbuf;
1679*042d53a7SEvalZero
1680*042d53a7SEvalZero /* only clear flags that are not set from HCI */
1681*042d53a7SEvalZero advsm->flags &= ~BLE_LL_ADV_SM_FLAG_TX_ADD;
1682*042d53a7SEvalZero advsm->flags &= ~BLE_LL_ADV_SM_FLAG_RX_ADD;
1683*042d53a7SEvalZero advsm->flags &= ~BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD;
1684*042d53a7SEvalZero
1685*042d53a7SEvalZero if (advsm->own_addr_type == BLE_HCI_ADV_OWN_ADDR_RANDOM) {
1686*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
1687*042d53a7SEvalZero if (!ble_ll_is_valid_random_addr(advsm->adv_random_addr)) {
1688*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
1689*042d53a7SEvalZero }
1690*042d53a7SEvalZero #else
1691*042d53a7SEvalZero if (!ble_ll_is_valid_random_addr(g_random_addr)) {
1692*042d53a7SEvalZero return BLE_ERR_CMD_DISALLOWED;
1693*042d53a7SEvalZero }
1694*042d53a7SEvalZero #endif
1695*042d53a7SEvalZero }
1696*042d53a7SEvalZero
1697*042d53a7SEvalZero /*
1698*042d53a7SEvalZero * Get an event with which to send the connection complete event if
1699*042d53a7SEvalZero * this is connectable
1700*042d53a7SEvalZero */
1701*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) {
1702*042d53a7SEvalZero /* We expect this to be NULL but if not we wont allocate one... */
1703*042d53a7SEvalZero if (advsm->conn_comp_ev == NULL) {
1704*042d53a7SEvalZero evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
1705*042d53a7SEvalZero if (!evbuf) {
1706*042d53a7SEvalZero return BLE_ERR_MEM_CAPACITY;
1707*042d53a7SEvalZero }
1708*042d53a7SEvalZero advsm->conn_comp_ev = evbuf;
1709*042d53a7SEvalZero }
1710*042d53a7SEvalZero }
1711*042d53a7SEvalZero
1712*042d53a7SEvalZero /* Set advertising address */
1713*042d53a7SEvalZero if ((advsm->own_addr_type & 1) == 0) {
1714*042d53a7SEvalZero addr = g_dev_addr;
1715*042d53a7SEvalZero } else {
1716*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
1717*042d53a7SEvalZero addr = advsm->adv_random_addr;
1718*042d53a7SEvalZero #else
1719*042d53a7SEvalZero addr = g_random_addr;
1720*042d53a7SEvalZero #endif
1721*042d53a7SEvalZero advsm->flags |= BLE_LL_ADV_SM_FLAG_TX_ADD;
1722*042d53a7SEvalZero }
1723*042d53a7SEvalZero memcpy(advsm->adva, addr, BLE_DEV_ADDR_LEN);
1724*042d53a7SEvalZero
1725*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) {
1726*042d53a7SEvalZero memcpy(advsm->initiator_addr, advsm->peer_addr, BLE_DEV_ADDR_LEN);
1727*042d53a7SEvalZero if (advsm->peer_addr_type & 1) {
1728*042d53a7SEvalZero advsm->flags |= BLE_LL_ADV_SM_FLAG_RX_ADD;
1729*042d53a7SEvalZero }
1730*042d53a7SEvalZero }
1731*042d53a7SEvalZero
1732*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
1733*042d53a7SEvalZero /* This will generate an RPA for both initiator addr and adva */
1734*042d53a7SEvalZero if (advsm->own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) {
1735*042d53a7SEvalZero ble_ll_adv_rpa_update(advsm);
1736*042d53a7SEvalZero }
1737*042d53a7SEvalZero #endif
1738*042d53a7SEvalZero
1739*042d53a7SEvalZero /* Set flag telling us that advertising is enabled */
1740*042d53a7SEvalZero advsm->adv_enabled = 1;
1741*042d53a7SEvalZero
1742*042d53a7SEvalZero /* Determine the advertising interval we will use */
1743*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) {
1744*042d53a7SEvalZero /* Set it to max. allowed for high duty cycle advertising */
1745*042d53a7SEvalZero advsm->adv_itvl_usecs = BLE_LL_ADV_PDU_ITVL_HD_MS_MAX;
1746*042d53a7SEvalZero } else {
1747*042d53a7SEvalZero advsm->adv_itvl_usecs = (uint32_t)advsm->adv_itvl_max;
1748*042d53a7SEvalZero advsm->adv_itvl_usecs *= BLE_LL_ADV_ITVL;
1749*042d53a7SEvalZero }
1750*042d53a7SEvalZero
1751*042d53a7SEvalZero /* Set first advertising channel */
1752*042d53a7SEvalZero adv_chan = ble_ll_adv_first_chan(advsm);
1753*042d53a7SEvalZero advsm->adv_chan = adv_chan;
1754*042d53a7SEvalZero
1755*042d53a7SEvalZero /*
1756*042d53a7SEvalZero * XXX: while this may not be the most efficient, schedule the first
1757*042d53a7SEvalZero * advertising event some time in the future (5 msecs). This will give
1758*042d53a7SEvalZero * time to start up any clocks or anything and also avoid a bunch of code
1759*042d53a7SEvalZero * to check if we are currently doing anything. Just makes this simple.
1760*042d53a7SEvalZero *
1761*042d53a7SEvalZero * Might also want to align this on a slot in the future.
1762*042d53a7SEvalZero *
1763*042d53a7SEvalZero * NOTE: adv_event_start_time gets set by the sched_adv_new
1764*042d53a7SEvalZero */
1765*042d53a7SEvalZero advsm->adv_pdu_start_time = os_cputime_get32() +
1766*042d53a7SEvalZero os_cputime_usecs_to_ticks(5000);
1767*042d53a7SEvalZero
1768*042d53a7SEvalZero /*
1769*042d53a7SEvalZero * Schedule advertising. We set the initial schedule start and end
1770*042d53a7SEvalZero * times to the earliest possible start/end.
1771*042d53a7SEvalZero */
1772*042d53a7SEvalZero ble_ll_adv_set_sched(advsm);
1773*042d53a7SEvalZero ble_ll_sched_adv_new(&advsm->adv_sch, ble_ll_adv_scheduled, NULL);
1774*042d53a7SEvalZero
1775*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
1776*042d53a7SEvalZero if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)) {
1777*042d53a7SEvalZero ble_ll_adv_aux_schedule(advsm);
1778*042d53a7SEvalZero }
1779*042d53a7SEvalZero #endif
1780*042d53a7SEvalZero
1781*042d53a7SEvalZero return BLE_ERR_SUCCESS;
1782*042d53a7SEvalZero }
1783*042d53a7SEvalZero
1784*042d53a7SEvalZero /**
1785*042d53a7SEvalZero * Called when the LE HCI command read advertising channel tx power command
1786*042d53a7SEvalZero * has been received. Returns the current advertising transmit power.
1787*042d53a7SEvalZero *
1788*042d53a7SEvalZero * Context: Link Layer task (HCI command parser)
1789*042d53a7SEvalZero *
1790*042d53a7SEvalZero * @return int
1791*042d53a7SEvalZero */
1792*042d53a7SEvalZero int
ble_ll_adv_read_txpwr(uint8_t * rspbuf,uint8_t * rsplen)1793*042d53a7SEvalZero ble_ll_adv_read_txpwr(uint8_t *rspbuf, uint8_t *rsplen)
1794*042d53a7SEvalZero {
1795*042d53a7SEvalZero rspbuf[0] = MYNEWT_VAL(BLE_LL_TX_PWR_DBM);
1796*042d53a7SEvalZero *rsplen = 1;
1797*042d53a7SEvalZero return BLE_ERR_SUCCESS;
1798*042d53a7SEvalZero }
1799*042d53a7SEvalZero
1800*042d53a7SEvalZero /**
1801*042d53a7SEvalZero * Turn advertising on/off.
1802*042d53a7SEvalZero *
1803*042d53a7SEvalZero * Context: Link Layer task
1804*042d53a7SEvalZero *
1805*042d53a7SEvalZero * @param cmd
1806*042d53a7SEvalZero *
1807*042d53a7SEvalZero * @return int
1808*042d53a7SEvalZero */
1809*042d53a7SEvalZero int
ble_ll_adv_set_enable(uint8_t instance,uint8_t enable,int duration,uint8_t events)1810*042d53a7SEvalZero ble_ll_adv_set_enable(uint8_t instance, uint8_t enable, int duration,
1811*042d53a7SEvalZero uint8_t events)
1812*042d53a7SEvalZero {
1813*042d53a7SEvalZero int rc;
1814*042d53a7SEvalZero struct ble_ll_adv_sm *advsm;
1815*042d53a7SEvalZero
1816*042d53a7SEvalZero if (instance >= BLE_ADV_INSTANCES) {
1817*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
1818*042d53a7SEvalZero }
1819*042d53a7SEvalZero
1820*042d53a7SEvalZero advsm = &g_ble_ll_adv_sm[instance];
1821*042d53a7SEvalZero
1822*042d53a7SEvalZero rc = BLE_ERR_SUCCESS;
1823*042d53a7SEvalZero if (enable == 1) {
1824*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
1825*042d53a7SEvalZero if (advsm->flags & BLE_LL_ADV_SM_FLAG_ADV_DATA_INCOMPLETE) {
1826*042d53a7SEvalZero return BLE_ERR_CMD_DISALLOWED;
1827*042d53a7SEvalZero }
1828*042d53a7SEvalZero
1829*042d53a7SEvalZero if (ble_ll_hci_adv_mode_ext() &&
1830*042d53a7SEvalZero (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE) &&
1831*042d53a7SEvalZero !(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) &&
1832*042d53a7SEvalZero SCAN_RSP_DATA_LEN(advsm) == 0) {
1833*042d53a7SEvalZero return BLE_ERR_CMD_DISALLOWED;
1834*042d53a7SEvalZero }
1835*042d53a7SEvalZero
1836*042d53a7SEvalZero /* handle specifics of HD dir adv enabled in legacy way */
1837*042d53a7SEvalZero if (duration < 0) {
1838*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) {
1839*042d53a7SEvalZero duration = BLE_LL_ADV_STATE_HD_MAX / 10;
1840*042d53a7SEvalZero } else {
1841*042d53a7SEvalZero duration = 0;
1842*042d53a7SEvalZero }
1843*042d53a7SEvalZero }
1844*042d53a7SEvalZero advsm->duration = duration;
1845*042d53a7SEvalZero advsm->events_max = events;
1846*042d53a7SEvalZero advsm->events = 0;
1847*042d53a7SEvalZero #endif
1848*042d53a7SEvalZero
1849*042d53a7SEvalZero /* If already enabled, do nothing */
1850*042d53a7SEvalZero if (!advsm->adv_enabled) {
1851*042d53a7SEvalZero /* Start the advertising state machine */
1852*042d53a7SEvalZero rc = ble_ll_adv_sm_start(advsm);
1853*042d53a7SEvalZero }
1854*042d53a7SEvalZero } else if (enable == 0) {
1855*042d53a7SEvalZero ble_ll_adv_sm_stop(advsm);
1856*042d53a7SEvalZero } else {
1857*042d53a7SEvalZero rc = BLE_ERR_INV_HCI_CMD_PARMS;
1858*042d53a7SEvalZero }
1859*042d53a7SEvalZero
1860*042d53a7SEvalZero return rc;
1861*042d53a7SEvalZero }
1862*042d53a7SEvalZero
1863*042d53a7SEvalZero static void
ble_ll_adv_update_data_mbuf(struct os_mbuf ** omp,bool new_data,uint16_t maxlen,const void * data,uint16_t datalen)1864*042d53a7SEvalZero ble_ll_adv_update_data_mbuf(struct os_mbuf **omp, bool new_data, uint16_t maxlen,
1865*042d53a7SEvalZero const void *data, uint16_t datalen)
1866*042d53a7SEvalZero {
1867*042d53a7SEvalZero struct os_mbuf *om;
1868*042d53a7SEvalZero int ret;
1869*042d53a7SEvalZero
1870*042d53a7SEvalZero om = *omp;
1871*042d53a7SEvalZero
1872*042d53a7SEvalZero if (new_data) {
1873*042d53a7SEvalZero if (om) {
1874*042d53a7SEvalZero os_mbuf_free_chain(om);
1875*042d53a7SEvalZero }
1876*042d53a7SEvalZero
1877*042d53a7SEvalZero om = os_msys_get_pkthdr(datalen, 0);
1878*042d53a7SEvalZero if (!om) {
1879*042d53a7SEvalZero goto done;
1880*042d53a7SEvalZero }
1881*042d53a7SEvalZero }
1882*042d53a7SEvalZero
1883*042d53a7SEvalZero assert(om);
1884*042d53a7SEvalZero
1885*042d53a7SEvalZero if (OS_MBUF_PKTLEN(om) + datalen > maxlen) {
1886*042d53a7SEvalZero os_mbuf_free_chain(om);
1887*042d53a7SEvalZero om = NULL;
1888*042d53a7SEvalZero goto done;
1889*042d53a7SEvalZero }
1890*042d53a7SEvalZero
1891*042d53a7SEvalZero ret = os_mbuf_append(om, data, datalen);
1892*042d53a7SEvalZero if (ret) {
1893*042d53a7SEvalZero os_mbuf_free_chain(om);
1894*042d53a7SEvalZero om = NULL;
1895*042d53a7SEvalZero }
1896*042d53a7SEvalZero
1897*042d53a7SEvalZero done:
1898*042d53a7SEvalZero *omp = om;
1899*042d53a7SEvalZero }
1900*042d53a7SEvalZero
1901*042d53a7SEvalZero static bool
instance_configured(struct ble_ll_adv_sm * advsm)1902*042d53a7SEvalZero instance_configured(struct ble_ll_adv_sm *advsm)
1903*042d53a7SEvalZero {
1904*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
1905*042d53a7SEvalZero if (ble_ll_hci_adv_mode_ext()) {
1906*042d53a7SEvalZero return advsm->flags & BLE_LL_ADV_SM_FLAG_CONFIGURED;
1907*042d53a7SEvalZero }
1908*042d53a7SEvalZero #endif
1909*042d53a7SEvalZero
1910*042d53a7SEvalZero /* legacy HCI instance is always configured */
1911*042d53a7SEvalZero return true;
1912*042d53a7SEvalZero }
1913*042d53a7SEvalZero
1914*042d53a7SEvalZero /**
1915*042d53a7SEvalZero * Set the scan response data that the controller will send.
1916*042d53a7SEvalZero *
1917*042d53a7SEvalZero * @param cmd
1918*042d53a7SEvalZero * @param len
1919*042d53a7SEvalZero *
1920*042d53a7SEvalZero * @return int
1921*042d53a7SEvalZero */
1922*042d53a7SEvalZero int
ble_ll_adv_set_scan_rsp_data(uint8_t * cmd,uint8_t cmd_len,uint8_t instance,uint8_t operation)1923*042d53a7SEvalZero ble_ll_adv_set_scan_rsp_data(uint8_t *cmd, uint8_t cmd_len, uint8_t instance,
1924*042d53a7SEvalZero uint8_t operation)
1925*042d53a7SEvalZero {
1926*042d53a7SEvalZero uint8_t datalen;
1927*042d53a7SEvalZero struct ble_ll_adv_sm *advsm;
1928*042d53a7SEvalZero bool new_data;
1929*042d53a7SEvalZero
1930*042d53a7SEvalZero if (instance >= BLE_ADV_INSTANCES) {
1931*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
1932*042d53a7SEvalZero }
1933*042d53a7SEvalZero
1934*042d53a7SEvalZero advsm = &g_ble_ll_adv_sm[instance];
1935*042d53a7SEvalZero datalen = cmd[0];
1936*042d53a7SEvalZero
1937*042d53a7SEvalZero if (datalen > 251 || datalen > cmd_len - 1) {
1938*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
1939*042d53a7SEvalZero }
1940*042d53a7SEvalZero
1941*042d53a7SEvalZero if (!instance_configured(advsm)) {
1942*042d53a7SEvalZero return BLE_ERR_UNK_ADV_INDENT;
1943*042d53a7SEvalZero }
1944*042d53a7SEvalZero
1945*042d53a7SEvalZero /* check if type of advertising support scan rsp */
1946*042d53a7SEvalZero if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE)) {
1947*042d53a7SEvalZero if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)) {
1948*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
1949*042d53a7SEvalZero }
1950*042d53a7SEvalZero }
1951*042d53a7SEvalZero
1952*042d53a7SEvalZero switch (operation) {
1953*042d53a7SEvalZero case BLE_HCI_LE_SET_EXT_SCAN_RSP_DATA_OPER_COMPLETE:
1954*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) {
1955*042d53a7SEvalZero if (datalen > BLE_SCAN_RSP_LEGACY_DATA_MAX_LEN) {
1956*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
1957*042d53a7SEvalZero }
1958*042d53a7SEvalZero }
1959*042d53a7SEvalZero
1960*042d53a7SEvalZero break;
1961*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
1962*042d53a7SEvalZero case BLE_HCI_LE_SET_EXT_SCAN_RSP_DATA_OPER_LAST:
1963*042d53a7SEvalZero /* TODO mark scan rsp as complete? */
1964*042d53a7SEvalZero /* fall through */
1965*042d53a7SEvalZero case BLE_HCI_LE_SET_EXT_SCAN_RSP_DATA_OPER_INT:
1966*042d53a7SEvalZero if (!advsm->scan_rsp_data) {
1967*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
1968*042d53a7SEvalZero }
1969*042d53a7SEvalZero
1970*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) {
1971*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
1972*042d53a7SEvalZero }
1973*042d53a7SEvalZero
1974*042d53a7SEvalZero if (advsm->adv_enabled) {
1975*042d53a7SEvalZero return BLE_ERR_CMD_DISALLOWED;
1976*042d53a7SEvalZero }
1977*042d53a7SEvalZero
1978*042d53a7SEvalZero if (!datalen) {
1979*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
1980*042d53a7SEvalZero }
1981*042d53a7SEvalZero break;
1982*042d53a7SEvalZero case BLE_HCI_LE_SET_EXT_SCAN_RSP_DATA_OPER_FIRST:
1983*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) {
1984*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
1985*042d53a7SEvalZero }
1986*042d53a7SEvalZero
1987*042d53a7SEvalZero if (advsm->adv_enabled) {
1988*042d53a7SEvalZero return BLE_ERR_CMD_DISALLOWED;
1989*042d53a7SEvalZero }
1990*042d53a7SEvalZero
1991*042d53a7SEvalZero if (!datalen) {
1992*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
1993*042d53a7SEvalZero }
1994*042d53a7SEvalZero
1995*042d53a7SEvalZero break;
1996*042d53a7SEvalZero #endif
1997*042d53a7SEvalZero default:
1998*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
1999*042d53a7SEvalZero }
2000*042d53a7SEvalZero
2001*042d53a7SEvalZero new_data = (operation == BLE_HCI_LE_SET_EXT_SCAN_RSP_DATA_OPER_COMPLETE) ||
2002*042d53a7SEvalZero (operation == BLE_HCI_LE_SET_EXT_SCAN_RSP_DATA_OPER_FIRST);
2003*042d53a7SEvalZero
2004*042d53a7SEvalZero ble_ll_adv_update_data_mbuf(&advsm->scan_rsp_data, new_data,
2005*042d53a7SEvalZero BLE_SCAN_RSP_DATA_MAX_LEN, cmd + 1, datalen);
2006*042d53a7SEvalZero if (!advsm->scan_rsp_data) {
2007*042d53a7SEvalZero return BLE_ERR_MEM_CAPACITY;
2008*042d53a7SEvalZero }
2009*042d53a7SEvalZero
2010*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2011*042d53a7SEvalZero /* DID shall be updated when host provides new scan response data */
2012*042d53a7SEvalZero advsm->adi = (advsm->adi & 0xf000) | (rand() & 0x0fff);
2013*042d53a7SEvalZero #endif
2014*042d53a7SEvalZero
2015*042d53a7SEvalZero return BLE_ERR_SUCCESS;
2016*042d53a7SEvalZero }
2017*042d53a7SEvalZero
2018*042d53a7SEvalZero /**
2019*042d53a7SEvalZero * Called by the LL HCI command parser when a set advertising
2020*042d53a7SEvalZero * data command has been sent from the host to the controller.
2021*042d53a7SEvalZero *
2022*042d53a7SEvalZero * @param cmd Pointer to command data
2023*042d53a7SEvalZero * @param len Length of command data
2024*042d53a7SEvalZero *
2025*042d53a7SEvalZero * @return int 0: success; BLE_ERR_INV_HCI_CMD_PARMS otherwise.
2026*042d53a7SEvalZero */
2027*042d53a7SEvalZero int
ble_ll_adv_set_adv_data(uint8_t * cmd,uint8_t cmd_len,uint8_t instance,uint8_t operation)2028*042d53a7SEvalZero ble_ll_adv_set_adv_data(uint8_t *cmd, uint8_t cmd_len, uint8_t instance,
2029*042d53a7SEvalZero uint8_t operation)
2030*042d53a7SEvalZero {
2031*042d53a7SEvalZero uint8_t datalen;
2032*042d53a7SEvalZero struct ble_ll_adv_sm *advsm;
2033*042d53a7SEvalZero bool new_data;
2034*042d53a7SEvalZero
2035*042d53a7SEvalZero if (instance >= BLE_ADV_INSTANCES) {
2036*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2037*042d53a7SEvalZero }
2038*042d53a7SEvalZero
2039*042d53a7SEvalZero advsm = &g_ble_ll_adv_sm[instance];
2040*042d53a7SEvalZero datalen = cmd[0];
2041*042d53a7SEvalZero
2042*042d53a7SEvalZero if (datalen > 251 || datalen > cmd_len - 1) {
2043*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2044*042d53a7SEvalZero }
2045*042d53a7SEvalZero
2046*042d53a7SEvalZero if (!instance_configured(advsm)) {
2047*042d53a7SEvalZero return BLE_ERR_UNK_ADV_INDENT;
2048*042d53a7SEvalZero }
2049*042d53a7SEvalZero
2050*042d53a7SEvalZero /* check if type of advertising support adv data */
2051*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) {
2052*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) {
2053*042d53a7SEvalZero if (ble_ll_hci_adv_mode_ext()) {
2054*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2055*042d53a7SEvalZero }
2056*042d53a7SEvalZero }
2057*042d53a7SEvalZero } else {
2058*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE) {
2059*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2060*042d53a7SEvalZero }
2061*042d53a7SEvalZero }
2062*042d53a7SEvalZero
2063*042d53a7SEvalZero switch (operation) {
2064*042d53a7SEvalZero case BLE_HCI_LE_SET_EXT_ADV_DATA_OPER_COMPLETE:
2065*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) {
2066*042d53a7SEvalZero if (datalen > BLE_ADV_LEGACY_DATA_MAX_LEN) {
2067*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2068*042d53a7SEvalZero }
2069*042d53a7SEvalZero }
2070*042d53a7SEvalZero
2071*042d53a7SEvalZero advsm->flags &= ~BLE_LL_ADV_SM_FLAG_ADV_DATA_INCOMPLETE;
2072*042d53a7SEvalZero break;
2073*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2074*042d53a7SEvalZero case BLE_HCI_LE_SET_EXT_ADV_DATA_OPER_UNCHANGED:
2075*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) {
2076*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2077*042d53a7SEvalZero }
2078*042d53a7SEvalZero
2079*042d53a7SEvalZero if (!advsm->adv_enabled || !ADV_DATA_LEN(advsm) || datalen) {
2080*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2081*042d53a7SEvalZero }
2082*042d53a7SEvalZero
2083*042d53a7SEvalZero /* update DID only */
2084*042d53a7SEvalZero advsm->adi = (advsm->adi & 0xf000) | (rand() & 0x0fff);
2085*042d53a7SEvalZero return BLE_ERR_SUCCESS;
2086*042d53a7SEvalZero case BLE_HCI_LE_SET_EXT_ADV_DATA_OPER_LAST:
2087*042d53a7SEvalZero advsm->flags &= ~BLE_LL_ADV_SM_FLAG_ADV_DATA_INCOMPLETE;
2088*042d53a7SEvalZero /* fall through */
2089*042d53a7SEvalZero case BLE_HCI_LE_SET_EXT_ADV_DATA_OPER_INT:
2090*042d53a7SEvalZero if (!advsm->adv_data) {
2091*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2092*042d53a7SEvalZero }
2093*042d53a7SEvalZero
2094*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) {
2095*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2096*042d53a7SEvalZero }
2097*042d53a7SEvalZero
2098*042d53a7SEvalZero if (!datalen) {
2099*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2100*042d53a7SEvalZero }
2101*042d53a7SEvalZero
2102*042d53a7SEvalZero if (advsm->adv_enabled) {
2103*042d53a7SEvalZero return BLE_ERR_CMD_DISALLOWED;
2104*042d53a7SEvalZero }
2105*042d53a7SEvalZero break;
2106*042d53a7SEvalZero case BLE_HCI_LE_SET_EXT_ADV_DATA_OPER_FIRST:
2107*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) {
2108*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2109*042d53a7SEvalZero }
2110*042d53a7SEvalZero
2111*042d53a7SEvalZero if (advsm->adv_enabled) {
2112*042d53a7SEvalZero return BLE_ERR_CMD_DISALLOWED;
2113*042d53a7SEvalZero }
2114*042d53a7SEvalZero
2115*042d53a7SEvalZero if (!datalen) {
2116*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2117*042d53a7SEvalZero }
2118*042d53a7SEvalZero
2119*042d53a7SEvalZero advsm->flags |= BLE_LL_ADV_SM_FLAG_ADV_DATA_INCOMPLETE;
2120*042d53a7SEvalZero break;
2121*042d53a7SEvalZero #endif
2122*042d53a7SEvalZero default:
2123*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2124*042d53a7SEvalZero }
2125*042d53a7SEvalZero
2126*042d53a7SEvalZero new_data = (operation == BLE_HCI_LE_SET_EXT_ADV_DATA_OPER_COMPLETE) ||
2127*042d53a7SEvalZero (operation == BLE_HCI_LE_SET_EXT_ADV_DATA_OPER_FIRST);
2128*042d53a7SEvalZero
2129*042d53a7SEvalZero ble_ll_adv_update_data_mbuf(&advsm->adv_data, new_data, BLE_ADV_DATA_MAX_LEN,
2130*042d53a7SEvalZero cmd + 1, datalen);
2131*042d53a7SEvalZero if (!advsm->adv_data) {
2132*042d53a7SEvalZero return BLE_ERR_MEM_CAPACITY;
2133*042d53a7SEvalZero }
2134*042d53a7SEvalZero
2135*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2136*042d53a7SEvalZero /* DID shall be updated when host provides new advertising data */
2137*042d53a7SEvalZero advsm->adi = (advsm->adi & 0xf000) | (rand() & 0x0fff);
2138*042d53a7SEvalZero #endif
2139*042d53a7SEvalZero
2140*042d53a7SEvalZero return BLE_ERR_SUCCESS;
2141*042d53a7SEvalZero }
2142*042d53a7SEvalZero
2143*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2144*042d53a7SEvalZero int
ble_ll_adv_ext_set_param(uint8_t * cmdbuf,uint8_t * rspbuf,uint8_t * rsplen)2145*042d53a7SEvalZero ble_ll_adv_ext_set_param(uint8_t *cmdbuf, uint8_t *rspbuf, uint8_t *rsplen)
2146*042d53a7SEvalZero {
2147*042d53a7SEvalZero int rc;
2148*042d53a7SEvalZero uint8_t adv_filter_policy;
2149*042d53a7SEvalZero uint8_t adv_chanmask;
2150*042d53a7SEvalZero uint8_t own_addr_type;
2151*042d53a7SEvalZero uint8_t peer_addr_type;
2152*042d53a7SEvalZero uint32_t adv_itvl_min;
2153*042d53a7SEvalZero uint32_t adv_itvl_max;
2154*042d53a7SEvalZero uint16_t props;
2155*042d53a7SEvalZero struct ble_ll_adv_sm *advsm;
2156*042d53a7SEvalZero uint8_t pri_phy;
2157*042d53a7SEvalZero uint8_t sec_phy;
2158*042d53a7SEvalZero uint8_t sid;
2159*042d53a7SEvalZero uint8_t scan_req_notif;
2160*042d53a7SEvalZero int8_t tx_power = 0;
2161*042d53a7SEvalZero
2162*042d53a7SEvalZero if (cmdbuf[0] >= BLE_ADV_INSTANCES) {
2163*042d53a7SEvalZero rc = BLE_ERR_INV_HCI_CMD_PARMS;
2164*042d53a7SEvalZero goto done;
2165*042d53a7SEvalZero }
2166*042d53a7SEvalZero
2167*042d53a7SEvalZero advsm = &g_ble_ll_adv_sm[cmdbuf[0]];
2168*042d53a7SEvalZero if (advsm->adv_enabled) {
2169*042d53a7SEvalZero rc = BLE_ERR_CMD_DISALLOWED;
2170*042d53a7SEvalZero goto done;
2171*042d53a7SEvalZero }
2172*042d53a7SEvalZero
2173*042d53a7SEvalZero props = get_le16(&cmdbuf[1]);
2174*042d53a7SEvalZero
2175*042d53a7SEvalZero adv_itvl_min = cmdbuf[5] << 16 | cmdbuf[4] << 8 | cmdbuf[3];
2176*042d53a7SEvalZero adv_itvl_max = cmdbuf[8] << 16 | cmdbuf[7] << 8 | cmdbuf[6];
2177*042d53a7SEvalZero
2178*042d53a7SEvalZero if (props & ~BLE_HCI_LE_SET_EXT_ADV_PROP_MASK) {
2179*042d53a7SEvalZero rc = BLE_ERR_INV_HCI_CMD_PARMS;
2180*042d53a7SEvalZero goto done;
2181*042d53a7SEvalZero }
2182*042d53a7SEvalZero
2183*042d53a7SEvalZero if (props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) {
2184*042d53a7SEvalZero if (ADV_DATA_LEN(advsm) > BLE_ADV_LEGACY_DATA_MAX_LEN ||
2185*042d53a7SEvalZero SCAN_RSP_DATA_LEN(advsm) > BLE_SCAN_RSP_LEGACY_DATA_MAX_LEN) {
2186*042d53a7SEvalZero rc = BLE_ERR_INV_HCI_CMD_PARMS;
2187*042d53a7SEvalZero goto done;
2188*042d53a7SEvalZero }
2189*042d53a7SEvalZero
2190*042d53a7SEvalZero /* if legacy bit is set possible values are limited */
2191*042d53a7SEvalZero switch (props) {
2192*042d53a7SEvalZero case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_IND:
2193*042d53a7SEvalZero case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_LD_DIR:
2194*042d53a7SEvalZero case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_HD_DIR:
2195*042d53a7SEvalZero case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_SCAN:
2196*042d53a7SEvalZero case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_NONCONN:
2197*042d53a7SEvalZero break;
2198*042d53a7SEvalZero default:
2199*042d53a7SEvalZero rc = BLE_ERR_INV_HCI_CMD_PARMS;
2200*042d53a7SEvalZero goto done;
2201*042d53a7SEvalZero }
2202*042d53a7SEvalZero } else {
2203*042d53a7SEvalZero /* HD directed advertising allowed only on legacy PDUs */
2204*042d53a7SEvalZero if (props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) {
2205*042d53a7SEvalZero rc = BLE_ERR_INV_HCI_CMD_PARMS;
2206*042d53a7SEvalZero goto done;
2207*042d53a7SEvalZero }
2208*042d53a7SEvalZero
2209*042d53a7SEvalZero /* if ext advertising PDUs are used then it shall not be both
2210*042d53a7SEvalZero * connectable and scanable
2211*042d53a7SEvalZero */
2212*042d53a7SEvalZero if ((props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) &&
2213*042d53a7SEvalZero (props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE)) {
2214*042d53a7SEvalZero rc = BLE_ERR_INV_HCI_CMD_PARMS;
2215*042d53a7SEvalZero goto done;
2216*042d53a7SEvalZero }
2217*042d53a7SEvalZero }
2218*042d53a7SEvalZero
2219*042d53a7SEvalZero /* High Duty Directed advertising is special */
2220*042d53a7SEvalZero if (props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) {
2221*042d53a7SEvalZero if (ADV_DATA_LEN(advsm) || SCAN_RSP_DATA_LEN(advsm)) {
2222*042d53a7SEvalZero rc = BLE_ERR_INV_HCI_CMD_PARMS;
2223*042d53a7SEvalZero goto done;
2224*042d53a7SEvalZero }
2225*042d53a7SEvalZero
2226*042d53a7SEvalZero /* Ignore min/max interval */
2227*042d53a7SEvalZero adv_itvl_min = 0;
2228*042d53a7SEvalZero adv_itvl_max = 0;
2229*042d53a7SEvalZero } else {
2230*042d53a7SEvalZero /* validate intervals for non HD-directed advertising */
2231*042d53a7SEvalZero if ((adv_itvl_min > adv_itvl_max) ||
2232*042d53a7SEvalZero (adv_itvl_min < BLE_HCI_ADV_ITVL_MIN) ||
2233*042d53a7SEvalZero (adv_itvl_max < BLE_HCI_ADV_ITVL_MIN)) {
2234*042d53a7SEvalZero rc = BLE_ERR_INV_HCI_CMD_PARMS;
2235*042d53a7SEvalZero goto done;
2236*042d53a7SEvalZero }
2237*042d53a7SEvalZero
2238*042d53a7SEvalZero /* TODO for now limit those to values from legacy advertising
2239*042d53a7SEvalZero *
2240*042d53a7SEvalZero * If the primary advertising interval range is outside the advertising
2241*042d53a7SEvalZero * interval range supported by the Controller, then the Controller shall
2242*042d53a7SEvalZero * return the error code Unsupported Feature or Parameter Value (0x11).
2243*042d53a7SEvalZero */
2244*042d53a7SEvalZero if ((adv_itvl_min > BLE_HCI_ADV_ITVL_MAX) ||
2245*042d53a7SEvalZero (adv_itvl_max > BLE_HCI_ADV_ITVL_MAX)) {
2246*042d53a7SEvalZero rc = BLE_ERR_UNSUPPORTED;
2247*042d53a7SEvalZero goto done;
2248*042d53a7SEvalZero }
2249*042d53a7SEvalZero }
2250*042d53a7SEvalZero
2251*042d53a7SEvalZero /* There are only three adv channels, so check for any outside the range */
2252*042d53a7SEvalZero adv_chanmask = cmdbuf[9];
2253*042d53a7SEvalZero if (((adv_chanmask & 0xF8) != 0) || (adv_chanmask == 0)) {
2254*042d53a7SEvalZero rc = BLE_ERR_INV_HCI_CMD_PARMS;
2255*042d53a7SEvalZero goto done;
2256*042d53a7SEvalZero }
2257*042d53a7SEvalZero
2258*042d53a7SEvalZero /* Check own and peer address type */
2259*042d53a7SEvalZero own_addr_type = cmdbuf[10];
2260*042d53a7SEvalZero peer_addr_type = cmdbuf[11];
2261*042d53a7SEvalZero
2262*042d53a7SEvalZero if ((own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) ||
2263*042d53a7SEvalZero (peer_addr_type > BLE_HCI_ADV_PEER_ADDR_MAX)) {
2264*042d53a7SEvalZero rc = BLE_ERR_INV_HCI_CMD_PARMS;
2265*042d53a7SEvalZero goto done;
2266*042d53a7SEvalZero }
2267*042d53a7SEvalZero
2268*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 0)
2269*042d53a7SEvalZero /* If we dont support privacy some address types wont work */
2270*042d53a7SEvalZero if (own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) {
2271*042d53a7SEvalZero rc = BLE_ERR_UNSUPPORTED;
2272*042d53a7SEvalZero goto done;
2273*042d53a7SEvalZero }
2274*042d53a7SEvalZero #endif
2275*042d53a7SEvalZero
2276*042d53a7SEvalZero adv_filter_policy = cmdbuf[18];
2277*042d53a7SEvalZero /* Check filter policy (valid only for undirected */
2278*042d53a7SEvalZero if (!(props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) &&
2279*042d53a7SEvalZero adv_filter_policy > BLE_HCI_ADV_FILT_MAX) {
2280*042d53a7SEvalZero rc = BLE_ERR_INV_HCI_CMD_PARMS;
2281*042d53a7SEvalZero goto done;
2282*042d53a7SEvalZero }
2283*042d53a7SEvalZero
2284*042d53a7SEvalZero pri_phy = cmdbuf[20];
2285*042d53a7SEvalZero if (pri_phy != BLE_HCI_LE_PHY_1M && pri_phy != BLE_HCI_LE_PHY_CODED) {
2286*042d53a7SEvalZero rc = BLE_ERR_INV_HCI_CMD_PARMS;
2287*042d53a7SEvalZero goto done;
2288*042d53a7SEvalZero }
2289*042d53a7SEvalZero
2290*042d53a7SEvalZero sec_phy = cmdbuf[22];
2291*042d53a7SEvalZero if (sec_phy != BLE_HCI_LE_PHY_1M && sec_phy != BLE_HCI_LE_PHY_2M &&
2292*042d53a7SEvalZero sec_phy != BLE_HCI_LE_PHY_CODED) {
2293*042d53a7SEvalZero rc = BLE_ERR_INV_HCI_CMD_PARMS;
2294*042d53a7SEvalZero goto done;
2295*042d53a7SEvalZero }
2296*042d53a7SEvalZero
2297*042d53a7SEvalZero sid = cmdbuf[23];
2298*042d53a7SEvalZero if (sid > 0x0f) {
2299*042d53a7SEvalZero rc = BLE_ERR_INV_HCI_CMD_PARMS;
2300*042d53a7SEvalZero goto done;
2301*042d53a7SEvalZero }
2302*042d53a7SEvalZero
2303*042d53a7SEvalZero scan_req_notif = cmdbuf[24];
2304*042d53a7SEvalZero if (scan_req_notif > 0x01) {
2305*042d53a7SEvalZero rc = BLE_ERR_INV_HCI_CMD_PARMS;
2306*042d53a7SEvalZero goto done;
2307*042d53a7SEvalZero }
2308*042d53a7SEvalZero
2309*042d53a7SEvalZero rc = BLE_ERR_SUCCESS;
2310*042d53a7SEvalZero
2311*042d53a7SEvalZero if (props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) {
2312*042d53a7SEvalZero memcpy(advsm->peer_addr, &cmdbuf[12], BLE_DEV_ADDR_LEN);
2313*042d53a7SEvalZero }
2314*042d53a7SEvalZero
2315*042d53a7SEvalZero tx_power = (int8_t) cmdbuf[19];
2316*042d53a7SEvalZero if (tx_power == 127) {
2317*042d53a7SEvalZero /* no preference */
2318*042d53a7SEvalZero advsm->adv_txpwr = MYNEWT_VAL(BLE_LL_TX_PWR_DBM);
2319*042d53a7SEvalZero } else {
2320*042d53a7SEvalZero advsm->adv_txpwr = ble_phy_txpower_round(tx_power);
2321*042d53a7SEvalZero }
2322*042d53a7SEvalZero
2323*042d53a7SEvalZero advsm->own_addr_type = own_addr_type;
2324*042d53a7SEvalZero advsm->peer_addr_type = peer_addr_type;
2325*042d53a7SEvalZero advsm->adv_filter_policy = adv_filter_policy;
2326*042d53a7SEvalZero advsm->adv_chanmask = adv_chanmask;
2327*042d53a7SEvalZero advsm->adv_itvl_min = adv_itvl_min;
2328*042d53a7SEvalZero advsm->adv_itvl_max = adv_itvl_max;
2329*042d53a7SEvalZero advsm->pri_phy = pri_phy;
2330*042d53a7SEvalZero advsm->sec_phy = sec_phy;
2331*042d53a7SEvalZero /* Update SID only */
2332*042d53a7SEvalZero advsm->adi = (advsm->adi & 0x0fff) | ((sid << 12));
2333*042d53a7SEvalZero
2334*042d53a7SEvalZero advsm->props = props;
2335*042d53a7SEvalZero
2336*042d53a7SEvalZero /* Set proper mbuf chain for aux data */
2337*042d53a7SEvalZero if (props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) {
2338*042d53a7SEvalZero advsm->aux_data = NULL;
2339*042d53a7SEvalZero } else if (props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE) {
2340*042d53a7SEvalZero advsm->aux_data = &advsm->scan_rsp_data;
2341*042d53a7SEvalZero } else {
2342*042d53a7SEvalZero advsm->aux_data = &advsm->adv_data;
2343*042d53a7SEvalZero }
2344*042d53a7SEvalZero
2345*042d53a7SEvalZero if (scan_req_notif) {
2346*042d53a7SEvalZero advsm->flags |= BLE_LL_ADV_SM_FLAG_SCAN_REQ_NOTIF;
2347*042d53a7SEvalZero } else {
2348*042d53a7SEvalZero advsm->flags &= ~BLE_LL_ADV_SM_FLAG_SCAN_REQ_NOTIF;
2349*042d53a7SEvalZero }
2350*042d53a7SEvalZero
2351*042d53a7SEvalZero advsm->flags |= BLE_LL_ADV_SM_FLAG_CONFIGURED;
2352*042d53a7SEvalZero
2353*042d53a7SEvalZero done:
2354*042d53a7SEvalZero /* Update TX power */
2355*042d53a7SEvalZero rspbuf[0] = ble_phy_txpower_round(tx_power);
2356*042d53a7SEvalZero *rsplen = 1;
2357*042d53a7SEvalZero
2358*042d53a7SEvalZero return rc;
2359*042d53a7SEvalZero }
2360*042d53a7SEvalZero
2361*042d53a7SEvalZero int
ble_ll_adv_ext_set_adv_data(uint8_t * cmdbuf,uint8_t cmdlen)2362*042d53a7SEvalZero ble_ll_adv_ext_set_adv_data(uint8_t *cmdbuf, uint8_t cmdlen)
2363*042d53a7SEvalZero {
2364*042d53a7SEvalZero /* check if length is correct */
2365*042d53a7SEvalZero if (cmdlen < 4) {
2366*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2367*042d53a7SEvalZero }
2368*042d53a7SEvalZero
2369*042d53a7SEvalZero /* TODO fragment preference ignored for now */
2370*042d53a7SEvalZero
2371*042d53a7SEvalZero return ble_ll_adv_set_adv_data(cmdbuf + 3, cmdlen - 3, cmdbuf[0],
2372*042d53a7SEvalZero cmdbuf[1]);
2373*042d53a7SEvalZero }
2374*042d53a7SEvalZero
2375*042d53a7SEvalZero int
ble_ll_adv_ext_set_scan_rsp(uint8_t * cmdbuf,uint8_t cmdlen)2376*042d53a7SEvalZero ble_ll_adv_ext_set_scan_rsp(uint8_t *cmdbuf, uint8_t cmdlen)
2377*042d53a7SEvalZero {
2378*042d53a7SEvalZero /* check if length is correct */
2379*042d53a7SEvalZero if (cmdlen < 4) {
2380*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2381*042d53a7SEvalZero }
2382*042d53a7SEvalZero
2383*042d53a7SEvalZero /* TODO fragment preference ignored for now */
2384*042d53a7SEvalZero
2385*042d53a7SEvalZero return ble_ll_adv_set_scan_rsp_data(cmdbuf + 3, cmdlen - 3, cmdbuf[0],
2386*042d53a7SEvalZero cmdbuf[1]);
2387*042d53a7SEvalZero }
2388*042d53a7SEvalZero
2389*042d53a7SEvalZero struct ext_adv_set {
2390*042d53a7SEvalZero uint8_t handle;
2391*042d53a7SEvalZero uint16_t duration;
2392*042d53a7SEvalZero uint8_t events;
2393*042d53a7SEvalZero } __attribute__((packed));
2394*042d53a7SEvalZero
2395*042d53a7SEvalZero /**
2396*042d53a7SEvalZero * HCI LE extended advertising enable command
2397*042d53a7SEvalZero *
2398*042d53a7SEvalZero * @param cmd Pointer to command data
2399*042d53a7SEvalZero * @param len Command data length
2400*042d53a7SEvalZero *
2401*042d53a7SEvalZero * @return int BLE error code
2402*042d53a7SEvalZero */
2403*042d53a7SEvalZero int
ble_ll_adv_ext_set_enable(uint8_t * cmd,uint8_t len)2404*042d53a7SEvalZero ble_ll_adv_ext_set_enable(uint8_t *cmd, uint8_t len)
2405*042d53a7SEvalZero {
2406*042d53a7SEvalZero struct ble_ll_adv_sm *advsm;
2407*042d53a7SEvalZero struct ext_adv_set* set;
2408*042d53a7SEvalZero uint8_t enable;
2409*042d53a7SEvalZero uint8_t sets;
2410*042d53a7SEvalZero int i, j, rc;
2411*042d53a7SEvalZero
2412*042d53a7SEvalZero if (len < 2) {
2413*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2414*042d53a7SEvalZero }
2415*042d53a7SEvalZero
2416*042d53a7SEvalZero enable = cmd[0];
2417*042d53a7SEvalZero sets = cmd[1];
2418*042d53a7SEvalZero cmd += 2;
2419*042d53a7SEvalZero
2420*042d53a7SEvalZero /* check if length is correct */
2421*042d53a7SEvalZero if (len != 2 + (sets * sizeof (*set))) {
2422*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2423*042d53a7SEvalZero }
2424*042d53a7SEvalZero
2425*042d53a7SEvalZero if (sets > BLE_ADV_INSTANCES) {
2426*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2427*042d53a7SEvalZero }
2428*042d53a7SEvalZero
2429*042d53a7SEvalZero if (sets == 0) {
2430*042d53a7SEvalZero if (enable) {
2431*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2432*042d53a7SEvalZero }
2433*042d53a7SEvalZero
2434*042d53a7SEvalZero /* disable all instances */
2435*042d53a7SEvalZero for (i = 0; i < BLE_ADV_INSTANCES; i++) {
2436*042d53a7SEvalZero ble_ll_adv_set_enable(i, 0, 0, 0);
2437*042d53a7SEvalZero }
2438*042d53a7SEvalZero
2439*042d53a7SEvalZero return BLE_ERR_SUCCESS;
2440*042d53a7SEvalZero }
2441*042d53a7SEvalZero
2442*042d53a7SEvalZero set = (void *) cmd;
2443*042d53a7SEvalZero /* validate instances */
2444*042d53a7SEvalZero for (i = 0; i < sets; i++) {
2445*042d53a7SEvalZero if (set->handle >= BLE_ADV_INSTANCES) {
2446*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2447*042d53a7SEvalZero }
2448*042d53a7SEvalZero
2449*042d53a7SEvalZero /* validate duplicated sets */
2450*042d53a7SEvalZero for (j = 1; j < sets - i; j++) {
2451*042d53a7SEvalZero if (set->handle == set[j].handle) {
2452*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2453*042d53a7SEvalZero }
2454*042d53a7SEvalZero }
2455*042d53a7SEvalZero
2456*042d53a7SEvalZero advsm = &g_ble_ll_adv_sm[set->handle];
2457*042d53a7SEvalZero
2458*042d53a7SEvalZero if (!instance_configured(advsm)) {
2459*042d53a7SEvalZero return BLE_ERR_UNK_ADV_INDENT;
2460*042d53a7SEvalZero }
2461*042d53a7SEvalZero
2462*042d53a7SEvalZero if (enable) {
2463*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) {
2464*042d53a7SEvalZero if (set->duration == 0 || le16toh(set->duration) > 128) {
2465*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2466*042d53a7SEvalZero }
2467*042d53a7SEvalZero }
2468*042d53a7SEvalZero }
2469*042d53a7SEvalZero
2470*042d53a7SEvalZero set++;
2471*042d53a7SEvalZero }
2472*042d53a7SEvalZero
2473*042d53a7SEvalZero set = (void *) cmd;
2474*042d53a7SEvalZero for (i = 0; i < sets; i++) {
2475*042d53a7SEvalZero rc = ble_ll_adv_set_enable(set->handle, enable, le16toh(set->duration),
2476*042d53a7SEvalZero set->events);
2477*042d53a7SEvalZero if (rc) {
2478*042d53a7SEvalZero return rc;
2479*042d53a7SEvalZero }
2480*042d53a7SEvalZero
2481*042d53a7SEvalZero set++;
2482*042d53a7SEvalZero }
2483*042d53a7SEvalZero
2484*042d53a7SEvalZero return BLE_ERR_SUCCESS;
2485*042d53a7SEvalZero }
2486*042d53a7SEvalZero
2487*042d53a7SEvalZero int
ble_ll_adv_set_random_addr(uint8_t * addr,uint8_t instance)2488*042d53a7SEvalZero ble_ll_adv_set_random_addr(uint8_t *addr, uint8_t instance)
2489*042d53a7SEvalZero {
2490*042d53a7SEvalZero struct ble_ll_adv_sm *advsm;
2491*042d53a7SEvalZero
2492*042d53a7SEvalZero if (instance >= BLE_ADV_INSTANCES) {
2493*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2494*042d53a7SEvalZero }
2495*042d53a7SEvalZero
2496*042d53a7SEvalZero advsm = &g_ble_ll_adv_sm[instance];
2497*042d53a7SEvalZero
2498*042d53a7SEvalZero /*
2499*042d53a7SEvalZero * Reject if connectable advertising is on
2500*042d53a7SEvalZero * Core Spec Vol. 2 Part E 7.8.52
2501*042d53a7SEvalZero */
2502*042d53a7SEvalZero if (advsm->adv_enabled &&
2503*042d53a7SEvalZero (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE)) {
2504*042d53a7SEvalZero return BLE_ERR_CMD_DISALLOWED;
2505*042d53a7SEvalZero }
2506*042d53a7SEvalZero
2507*042d53a7SEvalZero memcpy(advsm->adv_random_addr, addr, BLE_DEV_ADDR_LEN);
2508*042d53a7SEvalZero return BLE_ERR_SUCCESS;
2509*042d53a7SEvalZero }
2510*042d53a7SEvalZero
2511*042d53a7SEvalZero /**
2512*042d53a7SEvalZero * HCI LE extended advertising remove command
2513*042d53a7SEvalZero *
2514*042d53a7SEvalZero * @param instance Advertising instance to be removed
2515*042d53a7SEvalZero *
2516*042d53a7SEvalZero * @return int BLE error code
2517*042d53a7SEvalZero */
2518*042d53a7SEvalZero int
ble_ll_adv_remove(uint8_t instance)2519*042d53a7SEvalZero ble_ll_adv_remove(uint8_t instance)
2520*042d53a7SEvalZero {
2521*042d53a7SEvalZero struct ble_ll_adv_sm *advsm;
2522*042d53a7SEvalZero
2523*042d53a7SEvalZero /* TODO
2524*042d53a7SEvalZero * Should we allow any value for instance ID?
2525*042d53a7SEvalZero */
2526*042d53a7SEvalZero
2527*042d53a7SEvalZero if (instance >= BLE_ADV_INSTANCES) {
2528*042d53a7SEvalZero return BLE_ERR_INV_HCI_CMD_PARMS;
2529*042d53a7SEvalZero }
2530*042d53a7SEvalZero
2531*042d53a7SEvalZero advsm = &g_ble_ll_adv_sm[instance];
2532*042d53a7SEvalZero
2533*042d53a7SEvalZero if (!instance_configured(advsm)) {
2534*042d53a7SEvalZero return BLE_ERR_UNK_ADV_INDENT;
2535*042d53a7SEvalZero }
2536*042d53a7SEvalZero
2537*042d53a7SEvalZero if (advsm->adv_enabled) {
2538*042d53a7SEvalZero return BLE_ERR_CMD_DISALLOWED;
2539*042d53a7SEvalZero }
2540*042d53a7SEvalZero
2541*042d53a7SEvalZero if (advsm->adv_data) {
2542*042d53a7SEvalZero os_mbuf_free_chain(advsm->adv_data);
2543*042d53a7SEvalZero }
2544*042d53a7SEvalZero if (advsm->scan_rsp_data) {
2545*042d53a7SEvalZero os_mbuf_free_chain(advsm->scan_rsp_data);
2546*042d53a7SEvalZero }
2547*042d53a7SEvalZero
2548*042d53a7SEvalZero ble_ll_adv_sm_init(advsm);
2549*042d53a7SEvalZero
2550*042d53a7SEvalZero return BLE_ERR_SUCCESS;
2551*042d53a7SEvalZero }
2552*042d53a7SEvalZero
2553*042d53a7SEvalZero /**
2554*042d53a7SEvalZero * HCI LE extended advertising clear command
2555*042d53a7SEvalZero *
2556*042d53a7SEvalZero * @return int BLE error code
2557*042d53a7SEvalZero */
2558*042d53a7SEvalZero int
ble_ll_adv_clear_all(void)2559*042d53a7SEvalZero ble_ll_adv_clear_all(void)
2560*042d53a7SEvalZero {
2561*042d53a7SEvalZero int i;
2562*042d53a7SEvalZero
2563*042d53a7SEvalZero for (i = 0; i < BLE_ADV_INSTANCES; i++) {
2564*042d53a7SEvalZero if (g_ble_ll_adv_sm[i].adv_enabled) {
2565*042d53a7SEvalZero return BLE_ERR_CMD_DISALLOWED;
2566*042d53a7SEvalZero }
2567*042d53a7SEvalZero }
2568*042d53a7SEvalZero
2569*042d53a7SEvalZero ble_ll_adv_reset();
2570*042d53a7SEvalZero
2571*042d53a7SEvalZero return BLE_ERR_SUCCESS;
2572*042d53a7SEvalZero }
2573*042d53a7SEvalZero #endif
2574*042d53a7SEvalZero
2575*042d53a7SEvalZero /**
2576*042d53a7SEvalZero * Says whether the specified address is already connected or not.
2577*042d53a7SEvalZero * @param [in] addr The peer address.
2578*042d53a7SEvalZero * @param [in] addr_type Public address (0) or random address (1).
2579*042d53a7SEvalZero * @return Return 1 if already connected, 0 otherwise.
2580*042d53a7SEvalZero */
2581*042d53a7SEvalZero static int
ble_ll_adv_already_connected(const uint8_t * addr,uint8_t addr_type)2582*042d53a7SEvalZero ble_ll_adv_already_connected(const uint8_t* addr, uint8_t addr_type)
2583*042d53a7SEvalZero {
2584*042d53a7SEvalZero struct ble_ll_conn_sm *connsm;
2585*042d53a7SEvalZero
2586*042d53a7SEvalZero /* extracted from ble_ll_conn_slave_start function */
2587*042d53a7SEvalZero SLIST_FOREACH(connsm, &g_ble_ll_conn_active_list, act_sle) {
2588*042d53a7SEvalZero if (!memcmp(&connsm->peer_addr, addr, BLE_DEV_ADDR_LEN)) {
2589*042d53a7SEvalZero if (addr_type == BLE_ADDR_RANDOM) {
2590*042d53a7SEvalZero if (connsm->peer_addr_type & 1) {
2591*042d53a7SEvalZero return 1;
2592*042d53a7SEvalZero }
2593*042d53a7SEvalZero } else {
2594*042d53a7SEvalZero if ((connsm->peer_addr_type & 1) == 0) {
2595*042d53a7SEvalZero return 1;
2596*042d53a7SEvalZero }
2597*042d53a7SEvalZero }
2598*042d53a7SEvalZero }
2599*042d53a7SEvalZero }
2600*042d53a7SEvalZero
2601*042d53a7SEvalZero return 0;
2602*042d53a7SEvalZero }
2603*042d53a7SEvalZero
2604*042d53a7SEvalZero /**
2605*042d53a7SEvalZero * Called when the LL receives a scan request or connection request
2606*042d53a7SEvalZero *
2607*042d53a7SEvalZero * Context: Called from interrupt context.
2608*042d53a7SEvalZero *
2609*042d53a7SEvalZero * @param rxbuf
2610*042d53a7SEvalZero *
2611*042d53a7SEvalZero * @return -1: request not for us or is a connect request.
2612*042d53a7SEvalZero * 0: request (scan) is for us and we successfully went from rx to tx.
2613*042d53a7SEvalZero * > 0: PHY error attempting to go from rx to tx.
2614*042d53a7SEvalZero */
2615*042d53a7SEvalZero static int
ble_ll_adv_rx_req(uint8_t pdu_type,struct os_mbuf * rxpdu)2616*042d53a7SEvalZero ble_ll_adv_rx_req(uint8_t pdu_type, struct os_mbuf *rxpdu)
2617*042d53a7SEvalZero {
2618*042d53a7SEvalZero int rc;
2619*042d53a7SEvalZero int resolved;
2620*042d53a7SEvalZero uint8_t chk_wl;
2621*042d53a7SEvalZero uint8_t txadd;
2622*042d53a7SEvalZero uint8_t peer_addr_type;
2623*042d53a7SEvalZero uint8_t *rxbuf;
2624*042d53a7SEvalZero uint8_t *adva;
2625*042d53a7SEvalZero uint8_t *peer;
2626*042d53a7SEvalZero struct ble_mbuf_hdr *ble_hdr;
2627*042d53a7SEvalZero struct ble_ll_adv_sm *advsm;
2628*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2629*042d53a7SEvalZero struct aux_conn_rsp_data rsp_data;
2630*042d53a7SEvalZero #endif
2631*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
2632*042d53a7SEvalZero struct ble_ll_resolv_entry *rl;
2633*042d53a7SEvalZero #endif
2634*042d53a7SEvalZero
2635*042d53a7SEvalZero /* See if adva in the request (scan or connect) matches what we sent */
2636*042d53a7SEvalZero advsm = g_ble_ll_cur_adv_sm;
2637*042d53a7SEvalZero rxbuf = rxpdu->om_data;
2638*042d53a7SEvalZero adva = rxbuf + BLE_LL_PDU_HDR_LEN + BLE_DEV_ADDR_LEN;
2639*042d53a7SEvalZero if (memcmp(advsm->adva, adva, BLE_DEV_ADDR_LEN)) {
2640*042d53a7SEvalZero return -1;
2641*042d53a7SEvalZero }
2642*042d53a7SEvalZero
2643*042d53a7SEvalZero /* Set device match bit if we are whitelisting */
2644*042d53a7SEvalZero if (pdu_type == BLE_ADV_PDU_TYPE_SCAN_REQ) {
2645*042d53a7SEvalZero chk_wl = advsm->adv_filter_policy & 1;
2646*042d53a7SEvalZero } else {
2647*042d53a7SEvalZero chk_wl = advsm->adv_filter_policy & 2;
2648*042d53a7SEvalZero }
2649*042d53a7SEvalZero
2650*042d53a7SEvalZero /* Get the peer address type */
2651*042d53a7SEvalZero if (rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK) {
2652*042d53a7SEvalZero txadd = BLE_ADDR_RANDOM;
2653*042d53a7SEvalZero } else {
2654*042d53a7SEvalZero txadd = BLE_ADDR_PUBLIC;
2655*042d53a7SEvalZero }
2656*042d53a7SEvalZero
2657*042d53a7SEvalZero ble_hdr = BLE_MBUF_HDR_PTR(rxpdu);
2658*042d53a7SEvalZero peer = rxbuf + BLE_LL_PDU_HDR_LEN;
2659*042d53a7SEvalZero peer_addr_type = txadd;
2660*042d53a7SEvalZero resolved = 0;
2661*042d53a7SEvalZero
2662*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
2663*042d53a7SEvalZero rl = NULL;
2664*042d53a7SEvalZero if (ble_ll_resolv_enabled()) {
2665*042d53a7SEvalZero if (ble_ll_is_rpa(peer, txadd)) {
2666*042d53a7SEvalZero advsm->adv_rpa_index = ble_hw_resolv_list_match();
2667*042d53a7SEvalZero if (advsm->adv_rpa_index >= 0) {
2668*042d53a7SEvalZero ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_RESOLVED;
2669*042d53a7SEvalZero rl = &g_ble_ll_resolv_list[advsm->adv_rpa_index];
2670*042d53a7SEvalZero if (chk_wl) {
2671*042d53a7SEvalZero peer = rl->rl_identity_addr;
2672*042d53a7SEvalZero peer_addr_type = rl->rl_addr_type;
2673*042d53a7SEvalZero resolved = 1;
2674*042d53a7SEvalZero }
2675*042d53a7SEvalZero } else {
2676*042d53a7SEvalZero if (chk_wl) {
2677*042d53a7SEvalZero return -1;
2678*042d53a7SEvalZero }
2679*042d53a7SEvalZero }
2680*042d53a7SEvalZero } else {
2681*042d53a7SEvalZero /* Verify privacy mode */
2682*042d53a7SEvalZero rl = ble_ll_resolv_list_find(peer, peer_addr_type);
2683*042d53a7SEvalZero if (rl && (rl->rl_priv_mode == BLE_HCI_PRIVACY_NETWORK) &&
2684*042d53a7SEvalZero ble_ll_resolv_irk_nonzero(rl->rl_peer_irk)) {
2685*042d53a7SEvalZero return -1;
2686*042d53a7SEvalZero }
2687*042d53a7SEvalZero }
2688*042d53a7SEvalZero }
2689*042d53a7SEvalZero #endif
2690*042d53a7SEvalZero
2691*042d53a7SEvalZero /* Set device match bit if we are whitelisting */
2692*042d53a7SEvalZero if (chk_wl && !ble_ll_whitelist_match(peer, peer_addr_type, resolved)) {
2693*042d53a7SEvalZero return -1;
2694*042d53a7SEvalZero }
2695*042d53a7SEvalZero
2696*042d53a7SEvalZero /*
2697*042d53a7SEvalZero * We set the device match bit to tell the upper layer that we will
2698*042d53a7SEvalZero * accept the request
2699*042d53a7SEvalZero */
2700*042d53a7SEvalZero ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_DEVMATCH;
2701*042d53a7SEvalZero
2702*042d53a7SEvalZero /* Setup to transmit the scan response if appropriate */
2703*042d53a7SEvalZero rc = -1;
2704*042d53a7SEvalZero
2705*042d53a7SEvalZero if (pdu_type == BLE_ADV_PDU_TYPE_SCAN_REQ) {
2706*042d53a7SEvalZero /* XXX TODO: assume we do not need to change phy mode */
2707*042d53a7SEvalZero ble_phy_set_txend_cb(ble_ll_adv_tx_done, advsm);
2708*042d53a7SEvalZero
2709*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2710*042d53a7SEvalZero if (advsm->flags & BLE_LL_ADV_SM_FLAG_SCAN_REQ_NOTIF) {
2711*042d53a7SEvalZero ble_ll_hci_ev_send_scan_req_recv(advsm->adv_instance, peer,
2712*042d53a7SEvalZero peer_addr_type);
2713*042d53a7SEvalZero }
2714*042d53a7SEvalZero
2715*042d53a7SEvalZero /*
2716*042d53a7SEvalZero * We need to store current rxed packet header temporarily so AuxPtr
2717*042d53a7SEvalZero * can be calculated (if necessary) relative to AUX_SCAN_RSP instead of
2718*042d53a7SEvalZero * AUX_ADV_IND.
2719*042d53a7SEvalZero */
2720*042d53a7SEvalZero
2721*042d53a7SEvalZero advsm->rx_ble_hdr = ble_hdr;
2722*042d53a7SEvalZero rc = ble_phy_tx(ble_ll_adv_scan_rsp_pdu_make, advsm,
2723*042d53a7SEvalZero BLE_PHY_TRANSITION_NONE);
2724*042d53a7SEvalZero advsm->rx_ble_hdr = NULL;
2725*042d53a7SEvalZero #else
2726*042d53a7SEvalZero rc = ble_phy_tx(ble_ll_adv_scan_rsp_legacy_pdu_make, advsm,
2727*042d53a7SEvalZero BLE_PHY_TRANSITION_NONE);
2728*042d53a7SEvalZero #endif
2729*042d53a7SEvalZero
2730*042d53a7SEvalZero if (!rc) {
2731*042d53a7SEvalZero ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_SCAN_RSP_TXD;
2732*042d53a7SEvalZero STATS_INC(ble_ll_stats, scan_rsp_txg);
2733*042d53a7SEvalZero }
2734*042d53a7SEvalZero } else if (pdu_type == BLE_ADV_PDU_TYPE_AUX_CONNECT_REQ) {
2735*042d53a7SEvalZero /* See if the device is already connected */
2736*042d53a7SEvalZero if (ble_ll_adv_already_connected(peer, peer_addr_type)) {
2737*042d53a7SEvalZero return -1;
2738*042d53a7SEvalZero }
2739*042d53a7SEvalZero
2740*042d53a7SEvalZero /*
2741*042d53a7SEvalZero * Only accept connect requests from the desired address if we
2742*042d53a7SEvalZero * are doing directed advertising
2743*042d53a7SEvalZero */
2744*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) {
2745*042d53a7SEvalZero if (memcmp(advsm->peer_addr, peer, BLE_DEV_ADDR_LEN)) {
2746*042d53a7SEvalZero return -1;
2747*042d53a7SEvalZero }
2748*042d53a7SEvalZero }
2749*042d53a7SEvalZero
2750*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2751*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) {
2752*042d53a7SEvalZero return -1;
2753*042d53a7SEvalZero }
2754*042d53a7SEvalZero
2755*042d53a7SEvalZero /* use remote address used over the air */
2756*042d53a7SEvalZero rsp_data.advsm = advsm;
2757*042d53a7SEvalZero rsp_data.peer = rxbuf + BLE_LL_PDU_HDR_LEN;
2758*042d53a7SEvalZero rsp_data.rxadd = rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK;
2759*042d53a7SEvalZero
2760*042d53a7SEvalZero ble_phy_set_txend_cb(ble_ll_adv_tx_done, advsm);
2761*042d53a7SEvalZero rc = ble_phy_tx(ble_ll_adv_aux_conn_rsp_pdu_make, &rsp_data,
2762*042d53a7SEvalZero BLE_PHY_TRANSITION_NONE);
2763*042d53a7SEvalZero if (!rc) {
2764*042d53a7SEvalZero advsm->flags |= BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD;
2765*042d53a7SEvalZero STATS_INC(ble_ll_stats, aux_conn_rsp_tx);
2766*042d53a7SEvalZero }
2767*042d53a7SEvalZero #endif
2768*042d53a7SEvalZero }
2769*042d53a7SEvalZero
2770*042d53a7SEvalZero return rc;
2771*042d53a7SEvalZero }
2772*042d53a7SEvalZero
2773*042d53a7SEvalZero /**
2774*042d53a7SEvalZero * Called when a connect request has been received.
2775*042d53a7SEvalZero *
2776*042d53a7SEvalZero * Context: Link Layer
2777*042d53a7SEvalZero *
2778*042d53a7SEvalZero * @param rxbuf
2779*042d53a7SEvalZero * @param flags
2780*042d53a7SEvalZero *
2781*042d53a7SEvalZero * @return 0: no connection started. 1: connection started
2782*042d53a7SEvalZero */
2783*042d53a7SEvalZero static int
ble_ll_adv_conn_req_rxd(uint8_t * rxbuf,struct ble_mbuf_hdr * hdr,struct ble_ll_adv_sm * advsm)2784*042d53a7SEvalZero ble_ll_adv_conn_req_rxd(uint8_t *rxbuf, struct ble_mbuf_hdr *hdr,
2785*042d53a7SEvalZero struct ble_ll_adv_sm *advsm)
2786*042d53a7SEvalZero {
2787*042d53a7SEvalZero int valid;
2788*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
2789*042d53a7SEvalZero uint8_t resolved;
2790*042d53a7SEvalZero #endif
2791*042d53a7SEvalZero uint8_t addr_type;
2792*042d53a7SEvalZero uint8_t *inita;
2793*042d53a7SEvalZero uint8_t *ident_addr;
2794*042d53a7SEvalZero
2795*042d53a7SEvalZero /* Don't create connection if AUX_CONNECT_RSP was not send */
2796*042d53a7SEvalZero if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)) {
2797*042d53a7SEvalZero if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD)) {
2798*042d53a7SEvalZero return 0;
2799*042d53a7SEvalZero }
2800*042d53a7SEvalZero }
2801*042d53a7SEvalZero
2802*042d53a7SEvalZero /* Check filter policy. */
2803*042d53a7SEvalZero valid = 0;
2804*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
2805*042d53a7SEvalZero resolved = BLE_MBUF_HDR_RESOLVED(hdr);
2806*042d53a7SEvalZero #endif
2807*042d53a7SEvalZero inita = rxbuf + BLE_LL_PDU_HDR_LEN;
2808*042d53a7SEvalZero if (hdr->rxinfo.flags & BLE_MBUF_HDR_F_DEVMATCH) {
2809*042d53a7SEvalZero
2810*042d53a7SEvalZero valid = 1;
2811*042d53a7SEvalZero if (rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK) {
2812*042d53a7SEvalZero addr_type = BLE_ADDR_RANDOM;
2813*042d53a7SEvalZero } else {
2814*042d53a7SEvalZero addr_type = BLE_ADDR_PUBLIC;
2815*042d53a7SEvalZero }
2816*042d53a7SEvalZero
2817*042d53a7SEvalZero /*
2818*042d53a7SEvalZero * Only accept connect requests from the desired address if we
2819*042d53a7SEvalZero * are doing directed advertising
2820*042d53a7SEvalZero */
2821*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) {
2822*042d53a7SEvalZero ident_addr = inita;
2823*042d53a7SEvalZero
2824*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
2825*042d53a7SEvalZero if (resolved) {
2826*042d53a7SEvalZero ident_addr = g_ble_ll_resolv_list[advsm->adv_rpa_index].rl_identity_addr;
2827*042d53a7SEvalZero addr_type = g_ble_ll_resolv_list[advsm->adv_rpa_index].rl_addr_type;
2828*042d53a7SEvalZero }
2829*042d53a7SEvalZero #endif
2830*042d53a7SEvalZero if ((addr_type != advsm->peer_addr_type) ||
2831*042d53a7SEvalZero memcmp(advsm->peer_addr, ident_addr, BLE_DEV_ADDR_LEN)) {
2832*042d53a7SEvalZero valid = 0;
2833*042d53a7SEvalZero }
2834*042d53a7SEvalZero }
2835*042d53a7SEvalZero }
2836*042d53a7SEvalZero
2837*042d53a7SEvalZero if (valid) {
2838*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
2839*042d53a7SEvalZero if (resolved) {
2840*042d53a7SEvalZero /* Retain the resolvable private address that we received. */
2841*042d53a7SEvalZero memcpy(advsm->adv_rpa, inita, BLE_DEV_ADDR_LEN);
2842*042d53a7SEvalZero
2843*042d53a7SEvalZero /* Update resolving list with current peer RPA */
2844*042d53a7SEvalZero ble_ll_resolv_set_peer_rpa(advsm->adv_rpa_index, inita);
2845*042d53a7SEvalZero
2846*042d53a7SEvalZero /*
2847*042d53a7SEvalZero * Overwrite received inita with identity address since that
2848*042d53a7SEvalZero * is used from now on.
2849*042d53a7SEvalZero */
2850*042d53a7SEvalZero memcpy(inita,
2851*042d53a7SEvalZero g_ble_ll_resolv_list[advsm->adv_rpa_index].rl_identity_addr,
2852*042d53a7SEvalZero BLE_DEV_ADDR_LEN);
2853*042d53a7SEvalZero
2854*042d53a7SEvalZero /* Peer address type is an identity address */
2855*042d53a7SEvalZero addr_type = g_ble_ll_resolv_list[advsm->adv_rpa_index].rl_addr_type;
2856*042d53a7SEvalZero addr_type += 2;
2857*042d53a7SEvalZero }
2858*042d53a7SEvalZero #endif
2859*042d53a7SEvalZero
2860*042d53a7SEvalZero /* Try to start slave connection. If successful, stop advertising */
2861*042d53a7SEvalZero valid = ble_ll_conn_slave_start(rxbuf, addr_type, hdr,
2862*042d53a7SEvalZero !(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY));
2863*042d53a7SEvalZero if (valid) {
2864*042d53a7SEvalZero /* stop advertising only if not transmitting connection response */
2865*042d53a7SEvalZero if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD)) {
2866*042d53a7SEvalZero ble_ll_adv_sm_stop(advsm);
2867*042d53a7SEvalZero }
2868*042d53a7SEvalZero }
2869*042d53a7SEvalZero }
2870*042d53a7SEvalZero
2871*042d53a7SEvalZero return valid;
2872*042d53a7SEvalZero }
2873*042d53a7SEvalZero
2874*042d53a7SEvalZero /**
2875*042d53a7SEvalZero * Called on phy rx pdu end when in advertising state.
2876*042d53a7SEvalZero *
2877*042d53a7SEvalZero * There are only two pdu types we care about in this state: scan requests
2878*042d53a7SEvalZero * and connection requests. When we receive a scan request we must determine if
2879*042d53a7SEvalZero * we need to send a scan response and that needs to be acted on within T_IFS.
2880*042d53a7SEvalZero *
2881*042d53a7SEvalZero * When we receive a connection request, we need to determine if we will allow
2882*042d53a7SEvalZero * this device to start a connection with us. However, no immediate response is
2883*042d53a7SEvalZero * sent so we handle this at the link layer task.
2884*042d53a7SEvalZero *
2885*042d53a7SEvalZero * Context: Interrupt
2886*042d53a7SEvalZero *
2887*042d53a7SEvalZero * @param pdu_type Type of pdu received.
2888*042d53a7SEvalZero * @param rxpdu Pointer to received PDU
2889*042d53a7SEvalZero *
2890*042d53a7SEvalZero * @return int
2891*042d53a7SEvalZero * < 0: Disable the phy after reception.
2892*042d53a7SEvalZero * == 0: Do not disable the PHY
2893*042d53a7SEvalZero * > 0: Do not disable PHY as that has already been done.
2894*042d53a7SEvalZero */
2895*042d53a7SEvalZero int
ble_ll_adv_rx_isr_end(uint8_t pdu_type,struct os_mbuf * rxpdu,int crcok)2896*042d53a7SEvalZero ble_ll_adv_rx_isr_end(uint8_t pdu_type, struct os_mbuf *rxpdu, int crcok)
2897*042d53a7SEvalZero {
2898*042d53a7SEvalZero int rc;
2899*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2900*042d53a7SEvalZero struct ble_mbuf_hdr *rxhdr;
2901*042d53a7SEvalZero #endif
2902*042d53a7SEvalZero
2903*042d53a7SEvalZero rc = -1;
2904*042d53a7SEvalZero if (rxpdu == NULL) {
2905*042d53a7SEvalZero ble_ll_adv_tx_done(g_ble_ll_cur_adv_sm);
2906*042d53a7SEvalZero } else {
2907*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2908*042d53a7SEvalZero rxhdr = BLE_MBUF_HDR_PTR(rxpdu);
2909*042d53a7SEvalZero rxhdr->rxinfo.user_data = g_ble_ll_cur_adv_sm;
2910*042d53a7SEvalZero if (ble_ll_adv_active_chanset_is_sec(g_ble_ll_cur_adv_sm)) {
2911*042d53a7SEvalZero rxhdr->rxinfo.flags |= BLE_MBUF_HDR_F_EXT_ADV_SEC;
2912*042d53a7SEvalZero } else {
2913*042d53a7SEvalZero assert(ble_ll_adv_active_chanset_is_pri(g_ble_ll_cur_adv_sm));
2914*042d53a7SEvalZero }
2915*042d53a7SEvalZero #endif
2916*042d53a7SEvalZero if (crcok) {
2917*042d53a7SEvalZero if ((pdu_type == BLE_ADV_PDU_TYPE_SCAN_REQ) ||
2918*042d53a7SEvalZero (pdu_type == BLE_ADV_PDU_TYPE_CONNECT_REQ)) {
2919*042d53a7SEvalZero /* Process request */
2920*042d53a7SEvalZero rc = ble_ll_adv_rx_req(pdu_type, rxpdu);
2921*042d53a7SEvalZero }
2922*042d53a7SEvalZero }
2923*042d53a7SEvalZero
2924*042d53a7SEvalZero if (rc) {
2925*042d53a7SEvalZero /* We no longer have a current state machine */
2926*042d53a7SEvalZero g_ble_ll_cur_adv_sm = NULL;
2927*042d53a7SEvalZero }
2928*042d53a7SEvalZero }
2929*042d53a7SEvalZero
2930*042d53a7SEvalZero if (rc) {
2931*042d53a7SEvalZero ble_ll_state_set(BLE_LL_STATE_STANDBY);
2932*042d53a7SEvalZero }
2933*042d53a7SEvalZero
2934*042d53a7SEvalZero return rc;
2935*042d53a7SEvalZero }
2936*042d53a7SEvalZero
2937*042d53a7SEvalZero /**
2938*042d53a7SEvalZero * Process a received packet at the link layer task when in the advertising
2939*042d53a7SEvalZero * state
2940*042d53a7SEvalZero *
2941*042d53a7SEvalZero * Context: Link Layer
2942*042d53a7SEvalZero *
2943*042d53a7SEvalZero *
2944*042d53a7SEvalZero * @param ptype
2945*042d53a7SEvalZero * @param rxbuf
2946*042d53a7SEvalZero * @param hdr
2947*042d53a7SEvalZero *
2948*042d53a7SEvalZero * @return int
2949*042d53a7SEvalZero */
2950*042d53a7SEvalZero void
ble_ll_adv_rx_pkt_in(uint8_t ptype,uint8_t * rxbuf,struct ble_mbuf_hdr * hdr)2951*042d53a7SEvalZero ble_ll_adv_rx_pkt_in(uint8_t ptype, uint8_t *rxbuf, struct ble_mbuf_hdr *hdr)
2952*042d53a7SEvalZero {
2953*042d53a7SEvalZero int adv_event_over;
2954*042d53a7SEvalZero struct ble_ll_adv_sm *advsm;
2955*042d53a7SEvalZero
2956*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
2957*042d53a7SEvalZero advsm = (struct ble_ll_adv_sm *)hdr->rxinfo.user_data;
2958*042d53a7SEvalZero #else
2959*042d53a7SEvalZero advsm = &g_ble_ll_adv_sm[0];
2960*042d53a7SEvalZero #endif
2961*042d53a7SEvalZero
2962*042d53a7SEvalZero /*
2963*042d53a7SEvalZero * It is possible that advertising was stopped and a packet plcaed on the
2964*042d53a7SEvalZero * LL receive packet queue. In this case, just ignore the received packet
2965*042d53a7SEvalZero * as the advertising state machine is no longer "valid"
2966*042d53a7SEvalZero */
2967*042d53a7SEvalZero if (!advsm->adv_enabled) {
2968*042d53a7SEvalZero return;
2969*042d53a7SEvalZero }
2970*042d53a7SEvalZero
2971*042d53a7SEvalZero /*
2972*042d53a7SEvalZero * If we have received a scan request and we are transmitting a response
2973*042d53a7SEvalZero * or we have received a valid connect request, dont "end" the advertising
2974*042d53a7SEvalZero * event. In the case of a connect request we will stop advertising. In
2975*042d53a7SEvalZero * the case of the scan response transmission we will get a transmit
2976*042d53a7SEvalZero * end callback.
2977*042d53a7SEvalZero */
2978*042d53a7SEvalZero adv_event_over = 1;
2979*042d53a7SEvalZero if (BLE_MBUF_HDR_CRC_OK(hdr)) {
2980*042d53a7SEvalZero if (ptype == BLE_ADV_PDU_TYPE_CONNECT_REQ) {
2981*042d53a7SEvalZero if (ble_ll_adv_conn_req_rxd(rxbuf, hdr, advsm)) {
2982*042d53a7SEvalZero adv_event_over = 0;
2983*042d53a7SEvalZero }
2984*042d53a7SEvalZero } else {
2985*042d53a7SEvalZero if ((ptype == BLE_ADV_PDU_TYPE_SCAN_REQ) &&
2986*042d53a7SEvalZero (hdr->rxinfo.flags & BLE_MBUF_HDR_F_SCAN_RSP_TXD)) {
2987*042d53a7SEvalZero adv_event_over = 0;
2988*042d53a7SEvalZero }
2989*042d53a7SEvalZero }
2990*042d53a7SEvalZero }
2991*042d53a7SEvalZero
2992*042d53a7SEvalZero if (adv_event_over) {
2993*042d53a7SEvalZero ble_ll_adv_make_done(advsm, hdr);
2994*042d53a7SEvalZero }
2995*042d53a7SEvalZero }
2996*042d53a7SEvalZero
2997*042d53a7SEvalZero /**
2998*042d53a7SEvalZero * Called when a receive PDU has started and we are advertising.
2999*042d53a7SEvalZero *
3000*042d53a7SEvalZero * Context: interrupt
3001*042d53a7SEvalZero *
3002*042d53a7SEvalZero * @param pdu_type
3003*042d53a7SEvalZero * @param rxpdu
3004*042d53a7SEvalZero *
3005*042d53a7SEvalZero * @return int
3006*042d53a7SEvalZero * < 0: A frame we dont want to receive.
3007*042d53a7SEvalZero * = 0: Continue to receive frame. Dont go from rx to tx
3008*042d53a7SEvalZero * > 0: Continue to receive frame and go from rx to tx when done
3009*042d53a7SEvalZero */
3010*042d53a7SEvalZero int
ble_ll_adv_rx_isr_start(uint8_t pdu_type)3011*042d53a7SEvalZero ble_ll_adv_rx_isr_start(uint8_t pdu_type)
3012*042d53a7SEvalZero {
3013*042d53a7SEvalZero int rc;
3014*042d53a7SEvalZero struct ble_ll_adv_sm *advsm;
3015*042d53a7SEvalZero
3016*042d53a7SEvalZero /* Assume we will abort the frame */
3017*042d53a7SEvalZero rc = -1;
3018*042d53a7SEvalZero
3019*042d53a7SEvalZero /* If we get a scan request we must tell the phy to go from rx to tx */
3020*042d53a7SEvalZero advsm = g_ble_ll_cur_adv_sm;
3021*042d53a7SEvalZero if (pdu_type == BLE_ADV_PDU_TYPE_SCAN_REQ) {
3022*042d53a7SEvalZero /* Only accept scan requests if we are indirect adv or scan adv */
3023*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE) {
3024*042d53a7SEvalZero rc = 1;
3025*042d53a7SEvalZero }
3026*042d53a7SEvalZero } else {
3027*042d53a7SEvalZero /* Only accept connect requests if connectable advertising event */
3028*042d53a7SEvalZero if (pdu_type == BLE_ADV_PDU_TYPE_CONNECT_REQ) {
3029*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) {
3030*042d53a7SEvalZero rc = 0;
3031*042d53a7SEvalZero }
3032*042d53a7SEvalZero }
3033*042d53a7SEvalZero }
3034*042d53a7SEvalZero
3035*042d53a7SEvalZero /*
3036*042d53a7SEvalZero * If we abort the frame, we need to post the LL task to check if the
3037*042d53a7SEvalZero * advertising event is over.
3038*042d53a7SEvalZero */
3039*042d53a7SEvalZero if (rc < 0) {
3040*042d53a7SEvalZero ble_ll_adv_tx_done(advsm);
3041*042d53a7SEvalZero }
3042*042d53a7SEvalZero
3043*042d53a7SEvalZero return rc;
3044*042d53a7SEvalZero }
3045*042d53a7SEvalZero
3046*042d53a7SEvalZero static void
ble_ll_adv_drop_event(struct ble_ll_adv_sm * advsm)3047*042d53a7SEvalZero ble_ll_adv_drop_event(struct ble_ll_adv_sm *advsm)
3048*042d53a7SEvalZero {
3049*042d53a7SEvalZero STATS_INC(ble_ll_stats, adv_drop_event);
3050*042d53a7SEvalZero
3051*042d53a7SEvalZero ble_ll_sched_rmv_elem(&advsm->adv_sch);
3052*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3053*042d53a7SEvalZero ble_ll_sched_rmv_elem(&advsm->aux[0].sch);
3054*042d53a7SEvalZero ble_ll_sched_rmv_elem(&advsm->aux[1].sch);
3055*042d53a7SEvalZero
3056*042d53a7SEvalZero ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_sec_txdone_ev);
3057*042d53a7SEvalZero advsm->aux_active = 0;
3058*042d53a7SEvalZero #endif
3059*042d53a7SEvalZero
3060*042d53a7SEvalZero advsm->adv_chan = ble_ll_adv_final_chan(advsm);
3061*042d53a7SEvalZero ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev);
3062*042d53a7SEvalZero }
3063*042d53a7SEvalZero
3064*042d53a7SEvalZero static void
ble_ll_adv_reschedule_event(struct ble_ll_adv_sm * advsm)3065*042d53a7SEvalZero ble_ll_adv_reschedule_event(struct ble_ll_adv_sm *advsm)
3066*042d53a7SEvalZero {
3067*042d53a7SEvalZero int rc;
3068*042d53a7SEvalZero uint32_t start_time;
3069*042d53a7SEvalZero uint32_t max_delay_ticks;
3070*042d53a7SEvalZero
3071*042d53a7SEvalZero assert(advsm->adv_enabled);
3072*042d53a7SEvalZero
3073*042d53a7SEvalZero if (!advsm->adv_sch.enqueued) {
3074*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) {
3075*042d53a7SEvalZero max_delay_ticks = 0;
3076*042d53a7SEvalZero } else {
3077*042d53a7SEvalZero max_delay_ticks =
3078*042d53a7SEvalZero os_cputime_usecs_to_ticks(BLE_LL_ADV_DELAY_MS_MAX * 1000);
3079*042d53a7SEvalZero }
3080*042d53a7SEvalZero
3081*042d53a7SEvalZero rc = ble_ll_sched_adv_reschedule(&advsm->adv_sch, &start_time,
3082*042d53a7SEvalZero max_delay_ticks);
3083*042d53a7SEvalZero if (rc) {
3084*042d53a7SEvalZero ble_ll_adv_drop_event(advsm);
3085*042d53a7SEvalZero return;
3086*042d53a7SEvalZero }
3087*042d53a7SEvalZero
3088*042d53a7SEvalZero start_time += g_ble_ll_sched_offset_ticks;
3089*042d53a7SEvalZero advsm->adv_event_start_time = start_time;
3090*042d53a7SEvalZero advsm->adv_pdu_start_time = start_time;
3091*042d53a7SEvalZero }
3092*042d53a7SEvalZero
3093*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3094*042d53a7SEvalZero if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) &&
3095*042d53a7SEvalZero !advsm->aux_active) {
3096*042d53a7SEvalZero ble_ll_adv_aux_schedule(advsm);
3097*042d53a7SEvalZero }
3098*042d53a7SEvalZero #endif
3099*042d53a7SEvalZero }
3100*042d53a7SEvalZero
3101*042d53a7SEvalZero /**
3102*042d53a7SEvalZero * Called when an advertising event is over.
3103*042d53a7SEvalZero *
3104*042d53a7SEvalZero * Context: Link Layer task.
3105*042d53a7SEvalZero *
3106*042d53a7SEvalZero * @param arg Pointer to advertising state machine.
3107*042d53a7SEvalZero */
3108*042d53a7SEvalZero static void
ble_ll_adv_done(struct ble_ll_adv_sm * advsm)3109*042d53a7SEvalZero ble_ll_adv_done(struct ble_ll_adv_sm *advsm)
3110*042d53a7SEvalZero
3111*042d53a7SEvalZero {
3112*042d53a7SEvalZero int rc;
3113*042d53a7SEvalZero int resched_pdu;
3114*042d53a7SEvalZero uint8_t mask;
3115*042d53a7SEvalZero uint8_t final_adv_chan;
3116*042d53a7SEvalZero int32_t delta_t;
3117*042d53a7SEvalZero uint32_t itvl;
3118*042d53a7SEvalZero uint32_t tick_itvl;
3119*042d53a7SEvalZero uint32_t start_time;
3120*042d53a7SEvalZero
3121*042d53a7SEvalZero assert(advsm->adv_enabled);
3122*042d53a7SEvalZero
3123*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3124*042d53a7SEvalZero if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) {
3125*042d53a7SEvalZero /* stop advertising this was due to transmitting connection response */
3126*042d53a7SEvalZero if (advsm->flags & BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD) {
3127*042d53a7SEvalZero ble_ll_adv_sm_stop(advsm);
3128*042d53a7SEvalZero return;
3129*042d53a7SEvalZero }
3130*042d53a7SEvalZero }
3131*042d53a7SEvalZero #endif
3132*042d53a7SEvalZero
3133*042d53a7SEvalZero /* Remove the element from the schedule if it is still there. */
3134*042d53a7SEvalZero ble_ll_sched_rmv_elem(&advsm->adv_sch);
3135*042d53a7SEvalZero
3136*042d53a7SEvalZero ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev);
3137*042d53a7SEvalZero
3138*042d53a7SEvalZero /*
3139*042d53a7SEvalZero * Check if we have ended our advertising event. If our last advertising
3140*042d53a7SEvalZero * packet was sent on the last channel, it means we are done with this
3141*042d53a7SEvalZero * event.
3142*042d53a7SEvalZero */
3143*042d53a7SEvalZero final_adv_chan = ble_ll_adv_final_chan(advsm);
3144*042d53a7SEvalZero
3145*042d53a7SEvalZero if (advsm->adv_chan == final_adv_chan) {
3146*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3147*042d53a7SEvalZero if (advsm->events_max) {
3148*042d53a7SEvalZero advsm->events++;
3149*042d53a7SEvalZero }
3150*042d53a7SEvalZero #endif
3151*042d53a7SEvalZero
3152*042d53a7SEvalZero /* Check if we need to resume scanning */
3153*042d53a7SEvalZero ble_ll_scan_chk_resume();
3154*042d53a7SEvalZero
3155*042d53a7SEvalZero /* Turn off the clock if not doing anything else */
3156*042d53a7SEvalZero #ifdef BLE_XCVR_RFCLK
3157*042d53a7SEvalZero ble_ll_sched_rfclk_chk_restart();
3158*042d53a7SEvalZero #endif
3159*042d53a7SEvalZero
3160*042d53a7SEvalZero /* This event is over. Set adv channel to first one */
3161*042d53a7SEvalZero advsm->adv_chan = ble_ll_adv_first_chan(advsm);
3162*042d53a7SEvalZero
3163*042d53a7SEvalZero /*
3164*042d53a7SEvalZero * Calculate start time of next advertising event. NOTE: we do not
3165*042d53a7SEvalZero * add the random advDelay as the scheduling code will do that.
3166*042d53a7SEvalZero */
3167*042d53a7SEvalZero itvl = advsm->adv_itvl_usecs;
3168*042d53a7SEvalZero tick_itvl = os_cputime_usecs_to_ticks(itvl);
3169*042d53a7SEvalZero advsm->adv_event_start_time += tick_itvl;
3170*042d53a7SEvalZero advsm->adv_pdu_start_time = advsm->adv_event_start_time;
3171*042d53a7SEvalZero
3172*042d53a7SEvalZero /*
3173*042d53a7SEvalZero * The scheduled time better be in the future! If it is not, we will
3174*042d53a7SEvalZero * just keep advancing until we the time is in the future
3175*042d53a7SEvalZero */
3176*042d53a7SEvalZero start_time = advsm->adv_pdu_start_time - g_ble_ll_sched_offset_ticks;
3177*042d53a7SEvalZero
3178*042d53a7SEvalZero delta_t = (int32_t)(start_time - os_cputime_get32());
3179*042d53a7SEvalZero if (delta_t < 0) {
3180*042d53a7SEvalZero /*
3181*042d53a7SEvalZero * NOTE: we just the same interval that we calculated earlier.
3182*042d53a7SEvalZero * No real need to keep recalculating a new interval.
3183*042d53a7SEvalZero */
3184*042d53a7SEvalZero while (delta_t < 0) {
3185*042d53a7SEvalZero advsm->adv_event_start_time += tick_itvl;
3186*042d53a7SEvalZero advsm->adv_pdu_start_time = advsm->adv_event_start_time;
3187*042d53a7SEvalZero delta_t += (int32_t)tick_itvl;
3188*042d53a7SEvalZero }
3189*042d53a7SEvalZero }
3190*042d53a7SEvalZero resched_pdu = 0;
3191*042d53a7SEvalZero } else {
3192*042d53a7SEvalZero /*
3193*042d53a7SEvalZero * Move to next advertising channel. If not in the mask, just
3194*042d53a7SEvalZero * increment by 1. We can do this because we already checked if we
3195*042d53a7SEvalZero * just transmitted on the last advertising channel
3196*042d53a7SEvalZero */
3197*042d53a7SEvalZero ++advsm->adv_chan;
3198*042d53a7SEvalZero mask = 1 << (advsm->adv_chan - BLE_PHY_ADV_CHAN_START);
3199*042d53a7SEvalZero if ((mask & advsm->adv_chanmask) == 0) {
3200*042d53a7SEvalZero ++advsm->adv_chan;
3201*042d53a7SEvalZero }
3202*042d53a7SEvalZero
3203*042d53a7SEvalZero /*
3204*042d53a7SEvalZero * We will transmit right away. Set next pdu start time to now
3205*042d53a7SEvalZero * plus a xcvr start delay just so we dont count late adv starts
3206*042d53a7SEvalZero */
3207*042d53a7SEvalZero advsm->adv_pdu_start_time = os_cputime_get32() +
3208*042d53a7SEvalZero g_ble_ll_sched_offset_ticks;
3209*042d53a7SEvalZero
3210*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3211*042d53a7SEvalZero /* If we're past aux (unlikely, but can happen), just drop an event */
3212*042d53a7SEvalZero if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) &&
3213*042d53a7SEvalZero advsm->aux_active &&
3214*042d53a7SEvalZero advsm->adv_pdu_start_time > AUX_CURRENT(advsm)->start_time) {
3215*042d53a7SEvalZero ble_ll_adv_drop_event(advsm);
3216*042d53a7SEvalZero return;
3217*042d53a7SEvalZero }
3218*042d53a7SEvalZero #endif
3219*042d53a7SEvalZero
3220*042d53a7SEvalZero resched_pdu = 1;
3221*042d53a7SEvalZero }
3222*042d53a7SEvalZero
3223*042d53a7SEvalZero /* check if advertising timed out */
3224*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3225*042d53a7SEvalZero if (advsm->duration &&
3226*042d53a7SEvalZero advsm->adv_pdu_start_time >= advsm->adv_end_time) {
3227*042d53a7SEvalZero /* Legacy PDUs need to be stop here.
3228*042d53a7SEvalZero * For ext adv it will be stopped when AUX is done (unless it was
3229*042d53a7SEvalZero * dropped so check if AUX is active here as well).
3230*042d53a7SEvalZero */
3231*042d53a7SEvalZero if ((advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) ||
3232*042d53a7SEvalZero !advsm->aux_active) {
3233*042d53a7SEvalZero ble_ll_adv_sm_stop_timeout(advsm);
3234*042d53a7SEvalZero }
3235*042d53a7SEvalZero
3236*042d53a7SEvalZero return;
3237*042d53a7SEvalZero }
3238*042d53a7SEvalZero #else
3239*042d53a7SEvalZero if ((advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) &&
3240*042d53a7SEvalZero (advsm->adv_pdu_start_time >= advsm->adv_end_time)) {
3241*042d53a7SEvalZero ble_ll_adv_sm_stop_timeout(advsm);
3242*042d53a7SEvalZero return;
3243*042d53a7SEvalZero }
3244*042d53a7SEvalZero #endif
3245*042d53a7SEvalZero
3246*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3247*042d53a7SEvalZero if (advsm->events_max && (advsm->events >= advsm->events_max)) {
3248*042d53a7SEvalZero /* Legacy PDUs need to be stop here.
3249*042d53a7SEvalZero * For ext adv it will be stopped when AUX is done (unless it was
3250*042d53a7SEvalZero * dropped so check if AUX is active here as well).
3251*042d53a7SEvalZero */
3252*042d53a7SEvalZero if ((advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) ||
3253*042d53a7SEvalZero !advsm->aux_active) {
3254*042d53a7SEvalZero ble_ll_adv_sm_stop_limit_reached(advsm);
3255*042d53a7SEvalZero }
3256*042d53a7SEvalZero
3257*042d53a7SEvalZero return;
3258*042d53a7SEvalZero }
3259*042d53a7SEvalZero #endif
3260*042d53a7SEvalZero
3261*042d53a7SEvalZero /* We need to regenerate our RPA's if we have passed timeout */
3262*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
3263*042d53a7SEvalZero ble_ll_adv_chk_rpa_timeout(advsm);
3264*042d53a7SEvalZero #endif
3265*042d53a7SEvalZero
3266*042d53a7SEvalZero /* Schedule advertising transmit */
3267*042d53a7SEvalZero ble_ll_adv_set_sched(advsm);
3268*042d53a7SEvalZero
3269*042d53a7SEvalZero if (!resched_pdu) {
3270*042d53a7SEvalZero ble_ll_adv_reschedule_event(advsm);
3271*042d53a7SEvalZero return;
3272*042d53a7SEvalZero }
3273*042d53a7SEvalZero
3274*042d53a7SEvalZero /*
3275*042d53a7SEvalZero * In the unlikely event we cant reschedule this, just post a done
3276*042d53a7SEvalZero * event and we will reschedule the next advertising event
3277*042d53a7SEvalZero */
3278*042d53a7SEvalZero rc = ble_ll_sched_adv_resched_pdu(&advsm->adv_sch);
3279*042d53a7SEvalZero if (rc) {
3280*042d53a7SEvalZero STATS_INC(ble_ll_stats, adv_resched_pdu_fail);
3281*042d53a7SEvalZero ble_ll_adv_drop_event(advsm);
3282*042d53a7SEvalZero }
3283*042d53a7SEvalZero }
3284*042d53a7SEvalZero
3285*042d53a7SEvalZero static void
ble_ll_adv_event_done(struct ble_npl_event * ev)3286*042d53a7SEvalZero ble_ll_adv_event_done(struct ble_npl_event *ev)
3287*042d53a7SEvalZero {
3288*042d53a7SEvalZero ble_ll_adv_done(ble_npl_event_get_arg(ev));
3289*042d53a7SEvalZero }
3290*042d53a7SEvalZero
3291*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3292*042d53a7SEvalZero /**
3293*042d53a7SEvalZero * Called when auxiliary packet is txd on secondary channel
3294*042d53a7SEvalZero *
3295*042d53a7SEvalZero * Context: Link Layer task.
3296*042d53a7SEvalZero *
3297*042d53a7SEvalZero * @param ev
3298*042d53a7SEvalZero */
3299*042d53a7SEvalZero static void
ble_ll_adv_sec_done(struct ble_ll_adv_sm * advsm)3300*042d53a7SEvalZero ble_ll_adv_sec_done(struct ble_ll_adv_sm *advsm)
3301*042d53a7SEvalZero {
3302*042d53a7SEvalZero struct ble_ll_adv_aux *aux;
3303*042d53a7SEvalZero struct ble_ll_adv_aux *aux_next;
3304*042d53a7SEvalZero
3305*042d53a7SEvalZero assert(advsm->adv_enabled);
3306*042d53a7SEvalZero assert(advsm->aux_active);
3307*042d53a7SEvalZero
3308*042d53a7SEvalZero aux = AUX_CURRENT(advsm);
3309*042d53a7SEvalZero aux_next = AUX_NEXT(advsm);
3310*042d53a7SEvalZero
3311*042d53a7SEvalZero if (advsm->aux_not_scanned) {
3312*042d53a7SEvalZero ble_ll_sched_rmv_elem(&aux_next->sch);
3313*042d53a7SEvalZero }
3314*042d53a7SEvalZero
3315*042d53a7SEvalZero /* Remove anything else scheduled for secondary channel */
3316*042d53a7SEvalZero ble_ll_sched_rmv_elem(&aux->sch);
3317*042d53a7SEvalZero ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_sec_txdone_ev);
3318*042d53a7SEvalZero
3319*042d53a7SEvalZero /* Stop advertising due to transmitting connection response */
3320*042d53a7SEvalZero if (advsm->flags & BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD) {
3321*042d53a7SEvalZero ble_ll_adv_sm_stop(advsm);
3322*042d53a7SEvalZero return;
3323*042d53a7SEvalZero }
3324*042d53a7SEvalZero
3325*042d53a7SEvalZero /* If we have next AUX scheduled, try to schedule another one */
3326*042d53a7SEvalZero if (aux_next->sch.enqueued) {
3327*042d53a7SEvalZero advsm->aux_index ^= 1;
3328*042d53a7SEvalZero advsm->aux_first_pdu = 0;
3329*042d53a7SEvalZero ble_ll_adv_aux_schedule_next(advsm);
3330*042d53a7SEvalZero return;
3331*042d53a7SEvalZero }
3332*042d53a7SEvalZero
3333*042d53a7SEvalZero /* Check if we need to resume scanning */
3334*042d53a7SEvalZero ble_ll_scan_chk_resume();
3335*042d53a7SEvalZero
3336*042d53a7SEvalZero /* Check if advertising timed out */
3337*042d53a7SEvalZero if (advsm->duration && (advsm->adv_pdu_start_time >= advsm->adv_end_time)) {
3338*042d53a7SEvalZero ble_ll_adv_sm_stop_timeout(advsm);
3339*042d53a7SEvalZero return;
3340*042d53a7SEvalZero }
3341*042d53a7SEvalZero
3342*042d53a7SEvalZero if (advsm->events_max && (advsm->events >= advsm->events_max)) {
3343*042d53a7SEvalZero ble_ll_adv_sm_stop_limit_reached(advsm);
3344*042d53a7SEvalZero return;
3345*042d53a7SEvalZero }
3346*042d53a7SEvalZero
3347*042d53a7SEvalZero advsm->aux_active = 0;
3348*042d53a7SEvalZero ble_ll_adv_reschedule_event(advsm);
3349*042d53a7SEvalZero }
3350*042d53a7SEvalZero
3351*042d53a7SEvalZero static void
ble_ll_adv_sec_event_done(struct ble_npl_event * ev)3352*042d53a7SEvalZero ble_ll_adv_sec_event_done(struct ble_npl_event *ev)
3353*042d53a7SEvalZero {
3354*042d53a7SEvalZero ble_ll_adv_sec_done(ble_npl_event_get_arg(ev));
3355*042d53a7SEvalZero }
3356*042d53a7SEvalZero #endif
3357*042d53a7SEvalZero
3358*042d53a7SEvalZero static void
ble_ll_adv_make_done(struct ble_ll_adv_sm * advsm,struct ble_mbuf_hdr * hdr)3359*042d53a7SEvalZero ble_ll_adv_make_done(struct ble_ll_adv_sm *advsm, struct ble_mbuf_hdr *hdr)
3360*042d53a7SEvalZero {
3361*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3362*042d53a7SEvalZero if (BLE_MBUF_HDR_EXT_ADV_SEC(hdr)) {
3363*042d53a7SEvalZero assert(!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY));
3364*042d53a7SEvalZero assert(ble_ll_adv_active_chanset_is_sec(advsm));
3365*042d53a7SEvalZero ble_ll_adv_active_chanset_clear(advsm);
3366*042d53a7SEvalZero ble_ll_adv_sec_done(advsm);
3367*042d53a7SEvalZero } else {
3368*042d53a7SEvalZero assert(ble_ll_adv_active_chanset_is_pri(advsm));
3369*042d53a7SEvalZero ble_ll_adv_active_chanset_clear(advsm);
3370*042d53a7SEvalZero ble_ll_adv_done(advsm);
3371*042d53a7SEvalZero }
3372*042d53a7SEvalZero #else
3373*042d53a7SEvalZero assert(ble_ll_adv_active_chanset_is_pri(advsm));
3374*042d53a7SEvalZero ble_ll_adv_active_chanset_clear(advsm);
3375*042d53a7SEvalZero ble_ll_adv_done(advsm);
3376*042d53a7SEvalZero #endif
3377*042d53a7SEvalZero }
3378*042d53a7SEvalZero
3379*042d53a7SEvalZero /**
3380*042d53a7SEvalZero * Checks if the controller can change the whitelist. If advertising is enabled
3381*042d53a7SEvalZero * and is using the whitelist the controller is not allowed to change the
3382*042d53a7SEvalZero * whitelist.
3383*042d53a7SEvalZero *
3384*042d53a7SEvalZero * @return int 0: not allowed to change whitelist; 1: change allowed.
3385*042d53a7SEvalZero */
3386*042d53a7SEvalZero int
ble_ll_adv_can_chg_whitelist(void)3387*042d53a7SEvalZero ble_ll_adv_can_chg_whitelist(void)
3388*042d53a7SEvalZero {
3389*042d53a7SEvalZero struct ble_ll_adv_sm *advsm;
3390*042d53a7SEvalZero int rc;
3391*042d53a7SEvalZero int i;
3392*042d53a7SEvalZero
3393*042d53a7SEvalZero rc = 1;
3394*042d53a7SEvalZero for (i = 0; i < BLE_ADV_INSTANCES; ++i) {
3395*042d53a7SEvalZero advsm = &g_ble_ll_adv_sm[i];
3396*042d53a7SEvalZero if (advsm->adv_enabled &&
3397*042d53a7SEvalZero (advsm->adv_filter_policy != BLE_HCI_ADV_FILT_NONE)) {
3398*042d53a7SEvalZero rc = 0;
3399*042d53a7SEvalZero break;
3400*042d53a7SEvalZero }
3401*042d53a7SEvalZero }
3402*042d53a7SEvalZero
3403*042d53a7SEvalZero return rc;
3404*042d53a7SEvalZero }
3405*042d53a7SEvalZero
3406*042d53a7SEvalZero /**
3407*042d53a7SEvalZero * Sends the connection complete event when advertising a connection starts.
3408*042d53a7SEvalZero *
3409*042d53a7SEvalZero * @return uint8_t* Pointer to event buffer
3410*042d53a7SEvalZero */
3411*042d53a7SEvalZero void
ble_ll_adv_send_conn_comp_ev(struct ble_ll_conn_sm * connsm,struct ble_mbuf_hdr * rxhdr)3412*042d53a7SEvalZero ble_ll_adv_send_conn_comp_ev(struct ble_ll_conn_sm *connsm,
3413*042d53a7SEvalZero struct ble_mbuf_hdr *rxhdr)
3414*042d53a7SEvalZero {
3415*042d53a7SEvalZero uint8_t *evbuf;
3416*042d53a7SEvalZero struct ble_ll_adv_sm *advsm;
3417*042d53a7SEvalZero
3418*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3419*042d53a7SEvalZero advsm = (struct ble_ll_adv_sm *)rxhdr->rxinfo.user_data;
3420*042d53a7SEvalZero #else
3421*042d53a7SEvalZero advsm = &g_ble_ll_adv_sm[0];
3422*042d53a7SEvalZero #endif
3423*042d53a7SEvalZero
3424*042d53a7SEvalZero evbuf = advsm->conn_comp_ev;
3425*042d53a7SEvalZero assert(evbuf != NULL);
3426*042d53a7SEvalZero advsm->conn_comp_ev = NULL;
3427*042d53a7SEvalZero
3428*042d53a7SEvalZero ble_ll_conn_comp_event_send(connsm, BLE_ERR_SUCCESS, evbuf, advsm);
3429*042d53a7SEvalZero
3430*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) == 1)
3431*042d53a7SEvalZero ble_ll_hci_ev_le_csa(connsm);
3432*042d53a7SEvalZero #endif
3433*042d53a7SEvalZero
3434*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3435*042d53a7SEvalZero if (ble_ll_hci_adv_mode_ext()) {
3436*042d53a7SEvalZero ble_ll_hci_ev_send_adv_set_terminated(0, advsm->adv_instance,
3437*042d53a7SEvalZero connsm->conn_handle, advsm->events);
3438*042d53a7SEvalZero }
3439*042d53a7SEvalZero #endif
3440*042d53a7SEvalZero }
3441*042d53a7SEvalZero
3442*042d53a7SEvalZero /**
3443*042d53a7SEvalZero * Returns the local resolvable private address currently being using by
3444*042d53a7SEvalZero * the advertiser
3445*042d53a7SEvalZero *
3446*042d53a7SEvalZero * @return uint8_t*
3447*042d53a7SEvalZero */
3448*042d53a7SEvalZero uint8_t *
ble_ll_adv_get_local_rpa(struct ble_ll_adv_sm * advsm)3449*042d53a7SEvalZero ble_ll_adv_get_local_rpa(struct ble_ll_adv_sm *advsm)
3450*042d53a7SEvalZero {
3451*042d53a7SEvalZero uint8_t *rpa = NULL;
3452*042d53a7SEvalZero
3453*042d53a7SEvalZero if (advsm->own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) {
3454*042d53a7SEvalZero if ((advsm->flags & BLE_LL_ADV_SM_FLAG_TX_ADD) &&
3455*042d53a7SEvalZero ble_ll_is_rpa(advsm->adva, 1)) {
3456*042d53a7SEvalZero rpa = advsm->adva;
3457*042d53a7SEvalZero }
3458*042d53a7SEvalZero }
3459*042d53a7SEvalZero
3460*042d53a7SEvalZero return rpa;
3461*042d53a7SEvalZero }
3462*042d53a7SEvalZero
3463*042d53a7SEvalZero /**
3464*042d53a7SEvalZero * Returns the peer resolvable private address of last device connecting to us
3465*042d53a7SEvalZero *
3466*042d53a7SEvalZero * @return uint8_t*
3467*042d53a7SEvalZero */
3468*042d53a7SEvalZero uint8_t *
ble_ll_adv_get_peer_rpa(struct ble_ll_adv_sm * advsm)3469*042d53a7SEvalZero ble_ll_adv_get_peer_rpa(struct ble_ll_adv_sm *advsm)
3470*042d53a7SEvalZero {
3471*042d53a7SEvalZero /* XXX: should this go into IRK list or connection? */
3472*042d53a7SEvalZero return advsm->adv_rpa;
3473*042d53a7SEvalZero }
3474*042d53a7SEvalZero
3475*042d53a7SEvalZero /**
3476*042d53a7SEvalZero * Called when the LL wait for response timer expires while in the advertising
3477*042d53a7SEvalZero * state. Disables the phy and
3478*042d53a7SEvalZero *
3479*042d53a7SEvalZero */
3480*042d53a7SEvalZero void
ble_ll_adv_wfr_timer_exp(void)3481*042d53a7SEvalZero ble_ll_adv_wfr_timer_exp(void)
3482*042d53a7SEvalZero {
3483*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3484*042d53a7SEvalZero g_ble_ll_cur_adv_sm->aux_not_scanned = 1;
3485*042d53a7SEvalZero #endif
3486*042d53a7SEvalZero
3487*042d53a7SEvalZero ble_phy_disable();
3488*042d53a7SEvalZero ble_ll_adv_tx_done(g_ble_ll_cur_adv_sm);
3489*042d53a7SEvalZero }
3490*042d53a7SEvalZero
3491*042d53a7SEvalZero /**
3492*042d53a7SEvalZero * Reset the advertising state machine.
3493*042d53a7SEvalZero *
3494*042d53a7SEvalZero * Context: Link Layer task
3495*042d53a7SEvalZero *
3496*042d53a7SEvalZero */
3497*042d53a7SEvalZero void
ble_ll_adv_reset(void)3498*042d53a7SEvalZero ble_ll_adv_reset(void)
3499*042d53a7SEvalZero {
3500*042d53a7SEvalZero int i;
3501*042d53a7SEvalZero struct ble_ll_adv_sm *advsm;
3502*042d53a7SEvalZero
3503*042d53a7SEvalZero for (i = 0; i < BLE_ADV_INSTANCES; ++i) {
3504*042d53a7SEvalZero advsm = &g_ble_ll_adv_sm[i];
3505*042d53a7SEvalZero
3506*042d53a7SEvalZero /* Stop advertising state machine */
3507*042d53a7SEvalZero ble_ll_adv_sm_stop(advsm);
3508*042d53a7SEvalZero
3509*042d53a7SEvalZero /* clear any data present */
3510*042d53a7SEvalZero os_mbuf_free_chain(advsm->adv_data);
3511*042d53a7SEvalZero os_mbuf_free_chain(advsm->scan_rsp_data);
3512*042d53a7SEvalZero
3513*042d53a7SEvalZero /* re-initialize the advertiser state machine */
3514*042d53a7SEvalZero ble_ll_adv_sm_init(advsm);
3515*042d53a7SEvalZero }
3516*042d53a7SEvalZero }
3517*042d53a7SEvalZero
3518*042d53a7SEvalZero /* Called to determine if advertising is enabled.
3519*042d53a7SEvalZero */
3520*042d53a7SEvalZero uint8_t
ble_ll_adv_enabled(void)3521*042d53a7SEvalZero ble_ll_adv_enabled(void)
3522*042d53a7SEvalZero {
3523*042d53a7SEvalZero int i;
3524*042d53a7SEvalZero
3525*042d53a7SEvalZero for (i = 0; i < BLE_ADV_INSTANCES; i++) {
3526*042d53a7SEvalZero if (g_ble_ll_adv_sm[i].adv_enabled) {
3527*042d53a7SEvalZero return 1;
3528*042d53a7SEvalZero }
3529*042d53a7SEvalZero }
3530*042d53a7SEvalZero
3531*042d53a7SEvalZero return 0;
3532*042d53a7SEvalZero }
3533*042d53a7SEvalZero
3534*042d53a7SEvalZero static void
ble_ll_adv_sm_init(struct ble_ll_adv_sm * advsm)3535*042d53a7SEvalZero ble_ll_adv_sm_init(struct ble_ll_adv_sm *advsm)
3536*042d53a7SEvalZero {
3537*042d53a7SEvalZero uint8_t i = advsm->adv_instance;
3538*042d53a7SEvalZero
3539*042d53a7SEvalZero memset(advsm, 0, sizeof(struct ble_ll_adv_sm));
3540*042d53a7SEvalZero
3541*042d53a7SEvalZero advsm->adv_instance = i;
3542*042d53a7SEvalZero advsm->adv_itvl_min = BLE_HCI_ADV_ITVL_DEF;
3543*042d53a7SEvalZero advsm->adv_itvl_max = BLE_HCI_ADV_ITVL_DEF;
3544*042d53a7SEvalZero advsm->adv_chanmask = BLE_HCI_ADV_CHANMASK_DEF;
3545*042d53a7SEvalZero
3546*042d53a7SEvalZero /* Initialize advertising tx done event */
3547*042d53a7SEvalZero ble_npl_event_init(&advsm->adv_txdone_ev, ble_ll_adv_event_done, advsm);
3548*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3549*042d53a7SEvalZero ble_npl_event_init(&advsm->adv_sec_txdone_ev, ble_ll_adv_sec_event_done, advsm);
3550*042d53a7SEvalZero #endif
3551*042d53a7SEvalZero
3552*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
3553*042d53a7SEvalZero /* Initialize aux schedulers */
3554*042d53a7SEvalZero advsm->aux_active = 0;
3555*042d53a7SEvalZero advsm->aux[0].sch.cb_arg = advsm;
3556*042d53a7SEvalZero advsm->aux[0].sch.sched_cb = ble_ll_adv_secondary_tx_start_cb;
3557*042d53a7SEvalZero advsm->aux[0].sch.sched_type = BLE_LL_SCHED_TYPE_ADV;
3558*042d53a7SEvalZero advsm->aux[1].sch.cb_arg = advsm;
3559*042d53a7SEvalZero advsm->aux[1].sch.sched_cb = ble_ll_adv_secondary_tx_start_cb;
3560*042d53a7SEvalZero advsm->aux[1].sch.sched_type = BLE_LL_SCHED_TYPE_ADV;
3561*042d53a7SEvalZero #endif
3562*042d53a7SEvalZero
3563*042d53a7SEvalZero /*XXX Configure instances to be legacy on start */
3564*042d53a7SEvalZero advsm->props |= BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE;
3565*042d53a7SEvalZero advsm->props |= BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY;
3566*042d53a7SEvalZero }
3567*042d53a7SEvalZero
3568*042d53a7SEvalZero /**
3569*042d53a7SEvalZero * Initialize the advertising functionality of a BLE device. This should
3570*042d53a7SEvalZero * be called once on initialization
3571*042d53a7SEvalZero */
3572*042d53a7SEvalZero void
ble_ll_adv_init(void)3573*042d53a7SEvalZero ble_ll_adv_init(void)
3574*042d53a7SEvalZero {
3575*042d53a7SEvalZero int i;
3576*042d53a7SEvalZero
3577*042d53a7SEvalZero /* Set default advertising parameters */
3578*042d53a7SEvalZero for (i = 0; i < BLE_ADV_INSTANCES; ++i) {
3579*042d53a7SEvalZero g_ble_ll_adv_sm[i].adv_instance = i;
3580*042d53a7SEvalZero ble_ll_adv_sm_init(&g_ble_ll_adv_sm[i]);
3581*042d53a7SEvalZero }
3582*042d53a7SEvalZero }
3583*042d53a7SEvalZero
3584