xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/host/src/ble_hs_hci_cmd.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 <assert.h>
21*042d53a7SEvalZero #include <string.h>
22*042d53a7SEvalZero #include <errno.h>
23*042d53a7SEvalZero #include <stdio.h>
24*042d53a7SEvalZero #include "os/os.h"
25*042d53a7SEvalZero #include "nimble/hci_common.h"
26*042d53a7SEvalZero #include "nimble/ble_hci_trans.h"
27*042d53a7SEvalZero #include "host/ble_monitor.h"
28*042d53a7SEvalZero #include "ble_hs_dbg_priv.h"
29*042d53a7SEvalZero #include "ble_hs_priv.h"
30*042d53a7SEvalZero #include "ble_monitor_priv.h"
31*042d53a7SEvalZero 
32*042d53a7SEvalZero static int
ble_hs_hci_cmd_transport(uint8_t * cmdbuf)33*042d53a7SEvalZero ble_hs_hci_cmd_transport(uint8_t *cmdbuf)
34*042d53a7SEvalZero {
35*042d53a7SEvalZero     int rc;
36*042d53a7SEvalZero 
37*042d53a7SEvalZero #if BLE_MONITOR
38*042d53a7SEvalZero     ble_monitor_send(BLE_MONITOR_OPCODE_COMMAND_PKT, cmdbuf,
39*042d53a7SEvalZero                      cmdbuf[2] + BLE_HCI_CMD_HDR_LEN);
40*042d53a7SEvalZero #endif
41*042d53a7SEvalZero 
42*042d53a7SEvalZero     rc = ble_hci_trans_hs_cmd_tx(cmdbuf);
43*042d53a7SEvalZero     switch (rc) {
44*042d53a7SEvalZero     case 0:
45*042d53a7SEvalZero         return 0;
46*042d53a7SEvalZero 
47*042d53a7SEvalZero     case BLE_ERR_MEM_CAPACITY:
48*042d53a7SEvalZero         return BLE_HS_ENOMEM_EVT;
49*042d53a7SEvalZero 
50*042d53a7SEvalZero     default:
51*042d53a7SEvalZero         return BLE_HS_EUNKNOWN;
52*042d53a7SEvalZero     }
53*042d53a7SEvalZero }
54*042d53a7SEvalZero 
55*042d53a7SEvalZero void
ble_hs_hci_cmd_write_hdr(uint8_t ogf,uint16_t ocf,uint8_t len,void * buf)56*042d53a7SEvalZero ble_hs_hci_cmd_write_hdr(uint8_t ogf, uint16_t ocf, uint8_t len, void *buf)
57*042d53a7SEvalZero {
58*042d53a7SEvalZero     uint16_t opcode;
59*042d53a7SEvalZero     uint8_t *u8ptr;
60*042d53a7SEvalZero 
61*042d53a7SEvalZero     u8ptr = buf;
62*042d53a7SEvalZero 
63*042d53a7SEvalZero     opcode = (ogf << 10) | ocf;
64*042d53a7SEvalZero     put_le16(u8ptr, opcode);
65*042d53a7SEvalZero     u8ptr[2] = len;
66*042d53a7SEvalZero }
67*042d53a7SEvalZero 
68*042d53a7SEvalZero static int
ble_hs_hci_cmd_send(uint16_t opcode,uint8_t len,const void * cmddata)69*042d53a7SEvalZero ble_hs_hci_cmd_send(uint16_t opcode, uint8_t len, const void *cmddata)
70*042d53a7SEvalZero {
71*042d53a7SEvalZero     uint8_t *buf;
72*042d53a7SEvalZero     int rc;
73*042d53a7SEvalZero 
74*042d53a7SEvalZero     buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD);
75*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(buf != NULL);
76*042d53a7SEvalZero 
77*042d53a7SEvalZero     put_le16(buf, opcode);
78*042d53a7SEvalZero     buf[2] = len;
79*042d53a7SEvalZero     if (len != 0) {
80*042d53a7SEvalZero         memcpy(buf + BLE_HCI_CMD_HDR_LEN, cmddata, len);
81*042d53a7SEvalZero     }
82*042d53a7SEvalZero 
83*042d53a7SEvalZero #if !BLE_MONITOR
84*042d53a7SEvalZero     BLE_HS_LOG(DEBUG, "ble_hs_hci_cmd_send: ogf=0x%02x ocf=0x%04x len=%d\n",
85*042d53a7SEvalZero                BLE_HCI_OGF(opcode), BLE_HCI_OCF(opcode), len);
86*042d53a7SEvalZero     ble_hs_log_flat_buf(buf, len + BLE_HCI_CMD_HDR_LEN);
87*042d53a7SEvalZero     BLE_HS_LOG(DEBUG, "\n");
88*042d53a7SEvalZero #endif
89*042d53a7SEvalZero 
90*042d53a7SEvalZero     rc = ble_hs_hci_cmd_transport(buf);
91*042d53a7SEvalZero 
92*042d53a7SEvalZero     if (rc == 0) {
93*042d53a7SEvalZero         STATS_INC(ble_hs_stats, hci_cmd);
94*042d53a7SEvalZero     } else {
95*042d53a7SEvalZero         BLE_HS_LOG(DEBUG, "ble_hs_hci_cmd_send failure; rc=%d\n", rc);
96*042d53a7SEvalZero     }
97*042d53a7SEvalZero 
98*042d53a7SEvalZero     return rc;
99*042d53a7SEvalZero }
100*042d53a7SEvalZero 
101*042d53a7SEvalZero int
ble_hs_hci_cmd_send_buf(uint16_t opcode,void * buf,uint8_t buf_len)102*042d53a7SEvalZero ble_hs_hci_cmd_send_buf(uint16_t opcode, void *buf, uint8_t buf_len)
103*042d53a7SEvalZero {
104*042d53a7SEvalZero     switch (ble_hs_sync_state) {
105*042d53a7SEvalZero     case BLE_HS_SYNC_STATE_BAD:
106*042d53a7SEvalZero         return BLE_HS_ENOTSYNCED;
107*042d53a7SEvalZero 
108*042d53a7SEvalZero     case BLE_HS_SYNC_STATE_BRINGUP:
109*042d53a7SEvalZero         if (!ble_hs_is_parent_task()) {
110*042d53a7SEvalZero             return BLE_HS_ENOTSYNCED;
111*042d53a7SEvalZero         }
112*042d53a7SEvalZero         break;
113*042d53a7SEvalZero 
114*042d53a7SEvalZero     case BLE_HS_SYNC_STATE_GOOD:
115*042d53a7SEvalZero         break;
116*042d53a7SEvalZero 
117*042d53a7SEvalZero     default:
118*042d53a7SEvalZero         BLE_HS_DBG_ASSERT(0);
119*042d53a7SEvalZero         return BLE_HS_EUNKNOWN;
120*042d53a7SEvalZero     }
121*042d53a7SEvalZero 
122*042d53a7SEvalZero     return ble_hs_hci_cmd_send(opcode, buf_len, buf);
123*042d53a7SEvalZero }
124*042d53a7SEvalZero 
125*042d53a7SEvalZero 
126*042d53a7SEvalZero /**
127*042d53a7SEvalZero  * Send a LE command from the host to the controller.
128*042d53a7SEvalZero  *
129*042d53a7SEvalZero  * @param ocf
130*042d53a7SEvalZero  * @param len
131*042d53a7SEvalZero  * @param cmddata
132*042d53a7SEvalZero  *
133*042d53a7SEvalZero  * @return int
134*042d53a7SEvalZero  */
135*042d53a7SEvalZero static int
ble_hs_hci_cmd_le_send(uint16_t ocf,uint8_t len,void * cmddata)136*042d53a7SEvalZero ble_hs_hci_cmd_le_send(uint16_t ocf, uint8_t len, void *cmddata)
137*042d53a7SEvalZero {
138*042d53a7SEvalZero     return ble_hs_hci_cmd_send(BLE_HCI_OP(BLE_HCI_OGF_LE, ocf), len, cmddata);
139*042d53a7SEvalZero }
140*042d53a7SEvalZero 
141*042d53a7SEvalZero static int
ble_hs_hci_cmd_body_le_whitelist_chg(const uint8_t * addr,uint8_t addr_type,uint8_t * dst)142*042d53a7SEvalZero ble_hs_hci_cmd_body_le_whitelist_chg(const uint8_t *addr, uint8_t addr_type,
143*042d53a7SEvalZero                                      uint8_t *dst)
144*042d53a7SEvalZero {
145*042d53a7SEvalZero     if (addr_type > BLE_ADDR_RANDOM) {
146*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
147*042d53a7SEvalZero     }
148*042d53a7SEvalZero 
149*042d53a7SEvalZero     dst[0] = addr_type;
150*042d53a7SEvalZero     memcpy(dst + 1, addr, BLE_DEV_ADDR_LEN);
151*042d53a7SEvalZero 
152*042d53a7SEvalZero     return 0;
153*042d53a7SEvalZero }
154*042d53a7SEvalZero 
155*042d53a7SEvalZero static int
ble_hs_hci_cmd_body_le_set_adv_params(const struct hci_adv_params * adv,uint8_t * dst)156*042d53a7SEvalZero ble_hs_hci_cmd_body_le_set_adv_params(const struct hci_adv_params *adv,
157*042d53a7SEvalZero                                       uint8_t *dst)
158*042d53a7SEvalZero {
159*042d53a7SEvalZero     uint16_t itvl;
160*042d53a7SEvalZero 
161*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(adv != NULL);
162*042d53a7SEvalZero 
163*042d53a7SEvalZero     /* Make sure parameters are valid */
164*042d53a7SEvalZero     if ((adv->adv_itvl_min > adv->adv_itvl_max) ||
165*042d53a7SEvalZero         (adv->own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) ||
166*042d53a7SEvalZero         (adv->peer_addr_type > BLE_HCI_ADV_PEER_ADDR_MAX) ||
167*042d53a7SEvalZero         (adv->adv_filter_policy > BLE_HCI_ADV_FILT_MAX) ||
168*042d53a7SEvalZero         (adv->adv_type > BLE_HCI_ADV_TYPE_MAX) ||
169*042d53a7SEvalZero         (adv->adv_channel_map == 0) ||
170*042d53a7SEvalZero         ((adv->adv_channel_map & 0xF8) != 0)) {
171*042d53a7SEvalZero         /* These parameters are not valid */
172*042d53a7SEvalZero         return -1;
173*042d53a7SEvalZero     }
174*042d53a7SEvalZero 
175*042d53a7SEvalZero /* When build with nimBLE controller we know it is BT5 compliant so no need
176*042d53a7SEvalZero  * to limit non-connectable advertising interval
177*042d53a7SEvalZero  */
178*042d53a7SEvalZero #if MYNEWT_VAL(BLE_DEVICE)
179*042d53a7SEvalZero     itvl = BLE_HCI_ADV_ITVL_MIN;
180*042d53a7SEvalZero #else
181*042d53a7SEvalZero     /* Make sure interval is valid for advertising type. */
182*042d53a7SEvalZero     if (((adv->adv_type == BLE_HCI_ADV_TYPE_ADV_NONCONN_IND) ||
183*042d53a7SEvalZero         (adv->adv_type == BLE_HCI_ADV_TYPE_ADV_SCAN_IND)) &&
184*042d53a7SEvalZero         ble_hs_hci_get_hci_version() < BLE_HCI_VER_BCS_5_0) {
185*042d53a7SEvalZero         itvl = BLE_HCI_ADV_ITVL_NONCONN_MIN;
186*042d53a7SEvalZero     } else {
187*042d53a7SEvalZero         itvl = BLE_HCI_ADV_ITVL_MIN;
188*042d53a7SEvalZero     }
189*042d53a7SEvalZero #endif
190*042d53a7SEvalZero 
191*042d53a7SEvalZero     /* Do not check if high duty-cycle directed */
192*042d53a7SEvalZero     if (adv->adv_type != BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) {
193*042d53a7SEvalZero         if ((adv->adv_itvl_min < itvl) ||
194*042d53a7SEvalZero             (adv->adv_itvl_min > BLE_HCI_ADV_ITVL_MAX)) {
195*042d53a7SEvalZero             return -1;
196*042d53a7SEvalZero         }
197*042d53a7SEvalZero     }
198*042d53a7SEvalZero 
199*042d53a7SEvalZero     put_le16(dst, adv->adv_itvl_min);
200*042d53a7SEvalZero     put_le16(dst + 2, adv->adv_itvl_max);
201*042d53a7SEvalZero     dst[4] = adv->adv_type;
202*042d53a7SEvalZero     dst[5] = adv->own_addr_type;
203*042d53a7SEvalZero     dst[6] = adv->peer_addr_type;
204*042d53a7SEvalZero     memcpy(dst + 7, adv->peer_addr, BLE_DEV_ADDR_LEN);
205*042d53a7SEvalZero     dst[13] = adv->adv_channel_map;
206*042d53a7SEvalZero     dst[14] = adv->adv_filter_policy;
207*042d53a7SEvalZero 
208*042d53a7SEvalZero     return 0;
209*042d53a7SEvalZero }
210*042d53a7SEvalZero 
211*042d53a7SEvalZero int
ble_hs_hci_cmd_build_le_set_adv_params(const struct hci_adv_params * adv,uint8_t * dst,int dst_len)212*042d53a7SEvalZero ble_hs_hci_cmd_build_le_set_adv_params(const struct hci_adv_params *adv,
213*042d53a7SEvalZero                                        uint8_t *dst, int dst_len)
214*042d53a7SEvalZero {
215*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_SET_ADV_PARAM_LEN);
216*042d53a7SEvalZero 
217*042d53a7SEvalZero     return ble_hs_hci_cmd_body_le_set_adv_params(adv, dst);
218*042d53a7SEvalZero }
219*042d53a7SEvalZero 
220*042d53a7SEvalZero /**
221*042d53a7SEvalZero  * Set advertising data
222*042d53a7SEvalZero  *
223*042d53a7SEvalZero  * OGF = 0x08 (LE)
224*042d53a7SEvalZero  * OCF = 0x0008
225*042d53a7SEvalZero  *
226*042d53a7SEvalZero  * @param data
227*042d53a7SEvalZero  * @param len
228*042d53a7SEvalZero  * @param dst
229*042d53a7SEvalZero  *
230*042d53a7SEvalZero  * @return int
231*042d53a7SEvalZero  */
232*042d53a7SEvalZero static int
ble_hs_hci_cmd_body_le_set_adv_data(const uint8_t * data,uint8_t len,uint8_t * dst)233*042d53a7SEvalZero ble_hs_hci_cmd_body_le_set_adv_data(const uint8_t *data, uint8_t len,
234*042d53a7SEvalZero                                     uint8_t *dst)
235*042d53a7SEvalZero {
236*042d53a7SEvalZero     /* Check for valid parameters */
237*042d53a7SEvalZero     if (((data == NULL) && (len != 0)) || (len > BLE_HCI_MAX_ADV_DATA_LEN)) {
238*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
239*042d53a7SEvalZero     }
240*042d53a7SEvalZero 
241*042d53a7SEvalZero     memset(dst, 0, BLE_HCI_SET_ADV_DATA_LEN);
242*042d53a7SEvalZero     dst[0] = len;
243*042d53a7SEvalZero     memcpy(dst + 1, data, len);
244*042d53a7SEvalZero 
245*042d53a7SEvalZero     return 0;
246*042d53a7SEvalZero }
247*042d53a7SEvalZero 
248*042d53a7SEvalZero /**
249*042d53a7SEvalZero  * Set advertising data
250*042d53a7SEvalZero  *
251*042d53a7SEvalZero  * OGF = 0x08 (LE)
252*042d53a7SEvalZero  * OCF = 0x0008
253*042d53a7SEvalZero  *
254*042d53a7SEvalZero  * @param data
255*042d53a7SEvalZero  * @param len
256*042d53a7SEvalZero  * @param dst
257*042d53a7SEvalZero  *
258*042d53a7SEvalZero  * @return int
259*042d53a7SEvalZero  */
260*042d53a7SEvalZero int
ble_hs_hci_cmd_build_le_set_adv_data(const uint8_t * data,uint8_t len,uint8_t * dst,int dst_len)261*042d53a7SEvalZero ble_hs_hci_cmd_build_le_set_adv_data(const uint8_t *data, uint8_t len,
262*042d53a7SEvalZero                                      uint8_t *dst, int dst_len)
263*042d53a7SEvalZero {
264*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_SET_ADV_DATA_LEN);
265*042d53a7SEvalZero 
266*042d53a7SEvalZero     return ble_hs_hci_cmd_body_le_set_adv_data(data, len, dst);
267*042d53a7SEvalZero }
268*042d53a7SEvalZero 
269*042d53a7SEvalZero static int
ble_hs_hci_cmd_body_le_set_scan_rsp_data(const uint8_t * data,uint8_t len,uint8_t * dst)270*042d53a7SEvalZero ble_hs_hci_cmd_body_le_set_scan_rsp_data(const uint8_t *data, uint8_t len,
271*042d53a7SEvalZero                                          uint8_t *dst)
272*042d53a7SEvalZero {
273*042d53a7SEvalZero     /* Check for valid parameters */
274*042d53a7SEvalZero     if (((data == NULL) && (len != 0)) ||
275*042d53a7SEvalZero          (len > BLE_HCI_MAX_SCAN_RSP_DATA_LEN)) {
276*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
277*042d53a7SEvalZero     }
278*042d53a7SEvalZero 
279*042d53a7SEvalZero     memset(dst, 0, BLE_HCI_SET_SCAN_RSP_DATA_LEN);
280*042d53a7SEvalZero     dst[0] = len;
281*042d53a7SEvalZero     memcpy(dst + 1, data, len);
282*042d53a7SEvalZero 
283*042d53a7SEvalZero     return 0;
284*042d53a7SEvalZero }
285*042d53a7SEvalZero 
286*042d53a7SEvalZero int
ble_hs_hci_cmd_build_le_set_scan_rsp_data(const uint8_t * data,uint8_t len,uint8_t * dst,int dst_len)287*042d53a7SEvalZero ble_hs_hci_cmd_build_le_set_scan_rsp_data(const uint8_t *data, uint8_t len,
288*042d53a7SEvalZero                                           uint8_t *dst, int dst_len)
289*042d53a7SEvalZero {
290*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_SET_SCAN_RSP_DATA_LEN);
291*042d53a7SEvalZero 
292*042d53a7SEvalZero     return ble_hs_hci_cmd_body_le_set_scan_rsp_data(data, len, dst);
293*042d53a7SEvalZero }
294*042d53a7SEvalZero 
295*042d53a7SEvalZero static void
ble_hs_hci_cmd_body_set_event_mask(uint64_t event_mask,uint8_t * dst)296*042d53a7SEvalZero ble_hs_hci_cmd_body_set_event_mask(uint64_t event_mask, uint8_t *dst)
297*042d53a7SEvalZero {
298*042d53a7SEvalZero     put_le64(dst, event_mask);
299*042d53a7SEvalZero }
300*042d53a7SEvalZero 
301*042d53a7SEvalZero void
ble_hs_hci_cmd_build_set_event_mask(uint64_t event_mask,uint8_t * dst,int dst_len)302*042d53a7SEvalZero ble_hs_hci_cmd_build_set_event_mask(uint64_t event_mask,
303*042d53a7SEvalZero                                     uint8_t *dst, int dst_len)
304*042d53a7SEvalZero {
305*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_SET_EVENT_MASK_LEN);
306*042d53a7SEvalZero 
307*042d53a7SEvalZero     ble_hs_hci_cmd_body_set_event_mask(event_mask, dst);
308*042d53a7SEvalZero }
309*042d53a7SEvalZero 
310*042d53a7SEvalZero void
ble_hs_hci_cmd_build_set_event_mask2(uint64_t event_mask,uint8_t * dst,int dst_len)311*042d53a7SEvalZero ble_hs_hci_cmd_build_set_event_mask2(uint64_t event_mask,
312*042d53a7SEvalZero                                      uint8_t *dst, int dst_len)
313*042d53a7SEvalZero {
314*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_SET_EVENT_MASK_LEN);
315*042d53a7SEvalZero 
316*042d53a7SEvalZero     ble_hs_hci_cmd_body_set_event_mask(event_mask, dst);
317*042d53a7SEvalZero }
318*042d53a7SEvalZero 
319*042d53a7SEvalZero static void
ble_hs_hci_cmd_body_disconnect(uint16_t handle,uint8_t reason,uint8_t * dst)320*042d53a7SEvalZero ble_hs_hci_cmd_body_disconnect(uint16_t handle, uint8_t reason, uint8_t *dst)
321*042d53a7SEvalZero {
322*042d53a7SEvalZero     put_le16(dst + 0, handle);
323*042d53a7SEvalZero     dst[2] = reason;
324*042d53a7SEvalZero }
325*042d53a7SEvalZero 
326*042d53a7SEvalZero void
ble_hs_hci_cmd_build_disconnect(uint16_t handle,uint8_t reason,uint8_t * dst,int dst_len)327*042d53a7SEvalZero ble_hs_hci_cmd_build_disconnect(uint16_t handle, uint8_t reason,
328*042d53a7SEvalZero                                 uint8_t *dst, int dst_len)
329*042d53a7SEvalZero {
330*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_DISCONNECT_CMD_LEN);
331*042d53a7SEvalZero 
332*042d53a7SEvalZero     ble_hs_hci_cmd_body_disconnect(handle, reason, dst);
333*042d53a7SEvalZero }
334*042d53a7SEvalZero 
335*042d53a7SEvalZero static void
ble_hs_hci_cmd_body_le_set_event_mask(uint64_t event_mask,uint8_t * dst)336*042d53a7SEvalZero ble_hs_hci_cmd_body_le_set_event_mask(uint64_t event_mask, uint8_t *dst)
337*042d53a7SEvalZero {
338*042d53a7SEvalZero     put_le64(dst, event_mask);
339*042d53a7SEvalZero }
340*042d53a7SEvalZero 
341*042d53a7SEvalZero void
ble_hs_hci_cmd_build_le_set_event_mask(uint64_t event_mask,uint8_t * dst,int dst_len)342*042d53a7SEvalZero ble_hs_hci_cmd_build_le_set_event_mask(uint64_t event_mask,
343*042d53a7SEvalZero                                        uint8_t *dst, int dst_len)
344*042d53a7SEvalZero {
345*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_SET_LE_EVENT_MASK_LEN);
346*042d53a7SEvalZero 
347*042d53a7SEvalZero     ble_hs_hci_cmd_body_le_set_event_mask(event_mask, dst);
348*042d53a7SEvalZero }
349*042d53a7SEvalZero 
350*042d53a7SEvalZero static void
ble_hs_hci_cmd_body_le_set_adv_enable(uint8_t enable,uint8_t * dst)351*042d53a7SEvalZero ble_hs_hci_cmd_body_le_set_adv_enable(uint8_t enable, uint8_t *dst)
352*042d53a7SEvalZero {
353*042d53a7SEvalZero     dst[0] = enable;
354*042d53a7SEvalZero }
355*042d53a7SEvalZero 
356*042d53a7SEvalZero void
ble_hs_hci_cmd_build_le_set_adv_enable(uint8_t enable,uint8_t * dst,int dst_len)357*042d53a7SEvalZero ble_hs_hci_cmd_build_le_set_adv_enable(uint8_t enable, uint8_t *dst,
358*042d53a7SEvalZero                                        int dst_len)
359*042d53a7SEvalZero {
360*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_SET_ADV_ENABLE_LEN);
361*042d53a7SEvalZero 
362*042d53a7SEvalZero     ble_hs_hci_cmd_body_le_set_adv_enable(enable, dst);
363*042d53a7SEvalZero }
364*042d53a7SEvalZero 
365*042d53a7SEvalZero static int
ble_hs_hci_cmd_body_le_set_scan_params(uint8_t scan_type,uint16_t scan_itvl,uint16_t scan_window,uint8_t own_addr_type,uint8_t filter_policy,uint8_t * dst)366*042d53a7SEvalZero ble_hs_hci_cmd_body_le_set_scan_params(
367*042d53a7SEvalZero     uint8_t scan_type, uint16_t scan_itvl, uint16_t scan_window,
368*042d53a7SEvalZero     uint8_t own_addr_type, uint8_t filter_policy, uint8_t *dst) {
369*042d53a7SEvalZero 
370*042d53a7SEvalZero     /* Make sure parameters are valid */
371*042d53a7SEvalZero     if ((scan_type != BLE_HCI_SCAN_TYPE_PASSIVE) &&
372*042d53a7SEvalZero         (scan_type != BLE_HCI_SCAN_TYPE_ACTIVE)) {
373*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
374*042d53a7SEvalZero     }
375*042d53a7SEvalZero 
376*042d53a7SEvalZero     /* Check interval and window */
377*042d53a7SEvalZero     if ((scan_itvl < BLE_HCI_SCAN_ITVL_MIN) ||
378*042d53a7SEvalZero         (scan_itvl > BLE_HCI_SCAN_ITVL_MAX) ||
379*042d53a7SEvalZero         (scan_window < BLE_HCI_SCAN_WINDOW_MIN) ||
380*042d53a7SEvalZero         (scan_window > BLE_HCI_SCAN_WINDOW_MAX) ||
381*042d53a7SEvalZero         (scan_itvl < scan_window)) {
382*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
383*042d53a7SEvalZero     }
384*042d53a7SEvalZero 
385*042d53a7SEvalZero     /* Check own addr type */
386*042d53a7SEvalZero     if (own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) {
387*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
388*042d53a7SEvalZero     }
389*042d53a7SEvalZero 
390*042d53a7SEvalZero     /* Check scanner filter policy */
391*042d53a7SEvalZero     if (filter_policy > BLE_HCI_SCAN_FILT_MAX) {
392*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
393*042d53a7SEvalZero     }
394*042d53a7SEvalZero 
395*042d53a7SEvalZero     dst[0] = scan_type;
396*042d53a7SEvalZero     put_le16(dst + 1, scan_itvl);
397*042d53a7SEvalZero     put_le16(dst + 3, scan_window);
398*042d53a7SEvalZero     dst[5] = own_addr_type;
399*042d53a7SEvalZero     dst[6] = filter_policy;
400*042d53a7SEvalZero 
401*042d53a7SEvalZero     return 0;
402*042d53a7SEvalZero }
403*042d53a7SEvalZero 
404*042d53a7SEvalZero int
ble_hs_hci_cmd_build_le_set_scan_params(uint8_t scan_type,uint16_t scan_itvl,uint16_t scan_window,uint8_t own_addr_type,uint8_t filter_policy,uint8_t * dst,int dst_len)405*042d53a7SEvalZero ble_hs_hci_cmd_build_le_set_scan_params(uint8_t scan_type,
406*042d53a7SEvalZero                                         uint16_t scan_itvl,
407*042d53a7SEvalZero                                         uint16_t scan_window,
408*042d53a7SEvalZero                                         uint8_t own_addr_type,
409*042d53a7SEvalZero                                         uint8_t filter_policy,
410*042d53a7SEvalZero                                         uint8_t *dst, int dst_len)
411*042d53a7SEvalZero {
412*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_SET_SCAN_PARAM_LEN);
413*042d53a7SEvalZero 
414*042d53a7SEvalZero     return ble_hs_hci_cmd_body_le_set_scan_params(scan_type, scan_itvl,
415*042d53a7SEvalZero                                               scan_window, own_addr_type,
416*042d53a7SEvalZero                                               filter_policy, dst);
417*042d53a7SEvalZero }
418*042d53a7SEvalZero 
419*042d53a7SEvalZero static void
ble_hs_hci_cmd_body_le_set_scan_enable(uint8_t enable,uint8_t filter_dups,uint8_t * dst)420*042d53a7SEvalZero ble_hs_hci_cmd_body_le_set_scan_enable(uint8_t enable, uint8_t filter_dups,
421*042d53a7SEvalZero                                        uint8_t *dst)
422*042d53a7SEvalZero {
423*042d53a7SEvalZero     dst[0] = enable;
424*042d53a7SEvalZero     dst[1] = filter_dups;
425*042d53a7SEvalZero }
426*042d53a7SEvalZero 
427*042d53a7SEvalZero void
ble_hs_hci_cmd_build_le_set_scan_enable(uint8_t enable,uint8_t filter_dups,uint8_t * dst,uint8_t dst_len)428*042d53a7SEvalZero ble_hs_hci_cmd_build_le_set_scan_enable(uint8_t enable, uint8_t filter_dups,
429*042d53a7SEvalZero                                         uint8_t *dst, uint8_t dst_len)
430*042d53a7SEvalZero {
431*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_SET_SCAN_ENABLE_LEN);
432*042d53a7SEvalZero 
433*042d53a7SEvalZero     ble_hs_hci_cmd_body_le_set_scan_enable(enable, filter_dups, dst);
434*042d53a7SEvalZero }
435*042d53a7SEvalZero 
436*042d53a7SEvalZero static int
ble_hs_hci_cmd_body_le_create_connection(const struct hci_create_conn * hcc,uint8_t * cmd)437*042d53a7SEvalZero ble_hs_hci_cmd_body_le_create_connection(const struct hci_create_conn *hcc,
438*042d53a7SEvalZero                                          uint8_t *cmd)
439*042d53a7SEvalZero {
440*042d53a7SEvalZero     /* Check scan interval and scan window */
441*042d53a7SEvalZero     if ((hcc->scan_itvl < BLE_HCI_SCAN_ITVL_MIN) ||
442*042d53a7SEvalZero         (hcc->scan_itvl > BLE_HCI_SCAN_ITVL_MAX) ||
443*042d53a7SEvalZero         (hcc->scan_window < BLE_HCI_SCAN_WINDOW_MIN) ||
444*042d53a7SEvalZero         (hcc->scan_window > BLE_HCI_SCAN_WINDOW_MAX) ||
445*042d53a7SEvalZero         (hcc->scan_itvl < hcc->scan_window)) {
446*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
447*042d53a7SEvalZero     }
448*042d53a7SEvalZero 
449*042d53a7SEvalZero     /* Check initiator filter policy */
450*042d53a7SEvalZero     if (hcc->filter_policy > BLE_HCI_CONN_FILT_MAX) {
451*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
452*042d53a7SEvalZero     }
453*042d53a7SEvalZero 
454*042d53a7SEvalZero     /* Check peer addr type */
455*042d53a7SEvalZero     if (hcc->peer_addr_type > BLE_HCI_CONN_PEER_ADDR_MAX) {
456*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
457*042d53a7SEvalZero     }
458*042d53a7SEvalZero 
459*042d53a7SEvalZero     /* Check own addr type */
460*042d53a7SEvalZero     if (hcc->own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) {
461*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
462*042d53a7SEvalZero     }
463*042d53a7SEvalZero 
464*042d53a7SEvalZero     /* Check connection interval min */
465*042d53a7SEvalZero     if ((hcc->conn_itvl_min < BLE_HCI_CONN_ITVL_MIN) ||
466*042d53a7SEvalZero         (hcc->conn_itvl_min > BLE_HCI_CONN_ITVL_MAX)) {
467*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
468*042d53a7SEvalZero     }
469*042d53a7SEvalZero 
470*042d53a7SEvalZero     /* Check connection interval max */
471*042d53a7SEvalZero     if ((hcc->conn_itvl_max < BLE_HCI_CONN_ITVL_MIN) ||
472*042d53a7SEvalZero         (hcc->conn_itvl_max > BLE_HCI_CONN_ITVL_MAX) ||
473*042d53a7SEvalZero         (hcc->conn_itvl_max < hcc->conn_itvl_min)) {
474*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
475*042d53a7SEvalZero     }
476*042d53a7SEvalZero 
477*042d53a7SEvalZero     /* Check connection latency */
478*042d53a7SEvalZero     if ((hcc->conn_latency < BLE_HCI_CONN_LATENCY_MIN) ||
479*042d53a7SEvalZero         (hcc->conn_latency > BLE_HCI_CONN_LATENCY_MAX)) {
480*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
481*042d53a7SEvalZero     }
482*042d53a7SEvalZero 
483*042d53a7SEvalZero     /* Check supervision timeout */
484*042d53a7SEvalZero     if ((hcc->supervision_timeout < BLE_HCI_CONN_SPVN_TIMEOUT_MIN) ||
485*042d53a7SEvalZero         (hcc->supervision_timeout > BLE_HCI_CONN_SPVN_TIMEOUT_MAX)) {
486*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
487*042d53a7SEvalZero     }
488*042d53a7SEvalZero 
489*042d53a7SEvalZero     /* Check connection event length */
490*042d53a7SEvalZero     if (hcc->min_ce_len > hcc->max_ce_len) {
491*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
492*042d53a7SEvalZero     }
493*042d53a7SEvalZero 
494*042d53a7SEvalZero     put_le16(cmd + 0, hcc->scan_itvl);
495*042d53a7SEvalZero     put_le16(cmd + 2, hcc->scan_window);
496*042d53a7SEvalZero     cmd[4] = hcc->filter_policy;
497*042d53a7SEvalZero     cmd[5] = hcc->peer_addr_type;
498*042d53a7SEvalZero     memcpy(cmd + 6, hcc->peer_addr, BLE_DEV_ADDR_LEN);
499*042d53a7SEvalZero     cmd[12] = hcc->own_addr_type;
500*042d53a7SEvalZero     put_le16(cmd + 13, hcc->conn_itvl_min);
501*042d53a7SEvalZero     put_le16(cmd + 15, hcc->conn_itvl_max);
502*042d53a7SEvalZero     put_le16(cmd + 17, hcc->conn_latency);
503*042d53a7SEvalZero     put_le16(cmd + 19, hcc->supervision_timeout);
504*042d53a7SEvalZero     put_le16(cmd + 21, hcc->min_ce_len);
505*042d53a7SEvalZero     put_le16(cmd + 23, hcc->max_ce_len);
506*042d53a7SEvalZero 
507*042d53a7SEvalZero     return 0;
508*042d53a7SEvalZero }
509*042d53a7SEvalZero 
510*042d53a7SEvalZero int
ble_hs_hci_cmd_build_le_create_connection(const struct hci_create_conn * hcc,uint8_t * cmd,int cmd_len)511*042d53a7SEvalZero ble_hs_hci_cmd_build_le_create_connection(const struct hci_create_conn *hcc,
512*042d53a7SEvalZero                                           uint8_t *cmd, int cmd_len)
513*042d53a7SEvalZero {
514*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(cmd_len >= BLE_HCI_CREATE_CONN_LEN);
515*042d53a7SEvalZero 
516*042d53a7SEvalZero     return ble_hs_hci_cmd_body_le_create_connection(hcc, cmd);
517*042d53a7SEvalZero }
518*042d53a7SEvalZero 
519*042d53a7SEvalZero int
ble_hs_hci_cmd_build_le_add_to_whitelist(const uint8_t * addr,uint8_t addr_type,uint8_t * dst,int dst_len)520*042d53a7SEvalZero ble_hs_hci_cmd_build_le_add_to_whitelist(const uint8_t *addr,
521*042d53a7SEvalZero                                          uint8_t addr_type,
522*042d53a7SEvalZero                                          uint8_t *dst, int dst_len)
523*042d53a7SEvalZero {
524*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_ADD_WHITE_LIST_LEN);
525*042d53a7SEvalZero 
526*042d53a7SEvalZero     return ble_hs_hci_cmd_body_le_whitelist_chg(addr, addr_type, dst);
527*042d53a7SEvalZero }
528*042d53a7SEvalZero 
529*042d53a7SEvalZero /**
530*042d53a7SEvalZero  * Reset the controller and link manager.
531*042d53a7SEvalZero  *
532*042d53a7SEvalZero  * @return int
533*042d53a7SEvalZero  */
534*042d53a7SEvalZero int
ble_hs_hci_cmd_reset(void)535*042d53a7SEvalZero ble_hs_hci_cmd_reset(void)
536*042d53a7SEvalZero {
537*042d53a7SEvalZero     return ble_hs_hci_cmd_send(BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND,
538*042d53a7SEvalZero                                           BLE_HCI_OCF_CB_RESET),
539*042d53a7SEvalZero                                0, NULL);
540*042d53a7SEvalZero }
541*042d53a7SEvalZero 
542*042d53a7SEvalZero /** Set controller to host flow control (OGF 0x03, OCF 0x0031). */
543*042d53a7SEvalZero int
ble_hs_hci_cmd_tx_set_ctlr_to_host_fc(uint8_t fc_enable)544*042d53a7SEvalZero ble_hs_hci_cmd_tx_set_ctlr_to_host_fc(uint8_t fc_enable)
545*042d53a7SEvalZero {
546*042d53a7SEvalZero     if (fc_enable > BLE_HCI_CTLR_TO_HOST_FC_BOTH) {
547*042d53a7SEvalZero         return BLE_HS_EINVAL;
548*042d53a7SEvalZero     }
549*042d53a7SEvalZero 
550*042d53a7SEvalZero     return ble_hs_hci_cmd_tx_empty_ack(
551*042d53a7SEvalZero         BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND,
552*042d53a7SEvalZero                    BLE_HCI_OCF_CB_SET_CTLR_TO_HOST_FC),
553*042d53a7SEvalZero         &fc_enable, 1);
554*042d53a7SEvalZero }
555*042d53a7SEvalZero 
556*042d53a7SEvalZero /* Host buffer size (OGF 0x03, OCF 0x0033). */
557*042d53a7SEvalZero int
ble_hs_hci_cmd_tx_host_buf_size(const struct hci_host_buf_size * cmd)558*042d53a7SEvalZero ble_hs_hci_cmd_tx_host_buf_size(const struct hci_host_buf_size *cmd)
559*042d53a7SEvalZero {
560*042d53a7SEvalZero     uint8_t buf[BLE_HCI_HOST_BUF_SIZE_LEN];
561*042d53a7SEvalZero 
562*042d53a7SEvalZero     put_le16(buf + 0, cmd->acl_pkt_len);
563*042d53a7SEvalZero     buf[2] = cmd->sync_pkt_len;
564*042d53a7SEvalZero     put_le16(buf + 3, cmd->num_acl_pkts);
565*042d53a7SEvalZero     put_le16(buf + 5, cmd->num_sync_pkts);
566*042d53a7SEvalZero 
567*042d53a7SEvalZero     return ble_hs_hci_cmd_tx_empty_ack(
568*042d53a7SEvalZero         BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, BLE_HCI_OCF_CB_HOST_BUF_SIZE),
569*042d53a7SEvalZero         buf, sizeof buf);
570*042d53a7SEvalZero }
571*042d53a7SEvalZero 
572*042d53a7SEvalZero /* Host number of completed packets (OGF 0x03, OCF 0x0035). */
573*042d53a7SEvalZero int
ble_hs_hci_cmd_build_host_num_comp_pkts_entry(const struct hci_host_num_comp_pkts_entry * entry,uint8_t * dst,int dst_len)574*042d53a7SEvalZero ble_hs_hci_cmd_build_host_num_comp_pkts_entry(
575*042d53a7SEvalZero     const struct hci_host_num_comp_pkts_entry *entry,
576*042d53a7SEvalZero     uint8_t *dst, int dst_len)
577*042d53a7SEvalZero {
578*042d53a7SEvalZero     if (dst_len < BLE_HCI_HOST_NUM_COMP_PKTS_ENT_LEN) {
579*042d53a7SEvalZero         return BLE_HS_EMSGSIZE;
580*042d53a7SEvalZero     }
581*042d53a7SEvalZero 
582*042d53a7SEvalZero     put_le16(dst + 0, entry->conn_handle);
583*042d53a7SEvalZero     put_le16(dst + 2, entry->num_pkts);
584*042d53a7SEvalZero 
585*042d53a7SEvalZero     return 0;
586*042d53a7SEvalZero }
587*042d53a7SEvalZero 
588*042d53a7SEvalZero /**
589*042d53a7SEvalZero  * Read the transmit power level used for LE advertising channel packets.
590*042d53a7SEvalZero  *
591*042d53a7SEvalZero  * @return int
592*042d53a7SEvalZero  */
593*042d53a7SEvalZero int
ble_hs_hci_cmd_read_adv_pwr(void)594*042d53a7SEvalZero ble_hs_hci_cmd_read_adv_pwr(void)
595*042d53a7SEvalZero {
596*042d53a7SEvalZero     return ble_hs_hci_cmd_send(BLE_HCI_OP(BLE_HCI_OGF_LE,
597*042d53a7SEvalZero                                           BLE_HCI_OCF_LE_RD_ADV_CHAN_TXPWR),
598*042d53a7SEvalZero                                0, NULL);
599*042d53a7SEvalZero }
600*042d53a7SEvalZero 
601*042d53a7SEvalZero int
ble_hs_hci_cmd_le_create_conn_cancel(void)602*042d53a7SEvalZero ble_hs_hci_cmd_le_create_conn_cancel(void)
603*042d53a7SEvalZero {
604*042d53a7SEvalZero     return ble_hs_hci_cmd_send(BLE_HCI_OP(BLE_HCI_OGF_LE,
605*042d53a7SEvalZero                                           BLE_HCI_OCF_LE_CREATE_CONN_CANCEL),
606*042d53a7SEvalZero                                0, NULL);
607*042d53a7SEvalZero }
608*042d53a7SEvalZero 
609*042d53a7SEvalZero static int
ble_hs_hci_cmd_body_le_conn_update(const struct hci_conn_update * hcu,uint8_t * dst)610*042d53a7SEvalZero ble_hs_hci_cmd_body_le_conn_update(const struct hci_conn_update *hcu,
611*042d53a7SEvalZero                                    uint8_t *dst)
612*042d53a7SEvalZero {
613*042d53a7SEvalZero     /* XXX: add parameter checking later */
614*042d53a7SEvalZero     put_le16(dst + 0, hcu->handle);
615*042d53a7SEvalZero     put_le16(dst + 2, hcu->conn_itvl_min);
616*042d53a7SEvalZero     put_le16(dst + 4, hcu->conn_itvl_max);
617*042d53a7SEvalZero     put_le16(dst + 6, hcu->conn_latency);
618*042d53a7SEvalZero     put_le16(dst + 8, hcu->supervision_timeout);
619*042d53a7SEvalZero     put_le16(dst + 10, hcu->min_ce_len);
620*042d53a7SEvalZero     put_le16(dst + 12, hcu->max_ce_len);
621*042d53a7SEvalZero 
622*042d53a7SEvalZero     return 0;
623*042d53a7SEvalZero }
624*042d53a7SEvalZero 
625*042d53a7SEvalZero int
ble_hs_hci_cmd_build_le_conn_update(const struct hci_conn_update * hcu,uint8_t * dst,int dst_len)626*042d53a7SEvalZero ble_hs_hci_cmd_build_le_conn_update(const struct hci_conn_update *hcu,
627*042d53a7SEvalZero                                     uint8_t *dst, int dst_len)
628*042d53a7SEvalZero {
629*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CONN_UPDATE_LEN);
630*042d53a7SEvalZero 
631*042d53a7SEvalZero     return ble_hs_hci_cmd_body_le_conn_update(hcu, dst);
632*042d53a7SEvalZero }
633*042d53a7SEvalZero 
634*042d53a7SEvalZero int
ble_hs_hci_cmd_le_conn_update(const struct hci_conn_update * hcu)635*042d53a7SEvalZero ble_hs_hci_cmd_le_conn_update(const struct hci_conn_update *hcu)
636*042d53a7SEvalZero {
637*042d53a7SEvalZero     uint8_t cmd[BLE_HCI_CONN_UPDATE_LEN];
638*042d53a7SEvalZero     int rc;
639*042d53a7SEvalZero 
640*042d53a7SEvalZero     rc = ble_hs_hci_cmd_body_le_conn_update(hcu, cmd);
641*042d53a7SEvalZero     if (rc != 0) {
642*042d53a7SEvalZero         return rc;
643*042d53a7SEvalZero     }
644*042d53a7SEvalZero 
645*042d53a7SEvalZero     return ble_hs_hci_cmd_le_send(BLE_HCI_OCF_LE_CONN_UPDATE,
646*042d53a7SEvalZero                               BLE_HCI_CONN_UPDATE_LEN, cmd);
647*042d53a7SEvalZero }
648*042d53a7SEvalZero 
649*042d53a7SEvalZero static void
ble_hs_hci_cmd_body_le_lt_key_req_reply(const struct hci_lt_key_req_reply * hkr,uint8_t * dst)650*042d53a7SEvalZero ble_hs_hci_cmd_body_le_lt_key_req_reply(const struct hci_lt_key_req_reply *hkr,
651*042d53a7SEvalZero                                         uint8_t *dst)
652*042d53a7SEvalZero {
653*042d53a7SEvalZero     put_le16(dst + 0, hkr->conn_handle);
654*042d53a7SEvalZero     memcpy(dst + 2, hkr->long_term_key, sizeof hkr->long_term_key);
655*042d53a7SEvalZero }
656*042d53a7SEvalZero 
657*042d53a7SEvalZero /**
658*042d53a7SEvalZero  * Sends the long-term key (LTK) to the controller.
659*042d53a7SEvalZero  *
660*042d53a7SEvalZero  * Note: This function expects the 128-bit key to be in little-endian byte
661*042d53a7SEvalZero  * order.
662*042d53a7SEvalZero  *
663*042d53a7SEvalZero  * OGF = 0x08 (LE)
664*042d53a7SEvalZero  * OCF = 0x001a
665*042d53a7SEvalZero  *
666*042d53a7SEvalZero  * @param key
667*042d53a7SEvalZero  * @param pt
668*042d53a7SEvalZero  *
669*042d53a7SEvalZero  * @return int
670*042d53a7SEvalZero  */
671*042d53a7SEvalZero void
ble_hs_hci_cmd_build_le_lt_key_req_reply(const struct hci_lt_key_req_reply * hkr,uint8_t * dst,int dst_len)672*042d53a7SEvalZero ble_hs_hci_cmd_build_le_lt_key_req_reply(
673*042d53a7SEvalZero     const struct hci_lt_key_req_reply *hkr, uint8_t *dst, int dst_len)
674*042d53a7SEvalZero {
675*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_LT_KEY_REQ_REPLY_LEN);
676*042d53a7SEvalZero 
677*042d53a7SEvalZero     ble_hs_hci_cmd_body_le_lt_key_req_reply(hkr, dst);
678*042d53a7SEvalZero }
679*042d53a7SEvalZero 
680*042d53a7SEvalZero void
ble_hs_hci_cmd_build_le_lt_key_req_neg_reply(uint16_t conn_handle,uint8_t * dst,int dst_len)681*042d53a7SEvalZero ble_hs_hci_cmd_build_le_lt_key_req_neg_reply(uint16_t conn_handle,
682*042d53a7SEvalZero                                              uint8_t *dst, int dst_len)
683*042d53a7SEvalZero {
684*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_LT_KEY_REQ_NEG_REPLY_LEN);
685*042d53a7SEvalZero 
686*042d53a7SEvalZero     put_le16(dst, conn_handle);
687*042d53a7SEvalZero }
688*042d53a7SEvalZero 
689*042d53a7SEvalZero static void
ble_hs_hci_cmd_body_le_conn_param_reply(const struct hci_conn_param_reply * hcr,uint8_t * dst)690*042d53a7SEvalZero ble_hs_hci_cmd_body_le_conn_param_reply(const struct hci_conn_param_reply *hcr,
691*042d53a7SEvalZero                                         uint8_t *dst)
692*042d53a7SEvalZero {
693*042d53a7SEvalZero     put_le16(dst + 0, hcr->handle);
694*042d53a7SEvalZero     put_le16(dst + 2, hcr->conn_itvl_min);
695*042d53a7SEvalZero     put_le16(dst + 4, hcr->conn_itvl_max);
696*042d53a7SEvalZero     put_le16(dst + 6, hcr->conn_latency);
697*042d53a7SEvalZero     put_le16(dst + 8, hcr->supervision_timeout);
698*042d53a7SEvalZero     put_le16(dst + 10, hcr->min_ce_len);
699*042d53a7SEvalZero     put_le16(dst + 12, hcr->max_ce_len);
700*042d53a7SEvalZero }
701*042d53a7SEvalZero 
702*042d53a7SEvalZero void
ble_hs_hci_cmd_build_le_conn_param_reply(const struct hci_conn_param_reply * hcr,uint8_t * dst,int dst_len)703*042d53a7SEvalZero ble_hs_hci_cmd_build_le_conn_param_reply(
704*042d53a7SEvalZero     const struct hci_conn_param_reply *hcr, uint8_t *dst, int dst_len)
705*042d53a7SEvalZero {
706*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CONN_PARAM_REPLY_LEN);
707*042d53a7SEvalZero 
708*042d53a7SEvalZero     ble_hs_hci_cmd_body_le_conn_param_reply(hcr, dst);
709*042d53a7SEvalZero }
710*042d53a7SEvalZero 
711*042d53a7SEvalZero int
ble_hs_hci_cmd_le_conn_param_reply(const struct hci_conn_param_reply * hcr)712*042d53a7SEvalZero ble_hs_hci_cmd_le_conn_param_reply(const struct hci_conn_param_reply *hcr)
713*042d53a7SEvalZero {
714*042d53a7SEvalZero     uint8_t cmd[BLE_HCI_CONN_PARAM_REPLY_LEN];
715*042d53a7SEvalZero 
716*042d53a7SEvalZero     put_le16(cmd + 0, hcr->handle);
717*042d53a7SEvalZero     put_le16(cmd + 2, hcr->conn_itvl_min);
718*042d53a7SEvalZero     put_le16(cmd + 4, hcr->conn_itvl_max);
719*042d53a7SEvalZero     put_le16(cmd + 6, hcr->conn_latency);
720*042d53a7SEvalZero     put_le16(cmd + 8, hcr->supervision_timeout);
721*042d53a7SEvalZero     put_le16(cmd + 10, hcr->min_ce_len);
722*042d53a7SEvalZero     put_le16(cmd + 12, hcr->max_ce_len);
723*042d53a7SEvalZero 
724*042d53a7SEvalZero     return ble_hs_hci_cmd_le_send(BLE_HCI_OCF_LE_REM_CONN_PARAM_RR,
725*042d53a7SEvalZero                               BLE_HCI_CONN_PARAM_REPLY_LEN, cmd);
726*042d53a7SEvalZero }
727*042d53a7SEvalZero 
728*042d53a7SEvalZero static void
ble_hs_hci_cmd_body_le_conn_param_neg_reply(const struct hci_conn_param_neg_reply * hcn,uint8_t * dst)729*042d53a7SEvalZero ble_hs_hci_cmd_body_le_conn_param_neg_reply(
730*042d53a7SEvalZero     const struct hci_conn_param_neg_reply *hcn, uint8_t *dst)
731*042d53a7SEvalZero {
732*042d53a7SEvalZero     put_le16(dst + 0, hcn->handle);
733*042d53a7SEvalZero     dst[2] = hcn->reason;
734*042d53a7SEvalZero }
735*042d53a7SEvalZero 
736*042d53a7SEvalZero 
737*042d53a7SEvalZero void
ble_hs_hci_cmd_build_le_conn_param_neg_reply(const struct hci_conn_param_neg_reply * hcn,uint8_t * dst,int dst_len)738*042d53a7SEvalZero ble_hs_hci_cmd_build_le_conn_param_neg_reply(
739*042d53a7SEvalZero     const struct hci_conn_param_neg_reply *hcn, uint8_t *dst, int dst_len)
740*042d53a7SEvalZero {
741*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CONN_PARAM_NEG_REPLY_LEN);
742*042d53a7SEvalZero 
743*042d53a7SEvalZero     ble_hs_hci_cmd_body_le_conn_param_neg_reply(hcn, dst);
744*042d53a7SEvalZero }
745*042d53a7SEvalZero 
746*042d53a7SEvalZero int
ble_hs_hci_cmd_le_conn_param_neg_reply(const struct hci_conn_param_neg_reply * hcn)747*042d53a7SEvalZero ble_hs_hci_cmd_le_conn_param_neg_reply(
748*042d53a7SEvalZero     const struct hci_conn_param_neg_reply *hcn)
749*042d53a7SEvalZero {
750*042d53a7SEvalZero     uint8_t cmd[BLE_HCI_CONN_PARAM_NEG_REPLY_LEN];
751*042d53a7SEvalZero 
752*042d53a7SEvalZero     ble_hs_hci_cmd_body_le_conn_param_neg_reply(hcn, cmd);
753*042d53a7SEvalZero 
754*042d53a7SEvalZero     return ble_hs_hci_cmd_le_send(BLE_HCI_OCF_LE_REM_CONN_PARAM_NRR,
755*042d53a7SEvalZero                               BLE_HCI_CONN_PARAM_NEG_REPLY_LEN, cmd);
756*042d53a7SEvalZero }
757*042d53a7SEvalZero 
758*042d53a7SEvalZero static void
ble_hs_hci_cmd_body_le_start_encrypt(const struct hci_start_encrypt * cmd,uint8_t * dst)759*042d53a7SEvalZero ble_hs_hci_cmd_body_le_start_encrypt(const struct hci_start_encrypt *cmd,
760*042d53a7SEvalZero                                      uint8_t *dst)
761*042d53a7SEvalZero {
762*042d53a7SEvalZero     put_le16(dst + 0, cmd->connection_handle);
763*042d53a7SEvalZero     put_le64(dst + 2, cmd->random_number);
764*042d53a7SEvalZero     put_le16(dst + 10, cmd->encrypted_diversifier);
765*042d53a7SEvalZero     memcpy(dst + 12, cmd->long_term_key, sizeof cmd->long_term_key);
766*042d53a7SEvalZero }
767*042d53a7SEvalZero 
768*042d53a7SEvalZero /*
769*042d53a7SEvalZero  * OGF=0x08 OCF=0x0019
770*042d53a7SEvalZero  */
771*042d53a7SEvalZero void
ble_hs_hci_cmd_build_le_start_encrypt(const struct hci_start_encrypt * cmd,uint8_t * dst,int dst_len)772*042d53a7SEvalZero ble_hs_hci_cmd_build_le_start_encrypt(const struct hci_start_encrypt *cmd,
773*042d53a7SEvalZero                                       uint8_t *dst, int dst_len)
774*042d53a7SEvalZero {
775*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_LE_START_ENCRYPT_LEN);
776*042d53a7SEvalZero 
777*042d53a7SEvalZero     ble_hs_hci_cmd_body_le_start_encrypt(cmd, dst);
778*042d53a7SEvalZero }
779*042d53a7SEvalZero 
780*042d53a7SEvalZero /**
781*042d53a7SEvalZero  * Read the RSSI for a given connection handle
782*042d53a7SEvalZero  *
783*042d53a7SEvalZero  * NOTE: OGF=0x05 OCF=0x0005
784*042d53a7SEvalZero  *
785*042d53a7SEvalZero  * @param handle
786*042d53a7SEvalZero  *
787*042d53a7SEvalZero  * @return int
788*042d53a7SEvalZero  */
789*042d53a7SEvalZero static void
ble_hs_hci_cmd_body_read_rssi(uint16_t handle,uint8_t * dst)790*042d53a7SEvalZero ble_hs_hci_cmd_body_read_rssi(uint16_t handle, uint8_t *dst)
791*042d53a7SEvalZero {
792*042d53a7SEvalZero     put_le16(dst, handle);
793*042d53a7SEvalZero }
794*042d53a7SEvalZero 
795*042d53a7SEvalZero void
ble_hs_hci_cmd_build_read_rssi(uint16_t handle,uint8_t * dst,int dst_len)796*042d53a7SEvalZero ble_hs_hci_cmd_build_read_rssi(uint16_t handle, uint8_t *dst, int dst_len)
797*042d53a7SEvalZero {
798*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_READ_RSSI_LEN);
799*042d53a7SEvalZero 
800*042d53a7SEvalZero     ble_hs_hci_cmd_body_read_rssi(handle, dst);
801*042d53a7SEvalZero }
802*042d53a7SEvalZero 
803*042d53a7SEvalZero /**
804*042d53a7SEvalZero  * LE Set Host Channel Classification
805*042d53a7SEvalZero  *
806*042d53a7SEvalZero  * OGF = 0x08 (LE)
807*042d53a7SEvalZero  * OCF = 0x0014
808*042d53a7SEvalZero  */
809*042d53a7SEvalZero void
ble_hs_hci_cmd_build_le_set_host_chan_class(const uint8_t * chan_map,uint8_t * dst,int dst_len)810*042d53a7SEvalZero ble_hs_hci_cmd_build_le_set_host_chan_class(const uint8_t *chan_map,
811*042d53a7SEvalZero                                             uint8_t *dst, int dst_len)
812*042d53a7SEvalZero {
813*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_SET_HOST_CHAN_CLASS_LEN);
814*042d53a7SEvalZero 
815*042d53a7SEvalZero     memcpy(dst, chan_map, BLE_HCI_SET_HOST_CHAN_CLASS_LEN);
816*042d53a7SEvalZero }
817*042d53a7SEvalZero 
818*042d53a7SEvalZero /**
819*042d53a7SEvalZero  * LE Read Channel Map
820*042d53a7SEvalZero  *
821*042d53a7SEvalZero  * OGF = 0x08 (LE)
822*042d53a7SEvalZero  * OCF = 0x0015
823*042d53a7SEvalZero  */
824*042d53a7SEvalZero void
ble_hs_hci_cmd_build_le_read_chan_map(uint16_t conn_handle,uint8_t * dst,int dst_len)825*042d53a7SEvalZero ble_hs_hci_cmd_build_le_read_chan_map(uint16_t conn_handle,
826*042d53a7SEvalZero                                       uint8_t *dst, int dst_len)
827*042d53a7SEvalZero {
828*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_RD_CHANMAP_LEN);
829*042d53a7SEvalZero 
830*042d53a7SEvalZero     put_le16(dst + 0, conn_handle);
831*042d53a7SEvalZero }
832*042d53a7SEvalZero 
833*042d53a7SEvalZero static int
ble_hs_hci_cmd_body_set_data_len(uint16_t connection_handle,uint16_t tx_octets,uint16_t tx_time,uint8_t * dst)834*042d53a7SEvalZero ble_hs_hci_cmd_body_set_data_len(uint16_t connection_handle,
835*042d53a7SEvalZero                                  uint16_t tx_octets,
836*042d53a7SEvalZero                                  uint16_t tx_time, uint8_t *dst)
837*042d53a7SEvalZero {
838*042d53a7SEvalZero 
839*042d53a7SEvalZero     if (tx_octets < BLE_HCI_SET_DATALEN_TX_OCTETS_MIN ||
840*042d53a7SEvalZero         tx_octets > BLE_HCI_SET_DATALEN_TX_OCTETS_MAX) {
841*042d53a7SEvalZero 
842*042d53a7SEvalZero         return BLE_HS_EINVAL;
843*042d53a7SEvalZero     }
844*042d53a7SEvalZero 
845*042d53a7SEvalZero     if (tx_time < BLE_HCI_SET_DATALEN_TX_TIME_MIN ||
846*042d53a7SEvalZero         tx_time > BLE_HCI_SET_DATALEN_TX_TIME_MAX) {
847*042d53a7SEvalZero 
848*042d53a7SEvalZero         return BLE_HS_EINVAL;
849*042d53a7SEvalZero     }
850*042d53a7SEvalZero 
851*042d53a7SEvalZero     put_le16(dst + 0, connection_handle);
852*042d53a7SEvalZero     put_le16(dst + 2, tx_octets);
853*042d53a7SEvalZero     put_le16(dst + 4, tx_time);
854*042d53a7SEvalZero 
855*042d53a7SEvalZero     return 0;
856*042d53a7SEvalZero }
857*042d53a7SEvalZero 
858*042d53a7SEvalZero /*
859*042d53a7SEvalZero  * OGF=0x08 OCF=0x0022
860*042d53a7SEvalZero  */
861*042d53a7SEvalZero int
ble_hs_hci_cmd_build_set_data_len(uint16_t connection_handle,uint16_t tx_octets,uint16_t tx_time,uint8_t * dst,int dst_len)862*042d53a7SEvalZero ble_hs_hci_cmd_build_set_data_len(uint16_t connection_handle,
863*042d53a7SEvalZero                                   uint16_t tx_octets, uint16_t tx_time,
864*042d53a7SEvalZero                                   uint8_t *dst, int dst_len)
865*042d53a7SEvalZero {
866*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_SET_DATALEN_LEN);
867*042d53a7SEvalZero 
868*042d53a7SEvalZero     return ble_hs_hci_cmd_body_set_data_len(connection_handle, tx_octets,
869*042d53a7SEvalZero                                           tx_time, dst);
870*042d53a7SEvalZero }
871*042d53a7SEvalZero 
872*042d53a7SEvalZero /**
873*042d53a7SEvalZero  * IRKs are in little endian.
874*042d53a7SEvalZero  */
875*042d53a7SEvalZero static int
ble_hs_hci_cmd_body_add_to_resolv_list(uint8_t addr_type,const uint8_t * addr,const uint8_t * peer_irk,const uint8_t * local_irk,uint8_t * dst)876*042d53a7SEvalZero ble_hs_hci_cmd_body_add_to_resolv_list(uint8_t addr_type, const uint8_t *addr,
877*042d53a7SEvalZero                                        const uint8_t *peer_irk,
878*042d53a7SEvalZero                                        const uint8_t *local_irk,
879*042d53a7SEvalZero                                        uint8_t *dst)
880*042d53a7SEvalZero {
881*042d53a7SEvalZero     if (addr_type > BLE_ADDR_RANDOM) {
882*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
883*042d53a7SEvalZero     }
884*042d53a7SEvalZero 
885*042d53a7SEvalZero     dst[0] = addr_type;
886*042d53a7SEvalZero     memcpy(dst + 1, addr, BLE_DEV_ADDR_LEN);
887*042d53a7SEvalZero     memcpy(dst + 1 + 6, peer_irk , 16);
888*042d53a7SEvalZero     memcpy(dst + 1 + 6 + 16, local_irk , 16);
889*042d53a7SEvalZero     /* 16 + 16 + 6 + 1 == 39 */
890*042d53a7SEvalZero     return 0;
891*042d53a7SEvalZero }
892*042d53a7SEvalZero 
893*042d53a7SEvalZero /**
894*042d53a7SEvalZero  * OGF=0x08 OCF=0x0027
895*042d53a7SEvalZero  *
896*042d53a7SEvalZero  * IRKs are in little endian.
897*042d53a7SEvalZero  */
898*042d53a7SEvalZero int
ble_hs_hci_cmd_build_add_to_resolv_list(const struct hci_add_dev_to_resolving_list * padd,uint8_t * dst,int dst_len)899*042d53a7SEvalZero ble_hs_hci_cmd_build_add_to_resolv_list(
900*042d53a7SEvalZero     const struct hci_add_dev_to_resolving_list *padd,
901*042d53a7SEvalZero     uint8_t *dst,
902*042d53a7SEvalZero     int dst_len)
903*042d53a7SEvalZero {
904*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_ADD_TO_RESOLV_LIST_LEN);
905*042d53a7SEvalZero 
906*042d53a7SEvalZero     return ble_hs_hci_cmd_body_add_to_resolv_list(
907*042d53a7SEvalZero             padd->addr_type, padd->addr, padd->peer_irk, padd->local_irk, dst);
908*042d53a7SEvalZero }
909*042d53a7SEvalZero 
910*042d53a7SEvalZero static int
ble_hs_hci_cmd_body_remove_from_resolv_list(uint8_t addr_type,const uint8_t * addr,uint8_t * dst)911*042d53a7SEvalZero ble_hs_hci_cmd_body_remove_from_resolv_list(uint8_t addr_type,
912*042d53a7SEvalZero                                             const uint8_t *addr,
913*042d53a7SEvalZero                                             uint8_t *dst)
914*042d53a7SEvalZero {
915*042d53a7SEvalZero     if (addr_type > BLE_ADDR_RANDOM) {
916*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
917*042d53a7SEvalZero     }
918*042d53a7SEvalZero 
919*042d53a7SEvalZero     dst[0] = addr_type;
920*042d53a7SEvalZero     memcpy(dst + 1, addr, BLE_DEV_ADDR_LEN);
921*042d53a7SEvalZero     return 0;
922*042d53a7SEvalZero }
923*042d53a7SEvalZero 
924*042d53a7SEvalZero 
925*042d53a7SEvalZero int
ble_hs_hci_cmd_build_remove_from_resolv_list(uint8_t addr_type,const uint8_t * addr,uint8_t * dst,int dst_len)926*042d53a7SEvalZero ble_hs_hci_cmd_build_remove_from_resolv_list(uint8_t addr_type,
927*042d53a7SEvalZero                                              const uint8_t *addr,
928*042d53a7SEvalZero                                              uint8_t *dst, int dst_len)
929*042d53a7SEvalZero {
930*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_RMV_FROM_RESOLV_LIST_LEN);
931*042d53a7SEvalZero 
932*042d53a7SEvalZero     return ble_hs_hci_cmd_body_remove_from_resolv_list(addr_type, addr, dst);
933*042d53a7SEvalZero }
934*042d53a7SEvalZero 
935*042d53a7SEvalZero static int
ble_hs_hci_cmd_body_read_peer_resolv_addr(uint8_t peer_identity_addr_type,const uint8_t * peer_identity_addr,uint8_t * dst)936*042d53a7SEvalZero ble_hs_hci_cmd_body_read_peer_resolv_addr(uint8_t peer_identity_addr_type,
937*042d53a7SEvalZero                                           const uint8_t *peer_identity_addr,
938*042d53a7SEvalZero                                           uint8_t *dst)
939*042d53a7SEvalZero {
940*042d53a7SEvalZero     if (peer_identity_addr_type > BLE_ADDR_RANDOM) {
941*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
942*042d53a7SEvalZero     }
943*042d53a7SEvalZero 
944*042d53a7SEvalZero     dst[0] = peer_identity_addr_type;
945*042d53a7SEvalZero     memcpy(dst + 1, peer_identity_addr, BLE_DEV_ADDR_LEN);
946*042d53a7SEvalZero     return 0;
947*042d53a7SEvalZero }
948*042d53a7SEvalZero 
949*042d53a7SEvalZero int
ble_hs_hci_cmd_build_read_peer_resolv_addr(uint8_t peer_identity_addr_type,const uint8_t * peer_identity_addr,uint8_t * dst,int dst_len)950*042d53a7SEvalZero ble_hs_hci_cmd_build_read_peer_resolv_addr(uint8_t peer_identity_addr_type,
951*042d53a7SEvalZero                                            const uint8_t *peer_identity_addr,
952*042d53a7SEvalZero                                            uint8_t *dst,
953*042d53a7SEvalZero                                            int dst_len)
954*042d53a7SEvalZero {
955*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_RD_PEER_RESOLV_ADDR_LEN);
956*042d53a7SEvalZero 
957*042d53a7SEvalZero     return ble_hs_hci_cmd_body_read_peer_resolv_addr(peer_identity_addr_type,
958*042d53a7SEvalZero                                                    peer_identity_addr, dst);
959*042d53a7SEvalZero }
960*042d53a7SEvalZero 
961*042d53a7SEvalZero static int
ble_hs_hci_cmd_body_read_lcl_resolv_addr(uint8_t local_identity_addr_type,const uint8_t * local_identity_addr,uint8_t * dst)962*042d53a7SEvalZero ble_hs_hci_cmd_body_read_lcl_resolv_addr(
963*042d53a7SEvalZero     uint8_t local_identity_addr_type,
964*042d53a7SEvalZero     const uint8_t *local_identity_addr,
965*042d53a7SEvalZero     uint8_t *dst)
966*042d53a7SEvalZero {
967*042d53a7SEvalZero     if (local_identity_addr_type > BLE_ADDR_RANDOM) {
968*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
969*042d53a7SEvalZero     }
970*042d53a7SEvalZero 
971*042d53a7SEvalZero     dst[0] = local_identity_addr_type;
972*042d53a7SEvalZero     memcpy(dst + 1, local_identity_addr, BLE_DEV_ADDR_LEN);
973*042d53a7SEvalZero     return 0;
974*042d53a7SEvalZero }
975*042d53a7SEvalZero 
976*042d53a7SEvalZero /*
977*042d53a7SEvalZero  * OGF=0x08 OCF=0x002c
978*042d53a7SEvalZero  */
979*042d53a7SEvalZero int
ble_hs_hci_cmd_build_read_lcl_resolv_addr(uint8_t local_identity_addr_type,const uint8_t * local_identity_addr,uint8_t * dst,int dst_len)980*042d53a7SEvalZero ble_hs_hci_cmd_build_read_lcl_resolv_addr(uint8_t local_identity_addr_type,
981*042d53a7SEvalZero                                           const uint8_t *local_identity_addr,
982*042d53a7SEvalZero                                           uint8_t *dst,
983*042d53a7SEvalZero                                           int dst_len)
984*042d53a7SEvalZero {
985*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_RD_LOC_RESOLV_ADDR_LEN);
986*042d53a7SEvalZero 
987*042d53a7SEvalZero     return ble_hs_hci_cmd_body_read_lcl_resolv_addr(local_identity_addr_type,
988*042d53a7SEvalZero                                                   local_identity_addr, dst);
989*042d53a7SEvalZero }
990*042d53a7SEvalZero 
991*042d53a7SEvalZero static int
ble_hs_hci_cmd_body_set_addr_res_en(uint8_t enable,uint8_t * dst)992*042d53a7SEvalZero ble_hs_hci_cmd_body_set_addr_res_en(uint8_t enable, uint8_t *dst)
993*042d53a7SEvalZero {
994*042d53a7SEvalZero     if (enable > 1) {
995*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
996*042d53a7SEvalZero     }
997*042d53a7SEvalZero 
998*042d53a7SEvalZero     dst[0] = enable;
999*042d53a7SEvalZero     return 0;
1000*042d53a7SEvalZero }
1001*042d53a7SEvalZero 
1002*042d53a7SEvalZero /*
1003*042d53a7SEvalZero  * OGF=0x08 OCF=0x002d
1004*042d53a7SEvalZero  */
1005*042d53a7SEvalZero int
ble_hs_hci_cmd_build_set_addr_res_en(uint8_t enable,uint8_t * dst,int dst_len)1006*042d53a7SEvalZero ble_hs_hci_cmd_build_set_addr_res_en(uint8_t enable, uint8_t *dst, int dst_len)
1007*042d53a7SEvalZero {
1008*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_SET_ADDR_RESOL_ENA_LEN);
1009*042d53a7SEvalZero 
1010*042d53a7SEvalZero     return ble_hs_hci_cmd_body_set_addr_res_en(enable, dst);
1011*042d53a7SEvalZero }
1012*042d53a7SEvalZero 
1013*042d53a7SEvalZero static int
ble_hs_hci_cmd_body_set_resolv_priv_addr_timeout(uint16_t timeout,uint8_t * dst)1014*042d53a7SEvalZero ble_hs_hci_cmd_body_set_resolv_priv_addr_timeout(uint16_t timeout,
1015*042d53a7SEvalZero                                                  uint8_t *dst)
1016*042d53a7SEvalZero {
1017*042d53a7SEvalZero     if (timeout == 0 || timeout > 0xA1B8) {
1018*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
1019*042d53a7SEvalZero     }
1020*042d53a7SEvalZero 
1021*042d53a7SEvalZero     put_le16(dst, timeout);
1022*042d53a7SEvalZero     return 0;
1023*042d53a7SEvalZero }
1024*042d53a7SEvalZero 
1025*042d53a7SEvalZero /*
1026*042d53a7SEvalZero  * OGF=0x08 OCF=0x002e
1027*042d53a7SEvalZero  */
1028*042d53a7SEvalZero int
ble_hs_hci_cmd_build_set_resolv_priv_addr_timeout(uint16_t timeout,uint8_t * dst,int dst_len)1029*042d53a7SEvalZero ble_hs_hci_cmd_build_set_resolv_priv_addr_timeout(
1030*042d53a7SEvalZero     uint16_t timeout, uint8_t *dst, int dst_len)
1031*042d53a7SEvalZero {
1032*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_SET_RESOLV_PRIV_ADDR_TO_LEN);
1033*042d53a7SEvalZero 
1034*042d53a7SEvalZero     return ble_hs_hci_cmd_body_set_resolv_priv_addr_timeout(timeout, dst);
1035*042d53a7SEvalZero }
1036*042d53a7SEvalZero 
1037*042d53a7SEvalZero /*
1038*042d53a7SEvalZero  * OGF=0x08 OCF=0x0030
1039*042d53a7SEvalZero  */
1040*042d53a7SEvalZero int
ble_hs_hci_cmd_build_le_read_phy(uint16_t conn_handle,uint8_t * dst,int dst_len)1041*042d53a7SEvalZero ble_hs_hci_cmd_build_le_read_phy(uint16_t conn_handle, uint8_t *dst, int dst_len)
1042*042d53a7SEvalZero {
1043*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_LE_RD_PHY_LEN);
1044*042d53a7SEvalZero 
1045*042d53a7SEvalZero     put_le16(dst, conn_handle);
1046*042d53a7SEvalZero 
1047*042d53a7SEvalZero     return 0;
1048*042d53a7SEvalZero }
1049*042d53a7SEvalZero 
1050*042d53a7SEvalZero static int
ble_hs_hci_verify_le_phy_params(uint8_t tx_phys_mask,uint8_t rx_phys_mask,uint16_t phy_opts)1051*042d53a7SEvalZero ble_hs_hci_verify_le_phy_params(uint8_t tx_phys_mask, uint8_t rx_phys_mask,
1052*042d53a7SEvalZero                                 uint16_t phy_opts)
1053*042d53a7SEvalZero {
1054*042d53a7SEvalZero     if (tx_phys_mask > (BLE_HCI_LE_PHY_1M_PREF_MASK |
1055*042d53a7SEvalZero                         BLE_HCI_LE_PHY_2M_PREF_MASK |
1056*042d53a7SEvalZero                         BLE_HCI_LE_PHY_CODED_PREF_MASK)) {
1057*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
1058*042d53a7SEvalZero     }
1059*042d53a7SEvalZero 
1060*042d53a7SEvalZero     if (rx_phys_mask > (BLE_HCI_LE_PHY_1M_PREF_MASK |
1061*042d53a7SEvalZero                         BLE_HCI_LE_PHY_2M_PREF_MASK |
1062*042d53a7SEvalZero                         BLE_HCI_LE_PHY_CODED_PREF_MASK)) {
1063*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
1064*042d53a7SEvalZero     }
1065*042d53a7SEvalZero 
1066*042d53a7SEvalZero     if (phy_opts > BLE_HCI_LE_PHY_CODED_S8_PREF) {
1067*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
1068*042d53a7SEvalZero     }
1069*042d53a7SEvalZero 
1070*042d53a7SEvalZero     return 0;
1071*042d53a7SEvalZero }
1072*042d53a7SEvalZero 
1073*042d53a7SEvalZero static int
ble_hs_hci_cmd_body_le_set_default_phy(uint8_t tx_phys_mask,uint8_t rx_phys_mask,uint8_t * dst)1074*042d53a7SEvalZero ble_hs_hci_cmd_body_le_set_default_phy(uint8_t tx_phys_mask,
1075*042d53a7SEvalZero                                        uint8_t rx_phys_mask, uint8_t *dst)
1076*042d53a7SEvalZero {
1077*042d53a7SEvalZero     int rc;
1078*042d53a7SEvalZero 
1079*042d53a7SEvalZero     rc = ble_hs_hci_verify_le_phy_params(tx_phys_mask, rx_phys_mask, 0);
1080*042d53a7SEvalZero     if (rc !=0 ) {
1081*042d53a7SEvalZero         return rc;
1082*042d53a7SEvalZero     }
1083*042d53a7SEvalZero 
1084*042d53a7SEvalZero     if (tx_phys_mask == 0) {
1085*042d53a7SEvalZero         dst[0] |= BLE_HCI_LE_PHY_NO_TX_PREF_MASK;
1086*042d53a7SEvalZero     } else {
1087*042d53a7SEvalZero         dst[1] = tx_phys_mask;
1088*042d53a7SEvalZero     }
1089*042d53a7SEvalZero 
1090*042d53a7SEvalZero     if (rx_phys_mask == 0){
1091*042d53a7SEvalZero         dst[0] |= BLE_HCI_LE_PHY_NO_RX_PREF_MASK;
1092*042d53a7SEvalZero     } else {
1093*042d53a7SEvalZero         dst[2] = rx_phys_mask;
1094*042d53a7SEvalZero     }
1095*042d53a7SEvalZero 
1096*042d53a7SEvalZero     return 0;
1097*042d53a7SEvalZero }
1098*042d53a7SEvalZero 
1099*042d53a7SEvalZero /*
1100*042d53a7SEvalZero  * OGF=0x08 OCF=0x0031
1101*042d53a7SEvalZero  */
1102*042d53a7SEvalZero int
ble_hs_hci_cmd_build_le_set_default_phy(uint8_t tx_phys_mask,uint8_t rx_phys_mask,uint8_t * dst,int dst_len)1103*042d53a7SEvalZero ble_hs_hci_cmd_build_le_set_default_phy(uint8_t tx_phys_mask, uint8_t rx_phys_mask,
1104*042d53a7SEvalZero                                         uint8_t *dst, int dst_len)
1105*042d53a7SEvalZero {
1106*042d53a7SEvalZero 
1107*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_LE_SET_DEFAULT_PHY_LEN);
1108*042d53a7SEvalZero 
1109*042d53a7SEvalZero     memset(dst, 0, dst_len);
1110*042d53a7SEvalZero 
1111*042d53a7SEvalZero     return ble_hs_hci_cmd_body_le_set_default_phy(tx_phys_mask, rx_phys_mask,
1112*042d53a7SEvalZero                                                   dst);
1113*042d53a7SEvalZero }
1114*042d53a7SEvalZero 
1115*042d53a7SEvalZero static int
ble_hs_hci_cmd_body_le_set_phy(uint16_t conn_handle,uint8_t tx_phys_mask,uint8_t rx_phys_mask,uint16_t phy_opts,uint8_t * dst)1116*042d53a7SEvalZero ble_hs_hci_cmd_body_le_set_phy(uint16_t conn_handle, uint8_t tx_phys_mask,
1117*042d53a7SEvalZero                                uint8_t rx_phys_mask, uint16_t phy_opts,
1118*042d53a7SEvalZero                                uint8_t *dst)
1119*042d53a7SEvalZero {
1120*042d53a7SEvalZero     int rc;
1121*042d53a7SEvalZero 
1122*042d53a7SEvalZero     rc = ble_hs_hci_verify_le_phy_params(tx_phys_mask, rx_phys_mask, phy_opts);
1123*042d53a7SEvalZero     if (rc != 0) {
1124*042d53a7SEvalZero         return rc;
1125*042d53a7SEvalZero     }
1126*042d53a7SEvalZero 
1127*042d53a7SEvalZero     put_le16(dst, conn_handle);
1128*042d53a7SEvalZero 
1129*042d53a7SEvalZero     if (tx_phys_mask == 0) {
1130*042d53a7SEvalZero         dst[2] |= BLE_HCI_LE_PHY_NO_TX_PREF_MASK;
1131*042d53a7SEvalZero     } else {
1132*042d53a7SEvalZero         dst[3] = tx_phys_mask;
1133*042d53a7SEvalZero     }
1134*042d53a7SEvalZero 
1135*042d53a7SEvalZero     if (rx_phys_mask == 0){
1136*042d53a7SEvalZero         dst[2] |= BLE_HCI_LE_PHY_NO_RX_PREF_MASK;
1137*042d53a7SEvalZero     } else {
1138*042d53a7SEvalZero         dst[4] = rx_phys_mask;
1139*042d53a7SEvalZero     }
1140*042d53a7SEvalZero 
1141*042d53a7SEvalZero     put_le16(dst + 5, phy_opts);
1142*042d53a7SEvalZero 
1143*042d53a7SEvalZero     return 0;
1144*042d53a7SEvalZero }
1145*042d53a7SEvalZero 
1146*042d53a7SEvalZero /*
1147*042d53a7SEvalZero  * OGF=0x08 OCF=0x0032
1148*042d53a7SEvalZero  */
1149*042d53a7SEvalZero int
ble_hs_hci_cmd_build_le_set_phy(uint16_t conn_handle,uint8_t tx_phys_mask,uint8_t rx_phys_mask,uint16_t phy_opts,uint8_t * dst,int dst_len)1150*042d53a7SEvalZero ble_hs_hci_cmd_build_le_set_phy(uint16_t conn_handle, uint8_t tx_phys_mask,
1151*042d53a7SEvalZero                                 uint8_t rx_phys_mask, uint16_t phy_opts,
1152*042d53a7SEvalZero                                 uint8_t *dst, int dst_len)
1153*042d53a7SEvalZero {
1154*042d53a7SEvalZero 
1155*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_LE_SET_PHY_LEN);
1156*042d53a7SEvalZero 
1157*042d53a7SEvalZero     memset(dst, 0, dst_len);
1158*042d53a7SEvalZero 
1159*042d53a7SEvalZero     return ble_hs_hci_cmd_body_le_set_phy(conn_handle, tx_phys_mask,
1160*042d53a7SEvalZero                                           rx_phys_mask, phy_opts, dst);
1161*042d53a7SEvalZero }
1162*042d53a7SEvalZero 
1163*042d53a7SEvalZero static int
ble_hs_hci_cmd_body_le_enhanced_recv_test(uint8_t chan,uint8_t phy,uint8_t mod_idx,uint8_t * dst)1164*042d53a7SEvalZero ble_hs_hci_cmd_body_le_enhanced_recv_test(uint8_t chan, uint8_t phy,
1165*042d53a7SEvalZero                                           uint8_t mod_idx, uint8_t *dst)
1166*042d53a7SEvalZero {
1167*042d53a7SEvalZero     /* Parameters check according to Bluetooth 5.0 Vol 2, Part E
1168*042d53a7SEvalZero      * 7.8.50 LE Enhanced Receiver Test Command
1169*042d53a7SEvalZero      */
1170*042d53a7SEvalZero     if (phy > BLE_HCI_LE_PHY_CODED || chan > 0x27 || mod_idx > 1) {
1171*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
1172*042d53a7SEvalZero     }
1173*042d53a7SEvalZero 
1174*042d53a7SEvalZero     dst[0] = chan;
1175*042d53a7SEvalZero     dst[1] = phy;
1176*042d53a7SEvalZero     dst[2] = mod_idx;
1177*042d53a7SEvalZero 
1178*042d53a7SEvalZero     return 0;
1179*042d53a7SEvalZero }
1180*042d53a7SEvalZero 
1181*042d53a7SEvalZero /*
1182*042d53a7SEvalZero  * OGF=0x08 OCF=0x0033
1183*042d53a7SEvalZero  */
1184*042d53a7SEvalZero int
ble_hs_hci_cmd_build_le_enh_recv_test(uint8_t rx_chan,uint8_t phy,uint8_t mod_idx,uint8_t * dst,uint16_t dst_len)1185*042d53a7SEvalZero ble_hs_hci_cmd_build_le_enh_recv_test(uint8_t rx_chan, uint8_t phy,
1186*042d53a7SEvalZero                                       uint8_t mod_idx,
1187*042d53a7SEvalZero                                       uint8_t *dst, uint16_t dst_len)
1188*042d53a7SEvalZero {
1189*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_LE_ENH_RX_TEST_LEN);
1190*042d53a7SEvalZero 
1191*042d53a7SEvalZero     return ble_hs_hci_cmd_body_le_enhanced_recv_test(rx_chan, phy, mod_idx, dst);
1192*042d53a7SEvalZero }
1193*042d53a7SEvalZero 
1194*042d53a7SEvalZero static int
ble_hs_hci_cmd_body_le_enhanced_trans_test(uint8_t chan,uint8_t test_data_len,uint8_t packet_payload_idx,uint8_t phy,uint8_t * dst)1195*042d53a7SEvalZero ble_hs_hci_cmd_body_le_enhanced_trans_test(uint8_t chan, uint8_t test_data_len,
1196*042d53a7SEvalZero                                            uint8_t packet_payload_idx,
1197*042d53a7SEvalZero                                            uint8_t phy,
1198*042d53a7SEvalZero                                            uint8_t *dst)
1199*042d53a7SEvalZero {
1200*042d53a7SEvalZero     /* Parameters check according to Bluetooth 5.0 Vol 2, Part E
1201*042d53a7SEvalZero      * 7.8.51 LE Enhanced Transmitter Test Command
1202*042d53a7SEvalZero      */
1203*042d53a7SEvalZero     if (phy > BLE_HCI_LE_PHY_CODED_S2 || chan > 0x27 ||
1204*042d53a7SEvalZero             packet_payload_idx > 0x07) {
1205*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
1206*042d53a7SEvalZero     }
1207*042d53a7SEvalZero 
1208*042d53a7SEvalZero     dst[0] = chan;
1209*042d53a7SEvalZero     dst[1] = test_data_len;
1210*042d53a7SEvalZero     dst[2] = packet_payload_idx;
1211*042d53a7SEvalZero     dst[3] = phy;
1212*042d53a7SEvalZero 
1213*042d53a7SEvalZero     return 0;
1214*042d53a7SEvalZero }
1215*042d53a7SEvalZero 
1216*042d53a7SEvalZero /*
1217*042d53a7SEvalZero  * OGF=0x08 OCF=0x0034
1218*042d53a7SEvalZero  */
1219*042d53a7SEvalZero int
ble_hs_hci_cmd_build_le_enh_trans_test(uint8_t tx_chan,uint8_t test_data_len,uint8_t packet_payload_idx,uint8_t phy,uint8_t * dst,uint16_t dst_len)1220*042d53a7SEvalZero ble_hs_hci_cmd_build_le_enh_trans_test(uint8_t tx_chan, uint8_t test_data_len,
1221*042d53a7SEvalZero                                        uint8_t packet_payload_idx, uint8_t phy,
1222*042d53a7SEvalZero                                        uint8_t *dst, uint16_t dst_len)
1223*042d53a7SEvalZero {
1224*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_LE_ENH_TX_TEST_LEN);
1225*042d53a7SEvalZero 
1226*042d53a7SEvalZero     return ble_hs_hci_cmd_body_le_enhanced_trans_test(tx_chan, test_data_len,
1227*042d53a7SEvalZero                                                       packet_payload_idx,
1228*042d53a7SEvalZero                                                       phy, dst);
1229*042d53a7SEvalZero }
1230*042d53a7SEvalZero 
1231*042d53a7SEvalZero #if MYNEWT_VAL(BLE_EXT_ADV)
1232*042d53a7SEvalZero static int
ble_hs_hci_check_scan_params(uint16_t scan_itvl,uint16_t scan_window)1233*042d53a7SEvalZero ble_hs_hci_check_scan_params(uint16_t scan_itvl, uint16_t scan_window)
1234*042d53a7SEvalZero {
1235*042d53a7SEvalZero     /* Check interval and window */
1236*042d53a7SEvalZero     if ((scan_itvl < BLE_HCI_SCAN_ITVL_MIN) ||
1237*042d53a7SEvalZero         (scan_itvl > BLE_HCI_SCAN_ITVL_MAX) ||
1238*042d53a7SEvalZero         (scan_window < BLE_HCI_SCAN_WINDOW_MIN) ||
1239*042d53a7SEvalZero         (scan_window > BLE_HCI_SCAN_WINDOW_MAX) ||
1240*042d53a7SEvalZero         (scan_itvl < scan_window)) {
1241*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
1242*042d53a7SEvalZero     }
1243*042d53a7SEvalZero 
1244*042d53a7SEvalZero     return 0;
1245*042d53a7SEvalZero }
1246*042d53a7SEvalZero 
1247*042d53a7SEvalZero static int
ble_hs_hci_cmd_body_le_set_ext_scan_param(uint8_t own_addr_type,uint8_t filter_policy,uint8_t phy_mask,uint8_t phy_count,struct ble_hs_hci_ext_scan_param * params[],uint8_t * dst)1248*042d53a7SEvalZero ble_hs_hci_cmd_body_le_set_ext_scan_param(uint8_t own_addr_type,
1249*042d53a7SEvalZero                                           uint8_t filter_policy,
1250*042d53a7SEvalZero                                           uint8_t phy_mask,
1251*042d53a7SEvalZero                                           uint8_t phy_count,
1252*042d53a7SEvalZero                                           struct ble_hs_hci_ext_scan_param *params[],
1253*042d53a7SEvalZero                                           uint8_t *dst)
1254*042d53a7SEvalZero {
1255*042d53a7SEvalZero     int i;
1256*042d53a7SEvalZero     int rc;
1257*042d53a7SEvalZero     uint8_t *dst_params;
1258*042d53a7SEvalZero     struct ble_hs_hci_ext_scan_param *p;
1259*042d53a7SEvalZero 
1260*042d53a7SEvalZero     if (phy_mask >
1261*042d53a7SEvalZero             (BLE_HCI_LE_PHY_1M_PREF_MASK | BLE_HCI_LE_PHY_CODED_PREF_MASK)) {
1262*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
1263*042d53a7SEvalZero     }
1264*042d53a7SEvalZero 
1265*042d53a7SEvalZero     /* Check own addr type */
1266*042d53a7SEvalZero     if (own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) {
1267*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
1268*042d53a7SEvalZero     }
1269*042d53a7SEvalZero 
1270*042d53a7SEvalZero     /* Check scanner filter policy */
1271*042d53a7SEvalZero     if (filter_policy > BLE_HCI_SCAN_FILT_MAX) {
1272*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
1273*042d53a7SEvalZero     }
1274*042d53a7SEvalZero 
1275*042d53a7SEvalZero     dst[0] = own_addr_type;
1276*042d53a7SEvalZero     dst[1] = filter_policy;
1277*042d53a7SEvalZero     dst[2] = phy_mask;
1278*042d53a7SEvalZero     dst_params = &dst[3];
1279*042d53a7SEvalZero 
1280*042d53a7SEvalZero     for (i = 0; i < phy_count; i++) {
1281*042d53a7SEvalZero         p = (*params) + i;
1282*042d53a7SEvalZero         rc = ble_hs_hci_check_scan_params(p->scan_itvl, p->scan_window);
1283*042d53a7SEvalZero         if (rc) {
1284*042d53a7SEvalZero             return rc;
1285*042d53a7SEvalZero         }
1286*042d53a7SEvalZero 
1287*042d53a7SEvalZero         dst_params[0] = p->scan_type;
1288*042d53a7SEvalZero         put_le16(dst_params + 1, p->scan_itvl);
1289*042d53a7SEvalZero         put_le16(dst_params + 3, p->scan_window);
1290*042d53a7SEvalZero 
1291*042d53a7SEvalZero         dst_params += BLE_HCI_LE_EXT_SCAN_SINGLE_PARAM_LEN;
1292*042d53a7SEvalZero     }
1293*042d53a7SEvalZero 
1294*042d53a7SEvalZero     return 0;
1295*042d53a7SEvalZero }
1296*042d53a7SEvalZero 
1297*042d53a7SEvalZero /*
1298*042d53a7SEvalZero  *  OGF=0x08 OCF=0x0041
1299*042d53a7SEvalZero  */
1300*042d53a7SEvalZero int
ble_hs_hci_cmd_build_le_set_ext_scan_params(uint8_t own_addr_type,uint8_t filter_policy,uint8_t phy_mask,uint8_t phy_count,struct ble_hs_hci_ext_scan_param * params[],uint8_t * dst,uint16_t dst_len)1301*042d53a7SEvalZero ble_hs_hci_cmd_build_le_set_ext_scan_params(uint8_t own_addr_type,
1302*042d53a7SEvalZero                                             uint8_t filter_policy,
1303*042d53a7SEvalZero                                             uint8_t phy_mask,
1304*042d53a7SEvalZero                                             uint8_t phy_count,
1305*042d53a7SEvalZero                                             struct ble_hs_hci_ext_scan_param *params[],
1306*042d53a7SEvalZero                                             uint8_t *dst, uint16_t dst_len)
1307*042d53a7SEvalZero {
1308*042d53a7SEvalZero     if (phy_count == 0) {
1309*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
1310*042d53a7SEvalZero     }
1311*042d53a7SEvalZero 
1312*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_LE_EXT_SCAN_BASE_LEN +
1313*042d53a7SEvalZero                               BLE_HCI_LE_EXT_SCAN_SINGLE_PARAM_LEN * phy_count);
1314*042d53a7SEvalZero 
1315*042d53a7SEvalZero     return ble_hs_hci_cmd_body_le_set_ext_scan_param(own_addr_type,
1316*042d53a7SEvalZero                                                      filter_policy,
1317*042d53a7SEvalZero                                                      phy_mask,
1318*042d53a7SEvalZero                                                      phy_count,
1319*042d53a7SEvalZero                                                      params,
1320*042d53a7SEvalZero                                                      dst);
1321*042d53a7SEvalZero }
1322*042d53a7SEvalZero 
1323*042d53a7SEvalZero static int
ble_hs_hci_cmd_body_le_set_ext_scan_enable(uint8_t enable,uint8_t filter_dups,uint16_t duration,uint16_t period,uint8_t * dst)1324*042d53a7SEvalZero ble_hs_hci_cmd_body_le_set_ext_scan_enable(uint8_t enable, uint8_t filter_dups,
1325*042d53a7SEvalZero                                            uint16_t duration, uint16_t period,
1326*042d53a7SEvalZero                                            uint8_t *dst)
1327*042d53a7SEvalZero {
1328*042d53a7SEvalZero     if (enable > 0x01 || filter_dups > 0x03) {
1329*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
1330*042d53a7SEvalZero     }
1331*042d53a7SEvalZero 
1332*042d53a7SEvalZero     dst[0] = enable;
1333*042d53a7SEvalZero     dst[1] = filter_dups;
1334*042d53a7SEvalZero     put_le16(dst + 2, duration);
1335*042d53a7SEvalZero     put_le16(dst + 4, period);
1336*042d53a7SEvalZero 
1337*042d53a7SEvalZero     return 0;
1338*042d53a7SEvalZero }
1339*042d53a7SEvalZero 
1340*042d53a7SEvalZero /*
1341*042d53a7SEvalZero  *  OGF=0x08 OCF=0x0042
1342*042d53a7SEvalZero  */
1343*042d53a7SEvalZero int
ble_hs_hci_cmd_build_le_set_ext_scan_enable(uint8_t enable,uint8_t filter_dups,uint16_t duration,uint16_t period,uint8_t * dst,uint16_t dst_len)1344*042d53a7SEvalZero ble_hs_hci_cmd_build_le_set_ext_scan_enable(uint8_t enable,
1345*042d53a7SEvalZero                                             uint8_t filter_dups,
1346*042d53a7SEvalZero                                             uint16_t duration,
1347*042d53a7SEvalZero                                             uint16_t period,
1348*042d53a7SEvalZero                                             uint8_t *dst, uint16_t dst_len)
1349*042d53a7SEvalZero {
1350*042d53a7SEvalZero 
1351*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_LE_SET_EXT_SCAN_ENABLE_LEN);
1352*042d53a7SEvalZero 
1353*042d53a7SEvalZero     return ble_hs_hci_cmd_body_le_set_ext_scan_enable(enable, filter_dups,
1354*042d53a7SEvalZero                                                       duration, period, dst);
1355*042d53a7SEvalZero }
1356*042d53a7SEvalZero 
1357*042d53a7SEvalZero static int
ble_hs_hci_check_conn_params(uint8_t phy,const struct hci_ext_conn_params * params)1358*042d53a7SEvalZero ble_hs_hci_check_conn_params(uint8_t phy,
1359*042d53a7SEvalZero                              const struct hci_ext_conn_params *params)
1360*042d53a7SEvalZero {
1361*042d53a7SEvalZero     if (phy != BLE_HCI_LE_PHY_2M) {
1362*042d53a7SEvalZero         if (ble_hs_hci_check_scan_params(params->scan_itvl, params->scan_window)) {
1363*042d53a7SEvalZero             return BLE_ERR_INV_HCI_CMD_PARMS;
1364*042d53a7SEvalZero         }
1365*042d53a7SEvalZero     }
1366*042d53a7SEvalZero         /* Check connection interval min */
1367*042d53a7SEvalZero     if ((params->conn_itvl_min < BLE_HCI_CONN_ITVL_MIN) ||
1368*042d53a7SEvalZero         (params->conn_itvl_min > BLE_HCI_CONN_ITVL_MAX)) {
1369*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
1370*042d53a7SEvalZero     }
1371*042d53a7SEvalZero     /* Check connection interval max */
1372*042d53a7SEvalZero     if ((params->conn_itvl_max < BLE_HCI_CONN_ITVL_MIN) ||
1373*042d53a7SEvalZero         (params->conn_itvl_max > BLE_HCI_CONN_ITVL_MAX) ||
1374*042d53a7SEvalZero         (params->conn_itvl_max < params->conn_itvl_min)) {
1375*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
1376*042d53a7SEvalZero     }
1377*042d53a7SEvalZero 
1378*042d53a7SEvalZero     /* Check connection latency */
1379*042d53a7SEvalZero     if ((params->conn_latency < BLE_HCI_CONN_LATENCY_MIN) ||
1380*042d53a7SEvalZero         (params->conn_latency > BLE_HCI_CONN_LATENCY_MAX)) {
1381*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
1382*042d53a7SEvalZero     }
1383*042d53a7SEvalZero 
1384*042d53a7SEvalZero     /* Check supervision timeout */
1385*042d53a7SEvalZero     if ((params->supervision_timeout < BLE_HCI_CONN_SPVN_TIMEOUT_MIN) ||
1386*042d53a7SEvalZero         (params->supervision_timeout > BLE_HCI_CONN_SPVN_TIMEOUT_MAX)) {
1387*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
1388*042d53a7SEvalZero     }
1389*042d53a7SEvalZero 
1390*042d53a7SEvalZero     /* Check connection event length */
1391*042d53a7SEvalZero     if (params->min_ce_len > params->max_ce_len) {
1392*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
1393*042d53a7SEvalZero     }
1394*042d53a7SEvalZero 
1395*042d53a7SEvalZero     return 0;
1396*042d53a7SEvalZero }
1397*042d53a7SEvalZero 
1398*042d53a7SEvalZero static int
ble_hs_hci_cmd_body_le_ext_create_conn(const struct hci_ext_create_conn * hcc,uint8_t * cmd)1399*042d53a7SEvalZero ble_hs_hci_cmd_body_le_ext_create_conn(const struct hci_ext_create_conn *hcc,
1400*042d53a7SEvalZero                                        uint8_t *cmd)
1401*042d53a7SEvalZero {
1402*042d53a7SEvalZero     int iter = 0;
1403*042d53a7SEvalZero     const struct hci_ext_conn_params *params;
1404*042d53a7SEvalZero 
1405*042d53a7SEvalZero     /* Check initiator filter policy */
1406*042d53a7SEvalZero     if (hcc->filter_policy > BLE_HCI_CONN_FILT_MAX) {
1407*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
1408*042d53a7SEvalZero     }
1409*042d53a7SEvalZero     cmd[iter] = hcc->filter_policy;
1410*042d53a7SEvalZero     iter++;
1411*042d53a7SEvalZero     /* Check own addr type */
1412*042d53a7SEvalZero     if (hcc->own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) {
1413*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
1414*042d53a7SEvalZero     }
1415*042d53a7SEvalZero     cmd[iter] = hcc->own_addr_type;
1416*042d53a7SEvalZero     iter++;
1417*042d53a7SEvalZero 
1418*042d53a7SEvalZero     /* Check peer addr type */
1419*042d53a7SEvalZero     if (hcc->peer_addr_type > BLE_HCI_CONN_PEER_ADDR_MAX) {
1420*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
1421*042d53a7SEvalZero     }
1422*042d53a7SEvalZero     cmd[iter] = hcc->peer_addr_type;
1423*042d53a7SEvalZero     iter++;
1424*042d53a7SEvalZero 
1425*042d53a7SEvalZero     memcpy(cmd + iter, hcc->peer_addr, BLE_DEV_ADDR_LEN);
1426*042d53a7SEvalZero     iter += BLE_DEV_ADDR_LEN;
1427*042d53a7SEvalZero 
1428*042d53a7SEvalZero     if (hcc->init_phy_mask > (BLE_HCI_LE_PHY_1M_PREF_MASK |
1429*042d53a7SEvalZero                                 BLE_HCI_LE_PHY_2M_PREF_MASK |
1430*042d53a7SEvalZero                                 BLE_HCI_LE_PHY_CODED_PREF_MASK)) {
1431*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
1432*042d53a7SEvalZero     }
1433*042d53a7SEvalZero     cmd[iter] = hcc->init_phy_mask;
1434*042d53a7SEvalZero     iter++;
1435*042d53a7SEvalZero 
1436*042d53a7SEvalZero     if (hcc->init_phy_mask & BLE_HCI_LE_PHY_1M_PREF_MASK) {
1437*042d53a7SEvalZero         params = &hcc->params[0];
1438*042d53a7SEvalZero         if (ble_hs_hci_check_conn_params(BLE_HCI_LE_PHY_1M, params)) {
1439*042d53a7SEvalZero             return BLE_ERR_INV_HCI_CMD_PARMS;
1440*042d53a7SEvalZero         }
1441*042d53a7SEvalZero         put_le16(cmd + iter, params->scan_itvl);
1442*042d53a7SEvalZero         put_le16(cmd + iter + 2, params->scan_window);
1443*042d53a7SEvalZero         put_le16(cmd + iter + 4, params->conn_itvl_min);
1444*042d53a7SEvalZero         put_le16(cmd + iter + 6, params->conn_itvl_max);
1445*042d53a7SEvalZero         put_le16(cmd + iter + 8, params->conn_latency);
1446*042d53a7SEvalZero         put_le16(cmd + iter + 10, params->supervision_timeout);
1447*042d53a7SEvalZero         put_le16(cmd + iter + 12, params->min_ce_len);
1448*042d53a7SEvalZero         put_le16(cmd + iter + 14, params->max_ce_len);
1449*042d53a7SEvalZero         iter += 16;
1450*042d53a7SEvalZero     }
1451*042d53a7SEvalZero 
1452*042d53a7SEvalZero     if (hcc->init_phy_mask & BLE_HCI_LE_PHY_2M_PREF_MASK) {
1453*042d53a7SEvalZero         params = &hcc->params[1];
1454*042d53a7SEvalZero         if (ble_hs_hci_check_conn_params(BLE_HCI_LE_PHY_2M, params)) {
1455*042d53a7SEvalZero             return BLE_ERR_INV_HCI_CMD_PARMS;
1456*042d53a7SEvalZero         }
1457*042d53a7SEvalZero         put_le16(cmd + iter, 0);
1458*042d53a7SEvalZero         put_le16(cmd + iter + 2, 0);
1459*042d53a7SEvalZero         put_le16(cmd + iter + 4, params->conn_itvl_min);
1460*042d53a7SEvalZero         put_le16(cmd + iter + 6, params->conn_itvl_max);
1461*042d53a7SEvalZero         put_le16(cmd + iter + 8, params->conn_latency);
1462*042d53a7SEvalZero         put_le16(cmd + iter + 10, params->supervision_timeout);
1463*042d53a7SEvalZero         put_le16(cmd + iter + 12, params->min_ce_len);
1464*042d53a7SEvalZero         put_le16(cmd + iter + 14, params->max_ce_len);
1465*042d53a7SEvalZero         iter += 16;
1466*042d53a7SEvalZero     }
1467*042d53a7SEvalZero 
1468*042d53a7SEvalZero     if (hcc->init_phy_mask & BLE_HCI_LE_PHY_CODED_PREF_MASK) {
1469*042d53a7SEvalZero         params = &hcc->params[2];
1470*042d53a7SEvalZero         if (ble_hs_hci_check_conn_params(BLE_HCI_LE_PHY_CODED, params)) {
1471*042d53a7SEvalZero             return BLE_ERR_INV_HCI_CMD_PARMS;
1472*042d53a7SEvalZero         }
1473*042d53a7SEvalZero         put_le16(cmd + iter, params->scan_itvl);
1474*042d53a7SEvalZero         put_le16(cmd + iter + 2, params->scan_window);
1475*042d53a7SEvalZero         put_le16(cmd + iter + 4, params->conn_itvl_min);
1476*042d53a7SEvalZero         put_le16(cmd + iter + 6, params->conn_itvl_max);
1477*042d53a7SEvalZero         put_le16(cmd + iter + 8, params->conn_latency);
1478*042d53a7SEvalZero         put_le16(cmd + iter + 10, params->supervision_timeout);
1479*042d53a7SEvalZero         put_le16(cmd + iter + 12, params->min_ce_len);
1480*042d53a7SEvalZero         put_le16(cmd + iter + 14, params->max_ce_len);
1481*042d53a7SEvalZero         iter += 16;
1482*042d53a7SEvalZero     }
1483*042d53a7SEvalZero 
1484*042d53a7SEvalZero     return 0;
1485*042d53a7SEvalZero }
1486*042d53a7SEvalZero 
1487*042d53a7SEvalZero int
ble_hs_hci_cmd_build_le_ext_create_conn(const struct hci_ext_create_conn * hcc,uint8_t * cmd,int cmd_len)1488*042d53a7SEvalZero ble_hs_hci_cmd_build_le_ext_create_conn(const struct hci_ext_create_conn *hcc,
1489*042d53a7SEvalZero                                         uint8_t *cmd, int cmd_len)
1490*042d53a7SEvalZero {
1491*042d53a7SEvalZero     uint8_t size;
1492*042d53a7SEvalZero 
1493*042d53a7SEvalZero     size = BLE_HCI_LE_EXT_CREATE_CONN_BASE_LEN;
1494*042d53a7SEvalZero     if (hcc->init_phy_mask & BLE_HCI_LE_PHY_1M_PREF_MASK) {
1495*042d53a7SEvalZero         size += sizeof(struct hci_ext_conn_params);
1496*042d53a7SEvalZero     }
1497*042d53a7SEvalZero 
1498*042d53a7SEvalZero     if (hcc->init_phy_mask & BLE_HCI_LE_PHY_2M_PREF_MASK) {
1499*042d53a7SEvalZero         size += sizeof(struct hci_ext_conn_params);
1500*042d53a7SEvalZero     }
1501*042d53a7SEvalZero 
1502*042d53a7SEvalZero     if (hcc->init_phy_mask & BLE_HCI_LE_PHY_CODED_PREF_MASK) {
1503*042d53a7SEvalZero         size += sizeof(struct hci_ext_conn_params);
1504*042d53a7SEvalZero     }
1505*042d53a7SEvalZero 
1506*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(cmd_len >= size);
1507*042d53a7SEvalZero 
1508*042d53a7SEvalZero     return ble_hs_hci_cmd_body_le_ext_create_conn(hcc, cmd);
1509*042d53a7SEvalZero }
1510*042d53a7SEvalZero 
1511*042d53a7SEvalZero int
ble_hs_hci_cmd_build_le_ext_adv_set_random_addr(uint8_t handle,const uint8_t * addr,uint8_t * cmd,int cmd_len)1512*042d53a7SEvalZero ble_hs_hci_cmd_build_le_ext_adv_set_random_addr(uint8_t handle,
1513*042d53a7SEvalZero                                                 const uint8_t *addr,
1514*042d53a7SEvalZero                                                 uint8_t *cmd, int cmd_len)
1515*042d53a7SEvalZero {
1516*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(cmd_len >= BLE_HCI_LE_SET_ADV_SET_RND_ADDR_LEN);
1517*042d53a7SEvalZero 
1518*042d53a7SEvalZero     cmd[0] = handle;
1519*042d53a7SEvalZero     memcpy(cmd + 1, addr, BLE_DEV_ADDR_LEN);
1520*042d53a7SEvalZero 
1521*042d53a7SEvalZero     return 0;
1522*042d53a7SEvalZero }
1523*042d53a7SEvalZero 
1524*042d53a7SEvalZero int
ble_hs_hci_cmd_build_le_ext_adv_data(uint8_t handle,uint8_t operation,uint8_t frag_pref,struct os_mbuf * data,uint8_t data_len,uint8_t * cmd,int cmd_len)1525*042d53a7SEvalZero ble_hs_hci_cmd_build_le_ext_adv_data(uint8_t handle, uint8_t operation,
1526*042d53a7SEvalZero                                      uint8_t frag_pref, struct os_mbuf *data,
1527*042d53a7SEvalZero                                      uint8_t data_len,
1528*042d53a7SEvalZero                                      uint8_t *cmd, int cmd_len)
1529*042d53a7SEvalZero {
1530*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(cmd_len >= 4 + data_len);
1531*042d53a7SEvalZero 
1532*042d53a7SEvalZero     cmd[0] = handle;
1533*042d53a7SEvalZero     cmd[1] = operation;
1534*042d53a7SEvalZero     cmd[2] = frag_pref;
1535*042d53a7SEvalZero     cmd[3] = data_len;
1536*042d53a7SEvalZero     os_mbuf_copydata(data, 0, data_len, cmd + 4);
1537*042d53a7SEvalZero 
1538*042d53a7SEvalZero     return 0;
1539*042d53a7SEvalZero }
1540*042d53a7SEvalZero 
1541*042d53a7SEvalZero int
ble_hs_hci_cmd_build_le_ext_adv_enable(uint8_t enable,uint8_t sets_num,const struct hci_ext_adv_set * sets,uint8_t * cmd,int cmd_len)1542*042d53a7SEvalZero ble_hs_hci_cmd_build_le_ext_adv_enable(uint8_t enable, uint8_t sets_num,
1543*042d53a7SEvalZero                                        const struct hci_ext_adv_set *sets,
1544*042d53a7SEvalZero                                        uint8_t *cmd, int cmd_len)
1545*042d53a7SEvalZero {
1546*042d53a7SEvalZero     int i;
1547*042d53a7SEvalZero 
1548*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(cmd_len >= 2 + (sets_num * 4));
1549*042d53a7SEvalZero 
1550*042d53a7SEvalZero     cmd[0] = enable;
1551*042d53a7SEvalZero     cmd[1] = sets_num;
1552*042d53a7SEvalZero 
1553*042d53a7SEvalZero     cmd += 2;
1554*042d53a7SEvalZero 
1555*042d53a7SEvalZero     for (i = 0; i < sets_num; i++) {
1556*042d53a7SEvalZero         cmd[0] = sets[i].handle;
1557*042d53a7SEvalZero         put_le16(&cmd[1], sets[i].duration);
1558*042d53a7SEvalZero         cmd[3] = sets[i].events;
1559*042d53a7SEvalZero 
1560*042d53a7SEvalZero         cmd += 4;
1561*042d53a7SEvalZero     }
1562*042d53a7SEvalZero 
1563*042d53a7SEvalZero     return 0;
1564*042d53a7SEvalZero }
1565*042d53a7SEvalZero 
1566*042d53a7SEvalZero int
ble_hs_hci_cmd_build_le_ext_adv_params(uint8_t handle,const struct hci_ext_adv_params * params,uint8_t * cmd,int cmd_len)1567*042d53a7SEvalZero ble_hs_hci_cmd_build_le_ext_adv_params(uint8_t handle,
1568*042d53a7SEvalZero                                        const struct hci_ext_adv_params *params,
1569*042d53a7SEvalZero                                        uint8_t *cmd, int cmd_len)
1570*042d53a7SEvalZero {
1571*042d53a7SEvalZero     uint32_t tmp;
1572*042d53a7SEvalZero 
1573*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(cmd_len >= BLE_HCI_LE_SET_EXT_ADV_PARAM_LEN);
1574*042d53a7SEvalZero 
1575*042d53a7SEvalZero     cmd[0] = handle;
1576*042d53a7SEvalZero     put_le16(&cmd[1], params->properties);
1577*042d53a7SEvalZero 
1578*042d53a7SEvalZero     tmp = htole32(params->min_interval);
1579*042d53a7SEvalZero     memcpy(&cmd[3], &tmp, 3);
1580*042d53a7SEvalZero 
1581*042d53a7SEvalZero     tmp = htole32(params->max_interval);
1582*042d53a7SEvalZero     memcpy(&cmd[6], &tmp, 3);
1583*042d53a7SEvalZero 
1584*042d53a7SEvalZero     cmd[9] = params->chan_map;
1585*042d53a7SEvalZero     cmd[10] = params->own_addr_type;
1586*042d53a7SEvalZero     cmd[11] = params->peer_addr_type;
1587*042d53a7SEvalZero     memcpy(&cmd[12], params->peer_addr, BLE_DEV_ADDR_LEN);
1588*042d53a7SEvalZero     cmd[18] = params->filter_policy;
1589*042d53a7SEvalZero     cmd[19] = params->tx_power;
1590*042d53a7SEvalZero     cmd[20] = params->primary_phy;
1591*042d53a7SEvalZero     cmd[21] = params->max_skip;
1592*042d53a7SEvalZero     cmd[22] = params->secondary_phy;
1593*042d53a7SEvalZero     cmd[23] = params->sid;
1594*042d53a7SEvalZero     cmd[24] = params->scan_req_notif;
1595*042d53a7SEvalZero 
1596*042d53a7SEvalZero     return 0;
1597*042d53a7SEvalZero }
1598*042d53a7SEvalZero int
ble_hs_hci_cmd_build_le_ext_adv_remove(uint8_t handle,uint8_t * cmd,int cmd_len)1599*042d53a7SEvalZero ble_hs_hci_cmd_build_le_ext_adv_remove(uint8_t handle,
1600*042d53a7SEvalZero                                        uint8_t *cmd, int cmd_len)
1601*042d53a7SEvalZero {
1602*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(cmd_len >= BLE_HCI_LE_REMOVE_ADV_SET_LEN);
1603*042d53a7SEvalZero 
1604*042d53a7SEvalZero     cmd[0] = handle;
1605*042d53a7SEvalZero 
1606*042d53a7SEvalZero     return 0;
1607*042d53a7SEvalZero }
1608*042d53a7SEvalZero #endif
1609*042d53a7SEvalZero 
1610*042d53a7SEvalZero static int
ble_hs_hci_cmd_body_le_set_priv_mode(const uint8_t * addr,uint8_t addr_type,uint8_t priv_mode,uint8_t * dst)1611*042d53a7SEvalZero ble_hs_hci_cmd_body_le_set_priv_mode(const uint8_t *addr, uint8_t addr_type,
1612*042d53a7SEvalZero                                      uint8_t priv_mode, uint8_t *dst)
1613*042d53a7SEvalZero {
1614*042d53a7SEvalZero     /* In this command addr type can be either:
1615*042d53a7SEvalZero      *  - public identity (0x00)
1616*042d53a7SEvalZero      *  - random (static) identity (0x01)
1617*042d53a7SEvalZero      */
1618*042d53a7SEvalZero     if (addr_type > BLE_ADDR_RANDOM) {
1619*042d53a7SEvalZero         return BLE_ERR_INV_HCI_CMD_PARMS;
1620*042d53a7SEvalZero     }
1621*042d53a7SEvalZero 
1622*042d53a7SEvalZero     dst[0] = addr_type;
1623*042d53a7SEvalZero     memcpy(dst + 1, addr, BLE_DEV_ADDR_LEN);
1624*042d53a7SEvalZero     dst[7] = priv_mode;
1625*042d53a7SEvalZero 
1626*042d53a7SEvalZero     return 0;
1627*042d53a7SEvalZero }
1628*042d53a7SEvalZero 
1629*042d53a7SEvalZero /*
1630*042d53a7SEvalZero  *  OGF=0x08 OCF=0x004e
1631*042d53a7SEvalZero  */
1632*042d53a7SEvalZero int
ble_hs_hci_cmd_build_le_set_priv_mode(const uint8_t * addr,uint8_t addr_type,uint8_t priv_mode,uint8_t * dst,uint16_t dst_len)1633*042d53a7SEvalZero ble_hs_hci_cmd_build_le_set_priv_mode(const uint8_t *addr, uint8_t addr_type,
1634*042d53a7SEvalZero                                       uint8_t priv_mode, uint8_t *dst,
1635*042d53a7SEvalZero                                       uint16_t dst_len)
1636*042d53a7SEvalZero {
1637*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_LE_SET_PRIVACY_MODE_LEN);
1638*042d53a7SEvalZero 
1639*042d53a7SEvalZero     return ble_hs_hci_cmd_body_le_set_priv_mode(addr, addr_type, priv_mode, dst);
1640*042d53a7SEvalZero }
1641*042d53a7SEvalZero 
1642*042d53a7SEvalZero static int
ble_hs_hci_cmd_body_set_random_addr(const struct hci_rand_addr * paddr,uint8_t * dst)1643*042d53a7SEvalZero ble_hs_hci_cmd_body_set_random_addr(const struct hci_rand_addr *paddr,
1644*042d53a7SEvalZero                                     uint8_t *dst)
1645*042d53a7SEvalZero {
1646*042d53a7SEvalZero     memcpy(dst, paddr->addr, BLE_DEV_ADDR_LEN);
1647*042d53a7SEvalZero     return 0;
1648*042d53a7SEvalZero }
1649*042d53a7SEvalZero 
1650*042d53a7SEvalZero int
ble_hs_hci_cmd_build_set_random_addr(const uint8_t * addr,uint8_t * dst,int dst_len)1651*042d53a7SEvalZero ble_hs_hci_cmd_build_set_random_addr(const uint8_t *addr,
1652*042d53a7SEvalZero                                      uint8_t *dst, int dst_len)
1653*042d53a7SEvalZero {
1654*042d53a7SEvalZero     struct hci_rand_addr r_addr;
1655*042d53a7SEvalZero 
1656*042d53a7SEvalZero     memcpy(r_addr.addr, addr, sizeof(r_addr.addr));
1657*042d53a7SEvalZero 
1658*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_SET_RAND_ADDR_LEN);
1659*042d53a7SEvalZero 
1660*042d53a7SEvalZero     return ble_hs_hci_cmd_body_set_random_addr(&r_addr, dst);
1661*042d53a7SEvalZero }
1662*042d53a7SEvalZero 
1663*042d53a7SEvalZero static void
ble_hs_hci_cmd_body_le_read_remote_feat(uint16_t handle,uint8_t * dst)1664*042d53a7SEvalZero ble_hs_hci_cmd_body_le_read_remote_feat(uint16_t handle, uint8_t *dst)
1665*042d53a7SEvalZero {
1666*042d53a7SEvalZero     put_le16(dst, handle);
1667*042d53a7SEvalZero }
1668*042d53a7SEvalZero 
1669*042d53a7SEvalZero int
ble_hs_hci_cmd_build_le_read_remote_feat(uint16_t handle,uint8_t * dst,int dst_len)1670*042d53a7SEvalZero ble_hs_hci_cmd_build_le_read_remote_feat(uint16_t handle, uint8_t *dst,
1671*042d53a7SEvalZero                                                                  int dst_len)
1672*042d53a7SEvalZero {
1673*042d53a7SEvalZero     BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CONN_RD_REM_FEAT_LEN);
1674*042d53a7SEvalZero 
1675*042d53a7SEvalZero     ble_hs_hci_cmd_body_le_read_remote_feat(handle, dst);
1676*042d53a7SEvalZero 
1677*042d53a7SEvalZero     return 0;
1678*042d53a7SEvalZero }
1679