/* * Copyright (c) 2016-2018 Nordic Semiconductor ASA * Copyright (c) 2016 Vinayak Kariappa Chettimada * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "util/util.h" #include "util/memq.h" #include "hal/ecb.h" #include "hal/ccm.h" #include "ll_sw/pdu.h" #include "ll_sw/lll.h" #include "ll_sw/lll_conn.h" #include "ll_sw/ull_conn_types.h" #include "ll.h" #include "ll_feat.h" #include "hci_internal.h" #if defined(CONFIG_BT_HCI_MESH_EXT) #include "ll_sw/ll_mesh.h" #endif /* CONFIG_BT_HCI_MESH_EXT */ #if defined(CONFIG_BT_CTLR_DTM_HCI) #include "ll_sw/ll_test.h" #endif /* CONFIG_BT_CTLR_DTM_HCI */ #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER) #define LOG_MODULE_NAME bt_ctlr_hci #include "common/log.h" #include "hal/debug.h" /* opcode of the HCI command currently being processed. The opcode is stored * by hci_cmd_handle() and then used during the creation of cmd complete and * cmd status events to avoid passing it up the call chain. */ static u16_t _opcode; #if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 /* Scan duplicate filter */ struct dup { u8_t mask; bt_addr_le_t addr; }; static struct dup dup_filter[CONFIG_BT_CTLR_DUP_FILTER_LEN]; static s32_t dup_count; static u32_t dup_curr; #endif #if defined(CONFIG_BT_HCI_MESH_EXT) struct scan_filter { u8_t count; u8_t lengths[CONFIG_BT_CTLR_MESH_SF_PATTERNS]; u8_t patterns[CONFIG_BT_CTLR_MESH_SF_PATTERNS] [BT_HCI_MESH_PATTERN_LEN_MAX]; }; static struct scan_filter scan_filters[CONFIG_BT_CTLR_MESH_SCAN_FILTERS]; static u8_t sf_curr; #endif #if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL) s32_t hci_hbuf_total; u32_t hci_hbuf_sent; u32_t hci_hbuf_acked; u16_t hci_hbuf_pend[CONFIG_BT_MAX_CONN]; atomic_t hci_state_mask; static struct k_poll_signal *hbuf_signal; #endif #if defined(CONFIG_BT_CONN) static u32_t conn_count; #endif #define DEFAULT_EVENT_MASK 0x1fffffffffff #define DEFAULT_EVENT_MASK_PAGE_2 0x0 #define DEFAULT_LE_EVENT_MASK 0x1f static u64_t event_mask = DEFAULT_EVENT_MASK; static u64_t event_mask_page_2 = DEFAULT_EVENT_MASK_PAGE_2; static u64_t le_event_mask = DEFAULT_LE_EVENT_MASK; #if defined(CONFIG_BT_CONN) static void le_conn_complete(struct pdu_data *pdu_data, u16_t handle, struct net_buf *buf); #endif /* CONFIG_BT_CONN */ static void evt_create(struct net_buf *buf, u8_t evt, u8_t len) { struct bt_hci_evt_hdr *hdr; hdr = net_buf_add(buf, sizeof(*hdr)); hdr->evt = evt; hdr->len = len; } static void *cmd_complete(struct net_buf **buf, u8_t plen) { struct bt_hci_evt_cmd_complete *cc; *buf = bt_buf_get_cmd_complete(K_FOREVER); evt_create(*buf, BT_HCI_EVT_CMD_COMPLETE, sizeof(*cc) + plen); cc = net_buf_add(*buf, sizeof(*cc)); cc->ncmd = 1U; cc->opcode = sys_cpu_to_le16(_opcode); return net_buf_add(*buf, plen); } #if defined(CONFIG_BT_CONN) static struct net_buf *cmd_status(u8_t status) { struct bt_hci_evt_cmd_status *cs; struct net_buf *buf; buf = bt_buf_get_cmd_complete(K_FOREVER); evt_create(buf, BT_HCI_EVT_CMD_STATUS, sizeof(*cs)); cs = net_buf_add(buf, sizeof(*cs)); cs->status = status; cs->ncmd = 1U; cs->opcode = sys_cpu_to_le16(_opcode); return buf; } #endif static void *meta_evt(struct net_buf *buf, u8_t subevt, u8_t melen) { struct bt_hci_evt_le_meta_event *me; evt_create(buf, BT_HCI_EVT_LE_META_EVENT, sizeof(*me) + melen); me = net_buf_add(buf, sizeof(*me)); me->subevent = subevt; return net_buf_add(buf, melen); } #if defined(CONFIG_BT_HCI_MESH_EXT) static void *mesh_evt(struct net_buf *buf, u8_t subevt, u8_t melen) { struct bt_hci_evt_mesh *me; evt_create(buf, BT_HCI_EVT_VENDOR, sizeof(*me) + melen); me = net_buf_add(buf, sizeof(*me)); me->prefix = BT_HCI_MESH_EVT_PREFIX; me->subevent = subevt; return net_buf_add(buf, melen); } #endif /* CONFIG_BT_HCI_MESH_EXT */ #if defined(CONFIG_BT_CONN) static void disconnect(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_disconnect *cmd = (void *)buf->data; u16_t handle; u8_t status; handle = sys_le16_to_cpu(cmd->handle); status = ll_terminate_ind_send(handle, cmd->reason); *evt = cmd_status(status); } static void read_remote_ver_info(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_read_remote_version_info *cmd = (void *)buf->data; u16_t handle; u8_t status; handle = sys_le16_to_cpu(cmd->handle); status = ll_version_ind_send(handle); *evt = cmd_status(status); } #endif /* CONFIG_BT_CONN */ static int link_control_cmd_handle(u16_t ocf, struct net_buf *cmd, struct net_buf **evt) { switch (ocf) { #if defined(CONFIG_BT_CONN) case BT_OCF(BT_HCI_OP_DISCONNECT): disconnect(cmd, evt); break; case BT_OCF(BT_HCI_OP_READ_REMOTE_VERSION_INFO): read_remote_ver_info(cmd, evt); break; #endif /* CONFIG_BT_CONN */ default: return -EINVAL; } return 0; } static void set_event_mask(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_set_event_mask *cmd = (void *)buf->data; struct bt_hci_evt_cc_status *ccst; event_mask = sys_get_le64(cmd->events); ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = 0x00; } static void set_event_mask_page_2(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_set_event_mask_page_2 *cmd = (void *)buf->data; struct bt_hci_evt_cc_status *ccst; event_mask_page_2 = sys_get_le64(cmd->events_page_2); ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = 0x00; } static void reset(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_evt_cc_status *ccst; #if defined(CONFIG_BT_HCI_MESH_EXT) int i; for (i = 0; i < ARRAY_SIZE(scan_filters); i++) { scan_filters[i].count = 0U; } sf_curr = 0xFF; #endif #if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 dup_count = -1; #endif /* reset event masks */ event_mask = DEFAULT_EVENT_MASK; event_mask_page_2 = DEFAULT_EVENT_MASK_PAGE_2; le_event_mask = DEFAULT_LE_EVENT_MASK; if (buf) { ll_reset(); ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = 0x00; } #if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL) hci_hbuf_total = 0; hci_hbuf_sent = 0U; hci_hbuf_acked = 0U; (void)memset(hci_hbuf_pend, 0, sizeof(hci_hbuf_pend)); conn_count = 0U; if (buf) { atomic_set_bit(&hci_state_mask, HCI_STATE_BIT_RESET); k_poll_signal_raise(hbuf_signal, 0x0); } #endif } #if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL) static void set_ctl_to_host_flow(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_set_ctl_to_host_flow *cmd = (void *)buf->data; u8_t flow_enable = cmd->flow_enable; struct bt_hci_evt_cc_status *ccst; ccst = cmd_complete(evt, sizeof(*ccst)); /* require host buffer size before enabling flow control, and * disallow if any connections are up */ if (!hci_hbuf_total || conn_count) { ccst->status = BT_HCI_ERR_CMD_DISALLOWED; return; } else { ccst->status = 0x00; } switch (flow_enable) { case BT_HCI_CTL_TO_HOST_FLOW_DISABLE: if (hci_hbuf_total < 0) { /* already disabled */ return; } break; case BT_HCI_CTL_TO_HOST_FLOW_ENABLE: if (hci_hbuf_total > 0) { /* already enabled */ return; } break; default: ccst->status = BT_HCI_ERR_INVALID_PARAM; return; } hci_hbuf_sent = 0U; hci_hbuf_acked = 0U; (void)memset(hci_hbuf_pend, 0, sizeof(hci_hbuf_pend)); hci_hbuf_total = -hci_hbuf_total; } static void host_buffer_size(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_host_buffer_size *cmd = (void *)buf->data; u16_t acl_pkts = sys_le16_to_cpu(cmd->acl_pkts); u16_t acl_mtu = sys_le16_to_cpu(cmd->acl_mtu); struct bt_hci_evt_cc_status *ccst; ccst = cmd_complete(evt, sizeof(*ccst)); if (hci_hbuf_total) { ccst->status = BT_HCI_ERR_CMD_DISALLOWED; return; } /* fragmentation from controller to host not supported, require * ACL MTU to be at least the LL MTU */ if (acl_mtu < LL_LENGTH_OCTETS_RX_MAX) { ccst->status = BT_HCI_ERR_INVALID_PARAM; return; } BT_DBG("FC: host buf size: %d", acl_pkts); hci_hbuf_total = -acl_pkts; } static void host_num_completed_packets(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_host_num_completed_packets *cmd = (void *)buf->data; struct bt_hci_evt_cc_status *ccst; u32_t count = 0U; int i; /* special case, no event returned except for error conditions */ if (hci_hbuf_total <= 0) { ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = BT_HCI_ERR_CMD_DISALLOWED; return; } else if (!conn_count) { ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = BT_HCI_ERR_INVALID_PARAM; return; } /* leave *evt == NULL so no event is generated */ for (i = 0; i < cmd->num_handles; i++) { u16_t h = sys_le16_to_cpu(cmd->h[i].handle); u16_t c = sys_le16_to_cpu(cmd->h[i].count); if ((h >= ARRAY_SIZE(hci_hbuf_pend)) || (c > hci_hbuf_pend[h])) { ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = BT_HCI_ERR_INVALID_PARAM; return; } hci_hbuf_pend[h] -= c; count += c; } BT_DBG("FC: acked: %d", count); hci_hbuf_acked += count; k_poll_signal_raise(hbuf_signal, 0x0); } #endif #if defined(CONFIG_BT_CTLR_LE_PING) static void read_auth_payload_timeout(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_read_auth_payload_timeout *cmd = (void *)buf->data; struct bt_hci_rp_read_auth_payload_timeout *rp; u16_t auth_payload_timeout; u16_t handle; u8_t status; handle = sys_le16_to_cpu(cmd->handle); status = ll_apto_get(handle, &auth_payload_timeout); rp = cmd_complete(evt, sizeof(*rp)); rp->status = status; rp->handle = sys_cpu_to_le16(handle); rp->auth_payload_timeout = sys_cpu_to_le16(auth_payload_timeout); } static void write_auth_payload_timeout(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_write_auth_payload_timeout *cmd = (void *)buf->data; struct bt_hci_rp_write_auth_payload_timeout *rp; u16_t auth_payload_timeout; u16_t handle; u8_t status; handle = sys_le16_to_cpu(cmd->handle); auth_payload_timeout = sys_le16_to_cpu(cmd->auth_payload_timeout); status = ll_apto_set(handle, auth_payload_timeout); rp = cmd_complete(evt, sizeof(*rp)); rp->status = status; rp->handle = sys_cpu_to_le16(handle); } #endif /* CONFIG_BT_CTLR_LE_PING */ #if defined(CONFIG_BT_CONN) static void read_tx_power_level(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_read_tx_power_level *cmd = (void *)buf->data; struct bt_hci_rp_read_tx_power_level *rp; u16_t handle; u8_t status; u8_t type; handle = sys_le16_to_cpu(cmd->handle); type = cmd->type; rp = cmd_complete(evt, sizeof(*rp)); status = ll_tx_pwr_lvl_get(handle, type, &rp->tx_power_level); rp->status = status; rp->handle = sys_cpu_to_le16(handle); } #endif /* CONFIG_BT_CONN */ static int ctrl_bb_cmd_handle(u16_t ocf, struct net_buf *cmd, struct net_buf **evt) { switch (ocf) { case BT_OCF(BT_HCI_OP_SET_EVENT_MASK): set_event_mask(cmd, evt); break; case BT_OCF(BT_HCI_OP_RESET): reset(cmd, evt); break; case BT_OCF(BT_HCI_OP_SET_EVENT_MASK_PAGE_2): set_event_mask_page_2(cmd, evt); break; #if defined(CONFIG_BT_CONN) case BT_OCF(BT_HCI_OP_READ_TX_POWER_LEVEL): read_tx_power_level(cmd, evt); break; #endif /* CONFIG_BT_CONN */ #if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL) case BT_OCF(BT_HCI_OP_SET_CTL_TO_HOST_FLOW): set_ctl_to_host_flow(cmd, evt); break; case BT_OCF(BT_HCI_OP_HOST_BUFFER_SIZE): host_buffer_size(cmd, evt); break; case BT_OCF(BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS): host_num_completed_packets(cmd, evt); break; #endif #if defined(CONFIG_BT_CTLR_LE_PING) case BT_OCF(BT_HCI_OP_READ_AUTH_PAYLOAD_TIMEOUT): read_auth_payload_timeout(cmd, evt); break; case BT_OCF(BT_HCI_OP_WRITE_AUTH_PAYLOAD_TIMEOUT): write_auth_payload_timeout(cmd, evt); break; #endif /* CONFIG_BT_CTLR_LE_PING */ default: return -EINVAL; } return 0; } static void read_local_version_info(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_rp_read_local_version_info *rp; rp = cmd_complete(evt, sizeof(*rp)); rp->status = 0x00; rp->hci_version = LL_VERSION_NUMBER; rp->hci_revision = sys_cpu_to_le16(0); rp->lmp_version = LL_VERSION_NUMBER; rp->manufacturer = sys_cpu_to_le16(CONFIG_BT_CTLR_COMPANY_ID); rp->lmp_subversion = sys_cpu_to_le16(CONFIG_BT_CTLR_SUBVERSION_NUMBER); } static void read_supported_commands(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_rp_read_supported_commands *rp; rp = cmd_complete(evt, sizeof(*rp)); rp->status = 0x00; (void)memset(&rp->commands[0], 0, sizeof(rp->commands)); /* Read Remote Version Info. */ rp->commands[2] |= BIT(7); /* Set Event Mask, and Reset. */ rp->commands[5] |= BIT(6) | BIT(7); /* Read TX Power Level. */ rp->commands[10] |= BIT(2); #if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL) /* Set FC, Host Buffer Size and Host Num Completed */ rp->commands[10] |= BIT(5) | BIT(6) | BIT(7); #endif /* CONFIG_BT_HCI_ACL_FLOW_CONTROL */ /* Read Local Version Info, Read Local Supported Features. */ rp->commands[14] |= BIT(3) | BIT(5); /* Read BD ADDR. */ rp->commands[15] |= BIT(1); #if defined(CONFIG_BT_CTLR_CONN_RSSI) /* Read RSSI. */ rp->commands[15] |= BIT(5); #endif /* CONFIG_BT_CTLR_CONN_RSSI */ /* Set Event Mask Page 2 */ rp->commands[22] |= BIT(2); /* LE Set Event Mask, LE Read Buffer Size, LE Read Local Supp Feats, * Set Random Addr */ rp->commands[25] |= BIT(0) | BIT(1) | BIT(2) | BIT(4); #if defined(CONFIG_BT_CTLR_FILTER) /* LE Read WL Size, LE Clear WL */ rp->commands[26] |= BIT(6) | BIT(7); /* LE Add Dev to WL, LE Remove Dev from WL */ rp->commands[27] |= BIT(0) | BIT(1); #endif /* CONFIG_BT_CTLR_FILTER */ /* LE Encrypt, LE Rand */ rp->commands[27] |= BIT(6) | BIT(7); /* LE Read Supported States */ rp->commands[28] |= BIT(3); #if defined(CONFIG_BT_BROADCASTER) /* LE Set Adv Params, LE Read Adv Channel TX Power, LE Set Adv Data */ rp->commands[25] |= BIT(5) | BIT(6) | BIT(7); /* LE Set Scan Response Data, LE Set Adv Enable */ rp->commands[26] |= BIT(0) | BIT(1); #endif /* CONFIG_BT_BROADCASTER */ #if defined(CONFIG_BT_OBSERVER) /* LE Set Scan Params, LE Set Scan Enable */ rp->commands[26] |= BIT(2) | BIT(3); #endif /* CONFIG_BT_OBSERVER */ #if defined(CONFIG_BT_CONN) #if defined(CONFIG_BT_CENTRAL) /* LE Create Connection, LE Create Connection Cancel */ rp->commands[26] |= BIT(4) | BIT(5); /* Set Host Channel Classification */ rp->commands[27] |= BIT(3); #if defined(CONFIG_BT_CTLR_LE_ENC) /* LE Start Encryption */ rp->commands[28] |= BIT(0); #endif /* CONFIG_BT_CTLR_LE_ENC */ #endif /* CONFIG_BT_CENTRAL */ #if defined(CONFIG_BT_PERIPHERAL) #if defined(CONFIG_BT_CTLR_LE_ENC) /* LE LTK Request Reply, LE LTK Request Negative Reply */ rp->commands[28] |= BIT(1) | BIT(2); #endif /* CONFIG_BT_CTLR_LE_ENC */ #endif /* CONFIG_BT_PERIPHERAL */ /* Disconnect. */ rp->commands[0] |= BIT(5); /* LE Connection Update, LE Read Channel Map, LE Read Remote Features */ rp->commands[27] |= BIT(2) | BIT(4) | BIT(5); #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ) /* LE Remote Conn Param Req and Neg Reply */ rp->commands[33] |= BIT(4) | BIT(5); #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */ #if defined(CONFIG_BT_CTLR_LE_PING) /* Read and Write authenticated payload timeout */ rp->commands[32] |= BIT(4) | BIT(5); #endif /* CONFIG_BT_CTLR_LE_PING */ #if defined(CONFIG_BT_CTLR_DATA_LENGTH) /* LE Set Data Length, and LE Read Suggested Data Length. */ rp->commands[33] |= BIT(6) | BIT(7); /* LE Write Suggested Data Length. */ rp->commands[34] |= BIT(0); /* LE Read Maximum Data Length. */ rp->commands[35] |= BIT(3); #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ #if defined(CONFIG_BT_CTLR_PHY) /* LE Read PHY Command. */ rp->commands[35] |= BIT(4); /* LE Set Default PHY Command. */ rp->commands[35] |= BIT(5); /* LE Set PHY Command. */ rp->commands[35] |= BIT(6); #endif /* CONFIG_BT_CTLR_PHY */ #endif /* CONFIG_BT_CONN */ #if defined(CONFIG_BT_CTLR_DTM_HCI) /* LE RX Test, LE TX Test, LE Test End */ rp->commands[28] |= BIT(4) | BIT(5) | BIT(6); /* LE Enhanced RX Test. */ rp->commands[35] |= BIT(7); /* LE Enhanced TX Test. */ rp->commands[36] |= BIT(0); #endif /* CONFIG_BT_CTLR_DTM_HCI */ #if defined(CONFIG_BT_CTLR_PRIVACY) /* LE resolving list commands, LE Read Peer RPA */ rp->commands[34] |= BIT(3) | BIT(4) | BIT(5) | BIT(6) | BIT(7); /* LE Read Local RPA, LE Set AR Enable, Set RPA Timeout */ rp->commands[35] |= BIT(0) | BIT(1) | BIT(2); /* LE Set Privacy Mode */ rp->commands[39] |= BIT(2); #endif /* CONFIG_BT_CTLR_PRIVACY */ #if defined(CONFIG_BT_HCI_RAW) && defined(CONFIG_BT_TINYCRYPT_ECC) /* LE Read Local P256 Public Key and LE Generate DH Key*/ rp->commands[34] |= BIT(1) | BIT(2); #endif /* CONFIG_BT_HCI_RAW && CONFIG_BT_TINYCRYPT_ECC */ /* LE Read TX Power. */ rp->commands[38] |= BIT(7); } static void read_local_features(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_rp_read_local_features *rp; rp = cmd_complete(evt, sizeof(*rp)); rp->status = 0x00; (void)memset(&rp->features[0], 0x00, sizeof(rp->features)); /* BR/EDR not supported and LE supported */ rp->features[4] = (1 << 5) | (1 << 6); } static void read_bd_addr(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_rp_read_bd_addr *rp; rp = cmd_complete(evt, sizeof(*rp)); rp->status = 0x00; ll_addr_get(0, &rp->bdaddr.val[0]); } static int info_cmd_handle(u16_t ocf, struct net_buf *cmd, struct net_buf **evt) { switch (ocf) { case BT_OCF(BT_HCI_OP_READ_LOCAL_VERSION_INFO): read_local_version_info(cmd, evt); break; case BT_OCF(BT_HCI_OP_READ_SUPPORTED_COMMANDS): read_supported_commands(cmd, evt); break; case BT_OCF(BT_HCI_OP_READ_LOCAL_FEATURES): read_local_features(cmd, evt); break; case BT_OCF(BT_HCI_OP_READ_BD_ADDR): read_bd_addr(cmd, evt); break; default: return -EINVAL; } return 0; } #if defined(CONFIG_BT_CTLR_CONN_RSSI) static void read_rssi(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_read_rssi *cmd = (void *)buf->data; struct bt_hci_rp_read_rssi *rp; u16_t handle; handle = sys_le16_to_cpu(cmd->handle); rp = cmd_complete(evt, sizeof(*rp)); rp->status = ll_rssi_get(handle, &rp->rssi); rp->handle = sys_cpu_to_le16(handle); /* The Link Layer currently returns RSSI as an absolute value */ rp->rssi = (!rp->status) ? -rp->rssi : 127; } #endif /* CONFIG_BT_CTLR_CONN_RSSI */ static int status_cmd_handle(u16_t ocf, struct net_buf *cmd, struct net_buf **evt) { switch (ocf) { #if defined(CONFIG_BT_CTLR_CONN_RSSI) case BT_OCF(BT_HCI_OP_READ_RSSI): read_rssi(cmd, evt); break; #endif /* CONFIG_BT_CTLR_CONN_RSSI */ default: return -EINVAL; } return 0; } static void le_set_event_mask(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_set_event_mask *cmd = (void *)buf->data; struct bt_hci_evt_cc_status *ccst; le_event_mask = sys_get_le64(cmd->events); ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = 0x00; } static void le_read_buffer_size(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_rp_le_read_buffer_size *rp; rp = cmd_complete(evt, sizeof(*rp)); rp->status = 0x00; rp->le_max_len = sys_cpu_to_le16(CONFIG_BT_CTLR_TX_BUFFER_SIZE); rp->le_max_num = CONFIG_BT_CTLR_TX_BUFFERS; } static void le_read_local_features(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_rp_le_read_local_features *rp; rp = cmd_complete(evt, sizeof(*rp)); rp->status = 0x00; (void)memset(&rp->features[0], 0x00, sizeof(rp->features)); rp->features[0] = LL_FEAT & 0xFF; rp->features[1] = (LL_FEAT >> 8) & 0xFF; rp->features[2] = (LL_FEAT >> 16) & 0xFF; } static void le_set_random_address(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_set_random_address *cmd = (void *)buf->data; struct bt_hci_evt_cc_status *ccst; u8_t status; status = ll_addr_set(1, &cmd->bdaddr.val[0]); ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = status; } #if defined(CONFIG_BT_CTLR_FILTER) static void le_read_wl_size(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_rp_le_read_wl_size *rp; rp = cmd_complete(evt, sizeof(*rp)); rp->status = 0x00; rp->wl_size = ll_wl_size_get(); } static void le_clear_wl(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_evt_cc_status *ccst; ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = ll_wl_clear(); } static void le_add_dev_to_wl(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_add_dev_to_wl *cmd = (void *)buf->data; struct bt_hci_evt_cc_status *ccst; u8_t status; status = ll_wl_add(&cmd->addr); ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = status; } static void le_rem_dev_from_wl(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_rem_dev_from_wl *cmd = (void *)buf->data; struct bt_hci_evt_cc_status *ccst; u8_t status; status = ll_wl_remove(&cmd->addr); ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = status; } #endif /* CONFIG_BT_CTLR_FILTER */ static void le_encrypt(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_encrypt *cmd = (void *)buf->data; struct bt_hci_rp_le_encrypt *rp; u8_t enc_data[16]; ecb_encrypt(cmd->key, cmd->plaintext, enc_data, NULL); rp = cmd_complete(evt, sizeof(*rp)); rp->status = 0x00; memcpy(rp->enc_data, enc_data, 16); } static void le_rand(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_rp_le_rand *rp; u8_t count = sizeof(rp->rand); rp = cmd_complete(evt, sizeof(*rp)); rp->status = 0x00; bt_rand(rp->rand, count); } static void le_read_supp_states(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_rp_le_read_supp_states *rp; u64_t states = 0U; rp = cmd_complete(evt, sizeof(*rp)); rp->status = 0x00; #define ST_ADV (BIT64(0) | BIT64(1) | BIT64(8) | BIT64(9) | BIT64(12) | \ BIT64(13) | BIT64(16) | BIT64(17) | BIT64(18) | BIT64(19) | \ BIT64(20) | BIT64(21)) #define ST_SCA (BIT64(4) | BIT64(5) | BIT64(8) | BIT64(9) | BIT64(10) | \ BIT64(11) | BIT64(12) | BIT64(13) | BIT64(14) | BIT64(15) | \ BIT64(22) | BIT64(23) | BIT64(24) | BIT64(25) | BIT64(26) | \ BIT64(27) | BIT64(30) | BIT64(31)) #define ST_SLA (BIT64(2) | BIT64(3) | BIT64(7) | BIT64(10) | BIT64(11) | \ BIT64(14) | BIT64(15) | BIT64(20) | BIT64(21) | BIT64(26) | \ BIT64(27) | BIT64(29) | BIT64(30) | BIT64(31) | BIT64(32) | \ BIT64(33) | BIT64(34) | BIT64(35) | BIT64(36) | BIT64(37) | \ BIT64(38) | BIT64(39) | BIT64(40) | BIT64(41)) #define ST_MAS (BIT64(6) | BIT64(16) | BIT64(17) | BIT64(18) | BIT64(19) | \ BIT64(22) | BIT64(23) | BIT64(24) | BIT64(25) | BIT64(28) | \ BIT64(32) | BIT64(33) | BIT64(34) | BIT64(35) | BIT64(36) | \ BIT64(37) | BIT64(41)) #if defined(CONFIG_BT_BROADCASTER) states |= ST_ADV; #else states &= ~ST_ADV; #endif #if defined(CONFIG_BT_OBSERVER) states |= ST_SCA; #else states &= ~ST_SCA; #endif #if defined(CONFIG_BT_PERIPHERAL) states |= ST_SLA; #else states &= ~ST_SLA; #endif #if defined(CONFIG_BT_CENTRAL) states |= ST_MAS; #else states &= ~ST_MAS; #endif /* All states and combinations supported except: * Initiating State + Passive Scanning * Initiating State + Active Scanning */ states &= ~(BIT64(22) | BIT64(23)); BT_DBG("states: 0x%08x%08x", (u32_t)(states >> 32), (u32_t)(states & 0xffffffff)); sys_put_le64(states, rp->le_states); } #if defined(CONFIG_BT_BROADCASTER) static void le_set_adv_param(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_set_adv_param *cmd = (void *)buf->data; struct bt_hci_evt_cc_status *ccst; u16_t min_interval; u8_t status; min_interval = sys_le16_to_cpu(cmd->min_interval); #if defined(CONFIG_BT_CTLR_ADV_EXT) status = ll_adv_params_set(0, 0, min_interval, cmd->type, cmd->own_addr_type, cmd->direct_addr.type, &cmd->direct_addr.a.val[0], cmd->channel_map, cmd->filter_policy, 0, 0, 0, 0, 0, 0); #else /* !CONFIG_BT_CTLR_ADV_EXT */ status = ll_adv_params_set(min_interval, cmd->type, cmd->own_addr_type, cmd->direct_addr.type, &cmd->direct_addr.a.val[0], cmd->channel_map, cmd->filter_policy); #endif /* !CONFIG_BT_CTLR_ADV_EXT */ ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = status; } static void le_read_adv_chan_tx_power(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_rp_le_read_chan_tx_power *rp; rp = cmd_complete(evt, sizeof(*rp)); rp->status = 0x00; rp->tx_power_level = 0; } static void le_set_adv_data(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_set_adv_data *cmd = (void *)buf->data; struct bt_hci_evt_cc_status *ccst; u8_t status; #if defined(CONFIG_BT_CTLR_ADV_EXT) status = ll_adv_data_set(0, cmd->len, &cmd->data[0]); #else /* !CONFIG_BT_CTLR_ADV_EXT */ status = ll_adv_data_set(cmd->len, &cmd->data[0]); #endif /* !CONFIG_BT_CTLR_ADV_EXT */ ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = status; } static void le_set_scan_rsp_data(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_set_scan_rsp_data *cmd = (void *)buf->data; struct bt_hci_evt_cc_status *ccst; u8_t status; #if defined(CONFIG_BT_CTLR_ADV_EXT) status = ll_adv_scan_rsp_set(0, cmd->len, &cmd->data[0]); #else /* !CONFIG_BT_CTLR_ADV_EXT */ status = ll_adv_scan_rsp_set(cmd->len, &cmd->data[0]); #endif /* !CONFIG_BT_CTLR_ADV_EXT */ ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = status; } static void le_set_adv_enable(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_set_adv_enable *cmd = (void *)buf->data; struct bt_hci_evt_cc_status *ccst; u8_t status; #if defined(CONFIG_BT_CTLR_ADV_EXT) || defined(CONFIG_BT_HCI_MESH_EXT) #if defined(CONFIG_BT_HCI_MESH_EXT) status = ll_adv_enable(0, cmd->enable, 0, 0, 0, 0, 0); #else /* !CONFIG_BT_HCI_MESH_EXT */ status = ll_adv_enable(0, cmd->enable); #endif /* !CONFIG_BT_HCI_MESH_EXT */ #else /* !CONFIG_BT_CTLR_ADV_EXT || !CONFIG_BT_HCI_MESH_EXT */ status = ll_adv_enable(cmd->enable); #endif /* !CONFIG_BT_CTLR_ADV_EXT || !CONFIG_BT_HCI_MESH_EXT */ ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = status; } #endif /* CONFIG_BT_BROADCASTER */ #if defined(CONFIG_BT_OBSERVER) static void le_set_scan_param(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_set_scan_param *cmd = (void *)buf->data; struct bt_hci_evt_cc_status *ccst; u16_t interval; u16_t window; u8_t status; interval = sys_le16_to_cpu(cmd->interval); window = sys_le16_to_cpu(cmd->window); status = ll_scan_params_set(cmd->scan_type, interval, window, cmd->addr_type, cmd->filter_policy); ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = status; } static void le_set_scan_enable(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_set_scan_enable *cmd = (void *)buf->data; struct bt_hci_evt_cc_status *ccst; u8_t status; #if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 /* initialize duplicate filtering */ if (cmd->enable && cmd->filter_dup) { dup_count = 0; dup_curr = 0U; } else { dup_count = -1; } #endif status = ll_scan_enable(cmd->enable); ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = status; } #endif /* CONFIG_BT_OBSERVER */ #if defined(CONFIG_BT_CONN) #if defined(CONFIG_BT_CENTRAL) static void le_create_connection(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_create_conn *cmd = (void *)buf->data; u16_t supervision_timeout; u16_t conn_interval_max; u16_t scan_interval; u16_t conn_latency; u16_t scan_window; u8_t status; scan_interval = sys_le16_to_cpu(cmd->scan_interval); scan_window = sys_le16_to_cpu(cmd->scan_window); conn_interval_max = sys_le16_to_cpu(cmd->conn_interval_max); conn_latency = sys_le16_to_cpu(cmd->conn_latency); supervision_timeout = sys_le16_to_cpu(cmd->supervision_timeout); status = ll_create_connection(scan_interval, scan_window, cmd->filter_policy, cmd->peer_addr.type, &cmd->peer_addr.a.val[0], cmd->own_addr_type, conn_interval_max, conn_latency, supervision_timeout); *evt = cmd_status(status); } static void le_create_conn_cancel(struct net_buf *buf, struct net_buf **evt, void **node_rx) { struct bt_hci_evt_cc_status *ccst; u8_t status; status = ll_connect_disable(node_rx); ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = status; } static void le_set_host_chan_classif(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_set_host_chan_classif *cmd = (void *)buf->data; struct bt_hci_evt_cc_status *ccst; u8_t status; status = ll_chm_update(&cmd->ch_map[0]); ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = status; } #if defined(CONFIG_BT_CTLR_LE_ENC) static void le_start_encryption(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_start_encryption *cmd = (void *)buf->data; u16_t handle; u8_t status; handle = sys_le16_to_cpu(cmd->handle); status = ll_enc_req_send(handle, (u8_t *)&cmd->rand, (u8_t *)&cmd->ediv, &cmd->ltk[0]); *evt = cmd_status(status); } #endif /* CONFIG_BT_CTLR_LE_ENC */ #endif /* CONFIG_BT_CENTRAL */ #if defined(CONFIG_BT_PERIPHERAL) #if defined(CONFIG_BT_CTLR_LE_ENC) static void le_ltk_req_reply(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_ltk_req_reply *cmd = (void *)buf->data; struct bt_hci_rp_le_ltk_req_reply *rp; u16_t handle; u8_t status; handle = sys_le16_to_cpu(cmd->handle); status = ll_start_enc_req_send(handle, 0x00, &cmd->ltk[0]); rp = cmd_complete(evt, sizeof(*rp)); rp->status = status; rp->handle = sys_cpu_to_le16(handle); } static void le_ltk_req_neg_reply(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_ltk_req_neg_reply *cmd = (void *)buf->data; struct bt_hci_rp_le_ltk_req_neg_reply *rp; u16_t handle; u8_t status; handle = sys_le16_to_cpu(cmd->handle); status = ll_start_enc_req_send(handle, BT_HCI_ERR_PIN_OR_KEY_MISSING, NULL); rp = cmd_complete(evt, sizeof(*rp)); rp->status = status; rp->handle = sys_le16_to_cpu(handle); } #endif /* CONFIG_BT_CTLR_LE_ENC */ #endif /* CONFIG_BT_PERIPHERAL */ static void le_read_remote_features(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_read_remote_features *cmd = (void *)buf->data; u16_t handle; u8_t status; handle = sys_le16_to_cpu(cmd->handle); status = ll_feature_req_send(handle); *evt = cmd_status(status); } static void le_read_chan_map(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_read_chan_map *cmd = (void *)buf->data; struct bt_hci_rp_le_read_chan_map *rp; u16_t handle; u8_t status; handle = sys_le16_to_cpu(cmd->handle); rp = cmd_complete(evt, sizeof(*rp)); status = ll_chm_get(handle, rp->ch_map); rp->status = status; rp->handle = sys_le16_to_cpu(handle); } static void le_conn_update(struct net_buf *buf, struct net_buf **evt) { struct hci_cp_le_conn_update *cmd = (void *)buf->data; u16_t supervision_timeout; u16_t conn_interval_min; u16_t conn_interval_max; u16_t conn_latency; u16_t handle; u8_t status; handle = sys_le16_to_cpu(cmd->handle); conn_interval_min = sys_le16_to_cpu(cmd->conn_interval_min); conn_interval_max = sys_le16_to_cpu(cmd->conn_interval_max); conn_latency = sys_le16_to_cpu(cmd->conn_latency); supervision_timeout = sys_le16_to_cpu(cmd->supervision_timeout); status = ll_conn_update(handle, 0, 0, conn_interval_min, conn_interval_max, conn_latency, supervision_timeout); *evt = cmd_status(status); } #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ) static void le_conn_param_req_reply(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_conn_param_req_reply *cmd = (void *)buf->data; struct bt_hci_rp_le_conn_param_req_reply *rp; u16_t interval_min; u16_t interval_max; u16_t latency; u16_t timeout; u16_t handle; u8_t status; handle = sys_le16_to_cpu(cmd->handle); interval_min = sys_le16_to_cpu(cmd->interval_min); interval_max = sys_le16_to_cpu(cmd->interval_max); latency = sys_le16_to_cpu(cmd->latency); timeout = sys_le16_to_cpu(cmd->timeout); status = ll_conn_update(handle, 2, 0, interval_min, interval_max, latency, timeout); rp = cmd_complete(evt, sizeof(*rp)); rp->status = status; rp->handle = sys_cpu_to_le16(handle); } static void le_conn_param_req_neg_reply(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_conn_param_req_neg_reply *cmd = (void *)buf->data; struct bt_hci_rp_le_conn_param_req_neg_reply *rp; u16_t handle; u8_t status; handle = sys_le16_to_cpu(cmd->handle); status = ll_conn_update(handle, 2, cmd->reason, 0, 0, 0, 0); rp = cmd_complete(evt, sizeof(*rp)); rp->status = status; rp->handle = sys_cpu_to_le16(handle); } #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */ #if defined(CONFIG_BT_CTLR_DATA_LENGTH) static void le_set_data_len(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_set_data_len *cmd = (void *)buf->data; struct bt_hci_rp_le_set_data_len *rp; u16_t tx_octets; u16_t tx_time; u16_t handle; u8_t status; handle = sys_le16_to_cpu(cmd->handle); tx_octets = sys_le16_to_cpu(cmd->tx_octets); tx_time = sys_le16_to_cpu(cmd->tx_time); status = ll_length_req_send(handle, tx_octets, tx_time); rp = cmd_complete(evt, sizeof(*rp)); rp->status = status; rp->handle = sys_cpu_to_le16(handle); } static void le_read_default_data_len(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_rp_le_read_default_data_len *rp; rp = cmd_complete(evt, sizeof(*rp)); ll_length_default_get(&rp->max_tx_octets, &rp->max_tx_time); rp->status = 0x00; } static void le_write_default_data_len(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_write_default_data_len *cmd = (void *)buf->data; struct bt_hci_evt_cc_status *ccst; u8_t status; status = ll_length_default_set(cmd->max_tx_octets, cmd->max_tx_time); ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = status; } static void le_read_max_data_len(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_rp_le_read_max_data_len *rp; rp = cmd_complete(evt, sizeof(*rp)); ll_length_max_get(&rp->max_tx_octets, &rp->max_tx_time, &rp->max_rx_octets, &rp->max_rx_time); rp->status = 0x00; } #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ #if defined(CONFIG_BT_CTLR_PHY) static void le_read_phy(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_read_phy *cmd = (void *) buf->data; struct bt_hci_rp_le_read_phy *rp; u16_t handle; u8_t status; handle = sys_le16_to_cpu(cmd->handle); rp = cmd_complete(evt, sizeof(*rp)); status = ll_phy_get(handle, &rp->tx_phy, &rp->rx_phy); rp->status = status; rp->handle = sys_cpu_to_le16(handle); rp->tx_phy = find_lsb_set(rp->tx_phy); rp->rx_phy = find_lsb_set(rp->rx_phy); } static void le_set_default_phy(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_set_default_phy *cmd = (void *)buf->data; struct bt_hci_evt_cc_status *ccst; u8_t status; if (cmd->all_phys & BT_HCI_LE_PHY_TX_ANY) { cmd->tx_phys = 0x07; } if (cmd->all_phys & BT_HCI_LE_PHY_RX_ANY) { cmd->rx_phys = 0x07; } status = ll_phy_default_set(cmd->tx_phys, cmd->rx_phys); ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = status; } static void le_set_phy(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_set_phy *cmd = (void *)buf->data; u16_t phy_opts; u8_t mask_phys; u16_t handle; u8_t status; handle = sys_le16_to_cpu(cmd->handle); phy_opts = sys_le16_to_cpu(cmd->phy_opts); mask_phys = 0x01; if (IS_ENABLED(CONFIG_BT_CTLR_PHY_2M)) { mask_phys |= BIT(1); } if (IS_ENABLED(CONFIG_BT_CTLR_PHY_CODED)) { mask_phys |= BIT(2); } if (cmd->all_phys & BT_HCI_LE_PHY_TX_ANY) { cmd->tx_phys |= mask_phys; } if (cmd->all_phys & BT_HCI_LE_PHY_RX_ANY) { cmd->rx_phys |= mask_phys; } if ((cmd->tx_phys | cmd->rx_phys) & ~mask_phys) { *evt = cmd_status(BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL); return; } if (!(cmd->tx_phys & 0x07) || !(cmd->rx_phys & 0x07)) { *evt = cmd_status(BT_HCI_ERR_INVALID_PARAM); return; } if (phy_opts & 0x03) { phy_opts -= 1U; phy_opts &= 1; } else { phy_opts = 0U; } status = ll_phy_req_send(handle, cmd->tx_phys, phy_opts, cmd->rx_phys); *evt = cmd_status(status); } #endif /* CONFIG_BT_CTLR_PHY */ #endif /* CONFIG_BT_CONN */ #if defined(CONFIG_BT_CTLR_PRIVACY) static void le_add_dev_to_rl(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_add_dev_to_rl *cmd = (void *)buf->data; struct bt_hci_evt_cc_status *ccst; u8_t status; status = ll_rl_add(&cmd->peer_id_addr, cmd->peer_irk, cmd->local_irk); ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = status; } static void le_rem_dev_from_rl(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_rem_dev_from_rl *cmd = (void *)buf->data; struct bt_hci_evt_cc_status *ccst; u8_t status; status = ll_rl_remove(&cmd->peer_id_addr); ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = status; } static void le_clear_rl(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_evt_cc_status *ccst; ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = ll_rl_clear(); } static void le_read_rl_size(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_rp_le_read_rl_size *rp; rp = cmd_complete(evt, sizeof(*rp)); rp->rl_size = ll_rl_size_get(); rp->status = 0x00; } static void le_read_peer_rpa(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_read_peer_rpa *cmd = (void *)buf->data; struct bt_hci_rp_le_read_peer_rpa *rp; bt_addr_le_t peer_id_addr; bt_addr_le_copy(&peer_id_addr, &cmd->peer_id_addr); rp = cmd_complete(evt, sizeof(*rp)); rp->status = ll_rl_crpa_get(&peer_id_addr, &rp->peer_rpa); } static void le_read_local_rpa(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_read_local_rpa *cmd = (void *)buf->data; struct bt_hci_rp_le_read_local_rpa *rp; bt_addr_le_t peer_id_addr; bt_addr_le_copy(&peer_id_addr, &cmd->peer_id_addr); rp = cmd_complete(evt, sizeof(*rp)); rp->status = ll_rl_lrpa_get(&peer_id_addr, &rp->local_rpa); } static void le_set_addr_res_enable(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_set_addr_res_enable *cmd = (void *)buf->data; struct bt_hci_evt_cc_status *ccst; u8_t enable = cmd->enable; ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = ll_rl_enable(enable); } static void le_set_rpa_timeout(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_set_rpa_timeout *cmd = (void *)buf->data; struct bt_hci_evt_cc_status *ccst; u16_t timeout = sys_le16_to_cpu(cmd->rpa_timeout); ll_rl_timeout_set(timeout); ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = 0x00; } static void le_set_privacy_mode(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_set_privacy_mode *cmd = (void *)buf->data; struct bt_hci_evt_cc_status *ccst; u8_t status; status = ll_priv_mode_set(&cmd->id_addr, cmd->mode); ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = status; } #endif /* CONFIG_BT_CTLR_PRIVACY */ static void le_read_tx_power(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_rp_le_read_tx_power *rp; rp = cmd_complete(evt, sizeof(*rp)); rp->status = 0x00; ll_tx_pwr_get(&rp->min_tx_power, &rp->max_tx_power); } #if defined(CONFIG_BT_CTLR_DTM_HCI) static void le_rx_test(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_rx_test *cmd = (void *)buf->data; struct bt_hci_evt_cc_status *ccst; u8_t status; status = ll_test_rx(cmd->rx_ch, 0x01, 0); ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = status; } static void le_tx_test(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_tx_test *cmd = (void *)buf->data; struct bt_hci_evt_cc_status *ccst; u8_t status; status = ll_test_tx(cmd->tx_ch, cmd->test_data_len, cmd->pkt_payload, 0x01); ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = status; } static void le_test_end(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_rp_le_test_end *rp; u16_t rx_pkt_count; ll_test_end(&rx_pkt_count); rp = cmd_complete(evt, sizeof(*rp)); rp->status = 0x00; rp->rx_pkt_count = sys_cpu_to_le16(rx_pkt_count); } static void le_enh_rx_test(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_enh_rx_test *cmd = (void *)buf->data; struct bt_hci_evt_cc_status *ccst; u8_t status; status = ll_test_rx(cmd->rx_ch, cmd->phy, cmd->mod_index); ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = status; } static void le_enh_tx_test(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_enh_tx_test *cmd = (void *)buf->data; struct bt_hci_evt_cc_status *ccst; u8_t status; status = ll_test_tx(cmd->tx_ch, cmd->test_data_len, cmd->pkt_payload, cmd->phy); ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = status; } #endif /* CONFIG_BT_CTLR_DTM_HCI */ static int controller_cmd_handle(u16_t ocf, struct net_buf *cmd, struct net_buf **evt, void **node_rx) { switch (ocf) { case BT_OCF(BT_HCI_OP_LE_SET_EVENT_MASK): le_set_event_mask(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_READ_BUFFER_SIZE): le_read_buffer_size(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_READ_LOCAL_FEATURES): le_read_local_features(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_SET_RANDOM_ADDRESS): le_set_random_address(cmd, evt); break; #if defined(CONFIG_BT_CTLR_FILTER) case BT_OCF(BT_HCI_OP_LE_READ_WL_SIZE): le_read_wl_size(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_CLEAR_WL): le_clear_wl(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_ADD_DEV_TO_WL): le_add_dev_to_wl(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_REM_DEV_FROM_WL): le_rem_dev_from_wl(cmd, evt); break; #endif /* CONFIG_BT_CTLR_FILTER */ case BT_OCF(BT_HCI_OP_LE_ENCRYPT): le_encrypt(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_RAND): le_rand(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_READ_SUPP_STATES): le_read_supp_states(cmd, evt); break; #if defined(CONFIG_BT_BROADCASTER) case BT_OCF(BT_HCI_OP_LE_SET_ADV_PARAM): le_set_adv_param(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_READ_ADV_CHAN_TX_POWER): le_read_adv_chan_tx_power(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_SET_ADV_DATA): le_set_adv_data(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_SET_SCAN_RSP_DATA): le_set_scan_rsp_data(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_SET_ADV_ENABLE): le_set_adv_enable(cmd, evt); break; #endif /* CONFIG_BT_BROADCASTER */ #if defined(CONFIG_BT_OBSERVER) case BT_OCF(BT_HCI_OP_LE_SET_SCAN_PARAM): le_set_scan_param(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_SET_SCAN_ENABLE): le_set_scan_enable(cmd, evt); break; #endif /* CONFIG_BT_OBSERVER */ #if defined(CONFIG_BT_CONN) #if defined(CONFIG_BT_CENTRAL) case BT_OCF(BT_HCI_OP_LE_CREATE_CONN): le_create_connection(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_CREATE_CONN_CANCEL): le_create_conn_cancel(cmd, evt, node_rx); break; case BT_OCF(BT_HCI_OP_LE_SET_HOST_CHAN_CLASSIF): le_set_host_chan_classif(cmd, evt); break; #if defined(CONFIG_BT_CTLR_LE_ENC) case BT_OCF(BT_HCI_OP_LE_START_ENCRYPTION): le_start_encryption(cmd, evt); break; #endif /* CONFIG_BT_CTLR_LE_ENC */ #endif /* CONFIG_BT_CENTRAL */ #if defined(CONFIG_BT_PERIPHERAL) #if defined(CONFIG_BT_CTLR_LE_ENC) case BT_OCF(BT_HCI_OP_LE_LTK_REQ_REPLY): le_ltk_req_reply(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_LTK_REQ_NEG_REPLY): le_ltk_req_neg_reply(cmd, evt); break; #endif /* CONFIG_BT_CTLR_LE_ENC */ #endif /* CONFIG_BT_PERIPHERAL */ case BT_OCF(BT_HCI_OP_LE_READ_CHAN_MAP): le_read_chan_map(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_READ_REMOTE_FEATURES): le_read_remote_features(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_CONN_UPDATE): le_conn_update(cmd, evt); break; #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ) case BT_OCF(BT_HCI_OP_LE_CONN_PARAM_REQ_REPLY): le_conn_param_req_reply(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_CONN_PARAM_REQ_NEG_REPLY): le_conn_param_req_neg_reply(cmd, evt); break; #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */ #if defined(CONFIG_BT_CTLR_DATA_LENGTH) case BT_OCF(BT_HCI_OP_LE_SET_DATA_LEN): le_set_data_len(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_READ_DEFAULT_DATA_LEN): le_read_default_data_len(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_WRITE_DEFAULT_DATA_LEN): le_write_default_data_len(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_READ_MAX_DATA_LEN): le_read_max_data_len(cmd, evt); break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ #if defined(CONFIG_BT_CTLR_PHY) case BT_OCF(BT_HCI_OP_LE_READ_PHY): le_read_phy(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_SET_DEFAULT_PHY): le_set_default_phy(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_SET_PHY): le_set_phy(cmd, evt); break; #endif /* CONFIG_BT_CTLR_PHY */ #endif /* CONFIG_BT_CONN */ #if defined(CONFIG_BT_CTLR_PRIVACY) case BT_OCF(BT_HCI_OP_LE_ADD_DEV_TO_RL): le_add_dev_to_rl(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_REM_DEV_FROM_RL): le_rem_dev_from_rl(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_CLEAR_RL): le_clear_rl(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_READ_RL_SIZE): le_read_rl_size(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_READ_PEER_RPA): le_read_peer_rpa(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_READ_LOCAL_RPA): le_read_local_rpa(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_SET_ADDR_RES_ENABLE): le_set_addr_res_enable(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_SET_RPA_TIMEOUT): le_set_rpa_timeout(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_SET_PRIVACY_MODE): le_set_privacy_mode(cmd, evt); break; #endif /* CONFIG_BT_CTLR_PRIVACY */ case BT_OCF(BT_HCI_OP_LE_READ_TX_POWER): le_read_tx_power(cmd, evt); break; #if defined(CONFIG_BT_CTLR_DTM_HCI) case BT_OCF(BT_HCI_OP_LE_RX_TEST): le_rx_test(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_TX_TEST): le_tx_test(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_TEST_END): le_test_end(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_ENH_RX_TEST): le_enh_rx_test(cmd, evt); break; case BT_OCF(BT_HCI_OP_LE_ENH_TX_TEST): le_enh_tx_test(cmd, evt); break; #endif /* CONFIG_BT_CTLR_DTM_HCI */ default: return -EINVAL; } return 0; } #if defined(CONFIG_BT_HCI_VS) static void vs_read_version_info(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_rp_vs_read_version_info *rp; rp = cmd_complete(evt, sizeof(*rp)); rp->status = 0x00; rp->hw_platform = sys_cpu_to_le16(BT_HCI_VS_HW_PLAT); rp->hw_variant = sys_cpu_to_le16(BT_HCI_VS_HW_VAR); rp->fw_variant = 0U; rp->fw_version = (KERNEL_VERSION_MAJOR & 0xff); rp->fw_revision = sys_cpu_to_le16(KERNEL_VERSION_MINOR); rp->fw_build = sys_cpu_to_le32(KERNEL_PATCHLEVEL & 0xffff); } static void vs_read_supported_commands(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_rp_vs_read_supported_commands *rp; rp = cmd_complete(evt, sizeof(*rp)); rp->status = 0x00; (void)memset(&rp->commands[0], 0, sizeof(rp->commands)); /* Set Version Information, Supported Commands, Supported Features. */ rp->commands[0] |= BIT(0) | BIT(1) | BIT(2); #if defined(CONFIG_BT_HCI_VS_EXT) /* Write BD_ADDR, Read Build Info */ rp->commands[0] |= BIT(5) | BIT(7); /* Read Static Addresses, Read Key Hierarchy Roots */ rp->commands[1] |= BIT(0) | BIT(1); #endif /* CONFIG_BT_HCI_VS_EXT */ } static void vs_read_supported_features(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_rp_vs_read_supported_features *rp; rp = cmd_complete(evt, sizeof(*rp)); rp->status = 0x00; (void)memset(&rp->features[0], 0x00, sizeof(rp->features)); } #if defined(CONFIG_BT_HCI_VS_EXT) static void vs_write_bd_addr(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_vs_write_bd_addr *cmd = (void *)buf->data; struct bt_hci_evt_cc_status *ccst; ll_addr_set(0, &cmd->bdaddr.val[0]); ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = 0x00; } static void vs_read_build_info(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_rp_vs_read_build_info *rp; #define HCI_VS_BUILD_INFO "Zephyr OS v" \ KERNEL_VERSION_STRING CONFIG_BT_CTLR_HCI_VS_BUILD_INFO const char build_info[] = HCI_VS_BUILD_INFO; #define BUILD_INFO_EVT_LEN (sizeof(struct bt_hci_evt_hdr) + \ sizeof(struct bt_hci_evt_cmd_complete) + \ sizeof(struct bt_hci_rp_vs_read_build_info) + \ sizeof(build_info)) BUILD_ASSERT(CONFIG_BT_RX_BUF_LEN >= BUILD_INFO_EVT_LEN); rp = cmd_complete(evt, sizeof(*rp) + sizeof(build_info)); rp->status = 0x00; memcpy(rp->info, build_info, sizeof(build_info)); } static void vs_read_static_addrs(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_rp_vs_read_static_addrs *rp; #if defined(CONFIG_SOC_COMPATIBLE_NRF) /* Read address from nRF5-specific storage * Non-initialized FICR values default to 0xFF, skip if no address * present. Also if a public address lives in FICR, do not use in this * function. */ if (((NRF_FICR->DEVICEADDR[0] != UINT32_MAX) || ((NRF_FICR->DEVICEADDR[1] & UINT16_MAX) != UINT16_MAX)) && (NRF_FICR->DEVICEADDRTYPE & 0x01)) { struct bt_hci_vs_static_addr *addr; rp = cmd_complete(evt, sizeof(*rp) + sizeof(*addr)); rp->status = 0x00; rp->num_addrs = 1U; addr = &rp->a[0]; sys_put_le32(NRF_FICR->DEVICEADDR[0], &addr->bdaddr.val[0]); sys_put_le16(NRF_FICR->DEVICEADDR[1], &addr->bdaddr.val[4]); /* The FICR value is a just a random number, with no knowledge * of the Bluetooth Specification requirements for random * static addresses. */ BT_ADDR_SET_STATIC(&addr->bdaddr); /* Mark IR as invalid */ (void)memset(addr->ir, 0x00, sizeof(addr->ir)); return; } #endif /* CONFIG_SOC_FAMILY_NRF */ rp = cmd_complete(evt, sizeof(*rp)); rp->status = 0x00; rp->num_addrs = 0U; } static void vs_read_key_hierarchy_roots(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_rp_vs_read_key_hierarchy_roots *rp; rp = cmd_complete(evt, sizeof(*rp)); rp->status = 0x00; #if defined(CONFIG_SOC_COMPATIBLE_NRF) /* Fill in IR if present */ if ((NRF_FICR->IR[0] != UINT32_MAX) && (NRF_FICR->IR[1] != UINT32_MAX) && (NRF_FICR->IR[2] != UINT32_MAX) && (NRF_FICR->IR[3] != UINT32_MAX)) { sys_put_le32(NRF_FICR->IR[0], &rp->ir[0]); sys_put_le32(NRF_FICR->IR[1], &rp->ir[4]); sys_put_le32(NRF_FICR->IR[2], &rp->ir[8]); sys_put_le32(NRF_FICR->IR[3], &rp->ir[12]); } else { /* Mark IR as invalid */ (void)memset(rp->ir, 0x00, sizeof(rp->ir)); } /* Fill in ER if present */ if ((NRF_FICR->ER[0] != UINT32_MAX) && (NRF_FICR->ER[1] != UINT32_MAX) && (NRF_FICR->ER[2] != UINT32_MAX) && (NRF_FICR->ER[3] != UINT32_MAX)) { sys_put_le32(NRF_FICR->ER[0], &rp->er[0]); sys_put_le32(NRF_FICR->ER[1], &rp->er[4]); sys_put_le32(NRF_FICR->ER[2], &rp->er[8]); sys_put_le32(NRF_FICR->ER[3], &rp->er[12]); } else { /* Mark ER as invalid */ (void)memset(rp->er, 0x00, sizeof(rp->er)); } return; #else /* Mark IR as invalid */ (void)memset(rp->ir, 0x00, sizeof(rp->ir)); /* Mark ER as invalid */ (void)memset(rp->er, 0x00, sizeof(rp->er)); #endif /* CONFIG_SOC_FAMILY_NRF */ } #endif /* CONFIG_BT_HCI_VS_EXT */ #if defined(CONFIG_BT_HCI_MESH_EXT) static void mesh_get_opts(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_rp_mesh_get_opts *rp; rp = cmd_complete(evt, sizeof(*rp)); rp->status = 0x00; rp->opcode = BT_HCI_OC_MESH_GET_OPTS; rp->revision = BT_HCI_MESH_REVISION; rp->ch_map = 0x7; /*@todo: nRF51 only */ rp->min_tx_power = -30; /*@todo: nRF51 only */ rp->max_tx_power = 4; rp->max_scan_filter = CONFIG_BT_CTLR_MESH_SCAN_FILTERS; rp->max_filter_pattern = CONFIG_BT_CTLR_MESH_SF_PATTERNS; rp->max_adv_slot = 1U; rp->evt_prefix_len = 0x01; rp->evt_prefix = BT_HCI_MESH_EVT_PREFIX; } static void mesh_set_scan_filter(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_mesh_set_scan_filter *cmd = (void *)buf->data; struct bt_hci_rp_mesh_set_scan_filter *rp; u8_t filter = cmd->scan_filter - 1; struct scan_filter *f; u8_t status = 0x00; u8_t i; if (filter > ARRAY_SIZE(scan_filters) || cmd->num_patterns > CONFIG_BT_CTLR_MESH_SF_PATTERNS) { status = BT_HCI_ERR_INVALID_PARAM; goto exit; } if (filter == sf_curr) { status = BT_HCI_ERR_CMD_DISALLOWED; goto exit; } /* duplicate filtering not supported yet */ if (cmd->filter_dup) { status = BT_HCI_ERR_INVALID_PARAM; goto exit; } f = &scan_filters[filter]; for (i = 0U; i < cmd->num_patterns; i++) { if (!cmd->patterns[i].pattern_len || cmd->patterns[i].pattern_len > BT_HCI_MESH_PATTERN_LEN_MAX) { status = BT_HCI_ERR_INVALID_PARAM; goto exit; } f->lengths[i] = cmd->patterns[i].pattern_len; memcpy(f->patterns[i], cmd->patterns[i].pattern, f->lengths[i]); } f->count = cmd->num_patterns; exit: rp = cmd_complete(evt, sizeof(*rp)); rp->status = status; rp->opcode = BT_HCI_OC_MESH_SET_SCAN_FILTER; rp->scan_filter = filter + 1; } static void mesh_advertise(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_mesh_advertise *cmd = (void *)buf->data; struct bt_hci_rp_mesh_advertise *rp; u8_t adv_slot = cmd->adv_slot; u8_t status; status = ll_mesh_advertise(adv_slot, cmd->own_addr_type, cmd->random_addr.val, cmd->ch_map, cmd->tx_power, cmd->min_tx_delay, cmd->max_tx_delay, cmd->retx_count, cmd->retx_interval, cmd->scan_duration, cmd->scan_delay, cmd->scan_filter, cmd->data_len, cmd->data); if (!status) { /* Yields 0xFF if no scan filter selected */ sf_curr = cmd->scan_filter - 1; } rp = cmd_complete(evt, sizeof(*rp)); rp->status = status; rp->opcode = BT_HCI_OC_MESH_ADVERTISE; rp->adv_slot = adv_slot; } static void mesh_advertise_cancel(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_mesh_advertise_cancel *cmd = (void *)buf->data; struct bt_hci_rp_mesh_advertise_cancel *rp; u8_t adv_slot = cmd->adv_slot; u8_t status; status = ll_mesh_advertise_cancel(adv_slot); if (!status) { /* Yields 0xFF if no scan filter selected */ sf_curr = 0xFF; } rp = cmd_complete(evt, sizeof(*rp)); rp->status = status; rp->opcode = BT_HCI_OC_MESH_ADVERTISE_CANCEL; rp->adv_slot = adv_slot; } static int mesh_cmd_handle(struct net_buf *cmd, struct net_buf **evt) { struct bt_hci_cp_mesh *cp_mesh; u8_t mesh_op; if (cmd->len < sizeof(*cp_mesh)) { BT_ERR("No HCI VSD Command header"); return -EINVAL; } cp_mesh = net_buf_pull_mem(cmd, sizeof(*cp_mesh)); mesh_op = cp_mesh->opcode; switch (mesh_op) { case BT_HCI_OC_MESH_GET_OPTS: mesh_get_opts(cmd, evt); break; case BT_HCI_OC_MESH_SET_SCAN_FILTER: mesh_set_scan_filter(cmd, evt); break; case BT_HCI_OC_MESH_ADVERTISE: mesh_advertise(cmd, evt); break; case BT_HCI_OC_MESH_ADVERTISE_CANCEL: mesh_advertise_cancel(cmd, evt); break; default: return -EINVAL; } return 0; } #endif /* CONFIG_BT_HCI_MESH_EXT */ static int vendor_cmd_handle(u16_t ocf, struct net_buf *cmd, struct net_buf **evt) { switch (ocf) { case BT_OCF(BT_HCI_OP_VS_READ_VERSION_INFO): vs_read_version_info(cmd, evt); break; case BT_OCF(BT_HCI_OP_VS_READ_SUPPORTED_COMMANDS): vs_read_supported_commands(cmd, evt); break; case BT_OCF(BT_HCI_OP_VS_READ_SUPPORTED_FEATURES): vs_read_supported_features(cmd, evt); break; #if defined(CONFIG_BT_HCI_VS_EXT) case BT_OCF(BT_HCI_OP_VS_READ_BUILD_INFO): vs_read_build_info(cmd, evt); break; case BT_OCF(BT_HCI_OP_VS_WRITE_BD_ADDR): vs_write_bd_addr(cmd, evt); break; case BT_OCF(BT_HCI_OP_VS_READ_STATIC_ADDRS): vs_read_static_addrs(cmd, evt); break; case BT_OCF(BT_HCI_OP_VS_READ_KEY_HIERARCHY_ROOTS): vs_read_key_hierarchy_roots(cmd, evt); break; #endif /* CONFIG_BT_HCI_VS_EXT */ #if defined(CONFIG_BT_HCI_MESH_EXT) case BT_OCF(BT_HCI_OP_VS_MESH): mesh_cmd_handle(cmd, evt); break; #endif /* CONFIG_BT_HCI_MESH_EXT */ default: return -EINVAL; } return 0; } #endif #if !defined(CONFIG_BT_HCI_VS_EXT) uint8_t bt_read_static_addr(bt_addr_le_t *addr) { #if defined(CONFIG_SOC_FAMILY_NRF) if (((NRF_FICR->DEVICEADDR[0] != UINT32_MAX) || ((NRF_FICR->DEVICEADDR[1] & UINT16_MAX) != UINT16_MAX)) && (NRF_FICR->DEVICEADDRTYPE & 0x01)) { sys_put_le32(NRF_FICR->DEVICEADDR[0], &addr->a.val[0]); sys_put_le16(NRF_FICR->DEVICEADDR[1], &addr->a.val[4]); /* The FICR value is a just a random number, with no knowledge * of the Bluetooth Specification requirements for random * static addresses. */ BT_ADDR_SET_STATIC(&addr->a); addr->type = BT_ADDR_LE_RANDOM; return 1; } #endif /* CONFIG_SOC_FAMILY_NRF */ return 0; } #endif /* !CONFIG_BT_HCI_VS_EXT */ struct net_buf *hci_cmd_handle(struct net_buf *cmd, void **node_rx) { struct bt_hci_evt_cc_status *ccst; struct bt_hci_cmd_hdr *chdr; struct net_buf *evt = NULL; u16_t ocf; int err; if (cmd->len < sizeof(*chdr)) { BT_ERR("No HCI Command header"); return NULL; } chdr = net_buf_pull_mem(cmd, sizeof(*chdr)); if (cmd->len < chdr->param_len) { BT_ERR("Invalid HCI CMD packet length"); return NULL; } /* store in a global for later CC/CS event creation */ _opcode = sys_le16_to_cpu(chdr->opcode); ocf = BT_OCF(_opcode); switch (BT_OGF(_opcode)) { case BT_OGF_LINK_CTRL: err = link_control_cmd_handle(ocf, cmd, &evt); break; case BT_OGF_BASEBAND: err = ctrl_bb_cmd_handle(ocf, cmd, &evt); break; case BT_OGF_INFO: err = info_cmd_handle(ocf, cmd, &evt); break; case BT_OGF_STATUS: err = status_cmd_handle(ocf, cmd, &evt); break; case BT_OGF_LE: err = controller_cmd_handle(ocf, cmd, &evt, node_rx); break; #if defined(CONFIG_BT_HCI_VS) case BT_OGF_VS: err = vendor_cmd_handle(ocf, cmd, &evt); break; #endif default: err = -EINVAL; break; } if (err == -EINVAL) { ccst = cmd_complete(&evt, sizeof(*ccst)); ccst->status = BT_HCI_ERR_UNKNOWN_CMD; } return evt; } #if defined(CONFIG_BT_CONN) static void data_buf_overflow(struct net_buf **buf) { struct bt_hci_evt_data_buf_overflow *ep; if (!(event_mask & BT_EVT_MASK_DATA_BUFFER_OVERFLOW)) { return; } *buf = bt_buf_get_rx(BT_BUF_EVT, K_FOREVER); evt_create(*buf, BT_HCI_EVT_DATA_BUF_OVERFLOW, sizeof(*ep)); ep = net_buf_add(*buf, sizeof(*ep)); ep->link_type = BT_OVERFLOW_LINK_ACL; } int hci_acl_handle(struct net_buf *buf, struct net_buf **evt) { struct node_tx *node_tx; struct bt_hci_acl_hdr *acl; struct pdu_data *pdu_data; u16_t handle; u8_t flags; u16_t len; *evt = NULL; if (buf->len < sizeof(*acl)) { BT_ERR("No HCI ACL header"); return -EINVAL; } acl = net_buf_pull_mem(buf, sizeof(*acl)); len = sys_le16_to_cpu(acl->len); handle = sys_le16_to_cpu(acl->handle); if (buf->len < len) { BT_ERR("Invalid HCI ACL packet length"); return -EINVAL; } /* assigning flags first because handle will be overwritten */ flags = bt_acl_flags(handle); handle = bt_acl_handle(handle); node_tx = ll_tx_mem_acquire(); if (!node_tx) { BT_ERR("Tx Buffer Overflow"); data_buf_overflow(evt); return -ENOBUFS; } pdu_data = (void *)node_tx->pdu; if (flags == BT_ACL_START_NO_FLUSH || flags == BT_ACL_START) { pdu_data->ll_id = PDU_DATA_LLID_DATA_START; } else { pdu_data->ll_id = PDU_DATA_LLID_DATA_CONTINUE; } pdu_data->len = len; memcpy(&pdu_data->lldata[0], buf->data, len); if (ll_tx_mem_enqueue(handle, node_tx)) { BT_ERR("Invalid Tx Enqueue"); ll_tx_mem_release(node_tx); return -EINVAL; } return 0; } #endif /* CONFIG_BT_CONN */ #if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 static inline bool dup_found(struct pdu_adv *adv) { /* check for duplicate filtering */ if (dup_count >= 0) { int i; for (i = 0; i < dup_count; i++) { if (!memcmp(&adv->adv_ind.addr[0], &dup_filter[i].addr.a.val[0], sizeof(bt_addr_t)) && adv->tx_addr == dup_filter[i].addr.type) { if (dup_filter[i].mask & BIT(adv->type)) { /* duplicate found */ return true; } /* report different adv types */ dup_filter[i].mask |= BIT(adv->type); return false; } } /* insert into the duplicate filter */ memcpy(&dup_filter[dup_curr].addr.a.val[0], &adv->adv_ind.addr[0], sizeof(bt_addr_t)); dup_filter[dup_curr].addr.type = adv->tx_addr; dup_filter[dup_curr].mask = BIT(adv->type); if (dup_count < CONFIG_BT_CTLR_DUP_FILTER_LEN) { dup_count++; dup_curr = dup_count; } else { dup_curr++; } if (dup_curr == CONFIG_BT_CTLR_DUP_FILTER_LEN) { dup_curr = 0U; } } return false; } #endif /* CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 */ #if defined(CONFIG_BT_CTLR_EXT_SCAN_FP) static inline void le_dir_adv_report(struct pdu_adv *adv, struct net_buf *buf, s8_t rssi, u8_t rl_idx) { struct bt_hci_evt_le_direct_adv_report *drp; struct bt_hci_evt_le_direct_adv_info *dir_info; if (!(event_mask & BT_EVT_MASK_LE_META_EVENT) || !(le_event_mask & BT_EVT_MASK_LE_DIRECT_ADV_REPORT)) { return; } LL_ASSERT(adv->type == PDU_ADV_TYPE_DIRECT_IND); #if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 if (dup_found(adv)) { return; } #endif /* CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 */ drp = meta_evt(buf, BT_HCI_EVT_LE_DIRECT_ADV_REPORT, sizeof(*drp) + sizeof(*dir_info)); drp->num_reports = 1U; dir_info = (void *)(((u8_t *)drp) + sizeof(*drp)); /* Directed Advertising */ dir_info->evt_type = BT_LE_ADV_DIRECT_IND; #if defined(CONFIG_BT_CTLR_PRIVACY) if (rl_idx < ll_rl_size_get()) { /* Store identity address */ ll_rl_id_addr_get(rl_idx, &dir_info->addr.type, &dir_info->addr.a.val[0]); /* Mark it as identity address from RPA (0x02, 0x03) */ dir_info->addr.type += 2U; } else { #else if (1) { #endif /* CONFIG_BT_CTLR_PRIVACY */ dir_info->addr.type = adv->tx_addr; memcpy(&dir_info->addr.a.val[0], &adv->direct_ind.adv_addr[0], sizeof(bt_addr_t)); } dir_info->dir_addr.type = 0x1; memcpy(&dir_info->dir_addr.a.val[0], &adv->direct_ind.tgt_addr[0], sizeof(bt_addr_t)); dir_info->rssi = rssi; } #endif /* CONFIG_BT_CTLR_EXT_SCAN_FP */ #if defined(CONFIG_BT_OBSERVER) #if defined(CONFIG_BT_HCI_MESH_EXT) static inline bool scan_filter_apply(u8_t filter, u8_t *data, u8_t len) { struct scan_filter *f = &scan_filters[filter]; int i; /* No patterns means filter out all advertising packets */ for (i = 0; i < f->count; i++) { /* Require at least the length of the pattern */ if (len >= f->lengths[i] && !memcmp(data, f->patterns[i], f->lengths[i])) { return true; } } return false; } static inline void le_mesh_scan_report(struct pdu_adv *adv, struct net_buf *buf, s8_t rssi, u8_t *extra) { u8_t data_len = (adv->len - BDADDR_SIZE); struct bt_hci_evt_mesh_scanning_report *mep; struct bt_hci_evt_mesh_scan_report *sr; u32_t instant; u8_t chan; LL_ASSERT(adv->type == PDU_ADV_TYPE_NONCONN_IND); /* Filter based on currently active Scan Filter */ if (sf_curr < ARRAY_SIZE(scan_filters) && !scan_filter_apply(sf_curr, &adv->adv_ind.data[0], data_len)) { /* Drop the report */ return; } chan = *extra; extra++; instant = sys_get_le32(extra); mep = mesh_evt(buf, BT_HCI_EVT_MESH_SCANNING_REPORT, sizeof(*mep) + sizeof(*sr)); mep->num_reports = 1U; sr = (void *)(((u8_t *)mep) + sizeof(*mep)); sr->addr.type = adv->tx_addr; memcpy(&sr->addr.a.val[0], &adv->adv_ind.addr[0], sizeof(bt_addr_t)); sr->chan = chan; sr->rssi = rssi; sys_put_le32(instant, (u8_t *)&sr->instant); sr->data_len = data_len; memcpy(&sr->data[0], &adv->adv_ind.data[0], data_len); } #endif /* CONFIG_BT_HCI_MESH_EXT */ static void le_advertising_report(struct pdu_data *pdu_data, u8_t *b, struct net_buf *buf) { const u8_t c_adv_type[] = { 0x00, 0x01, 0x03, 0xff, 0x04, 0xff, 0x02 }; struct bt_hci_evt_le_advertising_report *sep; struct pdu_adv *adv = (void *)pdu_data; struct bt_hci_evt_le_advertising_info *adv_info; u8_t data_len; u8_t info_len; u8_t *extra; s8_t rssi; #if defined(CONFIG_BT_CTLR_PRIVACY) u8_t rl_idx; #endif /* CONFIG_BT_CTLR_PRIVACY */ #if defined(CONFIG_BT_CTLR_EXT_SCAN_FP) u8_t direct; #endif /* CONFIG_BT_CTLR_EXT_SCAN_FP */ s8_t *prssi; extra = &b[offsetof(struct node_rx_pdu, pdu) + offsetof(struct pdu_adv, payload) + adv->len]; /* The Link Layer currently returns RSSI as an absolute value */ rssi = -(*extra); extra += 1; #if defined(CONFIG_BT_CTLR_PRIVACY) rl_idx = *extra; extra += 1; /* Update current RPA */ if (adv->tx_addr) { ll_rl_crpa_set(0x00, NULL, rl_idx, &adv->adv_ind.addr[0]); } #endif /* CONFIG_BT_CTLR_PRIVACY */ #if defined(CONFIG_BT_CTLR_EXT_SCAN_FP) direct = *extra; extra += 1; if (direct) { #if defined(CONFIG_BT_CTLR_PRIVACY) le_dir_adv_report(adv, buf, rssi, rl_idx); #else le_dir_adv_report(adv, buf, rssi, 0xFF); #endif /* CONFIG_BT_CTLR_PRIVACY */ return; } #endif /* CONFIG_BT_CTLR_EXT_SCAN_FP */ #if defined(CONFIG_BT_HCI_MESH_EXT) if (((struct node_rx_pdu *)b)->hdr.type == NODE_RX_TYPE_MESH_REPORT) { le_mesh_scan_report(adv, buf, rssi, extra); return; } #endif /* CONFIG_BT_HCI_MESH_EXT */ if (!(event_mask & BT_EVT_MASK_LE_META_EVENT) || !(le_event_mask & BT_EVT_MASK_LE_ADVERTISING_REPORT)) { return; } #if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 if (dup_found(adv)) { return; } #endif /* CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 */ if (adv->type != PDU_ADV_TYPE_DIRECT_IND) { data_len = (adv->len - BDADDR_SIZE); } else { data_len = 0U; } info_len = sizeof(struct bt_hci_evt_le_advertising_info) + data_len + sizeof(*prssi); sep = meta_evt(buf, BT_HCI_EVT_LE_ADVERTISING_REPORT, sizeof(*sep) + info_len); sep->num_reports = 1U; adv_info = (void *)(((u8_t *)sep) + sizeof(*sep)); adv_info->evt_type = c_adv_type[adv->type]; #if defined(CONFIG_BT_CTLR_PRIVACY) if (rl_idx < ll_rl_size_get()) { /* Store identity address */ ll_rl_id_addr_get(rl_idx, &adv_info->addr.type, &adv_info->addr.a.val[0]); /* Mark it as identity address from RPA (0x02, 0x03) */ adv_info->addr.type += 2U; } else { #else if (1) { #endif /* CONFIG_BT_CTLR_PRIVACY */ adv_info->addr.type = adv->tx_addr; memcpy(&adv_info->addr.a.val[0], &adv->adv_ind.addr[0], sizeof(bt_addr_t)); } adv_info->length = data_len; memcpy(&adv_info->data[0], &adv->adv_ind.data[0], data_len); /* RSSI */ prssi = &adv_info->data[0] + data_len; *prssi = rssi; } #if defined(CONFIG_BT_CTLR_ADV_EXT) static void le_adv_ext_report(struct pdu_data *pdu_data, u8_t *b, struct net_buf *buf, u8_t phy) { struct pdu_adv *adv = (void *)pdu_data; s8_t rssi; /* The Link Layer currently returns RSSI as an absolute value */ rssi = -b[offsetof(struct node_rx_pdu, pdu) + offsetof(struct pdu_adv, payload) + adv->len]; BT_DBG("phy= 0x%x, type= 0x%x, len= %u, tat= %u, rat= %u, rssi=%d dB", phy, adv->type, adv->len, adv->tx_addr, adv->rx_addr, rssi); if ((adv->type == PDU_ADV_TYPE_EXT_IND) && adv->len) { struct pdu_adv_com_ext_adv *p; struct ext_adv_hdr *h; u8_t *ptr; p = (void *)&adv->adv_ext_ind; h = (void *)p->ext_hdr_adi_adv_data; ptr = (u8_t *)h + sizeof(*h); BT_DBG("Ext. adv mode= 0x%x, hdr len= %u", p->adv_mode, p->ext_hdr_len); if (!p->ext_hdr_len) { goto no_ext_hdr; } if (h->adv_addr) { char addr_str[BT_ADDR_LE_STR_LEN]; bt_addr_le_t addr; addr.type = adv->tx_addr; memcpy(&addr.a.val[0], ptr, sizeof(bt_addr_t)); ptr += BDADDR_SIZE; bt_addr_le_to_str(&addr, addr_str, sizeof(addr_str)); BT_DBG("AdvA: %s", addr_str); } if (h->tx_pwr) { s8_t tx_pwr; tx_pwr = *(s8_t *)ptr; ptr++; BT_DBG("Tx pwr= %d dB", tx_pwr); } /* TODO: length check? */ } no_ext_hdr: return; } static void le_adv_ext_1M_report(struct pdu_data *pdu_data, u8_t *b, struct net_buf *buf) { le_adv_ext_report(pdu_data, b, buf, BIT(0)); } static void le_adv_ext_coded_report(struct pdu_data *pdu_data, u8_t *b, struct net_buf *buf) { le_adv_ext_report(pdu_data, b, buf, BIT(2)); } #endif /* CONFIG_BT_CTLR_ADV_EXT */ #endif /* CONFIG_BT_OBSERVER */ #if defined(CONFIG_BT_CTLR_SCAN_REQ_NOTIFY) static void le_scan_req_received(struct pdu_data *pdu_data, u8_t *b, struct net_buf *buf) { struct pdu_adv *adv = (void *)pdu_data; struct bt_hci_evt_le_scan_req_received *sep; /* TODO: fill handle when Adv Ext. feature is implemented. */ if (!(event_mask & BT_EVT_MASK_LE_META_EVENT) || !(le_event_mask & BT_EVT_MASK_LE_SCAN_REQ_RECEIVED)) { char addr_str[BT_ADDR_LE_STR_LEN]; bt_addr_le_t addr; u8_t handle; s8_t rssi; handle = 0U; addr.type = adv->tx_addr; memcpy(&addr.a.val[0], &adv->scan_req.scan_addr[0], sizeof(bt_addr_t)); /* The Link Layer currently returns RSSI as an absolute value */ rssi = -b[offsetof(struct node_rx_pdu, pdu) + offsetof(struct pdu_adv, payload) + adv->len]; bt_addr_le_to_str(&addr, addr_str, sizeof(addr_str)); BT_DBG("handle: %d, addr: %s, rssi: %d dB.", handle, addr_str, rssi); return; } sep = meta_evt(buf, BT_HCI_EVT_LE_SCAN_REQ_RECEIVED, sizeof(*sep)); sep->handle = 0U; sep->addr.type = adv->tx_addr; memcpy(&sep->addr.a.val[0], &adv->scan_req.scan_addr[0], sizeof(bt_addr_t)); } #endif /* CONFIG_BT_CTLR_SCAN_REQ_NOTIFY */ #if defined(CONFIG_BT_CONN) static void le_conn_complete(struct pdu_data *pdu_data, u16_t handle, struct net_buf *buf) { struct node_rx_cc *node_rx = (void *)pdu_data; struct bt_hci_evt_le_conn_complete *lecc; u8_t status = node_rx->status; #if defined(CONFIG_BT_CTLR_PRIVACY) if (!status) { /* Update current RPA */ ll_rl_crpa_set(node_rx->peer_addr_type, &node_rx->peer_addr[0], 0xff, &node_rx->peer_rpa[0]); } #endif if (!(event_mask & BT_EVT_MASK_LE_META_EVENT) || (!(le_event_mask & BT_EVT_MASK_LE_CONN_COMPLETE) && #if defined(CONFIG_BT_CTLR_PRIVACY) !(le_event_mask & BT_EVT_MASK_LE_ENH_CONN_COMPLETE))) { #else 1)) { #endif /* CONFIG_BT_CTLR_PRIVACY */ return; } if (!status) { conn_count++; } #if defined(CONFIG_BT_CTLR_PRIVACY) if (le_event_mask & BT_EVT_MASK_LE_ENH_CONN_COMPLETE) { struct bt_hci_evt_le_enh_conn_complete *leecc; leecc = meta_evt(buf, BT_HCI_EVT_LE_ENH_CONN_COMPLETE, sizeof(*leecc)); if (status) { (void)memset(leecc, 0x00, sizeof(*leecc)); leecc->status = status; return; } leecc->status = 0x00; leecc->handle = sys_cpu_to_le16(handle); leecc->role = node_rx->role; leecc->peer_addr.type = node_rx->peer_addr_type; memcpy(&leecc->peer_addr.a.val[0], &node_rx->peer_addr[0], BDADDR_SIZE); /* Note: this could be an RPA set as the random address by * the Host instead of generated by the controller. That said, * this should make no difference. */ if ((node_rx->own_addr_type) && ((node_rx->own_addr[5] & 0xc0) == 0x40)) { memcpy(&leecc->local_rpa.val[0], &node_rx->own_addr[0], BDADDR_SIZE); } else { (void)memset(&leecc->local_rpa.val[0], 0x0, BDADDR_SIZE); } memcpy(&leecc->peer_rpa.val[0], &node_rx->peer_rpa[0], BDADDR_SIZE); leecc->interval = sys_cpu_to_le16(node_rx->interval); leecc->latency = sys_cpu_to_le16(node_rx->latency); leecc->supv_timeout = sys_cpu_to_le16(node_rx->timeout); leecc->clock_accuracy = node_rx->sca; return; } #endif /* CONFIG_BT_CTLR_PRIVACY */ lecc = meta_evt(buf, BT_HCI_EVT_LE_CONN_COMPLETE, sizeof(*lecc)); if (status) { (void)memset(lecc, 0x00, sizeof(*lecc)); lecc->status = status; return; } lecc->status = 0x00; lecc->handle = sys_cpu_to_le16(handle); lecc->role = node_rx->role; lecc->peer_addr.type = node_rx->peer_addr_type; memcpy(&lecc->peer_addr.a.val[0], &node_rx->peer_addr[0], BDADDR_SIZE); lecc->interval = sys_cpu_to_le16(node_rx->interval); lecc->latency = sys_cpu_to_le16(node_rx->latency); lecc->supv_timeout = sys_cpu_to_le16(node_rx->timeout); lecc->clock_accuracy = node_rx->sca; } static void disconn_complete(struct pdu_data *pdu_data, u16_t handle, struct net_buf *buf) { struct bt_hci_evt_disconn_complete *ep; if (!(event_mask & BT_EVT_MASK_DISCONN_COMPLETE)) { return; } evt_create(buf, BT_HCI_EVT_DISCONN_COMPLETE, sizeof(*ep)); ep = net_buf_add(buf, sizeof(*ep)); ep->status = 0x00; ep->handle = sys_cpu_to_le16(handle); ep->reason = *((u8_t *)pdu_data); #if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL) /* Clear any pending packets upon disconnection */ /* Note: This requires linear handle values starting from 0 */ LL_ASSERT(handle < ARRAY_SIZE(hci_hbuf_pend)); hci_hbuf_acked += hci_hbuf_pend[handle]; hci_hbuf_pend[handle] = 0U; #endif /* CONFIG_BT_HCI_ACL_FLOW_CONTROL */ conn_count--; } static void le_conn_update_complete(struct pdu_data *pdu_data, u16_t handle, struct net_buf *buf) { struct bt_hci_evt_le_conn_update_complete *sep; struct node_rx_cu *cu; if (!(event_mask & BT_EVT_MASK_LE_META_EVENT) || !(le_event_mask & BT_EVT_MASK_LE_CONN_UPDATE_COMPLETE)) { return; } sep = meta_evt(buf, BT_HCI_EVT_LE_CONN_UPDATE_COMPLETE, sizeof(*sep)); cu = (void *)pdu_data; sep->status = cu->status; sep->handle = sys_cpu_to_le16(handle); sep->interval = sys_cpu_to_le16(cu->interval); sep->latency = sys_cpu_to_le16(cu->latency); sep->supv_timeout = sys_cpu_to_le16(cu->timeout); } #if defined(CONFIG_BT_CTLR_LE_ENC) static void enc_refresh_complete(struct pdu_data *pdu_data, u16_t handle, struct net_buf *buf) { struct bt_hci_evt_encrypt_key_refresh_complete *ep; if (!(event_mask & BT_EVT_MASK_ENCRYPT_KEY_REFRESH_COMPLETE)) { return; } evt_create(buf, BT_HCI_EVT_ENCRYPT_KEY_REFRESH_COMPLETE, sizeof(*ep)); ep = net_buf_add(buf, sizeof(*ep)); ep->status = 0x00; ep->handle = sys_cpu_to_le16(handle); } #endif /* CONFIG_BT_CTLR_LE_ENC */ #if defined(CONFIG_BT_CTLR_LE_PING) static void auth_payload_timeout_exp(struct pdu_data *pdu_data, u16_t handle, struct net_buf *buf) { struct bt_hci_evt_auth_payload_timeout_exp *ep; if (!(event_mask_page_2 & BT_EVT_MASK_AUTH_PAYLOAD_TIMEOUT_EXP)) { return; } evt_create(buf, BT_HCI_EVT_AUTH_PAYLOAD_TIMEOUT_EXP, sizeof(*ep)); ep = net_buf_add(buf, sizeof(*ep)); ep->handle = sys_cpu_to_le16(handle); } #endif /* CONFIG_BT_CTLR_LE_PING */ #if defined(CONFIG_BT_CTLR_CHAN_SEL_2) static void le_chan_sel_algo(struct pdu_data *pdu_data, u16_t handle, struct net_buf *buf) { struct bt_hci_evt_le_chan_sel_algo *sep; struct node_rx_cs *cs; cs = (void *)pdu_data; if (!(event_mask & BT_EVT_MASK_LE_META_EVENT) || !(le_event_mask & BT_EVT_MASK_LE_CHAN_SEL_ALGO)) { BT_DBG("handle: 0x%04x, CSA: %x.", handle, cs->csa); return; } sep = meta_evt(buf, BT_HCI_EVT_LE_CHAN_SEL_ALGO, sizeof(*sep)); sep->handle = sys_cpu_to_le16(handle); sep->chan_sel_algo = cs->csa; } #endif /* CONFIG_BT_CTLR_CHAN_SEL_2 */ #if defined(CONFIG_BT_CTLR_PHY) static void le_phy_upd_complete(struct pdu_data *pdu_data, u16_t handle, struct net_buf *buf) { struct bt_hci_evt_le_phy_update_complete *sep; struct node_rx_pu *pu; pu = (void *)pdu_data; if (!(event_mask & BT_EVT_MASK_LE_META_EVENT) || !(le_event_mask & BT_EVT_MASK_LE_PHY_UPDATE_COMPLETE)) { BT_WARN("handle: 0x%04x, status: %x, tx: %x, rx: %x.", handle, pu->status, find_lsb_set(pu->tx), find_lsb_set(pu->rx)); return; } sep = meta_evt(buf, BT_HCI_EVT_LE_PHY_UPDATE_COMPLETE, sizeof(*sep)); sep->status = pu->status; sep->handle = sys_cpu_to_le16(handle); sep->tx_phy = find_lsb_set(pu->tx); sep->rx_phy = find_lsb_set(pu->rx); } #endif /* CONFIG_BT_CTLR_PHY */ #endif /* CONFIG_BT_CONN */ #if defined(CONFIG_BT_HCI_MESH_EXT) static void mesh_adv_cplt(struct pdu_data *pdu_data, u8_t *b, struct net_buf *buf) { struct bt_hci_evt_mesh_adv_complete *mep; mep = mesh_evt(buf, BT_HCI_EVT_MESH_ADV_COMPLETE, sizeof(*mep)); mep->adv_slot = ((u8_t *)pdu_data)[0]; } #endif /* CONFIG_BT_HCI_MESH_EXT */ static void encode_control(struct node_rx_pdu *node_rx, struct pdu_data *pdu_data, struct net_buf *buf) { #if defined(CONFIG_BT_OBSERVER) || defined(CONFIG_BT_CTLR_SCAN_REQ_NOTIFY) u8_t *b = (u8_t *)node_rx; #endif /* CONFIG_BT_OBSERVER || CONFIG_BT_CTLR_SCAN_REQ_NOTIFY */ u16_t handle; handle = node_rx->hdr.handle; switch (node_rx->hdr.type) { #if defined(CONFIG_BT_OBSERVER) case NODE_RX_TYPE_REPORT: le_advertising_report(pdu_data, b, buf); break; #if defined(CONFIG_BT_CTLR_ADV_EXT) case NODE_RX_TYPE_EXT_1M_REPORT: le_adv_ext_1M_report(pdu_data, b, buf); break; case NODE_RX_TYPE_EXT_CODED_REPORT: le_adv_ext_coded_report(pdu_data, b, buf); break; #endif /* CONFIG_BT_CTLR_ADV_EXT */ #endif /* CONFIG_BT_OBSERVER */ #if defined(CONFIG_BT_CTLR_SCAN_REQ_NOTIFY) case NODE_RX_TYPE_SCAN_REQ: le_scan_req_received(pdu_data, b, buf); break; #endif /* CONFIG_BT_CTLR_SCAN_REQ_NOTIFY */ #if defined(CONFIG_BT_CONN) case NODE_RX_TYPE_CONNECTION: le_conn_complete(pdu_data, handle, buf); break; case NODE_RX_TYPE_TERMINATE: disconn_complete(pdu_data, handle, buf); break; case NODE_RX_TYPE_CONN_UPDATE: le_conn_update_complete(pdu_data, handle, buf); break; #if defined(CONFIG_BT_CTLR_LE_ENC) case NODE_RX_TYPE_ENC_REFRESH: enc_refresh_complete(pdu_data, handle, buf); break; #endif /* CONFIG_BT_CTLR_LE_ENC */ #if defined(CONFIG_BT_CTLR_LE_PING) case NODE_RX_TYPE_APTO: auth_payload_timeout_exp(pdu_data, handle, buf); break; #endif /* CONFIG_BT_CTLR_LE_PING */ #if defined(CONFIG_BT_CTLR_CHAN_SEL_2) case NODE_RX_TYPE_CHAN_SEL_ALGO: le_chan_sel_algo(pdu_data, handle, buf); break; #endif /* CONFIG_BT_CTLR_CHAN_SEL_2 */ #if defined(CONFIG_BT_CTLR_PHY) case NODE_RX_TYPE_PHY_UPDATE: le_phy_upd_complete(pdu_data, handle, buf); return; #endif /* CONFIG_BT_CTLR_PHY */ #if defined(CONFIG_BT_CTLR_CONN_RSSI) case NODE_RX_TYPE_RSSI: BT_INFO("handle: 0x%04x, rssi: -%d dB.", handle, pdu_data->rssi); return; #endif /* CONFIG_BT_CTLR_CONN_RSSI */ #endif /* CONFIG_BT_CONN */ #if defined(CONFIG_BT_CTLR_ADV_INDICATION) case NODE_RX_TYPE_ADV_INDICATION: BT_INFO("Advertised."); return; #endif /* CONFIG_BT_CTLR_ADV_INDICATION */ #if defined(CONFIG_BT_CTLR_SCAN_INDICATION) case NODE_RX_TYPE_SCAN_INDICATION: BT_INFO("Scanned."); return; #endif /* CONFIG_BT_CTLR_SCAN_INDICATION */ #if defined(CONFIG_BT_CTLR_PROFILE_ISR) case NODE_RX_TYPE_PROFILE: BT_INFO("l: %d, %d, %d; t: %d, %d, %d.", pdu_data->profile.lcur, pdu_data->profile.lmin, pdu_data->profile.lmax, pdu_data->profile.cur, pdu_data->profile.min, pdu_data->profile.max); return; #endif /* CONFIG_BT_CTLR_PROFILE_ISR */ #if defined(CONFIG_BT_HCI_MESH_EXT) case NODE_RX_TYPE_MESH_ADV_CPLT: mesh_adv_cplt(pdu_data, b, buf); return; case NODE_RX_TYPE_MESH_REPORT: le_advertising_report(pdu_data, b, buf); return; #endif /* CONFIG_BT_HCI_MESH_EXT */ default: LL_ASSERT(0); return; } } #if defined(CONFIG_BT_CTLR_LE_ENC) static void le_ltk_request(struct pdu_data *pdu_data, u16_t handle, struct net_buf *buf) { struct bt_hci_evt_le_ltk_request *sep; if (!(event_mask & BT_EVT_MASK_LE_META_EVENT) || !(le_event_mask & BT_EVT_MASK_LE_LTK_REQUEST)) { return; } sep = meta_evt(buf, BT_HCI_EVT_LE_LTK_REQUEST, sizeof(*sep)); sep->handle = sys_cpu_to_le16(handle); memcpy(&sep->rand, pdu_data->llctrl.enc_req.rand, sizeof(u64_t)); memcpy(&sep->ediv, pdu_data->llctrl.enc_req.ediv, sizeof(u16_t)); } static void encrypt_change(u8_t err, u16_t handle, struct net_buf *buf) { struct bt_hci_evt_encrypt_change *ep; if (!(event_mask & BT_EVT_MASK_ENCRYPT_CHANGE)) { return; } evt_create(buf, BT_HCI_EVT_ENCRYPT_CHANGE, sizeof(*ep)); ep = net_buf_add(buf, sizeof(*ep)); ep->status = err; ep->handle = sys_cpu_to_le16(handle); ep->encrypt = !err ? 1 : 0; } #endif /* CONFIG_BT_CTLR_LE_ENC */ static void le_remote_feat_complete(u8_t status, struct pdu_data *pdu_data, u16_t handle, struct net_buf *buf) { struct bt_hci_evt_le_remote_feat_complete *sep; if (!(event_mask & BT_EVT_MASK_LE_META_EVENT) || !(le_event_mask & BT_EVT_MASK_LE_REMOTE_FEAT_COMPLETE)) { return; } sep = meta_evt(buf, BT_HCI_EV_LE_REMOTE_FEAT_COMPLETE, sizeof(*sep)); sep->status = status; sep->handle = sys_cpu_to_le16(handle); if (!status) { memcpy(&sep->features[0], &pdu_data->llctrl.feature_rsp.features[0], sizeof(sep->features)); } else { (void)memset(&sep->features[0], 0x00, sizeof(sep->features)); } } static void le_unknown_rsp(struct pdu_data *pdu_data, u16_t handle, struct net_buf *buf) { switch (pdu_data->llctrl.unknown_rsp.type) { case PDU_DATA_LLCTRL_TYPE_SLAVE_FEATURE_REQ: le_remote_feat_complete(BT_HCI_ERR_UNSUPP_REMOTE_FEATURE, NULL, handle, buf); break; default: BT_WARN("type: 0x%02x", pdu_data->llctrl.unknown_rsp.type); break; } } static void remote_version_info(struct pdu_data *pdu_data, u16_t handle, struct net_buf *buf) { struct pdu_data_llctrl_version_ind *ver_ind; struct bt_hci_evt_remote_version_info *ep; if (!(event_mask & BT_EVT_MASK_REMOTE_VERSION_INFO)) { return; } evt_create(buf, BT_HCI_EVT_REMOTE_VERSION_INFO, sizeof(*ep)); ep = net_buf_add(buf, sizeof(*ep)); ver_ind = &pdu_data->llctrl.version_ind; ep->status = 0x00; ep->handle = sys_cpu_to_le16(handle); ep->version = ver_ind->version_number; ep->manufacturer = ver_ind->company_id; ep->subversion = ver_ind->sub_version_number; } #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ) static void le_conn_param_req(struct pdu_data *pdu_data, u16_t handle, struct net_buf *buf) { struct bt_hci_evt_le_conn_param_req *sep; if (!(event_mask & BT_EVT_MASK_LE_META_EVENT) || !(le_event_mask & BT_EVT_MASK_LE_CONN_PARAM_REQ)) { /* event masked, reject the conn param req */ ll_conn_update(handle, 2, BT_HCI_ERR_UNSUPP_REMOTE_FEATURE, 0, 0, 0, 0); return; } sep = meta_evt(buf, BT_HCI_EVT_LE_CONN_PARAM_REQ, sizeof(*sep)); sep->handle = sys_cpu_to_le16(handle); sep->interval_min = pdu_data->llctrl.conn_param_req.interval_min; sep->interval_max = pdu_data->llctrl.conn_param_req.interval_max; sep->latency = pdu_data->llctrl.conn_param_req.latency; sep->timeout = pdu_data->llctrl.conn_param_req.timeout; } #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */ #if defined(CONFIG_BT_CTLR_DATA_LENGTH) static void le_data_len_change(struct pdu_data *pdu_data, u16_t handle, struct net_buf *buf) { struct bt_hci_evt_le_data_len_change *sep; if (!(event_mask & BT_EVT_MASK_LE_META_EVENT) || !(le_event_mask & BT_EVT_MASK_LE_DATA_LEN_CHANGE)) { return; } sep = meta_evt(buf, BT_HCI_EVT_LE_DATA_LEN_CHANGE, sizeof(*sep)); sep->handle = sys_cpu_to_le16(handle); sep->max_tx_octets = pdu_data->llctrl.length_rsp.max_tx_octets; sep->max_tx_time = pdu_data->llctrl.length_rsp.max_tx_time; sep->max_rx_octets = pdu_data->llctrl.length_rsp.max_rx_octets; sep->max_rx_time = pdu_data->llctrl.length_rsp.max_rx_time; } #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ static void encode_data_ctrl(struct node_rx_pdu *node_rx, struct pdu_data *pdu_data, struct net_buf *buf) { u16_t handle = node_rx->hdr.handle; switch (pdu_data->llctrl.opcode) { #if defined(CONFIG_BT_CTLR_LE_ENC) case PDU_DATA_LLCTRL_TYPE_ENC_REQ: le_ltk_request(pdu_data, handle, buf); break; case PDU_DATA_LLCTRL_TYPE_START_ENC_RSP: encrypt_change(0x00, handle, buf); break; #endif /* CONFIG_BT_CTLR_LE_ENC */ case PDU_DATA_LLCTRL_TYPE_FEATURE_RSP: le_remote_feat_complete(0x00, pdu_data, handle, buf); break; case PDU_DATA_LLCTRL_TYPE_VERSION_IND: remote_version_info(pdu_data, handle, buf); break; #if defined(CONFIG_BT_CTLR_LE_ENC) case PDU_DATA_LLCTRL_TYPE_REJECT_IND: encrypt_change(pdu_data->llctrl.reject_ind.error_code, handle, buf); break; #endif /* CONFIG_BT_CTLR_LE_ENC */ #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ) case PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ: le_conn_param_req(pdu_data, handle, buf); break; #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */ #if defined(CONFIG_BT_CTLR_DATA_LENGTH) case PDU_DATA_LLCTRL_TYPE_LENGTH_REQ: case PDU_DATA_LLCTRL_TYPE_LENGTH_RSP: le_data_len_change(pdu_data, handle, buf); break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ case PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP: le_unknown_rsp(pdu_data, handle, buf); break; default: LL_ASSERT(0); return; } } #if defined(CONFIG_BT_CONN) void hci_acl_encode(struct node_rx_pdu *node_rx, struct net_buf *buf) { struct bt_hci_acl_hdr *acl; struct pdu_data *pdu_data; u16_t handle_flags; u16_t handle; u8_t *data; pdu_data = (void *)node_rx->pdu; handle = node_rx->hdr.handle; switch (pdu_data->ll_id) { case PDU_DATA_LLID_DATA_CONTINUE: case PDU_DATA_LLID_DATA_START: acl = (void *)net_buf_add(buf, sizeof(*acl)); if (pdu_data->ll_id == PDU_DATA_LLID_DATA_START) { handle_flags = bt_acl_handle_pack(handle, BT_ACL_START); } else { handle_flags = bt_acl_handle_pack(handle, BT_ACL_CONT); } acl->handle = sys_cpu_to_le16(handle_flags); acl->len = sys_cpu_to_le16(pdu_data->len); data = (void *)net_buf_add(buf, pdu_data->len); memcpy(data, pdu_data->lldata, pdu_data->len); #if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL) if (hci_hbuf_total > 0) { LL_ASSERT((hci_hbuf_sent - hci_hbuf_acked) < hci_hbuf_total); hci_hbuf_sent++; /* Note: This requires linear handle values starting * from 0 */ LL_ASSERT(handle < ARRAY_SIZE(hci_hbuf_pend)); hci_hbuf_pend[handle]++; } #endif break; default: LL_ASSERT(0); break; } } #endif void hci_evt_encode(struct node_rx_pdu *node_rx, struct net_buf *buf) { struct pdu_data *pdu_data; pdu_data = (void *)node_rx->pdu; if (node_rx->hdr.type != NODE_RX_TYPE_DC_PDU) { encode_control(node_rx, pdu_data, buf); } else { encode_data_ctrl(node_rx, pdu_data, buf); } } void hci_num_cmplt_encode(struct net_buf *buf, u16_t handle, u8_t num) { struct bt_hci_evt_num_completed_packets *ep; struct bt_hci_handle_count *hc; u8_t num_handles; u8_t len; num_handles = 1U; len = (sizeof(*ep) + (sizeof(*hc) * num_handles)); evt_create(buf, BT_HCI_EVT_NUM_COMPLETED_PACKETS, len); ep = net_buf_add(buf, len); ep->num_handles = num_handles; hc = &ep->h[0]; hc->handle = sys_cpu_to_le16(handle); hc->count = sys_cpu_to_le16(num); } s8_t hci_get_class(struct node_rx_pdu *node_rx) { struct pdu_data *pdu_data; pdu_data = (void *)node_rx->pdu; if (node_rx->hdr.type != NODE_RX_TYPE_DC_PDU) { switch (node_rx->hdr.type) { #if defined(CONFIG_BT_OBSERVER) || \ defined(CONFIG_BT_CTLR_SCAN_REQ_NOTIFY) || \ defined(CONFIG_BT_CTLR_ADV_INDICATION) || \ defined(CONFIG_BT_CTLR_SCAN_INDICATION) || \ defined(CONFIG_BT_CTLR_PROFILE_ISR) #if defined(CONFIG_BT_OBSERVER) case NODE_RX_TYPE_REPORT: #if defined(CONFIG_BT_CTLR_ADV_EXT) case NODE_RX_TYPE_EXT_1M_REPORT: case NODE_RX_TYPE_EXT_CODED_REPORT: #endif /* CONFIG_BT_CTLR_ADV_EXT */ #endif /* CONFIG_BT_OBSERVER */ #if defined(CONFIG_BT_CTLR_SCAN_REQ_NOTIFY) case NODE_RX_TYPE_SCAN_REQ: #endif /* CONFIG_BT_CTLR_SCAN_REQ_NOTIFY */ #if defined(CONFIG_BT_CTLR_ADV_INDICATION) case NODE_RX_TYPE_ADV_INDICATION: #endif /* CONFIG_BT_CTLR_ADV_INDICATION */ #if defined(CONFIG_BT_CTLR_SCAN_INDICATION) case NODE_RX_TYPE_SCAN_INDICATION: #endif /* CONFIG_BT_CTLR_SCAN_INDICATION */ #if defined(CONFIG_BT_CTLR_PROFILE_ISR) case NODE_RX_TYPE_PROFILE: #endif /* CONFIG_BT_CTLR_PROFILE_ISR */ return HCI_CLASS_EVT_DISCARDABLE; #endif #if defined(CONFIG_BT_HCI_MESH_EXT) case NODE_RX_TYPE_MESH_ADV_CPLT: case NODE_RX_TYPE_MESH_REPORT: #endif /* CONFIG_BT_HCI_MESH_EXT */ #if defined(CONFIG_BT_CONN) case NODE_RX_TYPE_CONNECTION: return HCI_CLASS_EVT_REQUIRED; case NODE_RX_TYPE_TERMINATE: case NODE_RX_TYPE_CONN_UPDATE: #if defined(CONFIG_BT_CTLR_LE_ENC) case NODE_RX_TYPE_ENC_REFRESH: #endif /* CONFIG_BT_CTLR_LE_ENC */ #if defined(CONFIG_BT_CTLR_CONN_RSSI) case NODE_RX_TYPE_RSSI: #endif /* CONFIG_BT_CTLR_CONN_RSSI */ #if defined(CONFIG_BT_CTLR_LE_PING) case NODE_RX_TYPE_APTO: #endif /* CONFIG_BT_CTLR_LE_PING */ #if defined(CONFIG_BT_CTLR_CHAN_SEL_2) case NODE_RX_TYPE_CHAN_SEL_ALGO: #endif /* CONFIG_BT_CTLR_CHAN_SEL_2 */ #if defined(CONFIG_BT_CTLR_PHY) case NODE_RX_TYPE_PHY_UPDATE: #endif /* CONFIG_BT_CTLR_PHY */ return HCI_CLASS_EVT_CONNECTION; #endif /* CONFIG_BT_CONN */ default: return -1; } } else if (pdu_data->ll_id == PDU_DATA_LLID_CTRL) { return HCI_CLASS_EVT_CONNECTION; } else { return HCI_CLASS_ACL_DATA; } } void hci_init(struct k_poll_signal *signal_host_buf) { #if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL) hbuf_signal = signal_host_buf; #endif reset(NULL, NULL); }