| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| #include <stddef.h> |
| #include <string.h> |
| #include "host/ble_hs.h" |
| #include "host/ble_hs_hci.h" |
| #include "ble_hs_priv.h" |
| |
| #if !MYNEWT_VAL(BLE_CONTROLLER) |
| static int |
| ble_hs_startup_read_sup_f_tx(void) |
| { |
| struct ble_hci_ip_rd_loc_supp_feat_rp rsp; |
| int rc; |
| |
| rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_INFO_PARAMS, |
| BLE_HCI_OCF_IP_RD_LOC_SUPP_FEAT), |
| NULL, 0, &rsp, sizeof(rsp)); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| /* for now we don't use it outside of init sequence so check this here |
| * LE Supported (Controller) byte 4, bit 6 |
| */ |
| if (!(le64toh(rsp.features) & 0x0000006000000000)) { |
| BLE_HS_LOG(ERROR, "Controller doesn't support LE\n"); |
| return BLE_HS_ECONTROLLER; |
| } |
| |
| return 0; |
| } |
| #endif |
| |
| static int |
| ble_hs_startup_read_local_ver_tx(void) |
| { |
| struct ble_hci_ip_rd_local_ver_rp rsp; |
| int rc; |
| |
| rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_INFO_PARAMS, |
| BLE_HCI_OCF_IP_RD_LOCAL_VER), |
| NULL, 0, &rsp, sizeof(rsp)); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| /* For now we are interested only in HCI Version */ |
| ble_hs_hci_set_hci_version(rsp.hci_ver); |
| |
| return 0; |
| } |
| |
| static int |
| ble_hs_startup_read_sup_cmd_tx(void) |
| { |
| struct ble_hci_ip_rd_loc_supp_cmd_rp rsp; |
| struct ble_hs_hci_sup_cmd sup_cmd; |
| int rc; |
| |
| rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_INFO_PARAMS, |
| BLE_HCI_OCF_IP_RD_LOC_SUPP_CMD), |
| NULL, 0, &rsp, sizeof(rsp)); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| /* Only check support for Set Event Mask Page 2 command */ |
| sup_cmd.event_mask2 = (rsp.commands[22] & 0x04) != 0; |
| ble_hs_hci_set_hci_supported_cmd(sup_cmd); |
| |
| return 0; |
| } |
| |
| static int |
| ble_hs_startup_le_read_sup_f_tx(void) |
| { |
| struct ble_hci_le_rd_loc_supp_feat_rp rsp; |
| int rc; |
| |
| rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, |
| BLE_HCI_OCF_LE_RD_LOC_SUPP_FEAT), |
| NULL,0, &rsp, sizeof(rsp)); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| ble_hs_hci_set_le_supported_feat(le64toh(rsp.features)); |
| |
| return 0; |
| } |
| |
| #if MYNEWT_VAL(BLE_ROLE_CENTRAL) || MYNEWT_VAL(BLE_ROLE_PERIPHERAL) |
| static int |
| ble_hs_startup_le_read_buf_sz_tx(uint16_t *out_pktlen, uint8_t *out_max_pkts) |
| { |
| struct ble_hci_le_rd_buf_size_rp rsp; |
| int rc; |
| |
| rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, |
| BLE_HCI_OCF_LE_RD_BUF_SIZE), NULL, 0, |
| &rsp, sizeof(rsp)); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| *out_pktlen = le16toh(rsp.data_len); |
| *out_max_pkts = rsp.data_packets; |
| |
| return 0; |
| } |
| |
| static int |
| ble_hs_startup_read_buf_sz_tx(uint16_t *out_pktlen, uint16_t *out_max_pkts) |
| { |
| struct ble_hci_ip_rd_buf_size_rp rsp; |
| int rc; |
| |
| rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_INFO_PARAMS, |
| BLE_HCI_OCF_IP_RD_BUF_SIZE), NULL, 0, |
| &rsp, sizeof(rsp)); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| *out_pktlen = le16toh(rsp.acl_data_len); |
| *out_max_pkts = le16toh(rsp.acl_num); |
| |
| return 0; |
| } |
| |
| static int |
| ble_hs_startup_read_buf_sz(void) |
| { |
| uint16_t le_pktlen = 0; |
| uint16_t max_pkts = 0; |
| uint16_t pktlen = 0; |
| uint8_t le_max_pkts = 0; |
| int rc; |
| |
| rc = ble_hs_startup_le_read_buf_sz_tx(&le_pktlen, &le_max_pkts); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| if (le_pktlen != 0) { |
| pktlen = le_pktlen; |
| max_pkts = le_max_pkts; |
| } else { |
| rc = ble_hs_startup_read_buf_sz_tx(&pktlen, &max_pkts); |
| if (rc != 0) { |
| return rc; |
| } |
| } |
| |
| rc = ble_hs_hci_set_buf_sz(pktlen, max_pkts); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| return 0; |
| } |
| #endif |
| |
| static int |
| ble_hs_startup_read_bd_addr(void) |
| { |
| struct ble_hci_ip_rd_bd_addr_rp rsp; |
| int rc; |
| |
| rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_INFO_PARAMS, |
| BLE_HCI_OCF_IP_RD_BD_ADDR), |
| NULL, 0, &rsp, sizeof(rsp)); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| ble_hs_id_set_pub(rsp.addr); |
| return 0; |
| } |
| |
| static int |
| ble_hs_startup_le_set_evmask_tx(void) |
| { |
| struct ble_hci_le_set_event_mask_cp cmd; |
| uint8_t version; |
| uint64_t mask; |
| int rc; |
| |
| version = ble_hs_hci_get_hci_version(); |
| |
| /* TODO should we also check for supported commands when setting this? */ |
| |
| /** |
| * Enable the following LE events: |
| * 0x0000000000000001 LE Connection Complete Event |
| * 0x0000000000000002 LE Advertising Report Event |
| * 0x0000000000000004 LE Connection Update Complete Event |
| * 0x0000000000000008 LE Read Remote Used Features Complete Event |
| * 0x0000000000000010 LE Long Term Key Request Event |
| */ |
| mask = 0x000000000000001f; |
| |
| if (version >= BLE_HCI_VER_BCS_4_1) { |
| /** |
| * Enable the following LE events: |
| * 0x0000000000000020 LE Remote Connection Parameter Request Event */ |
| mask |= 0x0000000000000020; |
| } |
| |
| if (version >= BLE_HCI_VER_BCS_4_2) { |
| /** |
| * Enable the following LE events: |
| * 0x0000000000000040 LE Data Length Change Event |
| * 0x0000000000000200 LE Enhanced Connection Complete Event |
| * 0x0000000000000400 LE Directed Advertising Report Event |
| */ |
| mask |= 0x0000000000000640; |
| } |
| |
| if (version >= BLE_HCI_VER_BCS_5_0) { |
| /** |
| * Enable the following LE events: |
| * 0x0000000000000800 LE PHY Update Complete Event |
| * 0x0000000000001000 LE Extended Advertising Report Event |
| * 0x0000000000002000 LE Periodic Advertising Sync Established Event |
| * 0x0000000000004000 LE Periodic Advertising Report Event |
| * 0x0000000000008000 LE Periodic Advertising Sync Lost Event |
| * 0x0000000000010000 LE Extended Scan Timeout Event |
| * 0x0000000000020000 LE Extended Advertising Set Terminated Event |
| * 0x0000000000040000 LE Scan Request Received Event |
| * 0x0000000000080000 LE Channel Selection Algorithm Event |
| */ |
| mask |= 0x00000000000ff800; |
| } |
| |
| #if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER) |
| if (version >= BLE_HCI_VER_BCS_5_1) { |
| /** |
| * Enable the following LE events: |
| * 0x0000000000800000 LE Periodic Advertising Sync Transfer Received event |
| */ |
| mask |= 0x0000000000800000; |
| } |
| #endif |
| |
| #if MYNEWT_VAL(BLE_CONN_SUBRATING) |
| if (version >= BLE_HCI_VER_BCS_5_3) { |
| /** |
| * Enable the following LE events: |
| * 0x0000000400000000 LE Subrate change event |
| */ |
| mask |= 0x0000000400000000; |
| } |
| #endif |
| |
| #if MYNEWT_VAL(BLE_POWER_CONTROL) |
| if (version >= BLE_HCI_VER_BCS_5_2) { |
| /** |
| * Enable the following LE events: |
| * 0x0000000080000000 LE Path Loss Threshold event |
| * 0x0000000100000000 LE Transmit Power Reporting event |
| */ |
| mask |= 0x0000000180000000; |
| } |
| #endif |
| |
| #if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS) |
| if (version >= BLE_HCI_VER_BCS_5_2) { |
| /** |
| * Enable the following LE events: |
| * 0x0000000200000000 LE BIGInfo Advertising Report event |
| */ |
| mask |= 0x0000000200000000; |
| } |
| #endif |
| |
| #if MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE) |
| if (version >= BLE_HCI_VER_BCS_5_2) { |
| /** |
| * Enable the following LE events: |
| * 0x0000000004000000 LE Create BIG Complete event |
| * 0x0000000008000000 LE Terminate BIG Complete event |
| */ |
| mask |= 0x000000000C000000; |
| } |
| #endif |
| |
| #if MYNEWT_VAL(BLE_ISO_BROADCAST_SINK) |
| if (version >= BLE_HCI_VER_BCS_5_2) { |
| /** |
| * Enable the following LE events: |
| * 0x0000000010000000 LE BIG Sync Established Complete event |
| * 0x0000000020000000 LE BIG Sync lost event |
| */ |
| mask |= 0x0000000030000000; |
| } |
| #endif |
| |
| #if MYNEWT_VAL(BLE_CHANNEL_SOUNDING) |
| if (version >= BLE_HCI_VER_BCS_5_4) { |
| /** |
| * Enable the following LE events: |
| * 0x0000080000000000 LE CS Read Remote Supported Capabilities Complete event |
| * 0x0000100000000000 LE CS Read Remote FAE Table Complete event |
| * 0x0000200000000000 LE CS Security Enable Complete event |
| * 0x0000400000000000 LE CS Config Complete event |
| * 0x0000800000000000 LE CS Procedure Enable Complete event |
| * 0x0001000000000000 LE CS Subevent Result event |
| * 0x0002000000000000 LE CS Subevent Result Continue event |
| * 0x0004000000000000 LE CS Test End Complete event |
| */ |
| mask |= 0x0007f80000000000; |
| } |
| #endif |
| |
| cmd.event_mask = htole64(mask); |
| |
| rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, |
| BLE_HCI_OCF_LE_SET_EVENT_MASK), |
| &cmd, sizeof(cmd), NULL, 0); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| static int |
| ble_hs_startup_set_evmask_tx(void) |
| { |
| struct ble_hci_cb_set_event_mask_cp cmd; |
| struct ble_hci_cb_set_event_mask2_cp cmd2; |
| uint8_t version; |
| struct ble_hs_hci_sup_cmd sup_cmd; |
| int rc; |
| |
| version = ble_hs_hci_get_hci_version(); |
| sup_cmd = ble_hs_hci_get_hci_supported_cmd(); |
| |
| /** |
| * Enable the following events: |
| * 0x0000000000000010 Disconnection Complete Event |
| * 0x0000000000000080 Encryption Change Event |
| * 0x0000000000008000 Hardware Error Event |
| * 0x0000000002000000 Data Buffer Overflow Event |
| * 0x0000800000000000 Encryption Key Refresh Complete Event |
| * 0x2000000000000000 LE Meta-Event |
| */ |
| cmd.event_mask = htole64(0x2000800002008090); |
| |
| rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, |
| BLE_HCI_OCF_CB_SET_EVENT_MASK), |
| &cmd, sizeof(cmd), NULL, 0); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| if ((version >= BLE_HCI_VER_BCS_4_1) && sup_cmd.event_mask2) { |
| /** |
| * Enable the following events: |
| * 0x0000000000800000 Authenticated Payload Timeout Event |
| */ |
| cmd2.event_mask2 = htole64(0x0000000000800000); |
| rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, |
| BLE_HCI_OCF_CB_SET_EVENT_MASK2), |
| &cmd2, sizeof(cmd2), NULL, 0); |
| if (rc != 0) { |
| return rc; |
| } |
| } |
| |
| return 0; |
| } |
| |
| static int |
| ble_hs_startup_reset_tx(void) |
| { |
| return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, |
| BLE_HCI_OCF_CB_RESET), |
| NULL, 0, NULL, 0); |
| } |
| |
| int |
| ble_hs_startup_go(void) |
| { |
| struct ble_store_gen_key gen_key; |
| int rc; |
| |
| rc = ble_hs_startup_reset_tx(); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| rc = ble_hs_startup_read_local_ver_tx(); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| /* Read local supported commands. */ |
| rc = ble_hs_startup_read_sup_cmd_tx(); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| /* we need to check this only if using external controller */ |
| #if !MYNEWT_VAL(BLE_CONTROLLER) |
| if (ble_hs_hci_get_hci_version() < BLE_HCI_VER_BCS_4_0) { |
| BLE_HS_LOG(ERROR, "Required controller version is 4.0 (6)\n"); |
| return BLE_HS_ECONTROLLER; |
| } |
| |
| rc = ble_hs_startup_read_sup_f_tx(); |
| if (rc != 0) { |
| return rc; |
| } |
| #endif |
| |
| rc = ble_hs_startup_set_evmask_tx(); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| rc = ble_hs_startup_le_set_evmask_tx(); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| #if MYNEWT_VAL(BLE_ROLE_CENTRAL) || MYNEWT_VAL(BLE_ROLE_PERIPHERAL) |
| rc = ble_hs_startup_read_buf_sz(); |
| if (rc != 0) { |
| return rc; |
| } |
| #endif |
| |
| rc = ble_hs_startup_le_read_sup_f_tx(); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| rc = ble_hs_startup_read_bd_addr(); |
| if (rc != 0) { |
| return rc; |
| } |
| |
| if (ble_hs_cfg.store_gen_key_cb) { |
| memset(&gen_key, 0, sizeof(gen_key)); |
| rc = ble_hs_cfg.store_gen_key_cb(BLE_STORE_GEN_KEY_IRK, &gen_key, |
| BLE_HS_CONN_HANDLE_NONE); |
| if (rc == 0) { |
| ble_hs_pvcy_set_our_irk(gen_key.irk); |
| } |
| } else { |
| rc = -1; |
| } |
| |
| if (rc != 0) { |
| ble_hs_pvcy_set_our_irk(NULL); |
| } |
| |
| /* If flow control is enabled, configure the controller to use it. */ |
| ble_hs_flow_startup(); |
| |
| return 0; |
| } |