xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/controller/src/ble_ll_adv.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
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