1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 #include <string.h>
21 #include "nimble/hci_common.h"
22 #include "host/ble_hs_hci.h"
23 #include "ble_hs_priv.h"
24
25 uint16_t
ble_hs_hci_util_handle_pb_bc_join(uint16_t handle,uint8_t pb,uint8_t bc)26 ble_hs_hci_util_handle_pb_bc_join(uint16_t handle, uint8_t pb, uint8_t bc)
27 {
28 BLE_HS_DBG_ASSERT(handle <= 0x0fff);
29 BLE_HS_DBG_ASSERT(pb <= 0x03);
30 BLE_HS_DBG_ASSERT(bc <= 0x03);
31
32 return (handle << 0) |
33 (pb << 12) |
34 (bc << 14);
35 }
36
37 int
ble_hs_hci_util_read_adv_tx_pwr(int8_t * out_tx_pwr)38 ble_hs_hci_util_read_adv_tx_pwr(int8_t *out_tx_pwr)
39 {
40 uint8_t params_len;
41 int rc;
42
43 rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
44 BLE_HCI_OCF_LE_RD_ADV_CHAN_TXPWR),
45 NULL, 0,out_tx_pwr, 1, ¶ms_len);
46 if (rc != 0) {
47 return rc;
48 }
49
50 if (params_len != 1 ||
51 *out_tx_pwr < BLE_HCI_ADV_CHAN_TXPWR_MIN ||
52 *out_tx_pwr > BLE_HCI_ADV_CHAN_TXPWR_MAX) {
53 BLE_HS_LOG(WARN, "advertiser txpwr out of range\n");
54 }
55
56 return 0;
57 }
58
59 int
ble_hs_hci_util_rand(void * dst,int len)60 ble_hs_hci_util_rand(void *dst, int len)
61 {
62 uint8_t rsp_buf[BLE_HCI_LE_RAND_LEN];
63 uint8_t params_len;
64 uint8_t *u8ptr;
65 int chunk_sz;
66 int rc;
67
68 u8ptr = dst;
69 while (len > 0) {
70 rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RAND),
71 NULL, 0, rsp_buf, sizeof rsp_buf, ¶ms_len);
72 if (rc != 0) {
73 return rc;
74 }
75 if (params_len != sizeof rsp_buf) {
76 return BLE_HS_ECONTROLLER;
77 }
78
79 chunk_sz = min(len, sizeof rsp_buf);
80 memcpy(u8ptr, rsp_buf, chunk_sz);
81
82 len -= chunk_sz;
83 u8ptr += chunk_sz;
84 }
85
86 return 0;
87 }
88
89 int
ble_hs_hci_util_read_rssi(uint16_t conn_handle,int8_t * out_rssi)90 ble_hs_hci_util_read_rssi(uint16_t conn_handle, int8_t *out_rssi)
91 {
92 uint8_t buf[BLE_HCI_READ_RSSI_LEN];
93 uint8_t params[BLE_HCI_READ_RSSI_ACK_PARAM_LEN];
94 uint16_t params_conn_handle;
95 uint8_t params_len;
96 int rc;
97
98 ble_hs_hci_cmd_build_read_rssi(conn_handle, buf, sizeof buf);
99 rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_STATUS_PARAMS,
100 BLE_HCI_OCF_RD_RSSI), buf, sizeof(buf),
101 params, sizeof(params), ¶ms_len);
102 if (rc != 0) {
103 return rc;
104 }
105
106 if (params_len != BLE_HCI_READ_RSSI_ACK_PARAM_LEN) {
107 return BLE_HS_ECONTROLLER;
108 }
109
110 params_conn_handle = get_le16(params + 0);
111 if (params_conn_handle != conn_handle) {
112 return BLE_HS_ECONTROLLER;
113 }
114
115 *out_rssi = params[2];
116
117 return 0;
118 }
119
120 int
ble_hs_hci_util_set_random_addr(const uint8_t * addr)121 ble_hs_hci_util_set_random_addr(const uint8_t *addr)
122 {
123 uint8_t buf[BLE_HCI_SET_RAND_ADDR_LEN];
124 int rc;
125
126 /* set the address in the controller */
127
128 rc = ble_hs_hci_cmd_build_set_random_addr(addr, buf, sizeof(buf));
129 if (rc != 0) {
130 return rc;
131 }
132
133 rc = ble_hs_hci_cmd_tx_empty_ack(BLE_HCI_OP(BLE_HCI_OGF_LE,
134 BLE_HCI_OCF_LE_SET_RAND_ADDR),
135 buf, BLE_HCI_SET_RAND_ADDR_LEN);
136 if (rc != 0) {
137 return rc;
138 }
139
140 return 0;
141 }
142
143 int
ble_hs_hci_util_set_data_len(uint16_t conn_handle,uint16_t tx_octets,uint16_t tx_time)144 ble_hs_hci_util_set_data_len(uint16_t conn_handle, uint16_t tx_octets,
145 uint16_t tx_time)
146 {
147
148 uint8_t buf[BLE_HCI_SET_DATALEN_LEN];
149 uint8_t params[BLE_HCI_SET_DATALEN_ACK_PARAM_LEN];
150 uint16_t params_conn_handle;
151 uint8_t params_len;
152 int rc;
153
154 rc = ble_hs_hci_cmd_build_set_data_len(conn_handle, tx_octets, tx_time,
155 buf, sizeof buf);
156 if (rc != 0) {
157 return BLE_HS_HCI_ERR(rc);
158 }
159
160 rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
161 BLE_HCI_OCF_LE_SET_DATA_LEN),
162 buf, sizeof(buf), params,
163 BLE_HCI_SET_DATALEN_ACK_PARAM_LEN, ¶ms_len);
164 if (rc != 0) {
165 return rc;
166 }
167
168 if (params_len != BLE_HCI_SET_DATALEN_ACK_PARAM_LEN) {
169 return BLE_HS_ECONTROLLER;
170 }
171
172 params_conn_handle = get_le16(params + 0);
173 if (params_conn_handle != conn_handle) {
174 return BLE_HS_ECONTROLLER;
175 }
176
177 return 0;
178 }
179
180 int
ble_hs_hci_util_data_hdr_strip(struct os_mbuf * om,struct hci_data_hdr * out_hdr)181 ble_hs_hci_util_data_hdr_strip(struct os_mbuf *om,
182 struct hci_data_hdr *out_hdr)
183 {
184 int rc;
185
186 rc = os_mbuf_copydata(om, 0, BLE_HCI_DATA_HDR_SZ, out_hdr);
187 if (rc != 0) {
188 return BLE_HS_ECONTROLLER;
189 }
190
191 /* Strip HCI ACL data header from the front of the packet. */
192 os_mbuf_adj(om, BLE_HCI_DATA_HDR_SZ);
193
194 out_hdr->hdh_handle_pb_bc = get_le16(&out_hdr->hdh_handle_pb_bc);
195 out_hdr->hdh_len = get_le16(&out_hdr->hdh_len);
196
197 return 0;
198 }
199
200 int
ble_hs_hci_read_chan_map(uint16_t conn_handle,uint8_t * out_chan_map)201 ble_hs_hci_read_chan_map(uint16_t conn_handle, uint8_t *out_chan_map)
202 {
203 uint8_t buf[BLE_HCI_RD_CHANMAP_LEN];
204 uint8_t params[BLE_HCI_RD_CHANMAP_RSP_LEN];
205 uint16_t params_conn_handle;
206 uint8_t params_len;
207 int rc;
208
209 ble_hs_hci_cmd_build_le_read_chan_map(conn_handle, buf, sizeof buf);
210 rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
211 BLE_HCI_OCF_LE_RD_CHAN_MAP),
212 buf, sizeof(buf), params, BLE_HCI_RD_CHANMAP_RSP_LEN,
213 ¶ms_len);
214 if (rc != 0) {
215 return rc;
216 }
217
218 if (params_len != BLE_HCI_RD_CHANMAP_RSP_LEN) {
219 return BLE_HS_ECONTROLLER;
220 }
221
222 params_conn_handle = get_le16(params + 0);
223 if (params_conn_handle != conn_handle) {
224 return BLE_HS_ECONTROLLER;
225 }
226
227 memcpy(out_chan_map, params + 2, 5);
228
229 return 0;
230 }
231
232 int
ble_hs_hci_set_chan_class(const uint8_t * chan_map)233 ble_hs_hci_set_chan_class(const uint8_t *chan_map)
234 {
235 uint8_t buf[BLE_HCI_SET_HOST_CHAN_CLASS_LEN];
236 int rc;
237
238 ble_hs_hci_cmd_build_le_set_host_chan_class(chan_map, buf, sizeof buf);
239 rc = ble_hs_hci_cmd_tx_empty_ack(BLE_HCI_OP(BLE_HCI_OGF_LE,
240 BLE_HCI_OCF_LE_SET_HOST_CHAN_CLASS),
241 buf, sizeof(buf));
242 if (rc != 0) {
243 return rc;
244 }
245
246 return 0;
247 }
248