diff options
| author | Mark Brown <broonie@kernel.org> | 2026-10-30 10:59:26 +0000 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-10-30 10:59:26 +0000 |
| commit | f7fd1491821bd8e6e0a013fa8d402e55e0bac6eb (patch) | |
| tree | 7f4e2678b71b56ba753641e183ccd74fc599af2f | |
| parent | af007b6a981e350d3a6c2dc8d15913eef5d2fc81 (diff) | |
| parent | 24a4c2f1f7cea608a3f8a94c023bb798093d1755 (diff) | |
| download | linux-next-f7fd1491821bd8e6e0a013fa8d402e55e0bac6eb.tar.gz linux-next-f7fd1491821bd8e6e0a013fa8d402e55e0bac6eb.zip | |
Merge branch 'master' of https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git
| -rw-r--r-- | drivers/bluetooth/Makefile | 2 | ||||
| -rw-r--r-- | drivers/bluetooth/btintel.c | 24 | ||||
| -rw-r--r-- | drivers/bluetooth/btintel_pcie.c | 591 | ||||
| -rw-r--r-- | drivers/bluetooth/btintel_pcie.h | 46 | ||||
| -rw-r--r-- | drivers/bluetooth/btintel_pcie_debug.c | 331 | ||||
| -rw-r--r-- | drivers/bluetooth/btintel_pcie_debug.h | 171 | ||||
| -rw-r--r-- | drivers/bluetooth/btmtk.c | 44 | ||||
| -rw-r--r-- | drivers/bluetooth/btqca.c | 3 | ||||
| -rw-r--r-- | drivers/bluetooth/hci_nokia.c | 9 | ||||
| -rw-r--r-- | include/net/bluetooth/hci.h | 3 | ||||
| -rw-r--r-- | include/net/bluetooth/hci_core.h | 106 | ||||
| -rw-r--r-- | net/bluetooth/hci_conn.c | 92 | ||||
| -rw-r--r-- | net/bluetooth/hci_core.c | 136 | ||||
| -rw-r--r-- | net/bluetooth/hci_event.c | 197 | ||||
| -rw-r--r-- | net/bluetooth/hci_sync.c | 186 | ||||
| -rw-r--r-- | net/bluetooth/iso.c | 20 | ||||
| -rw-r--r-- | net/bluetooth/l2cap_core.c | 18 | ||||
| -rw-r--r-- | net/bluetooth/mgmt.c | 22 | ||||
| -rw-r--r-- | net/bluetooth/smp.c | 24 |
19 files changed, 1672 insertions, 353 deletions
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index d5eb2568af2e..7d933755b291 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -14,7 +14,7 @@ obj-$(CONFIG_BT_HCIBTUSB) += btusb.o obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o obj-$(CONFIG_BT_INTEL) += btintel.o -obj-$(CONFIG_BT_INTEL_PCIE) += btintel_pcie.o btintel.o +obj-$(CONFIG_BT_INTEL_PCIE) += btintel_pcie.o btintel.o btintel_pcie_debug.o obj-$(CONFIG_BT_ATH3K) += ath3k.o obj-$(CONFIG_BT_MRVL) += btmrvl.o obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index 0709fb3212f9..929018428c19 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -1201,7 +1201,29 @@ static int btintel_download_firmware_payload(struct hci_dev *hdev, err = -EINVAL; while (fw_ptr - fw->data < fw->size) { - struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len); + struct hci_command_hdr *cmd; + size_t remain = fw->size - (fw_ptr - fw->data); + + /* Ensure the header fits before dereferencing */ + if (frag_len + sizeof(*cmd) > remain) { + bt_dev_err(hdev, + "Firmware buffer overrun at header (frag_len %u, need %zu, remain %zu)", + frag_len, frag_len + sizeof(*cmd), remain); + err = -EINVAL; + goto done; + } + + cmd = (void *)(fw_ptr + frag_len); + + /* Ensure the full command (header + payload) fits before use */ + if (frag_len + sizeof(*cmd) + cmd->plen > remain) { + bt_dev_err(hdev, + "Firmware buffer overrun at payload (frag_len %u, plen %u, need %zu, remain %zu)", + frag_len, cmd->plen, + frag_len + sizeof(*cmd) + cmd->plen, remain); + err = -EINVAL; + goto done; + } frag_len += sizeof(*cmd) + cmd->plen; diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index 91b1ee9d6010..df95d16a163c 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -205,6 +205,108 @@ static inline bool btintel_pcie_dbg_to_wifi(struct btintel_pcie_data *data) return data->dbg_path_cache != BTINTEL_PCIE_DRAM; } +/* Name of the optional INI file used to override the default dbg_path + * (data->dbg_path_cache) and yoyo ini settings. + */ +#define BTINTEL_PCIE_DBG_INI_FILE "ibt_bt_dbg_cfg.ini" + +/* Loads optional "DBG_PATH=<value>" and ENABLE_INI=<value> + * overrides from BTINTEL_PCIE_DBG_INI_FILE + * and applies them to data->dbg_path_cache and data->enable_ini. + * + * DBG_PATH accepts BTINTEL_PCIE_WIFI_DBGC (0x06, default) and + * BTINTEL_PCIE_DRAM (0x01, legacy); an invalid or missing entry leaves + * the cached value set by the caller unchanged. + * + * ENABLE_INI accepts 1 (enabled) or 0 (disabled); an invalid or missing + * entry leaves data->enable_ini unchanged. + */ +static void btintel_pcie_load_dbg_path_from_ini(struct btintel_pcie_data *data) +{ + const struct firmware *fw; + const char *ini_file = BTINTEL_PCIE_DBG_INI_FILE; + char *buf, *cursor, *line; + bool dbg_path_applied = false; + int err; + + err = request_firmware_direct(&fw, ini_file, &data->pdev->dev); + if (err < 0) { + BT_DBG("%s not found (%d), using dbg_path=0x%02x", + ini_file, err, data->dbg_path_cache); + if (data->dbg_path_cache != BTINTEL_PCIE_DRAM) + data->enable_ini = false; + return; + } + + buf = kmemdup_nul(fw->data, fw->size, GFP_KERNEL); + release_firmware(fw); + if (!buf) + return; + + cursor = buf; + while ((line = strsep(&cursor, "\n"))) { + char *eq; + char *val; + uint parsed; + + line = strim(line); + if (!line[0] || line[0] == '#' || line[0] == ';') + continue; + + eq = strchr(line, '='); + if (!eq) + continue; + + *eq = '\0'; + line = strim(line); + val = strim(eq + 1); + + /* Accept "DBG_PATH"/"dbg_path" + * case-insensitively as the key. + */ + if (!strcasecmp(line, "DBG_PATH")) { + BT_INFO("Read DBG_PATH from %s: '%s'", ini_file, val); + + /* base 0 lets kstrtouint accept "0x06", "6", etc. */ + if (kstrtouint(val, 0, &parsed) == 0 && + (parsed == BTINTEL_PCIE_DRAM || + parsed == BTINTEL_PCIE_WIFI_DBGC)) { + data->dbg_path_cache = parsed; + dbg_path_applied = true; + BT_INFO("WRT dbg_path accepted: 0x%02x", + data->dbg_path_cache); + } else { + BT_WARN("Invalid DBG_PATH='%s' in %s, using dbg_path=0x%02x", + val, ini_file, data->dbg_path_cache); + } + } else if (!strcasecmp(line, "ENABLE_INI")) { + BT_INFO("Read ENABLE_INI from %s: '%s'", ini_file, val); + + if (kstrtouint(val, 0, &parsed) == 0 && + (parsed == 0 || parsed == 1)) { + data->enable_ini = !!parsed; + BT_INFO("WRT enable_ini accepted: %u", + data->enable_ini); + } else { + BT_WARN("Invalid ENABLE_INI='%s' in %s, using enable_ini=%u", + val, ini_file, data->enable_ini); + } + } + } + + if (data->dbg_path_cache != BTINTEL_PCIE_DRAM) + data->enable_ini = false; + + if (dbg_path_applied) + BT_DBG("Loaded dbg_path=0x%02x from %s", data->dbg_path_cache, ini_file); + else + BT_WARN("No valid DBG_PATH in %s, dbg_path=0x%02x", ini_file, data->dbg_path_cache); + + BT_DBG("ENABLE_INI effective state: %u", data->enable_ini); + + kfree(buf); +} + /* Helper function to allocate and setup a debug buffer group * @data: driver data structure * @buf: pointer to data_buf array pointer @@ -220,7 +322,8 @@ static int btintel_pcie_alloc_dbgc_buf(struct btintel_pcie_data *data, void **v_addr, struct btintel_pcie_dbgc_ctxt_buf *frag, u32 buf_index, - u32 buf_count) + u32 buf_count, + u32 per_buf_size) { struct data_buf *b; int i; @@ -233,8 +336,7 @@ static int btintel_pcie_alloc_dbgc_buf(struct btintel_pcie_data *data, } *v_addr = dmam_alloc_coherent(&data->pdev->dev, - buf_count * - BTINTEL_PCIE_DBGC_BUFFER_SIZE, + buf_count * per_buf_size, p_addr, GFP_KERNEL | __GFP_NOWARN); if (!*v_addr) { @@ -244,16 +346,40 @@ static int btintel_pcie_alloc_dbgc_buf(struct btintel_pcie_data *data, for (i = 0; i < buf_count; i++) { b = &(*buf)[i]; - b->data_p_addr = *p_addr + i * BTINTEL_PCIE_DBGC_BUFFER_SIZE; - b->data = *v_addr + i * BTINTEL_PCIE_DBGC_BUFFER_SIZE; + b->data_p_addr = *p_addr + i * per_buf_size; + b->data = *v_addr + i * per_buf_size; frag[i].buf_addr_lsb = lower_32_bits(b->data_p_addr); frag[i].buf_addr_msb = upper_32_bits(b->data_p_addr); - frag[i].buf_size = BTINTEL_PCIE_DBGC_BUFFER_SIZE; + frag[i].buf_size = per_buf_size; } + BT_INFO("dbgc buf %u allocated: frag_num=%u per_buf_size=%u total_size=%u", + buf_index + 1, buf_count, per_buf_size, buf_count * per_buf_size); + return 0; } +/* Returns false if YoYo is enabled and @alloc_id is not configured */ +static bool btintel_pcie_get_mdbgc_cfg(struct btintel_pcie_data *data, + u32 alloc_id, u32 *count, u32 *size) +{ + const struct btintel_pcie_buf_alloc *ba; + + ba = btintel_pcie_yoyo_get_buf_alloc(&data->yoyo, alloc_id); + if (ba) { + *count = ba->max_num_frags; + *size = ba->req_buf_size / ba->max_num_frags; + return true; + } + + if (data->yoyo.enabled) + return false; + + *count = BTINTEL_PCIE_DBGC_BUFFER_COUNT; + *size = BTINTEL_PCIE_DBGC_BUFFER_SIZE; + return true; +} + /* This function initializes the memory for MDBGC buffers and formats the * DBGC fragment which consists header info and DBGC buffer's LSB, MSB and * size as the payload @@ -263,10 +389,9 @@ static int btintel_pcie_setup_mdbgc(struct btintel_pcie_data *data) struct btintel_pcie_mdbgc_ctxt db_frag; u32 frag_size = sizeof(db_frag); void *frag_v_addr; + u32 buf_count, buf_size; int err; - data->mdbgc.count = BTINTEL_PCIE_DBGC_BUFFER_COUNT; - /* Allocate fragment context structure */ frag_v_addr = dmam_alloc_coherent(&data->pdev->dev, frag_size, &data->mdbgc.frag_p_addr, @@ -285,46 +410,71 @@ static int btintel_pcie_setup_mdbgc(struct btintel_pcie_data *data) db_frag.ver = BTINTEL_PCIE_MDBGC_FRAG_VERSION; /* Allocate DBGC buffer 1 */ - db_frag.buf1_index = BTINTEL_PCIE_MDBGC_ALLOCATIONID_1; - db_frag.buf1_count = data->mdbgc.count; - err = btintel_pcie_alloc_dbgc_buf(data, - &data->mdbgc.buf1, - &data->mdbgc.buf1_p_addr, - &data->mdbgc.buf1_v_addr, - db_frag.buf1, - 0, - data->mdbgc.count); - if (err) - return err; + if (btintel_pcie_get_mdbgc_cfg(data, BTINTEL_PCIE_ALLOC_ID_DBGC1, + &buf_count, &buf_size)) { + db_frag.buf1_index = BTINTEL_PCIE_MDBGC_ALLOCATIONID_1; + data->mdbgc.buf1_count = buf_count; + data->mdbgc.buf1_size = buf_size; + db_frag.buf1_count = buf_count; + + err = btintel_pcie_alloc_dbgc_buf(data, + &data->mdbgc.buf1, + &data->mdbgc.buf1_p_addr, + &data->mdbgc.buf1_v_addr, + db_frag.buf1, + 0, + buf_count, + buf_size); + if (err) + return err; + } /* Allocate DBGC buffer 2 */ - db_frag.buf2_index = BTINTEL_PCIE_MDBGC_ALLOCATIONID_2; - db_frag.buf2_count = data->mdbgc.count; - err = btintel_pcie_alloc_dbgc_buf(data, - &data->mdbgc.buf2, - &data->mdbgc.buf2_p_addr, - &data->mdbgc.buf2_v_addr, - db_frag.buf2, - 1, - data->mdbgc.count); - if (err) - return err; + if (btintel_pcie_get_mdbgc_cfg(data, BTINTEL_PCIE_ALLOC_ID_DBGC2, + &buf_count, &buf_size)) { + db_frag.buf2_index = BTINTEL_PCIE_MDBGC_ALLOCATIONID_2; + data->mdbgc.buf2_count = buf_count; + data->mdbgc.buf2_size = buf_size; + db_frag.buf2_count = buf_count; + + err = btintel_pcie_alloc_dbgc_buf(data, + &data->mdbgc.buf2, + &data->mdbgc.buf2_p_addr, + &data->mdbgc.buf2_v_addr, + db_frag.buf2, + 1, + buf_count, + buf_size); + if (err) + return err; + } /* Allocate DBGC buffer 3 */ - db_frag.buf3_index = BTINTEL_PCIE_MDBGC_ALLOCATIONID_3; - db_frag.buf3_count = data->mdbgc.count; - err = btintel_pcie_alloc_dbgc_buf(data, - &data->mdbgc.buf3, - &data->mdbgc.buf3_p_addr, - &data->mdbgc.buf3_v_addr, - db_frag.buf3, - 2, - data->mdbgc.count); - if (err) - return err; + if (btintel_pcie_get_mdbgc_cfg(data, BTINTEL_PCIE_ALLOC_ID_DBGC3, + &buf_count, &buf_size)) { + db_frag.buf3_index = BTINTEL_PCIE_MDBGC_ALLOCATIONID_3; + data->mdbgc.buf3_count = buf_count; + data->mdbgc.buf3_size = buf_size; + db_frag.buf3_count = buf_count; + + err = btintel_pcie_alloc_dbgc_buf(data, + &data->mdbgc.buf3, + &data->mdbgc.buf3_p_addr, + &data->mdbgc.buf3_v_addr, + db_frag.buf3, + 2, + buf_count, + buf_size); + if (err) + return err; + } /* Copy fragment to DMA coherent memory */ memcpy(data->mdbgc.frag_v_addr, &db_frag, sizeof(db_frag)); + BT_INFO("MDBGC: buf1 frag=%u size=%u; buf2 frag=%u size=%u; buf3 frag=%u size=%u", + db_frag.buf1_count, db_frag.buf1_count * db_frag.buf1[0].buf_size, + db_frag.buf2_count, db_frag.buf2_count * db_frag.buf2[0].buf_size, + db_frag.buf3_count, db_frag.buf3_count * db_frag.buf3[0].buf_size); return 0; } @@ -336,9 +486,21 @@ static int btintel_pcie_setup_dbgc(struct btintel_pcie_data *data) { struct btintel_pcie_dbgc_ctxt db_frag; u32 frag_size = sizeof(db_frag); + const struct btintel_pcie_buf_alloc *ba; + u32 buf_count, buf_size; int err; - data->dbgc.count = BTINTEL_PCIE_DBGC_BUFFER_COUNT; + ba = btintel_pcie_yoyo_get_buf_alloc(&data->yoyo, + BTINTEL_PCIE_ALLOC_ID_DBGC1); + buf_count = ba ? ba->max_num_frags : BTINTEL_PCIE_DBGC_BUFFER_COUNT; + buf_size = ba ? ba->req_buf_size / ba->max_num_frags : + BTINTEL_PCIE_DBGC_BUFFER_SIZE; + + BT_INFO("dbgc setup: frag_num=%u per_buf_size=%u total_size=%u", + buf_count, buf_size, buf_count * buf_size); + + data->dbgc.count = buf_count; + data->dbgc.buf_size = buf_size; /* Allocate fragment context structure */ data->dbgc.frag_v_addr = dmam_alloc_coherent(&data->pdev->dev, @@ -356,8 +518,9 @@ static int btintel_pcie_setup_dbgc(struct btintel_pcie_data *data) memset(&db_frag, 0, sizeof(db_frag)); db_frag.magic_num = BTINTEL_PCIE_MAGIC_NUM; db_frag.ver = BTINTEL_PCIE_DBGC_FRAG_VERSION; - db_frag.total_size = BTINTEL_PCIE_DBGC_FRAG_PAYLOAD_SIZE; - db_frag.num_buf = BTINTEL_PCIE_DBGC_FRAG_BUFFER_COUNT; + db_frag.total_size = sizeof(db_frag.num_buf) + + buf_count * sizeof(db_frag.bufs[0]); + db_frag.num_buf = buf_count; /* Allocate DBGC buffers */ err = btintel_pcie_alloc_dbgc_buf(data, @@ -366,7 +529,8 @@ static int btintel_pcie_setup_dbgc(struct btintel_pcie_data *data) &data->dbgc.buf_v_addr, db_frag.bufs, 0, - data->dbgc.count); + buf_count, + buf_size); if (err) return err; @@ -859,7 +1023,8 @@ static u32 btintel_pcie_dump_list_total_size(struct list_head *list) } static int btintel_pcie_dump_dram(struct list_head *list, - u8 count, struct data_buf *bufs, + u8 count, u32 buf_size, + struct data_buf *bufs, u32 write_ptr, u32 wrap_ctr, u32 cur_frag, u32 region_id, const char *name) { @@ -871,7 +1036,7 @@ static int btintel_pcie_dump_dram(struct list_head *list, int i; mon_hdr_size = sizeof(*mon_dump); - ranges_size = count * (sizeof(*range) + BTINTEL_PCIE_DBGC_BUFFER_SIZE); + ranges_size = count * (sizeof(*range) + buf_size); payload_size = mon_hdr_size + ranges_size; total_size = sizeof(*dump_data) + payload_size; @@ -900,12 +1065,10 @@ static int btintel_pcie_dump_dram(struct list_head *list, range = (void *)mon_dump->data; for (i = 0; i < count; i++) { - range->range_data_size = - cpu_to_le32(BTINTEL_PCIE_DBGC_BUFFER_SIZE); + range->range_data_size = cpu_to_le32(buf_size); range->dram_base_addr = cpu_to_le64(bufs[i].data_p_addr); - memcpy(range->data, bufs[i].data, - BTINTEL_PCIE_DBGC_BUFFER_SIZE); - range = (void *)range->data + BTINTEL_PCIE_DBGC_BUFFER_SIZE; + memcpy(range->data, bufs[i].data, buf_size); + range = (void *)range->data + buf_size; } list_add_tail(&entry->list, list); @@ -914,7 +1077,8 @@ static int btintel_pcie_dump_dram(struct list_head *list, static int btintel_pcie_dump_dram_monitor(struct btintel_pcie_data *data, - struct list_head *list, u8 count, + struct list_head *list, u8 count, + u32 buf_size, struct data_buf *bufs, u32 status_reg, u32 wrap_reg, u8 allocation_id, u32 region_id, const char *name) @@ -922,6 +1086,9 @@ btintel_pcie_dump_dram_monitor(struct btintel_pcie_data *data, u32 allocation_offset, write_ptr, wrap_ctr, wr_ptr_status; u8 cur_frag; + if (!count) + return -ENOENT; + allocation_offset = allocation_id * BTINTEL_PCIE_DBGC_ALLOCATION_OFFSET; wr_ptr_status = btintel_pcie_rd_dev_mem(data, status_reg + @@ -943,8 +1110,8 @@ btintel_pcie_dump_dram_monitor(struct btintel_pcie_data *data, "allocation=%u wr_ptr_status=0x%08x write_ptr=0x%06x cur_frag=%u wrap_ctr=0x%08x", allocation_id, wr_ptr_status, write_ptr, cur_frag, wrap_ctr); - return btintel_pcie_dump_dram(list, count, bufs, write_ptr, wrap_ctr, - cur_frag, region_id, name); + return btintel_pcie_dump_dram(list, count, buf_size, bufs, write_ptr, + wrap_ctr, cur_frag, region_id, name); } static int btintel_pcie_dump_target_region(struct btintel_pcie_data *data, @@ -1225,6 +1392,7 @@ static int btintel_pcie_read_debug_regions(struct btintel_pcie_data *data) u8 hw_variant; u32 file_len; u8 count; + u32 buf_size; int ret; LIST_HEAD(dump_list); @@ -1233,10 +1401,12 @@ static int btintel_pcie_read_debug_regions(struct btintel_pcie_data *data) if (btintel_pcie_is_mdbgc_supported(data)) { mdbgc = &data->mdbgc; - count = mdbgc->count; + count = mdbgc->buf1_count; + buf_size = mdbgc->buf1_size; } else { dbgc = &data->dbgc; count = dbgc->count; + buf_size = dbgc->buf_size; } hw_variant = INTEL_HW_VARIANT(data->cnvi); @@ -1256,7 +1426,9 @@ static int btintel_pcie_read_debug_regions(struct btintel_pcie_data *data) } if (btintel_pcie_is_mdbgc_supported(data)) { - ret = btintel_pcie_dump_dram_monitor(data, &dump_list, count, + ret = btintel_pcie_dump_dram_monitor(data, &dump_list, + mdbgc->buf1_count, + mdbgc->buf1_size, mdbgc->buf1, status_reg, wrap_reg, BTINTEL_PCIE_MDBGC_ALLOCATIONID_1, @@ -1265,10 +1437,12 @@ static int btintel_pcie_read_debug_regions(struct btintel_pcie_data *data) if (!ret) regions_mask |= BIT_ULL(BTINTEL_PCIE_INI_ID_DRAM_MONITOR1); - else + else if (ret != -ENOENT) bt_dev_warn(hdev, "Failed to dump DRAM buf1: %d", ret); - ret = btintel_pcie_dump_dram_monitor(data, &dump_list, count, + ret = btintel_pcie_dump_dram_monitor(data, &dump_list, + mdbgc->buf2_count, + mdbgc->buf2_size, mdbgc->buf2, status_reg, wrap_reg, BTINTEL_PCIE_MDBGC_ALLOCATIONID_2, @@ -1277,10 +1451,12 @@ static int btintel_pcie_read_debug_regions(struct btintel_pcie_data *data) if (!ret) regions_mask |= BIT_ULL(BTINTEL_PCIE_INI_ID_DRAM_MONITOR2); - else + else if (ret != -ENOENT) bt_dev_warn(hdev, "Failed to dump DRAM buf2: %d", ret); - ret = btintel_pcie_dump_dram_monitor(data, &dump_list, count, + ret = btintel_pcie_dump_dram_monitor(data, &dump_list, + mdbgc->buf3_count, + mdbgc->buf3_size, mdbgc->buf3, status_reg, wrap_reg, BTINTEL_PCIE_MDBGC_ALLOCATIONID_3, @@ -1289,11 +1465,12 @@ static int btintel_pcie_read_debug_regions(struct btintel_pcie_data *data) if (!ret) regions_mask |= BIT_ULL(BTINTEL_PCIE_INI_ID_DRAM_MONITOR3); - else + else if (ret != -ENOENT) bt_dev_warn(hdev, "Failed to dump DRAM buf3: %d", ret); } else { ret = btintel_pcie_dump_dram_monitor(data, &dump_list, count, - dbgc->bufs, status_reg, + buf_size, dbgc->bufs, + status_reg, wrap_reg, BTINTEL_PCIE_MDBGC_ALLOCATIONID_1, BTINTEL_PCIE_INI_ID_DRAM_MONITOR1, @@ -2710,15 +2887,149 @@ static inline bool btintel_pcie_is_txackq_empty(struct btintel_pcie_data *data) return data->ia.cr_tia[BTINTEL_PCIE_TXQ_NUM] == data->ia.cr_hia[BTINTEL_PCIE_TXQ_NUM]; } +static bool btintel_pcie_hw_rfkill_doorbell(struct btintel_pcie_data *data, + bool state) +{ + unsigned long flags; + u32 reg; + int err; + + /* Set under ipc_lock so a late GP2 for a previous doorbell cannot + * complete this one. + */ + spin_lock_irqsave(&data->ipc_lock, flags); + WRITE_ONCE(data->rfkill_wait_state, state); + WRITE_ONCE(data->rfkill_wait_done, false); + reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_IPC_CONTROL_REG); + if (state) + reg |= BTINTEL_PCIE_CSR_IPC_CONTROL_HW_RFKILL; + else + reg &= ~BTINTEL_PCIE_CSR_IPC_CONTROL_HW_RFKILL; + btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_IPC_CONTROL_REG, reg); + spin_unlock_irqrestore(&data->ipc_lock, flags); + + err = wait_event_timeout(data->rfkill_wait_q, + READ_ONCE(data->rfkill_wait_done), + msecs_to_jiffies(BTINTEL_PCIE_HW_RFKILL_INTERRUPT_TIMEOUT)); + if (!err) { + bt_dev_err(data->hdev, "Timeout (%u ms) on alive interrupt for RFKILL", + BTINTEL_PCIE_HW_RFKILL_INTERRUPT_TIMEOUT); + return false; + } + + return true; +} + +static void btintel_pcie_hw_rfkill_delay_work(struct work_struct *wk) +{ + struct btintel_pcie_data *data = + container_of(wk, struct btintel_pcie_data, hw_rfkill_work.work); + u32 func_ctrl, ipc_ctrl; + bool set_rfkill, first_check, released; + + if (!data->hdev) + return; + + /* Firmware is not ready for the rfkill handshake before setup + * completes; setup schedules its own state check afterwards. + */ + if (!test_bit(BTINTEL_PCIE_SETUP_DONE, &data->flags)) + return; + + /* Do not report an initial clear when rfkill was never asserted. + * After resume, however, a previously asserted rfkill must be + * cleared and reported to the HCI stack. + */ + first_check = test_and_clear_bit(BTINTEL_PCIE_HW_RFKILL_STATE_CHECK, + &data->flags); + + func_ctrl = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG); + ipc_ctrl = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_IPC_CONTROL_REG); + + set_rfkill = !(func_ctrl & BTINTEL_PCIE_CSR_FUNC_CTRL_HW_RFKILL) && + !(ipc_ctrl & BTINTEL_PCIE_CSR_IPC_CONTROL_HW_RFKILL); + if (set_rfkill) { + bt_dev_dbg(data->hdev, "hw rfkill on"); + set_bit(BTINTEL_PCIE_HWRFKILL_ON, &data->flags); + hci_rfkill_set_hw_state(data->hdev, true); + } else { + bt_dev_dbg(data->hdev, "hw rfkill off"); + /* Nothing changed at the initial post-setup check, so there + * is no transition to report. + */ + if (first_check && + !test_bit(BTINTEL_PCIE_HWRFKILL_ON, &data->flags)) + return; + + /* Switch still asserted; IPC_CONTROL only holds the ack that + * shutdown sent, so this is not a release. + */ + if (!(func_ctrl & BTINTEL_PCIE_CSR_FUNC_CTRL_HW_RFKILL)) + return; + + mutex_lock(&data->rfkill_doorbell_lock); + released = btintel_pcie_hw_rfkill_doorbell(data, false); + if (released) + clear_bit(BTINTEL_PCIE_HWRFKILL_ON, &data->flags); + mutex_unlock(&data->rfkill_doorbell_lock); + + if (released) + hci_rfkill_set_hw_state(data->hdev, false); + } +} + +static void btintel_delayed_hw_rfkill(struct btintel_pcie_data *data, + bool delay) +{ + mod_delayed_work(system_wq, &data->hw_rfkill_work, + delay ? msecs_to_jiffies(BTINTEL_PCIE_HW_RFKILL_DELAY) : 0); +} + +static void btintel_pcie_msix_gp2_handler(struct btintel_pcie_data *data) +{ + unsigned long flags; + u32 reg, boot_stage_reg; + bool state, done; + + spin_lock_irqsave(&data->ipc_lock, flags); + boot_stage_reg = btintel_pcie_rd_reg32(data, + BTINTEL_PCIE_CSR_BOOT_STAGE_REG); + reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_IPC_STATUS_REG); + state = READ_ONCE(data->rfkill_wait_state); + + if (state && + (reg & BTINTEL_PCIE_CSR_IPC_STATUS_HW_RFKILL) && + (boot_stage_reg & BTINTEL_PCIE_CSR_BOOT_STAGE_HW_RFKILL_STATE)) { + bt_dev_dbg(data->hdev, + "firmware done handling HW RF-KILL SET state update"); + WRITE_ONCE(data->rfkill_wait_done, true); + } + + if (!state && + !(reg & BTINTEL_PCIE_CSR_IPC_STATUS_HW_RFKILL) && + !(boot_stage_reg & BTINTEL_PCIE_CSR_BOOT_STAGE_HW_RFKILL_STATE)) { + bt_dev_dbg(data->hdev, + "firmware done handling HW RF-KILL CLEAR state update"); + WRITE_ONCE(data->rfkill_wait_done, true); + } + + done = READ_ONCE(data->rfkill_wait_done); + spin_unlock_irqrestore(&data->ipc_lock, flags); + + if (done) + wake_up(&data->rfkill_wait_q); +} + static irqreturn_t btintel_pcie_irq_msix_handler(int irq, void *dev_id) { struct msix_entry *entry = dev_id; struct btintel_pcie_data *data = btintel_pcie_get_data(entry); - u32 intr_fh, intr_hw; + u32 intr_fh, intr_hw, hw_mask; spin_lock(&data->irq_lock); intr_fh = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_MSIX_FH_INT_CAUSES); intr_hw = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_MSIX_HW_INT_CAUSES); + hw_mask = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_MSIX_HW_INT_MASK); /* Clear causes registers to avoid being handling the same cause */ btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_MSIX_FH_INT_CAUSES, intr_fh); @@ -2740,6 +3051,8 @@ static irqreturn_t btintel_pcie_irq_msix_handler(int irq, void *dev_id) if (intr_hw & BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP1) btintel_pcie_msix_gp1_handler(data); + if (intr_hw & BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP2) + btintel_pcie_msix_gp2_handler(data); /* For TX */ if (intr_fh & BTINTEL_PCIE_MSIX_FH_INT_CAUSES_0) { @@ -2758,6 +3071,11 @@ static irqreturn_t btintel_pcie_irq_msix_handler(int irq, void *dev_id) if (intr_hw & BTINTEL_PCIE_MSIX_HW_INT_CAUSES_FWTRIG) btintel_pcie_msix_fw_trigger_handler(data); + /* A masked cause still latches; ignore it once masked. */ + if ((intr_hw & BTINTEL_PCIE_MSIX_HW_INT_CAUSES_HW_RFKILL) && + !(hw_mask & BTINTEL_PCIE_MSIX_HW_INT_CAUSES_HW_RFKILL)) + btintel_delayed_hw_rfkill(data, false); + /* This interrupt is triggered by the firmware after updating * boot_stage register and image_response register */ @@ -2835,8 +3153,10 @@ static struct btintel_pcie_causes_list causes_list[] = { { BTINTEL_PCIE_MSIX_FH_INT_CAUSES_0, BTINTEL_PCIE_CSR_MSIX_FH_INT_MASK, 0x00 }, { BTINTEL_PCIE_MSIX_FH_INT_CAUSES_1, BTINTEL_PCIE_CSR_MSIX_FH_INT_MASK, 0x01 }, { BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0, BTINTEL_PCIE_CSR_MSIX_HW_INT_MASK, 0x20 }, + { BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP2, BTINTEL_PCIE_CSR_MSIX_HW_INT_MASK, 0x22 }, { BTINTEL_PCIE_MSIX_HW_INT_CAUSES_HWEXP, BTINTEL_PCIE_CSR_MSIX_HW_INT_MASK, 0x23 }, { BTINTEL_PCIE_MSIX_HW_INT_CAUSES_FWTRIG, BTINTEL_PCIE_CSR_MSIX_HW_INT_MASK, 0x25 }, + { BTINTEL_PCIE_MSIX_HW_INT_CAUSES_HW_RFKILL, BTINTEL_PCIE_CSR_MSIX_HW_INT_MASK, 0x27 }, }; /* This function configures the interrupt masks for both HW_INT_CAUSES and @@ -3185,7 +3505,7 @@ static int btintel_pcie_alloc(struct btintel_pcie_data *data) err = btintel_pcie_setup_dbgc(data); } if (err) - goto exit_error_txq; + goto exit_error_rxq; /* Setup Context Information */ data->ci = v_addr; @@ -3194,8 +3514,13 @@ static int btintel_pcie_alloc(struct btintel_pcie_data *data) /* Initialize the CI */ btintel_pcie_init_ci(data, data->ci); + data->pcie_alloc_init = true; + return 0; +exit_error_rxq: + /* RX setup succeeded, so release its buffers before the shared unwind. */ + btintel_pcie_free_rxq_bufs(data, &data->rxq); exit_error_txq: btintel_pcie_free_txq_bufs(data, &data->txq); exit_error_pool: @@ -3353,6 +3678,25 @@ static void btintel_pcie_disable_interrupts(struct btintel_pcie_data *data) spin_unlock(&data->irq_lock); } +/* irq_lock is never taken in hardirq context: the MSI-X handler is a + * threaded IRQ with no primary handler, so plain spin_lock() is enough. + */ +static void btintel_pcie_mask_hw_rfkill(struct btintel_pcie_data *data) +{ + spin_lock(&data->irq_lock); + btintel_pcie_set_reg_bits(data, BTINTEL_PCIE_CSR_MSIX_HW_INT_MASK, + BTINTEL_PCIE_MSIX_HW_INT_CAUSES_HW_RFKILL); + spin_unlock(&data->irq_lock); +} + +static void btintel_pcie_unmask_hw_rfkill(struct btintel_pcie_data *data) +{ + spin_lock(&data->irq_lock); + btintel_pcie_clr_reg_bits(data, BTINTEL_PCIE_CSR_MSIX_HW_INT_MASK, + BTINTEL_PCIE_MSIX_HW_INT_CAUSES_HW_RFKILL); + spin_unlock(&data->irq_lock); +} + static void btintel_pcie_enable_interrupts(struct btintel_pcie_data *data) { spin_lock(&data->irq_lock); @@ -3367,6 +3711,32 @@ static void btintel_pcie_synchronize_irqs(struct btintel_pcie_data *data) synchronize_irq(data->msix_entries[i].vector); } +static void btintel_pcie_probe_cleanup(struct btintel_pcie_data *data) +{ + struct pci_dev *pdev = data->pdev; + + btintel_pcie_disable_interrupts(data); + btintel_pcie_synchronize_irqs(data); + + disable_work_sync(&data->coredump_work); + disable_work_sync(&data->hwexp_work); + disable_work_sync(&data->fwtrigger_work); + disable_work_sync(&data->mbox_work); + disable_delayed_work_sync(&data->hw_rfkill_work); + + flush_work(&data->rx_work); + + btintel_pcie_reset_bt(data); + for (int i = 0; i < data->alloc_vecs; i++) { + struct msix_entry *msix_entry; + + msix_entry = &data->msix_entries[i]; + devm_free_irq(&pdev->dev, msix_entry->vector, msix_entry); + } + + pci_free_irq_vectors(pdev); +} + static int btintel_pcie_get_debug_info_addr(struct hci_dev *hdev) { struct btintel_pcie_data *data = hci_get_drvdata(hdev); @@ -3554,8 +3924,12 @@ static int btintel_pcie_setup(struct hci_dev *hdev) btintel_pcie_start_rx(data); } - if (!err) + if (!err) { set_bit(BTINTEL_PCIE_SETUP_DONE, &data->flags); + set_bit(BTINTEL_PCIE_HW_RFKILL_STATE_CHECK, &data->flags); + btintel_pcie_unmask_hw_rfkill(data); + btintel_delayed_hw_rfkill(data, true); + } return err; } @@ -3783,18 +4157,20 @@ static void btintel_pcie_reset_work(struct work_struct *wk) if (!data) goto out; + btintel_pcie_mask_hw_rfkill(data); + btintel_pcie_synchronize_irqs(data); + disable_delayed_work_sync(&data->hw_rfkill_work); btintel_pcie_disable_interrupts(data); btintel_pcie_synchronize_irqs(data); flush_work(&data->rx_work); - /* Drain any in-flight dump workers and block new ones across reset. - * Safe from self-deadlock: they all run on a separate wq. + /* Drain any in-flight dump/rfkill workers and block new ones across + * reset. Safe from self-deadlock: they all run on a separate wq. */ disable_work_sync(&data->coredump_work); disable_work_sync(&data->hwexp_work); disable_work_sync(&data->fwtrigger_work); disable_work_sync(&data->mbox_work); - bt_dev_dbg(data->hdev, "Release bluetooth interface"); /* Both reset paths follow the same contract: on success they @@ -3819,6 +4195,7 @@ static void btintel_pcie_reset_work(struct work_struct *wk) enable_work(&data->hwexp_work); enable_work(&data->fwtrigger_work); enable_work(&data->mbox_work); + enable_delayed_work(&data->hw_rfkill_work); } out: @@ -4009,6 +4386,30 @@ static struct hci_drv btintel_pcie_hci_drv = { .specific_handlers = btintel_pcie_hci_drv_specific_handlers, }; +static int btintel_pcie_shutdown(struct hci_dev *hdev) +{ + struct btintel_pcie_data *data = hci_get_drvdata(hdev); + + /* Keep HW rfkill monitoring while HCI is down. On an active + * assertion, ack it right before the mandatory HCI reset. + * + * The cached flag is enough: firmware accepts HCI reset in any + * HW rfkill state, also in the middle of the doorbell flow. An + * assertion the worker has not seen yet is then handled like one + * while HCI is down; the worker still reports the block and + * handles the release. + * + * Not called from remove: hci_unregister_dev() sets HCI_UNREGISTER + * first, and hci_dev_close_sync() then skips hdev->shutdown(). + */ + mutex_lock(&data->rfkill_doorbell_lock); + if (test_bit(BTINTEL_PCIE_HWRFKILL_ON, &data->flags)) + btintel_pcie_hw_rfkill_doorbell(data, true); + mutex_unlock(&data->rfkill_doorbell_lock); + + return btintel_shutdown_combined(hdev); +} + static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data) { int err; @@ -4028,7 +4429,7 @@ static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data) hdev->close = btintel_pcie_close; hdev->send = btintel_pcie_send_frame; hdev->setup = btintel_pcie_setup; - hdev->shutdown = btintel_shutdown_combined; + hdev->shutdown = btintel_pcie_shutdown; hdev->hw_error = btintel_pcie_hw_error; hdev->set_diag = btintel_set_diag; hdev->set_bdaddr = btintel_set_bdaddr; @@ -4056,6 +4457,7 @@ static int btintel_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int err; + bool pcie_configured = false; struct btintel_pcie_data *data; if (!pdev) @@ -4069,6 +4471,8 @@ static int btintel_pcie_probe(struct pci_dev *pdev, spin_lock_init(&data->irq_lock); spin_lock_init(&data->hci_rx_lock); + spin_lock_init(&data->ipc_lock); + mutex_init(&data->rfkill_doorbell_lock); init_waitqueue_head(&data->gp0_wait_q); data->gp0_received = false; @@ -4076,6 +4480,9 @@ static int btintel_pcie_probe(struct pci_dev *pdev, init_waitqueue_head(&data->tx_wait_q); data->tx_wait_done = false; + init_waitqueue_head(&data->rfkill_wait_q); + data->rfkill_wait_done = false; + init_waitqueue_head(&data->mbox_parse_wait_q); data->workqueue = alloc_ordered_workqueue(KBUILD_MODNAME, WQ_HIGHPRI); @@ -4090,6 +4497,8 @@ static int btintel_pcie_probe(struct pci_dev *pdev, skb_queue_head_init(&data->rx_skb_q); INIT_WORK(&data->rx_work, btintel_pcie_rx_work); + INIT_DELAYED_WORK(&data->hw_rfkill_work, + btintel_pcie_hw_rfkill_delay_work); INIT_WORK(&data->reset_work, btintel_pcie_reset_work); INIT_WORK(&data->coredump_work, btintel_pcie_coredump_worker); INIT_WORK(&data->hwexp_work, btintel_pcie_hwexp_worker); @@ -4099,15 +4508,30 @@ static int btintel_pcie_probe(struct pci_dev *pdev, data->boot_stage_cache = 0x00; data->img_resp_cache = 0x00; data->dbg_path_cache = BTINTEL_PCIE_WIFI_DBGC; + data->pcie_alloc_init = false; + data->enable_ini = false; + btintel_pcie_yoyo_init(&data->yoyo); /* FLR can be invoked by echoing to debugfs path, so explicitly * initialized */ data->reset_type = BTINTEL_PCIE_IOSF_PRR_FLR; + + btintel_pcie_load_dbg_path_from_ini(data); + err = btintel_pcie_config_pcie(pdev, data); if (err) goto exit_error; + pcie_configured = true; + pci_set_drvdata(pdev, data); + if (data->enable_ini) { + err = btintel_pcie_yoyo_load_and_parse(&data->yoyo, &pdev->dev); + if (err) { + BT_WARN("YoYo is not configured (%d)", err); + btintel_pcie_yoyo_cleanup(&data->yoyo); + } + } err = btintel_pcie_alloc(data); if (err) @@ -4130,15 +4554,22 @@ static int btintel_pcie_probe(struct pci_dev *pdev, if (err) goto exit_error; + data->yoyo.hdev = data->hdev; bt_dev_dbg(data->hdev, "cnvi: 0x%8.8x cnvr: 0x%8.8x", data->cnvi, data->cnvr); return 0; exit_error: - /* reset device before exit */ - btintel_pcie_reset_bt(data); + btintel_pcie_yoyo_cleanup(&data->yoyo); + + if (pcie_configured) + btintel_pcie_probe_cleanup(data); + + if (data->pcie_alloc_init) + btintel_pcie_free(data); destroy_workqueue(data->dump_workqueue); + destroy_workqueue(data->workqueue); pci_clear_master(pdev); @@ -4175,6 +4606,12 @@ static void btintel_pcie_remove(struct pci_dev *pdev) if (current_work() != &data->reset_work) disable_work_sync(&data->reset_work); + btintel_pcie_mask_hw_rfkill(data); + btintel_pcie_synchronize_irqs(data); + disable_delayed_work_sync(&data->hw_rfkill_work); + + btintel_pcie_yoyo_cleanup(&data->yoyo); + btintel_pcie_disable_interrupts(data); btintel_pcie_synchronize_irqs(data); @@ -4317,6 +4754,10 @@ static int btintel_pcie_suspend_late(struct device *dev, pm_message_t mesg) data = pci_get_drvdata(pdev); + btintel_pcie_mask_hw_rfkill(data); + btintel_pcie_synchronize_irqs(data); + cancel_delayed_work_sync(&data->hw_rfkill_work); + /* S0ix (s2idle) uses D3_HOT; S3, freeze and hibernate use D3_COLD. */ if (mesg.event == PM_EVENT_SUSPEND && pm_suspend_target_state == PM_SUSPEND_TO_IDLE) @@ -4330,6 +4771,9 @@ static int btintel_pcie_suspend_late(struct device *dev, pm_message_t mesg) err = btintel_pcie_set_dxstate(data, dxstate); if (err) { + btintel_pcie_unmask_hw_rfkill(data); + set_bit(BTINTEL_PCIE_HW_RFKILL_STATE_CHECK, &data->flags); + btintel_delayed_hw_rfkill(data, true); bt_dev_err(data->hdev, "Failed to set dxstate:%u (%d)", dxstate, err); return err; @@ -4384,6 +4828,9 @@ static int btintel_pcie_resume_event(struct device *dev, pm_message_t mesg) if (err) { bt_dev_err(data->hdev, "Failed to set D0 state (%d)", err); } else { + btintel_pcie_unmask_hw_rfkill(data); + set_bit(BTINTEL_PCIE_HW_RFKILL_STATE_CHECK, &data->flags); + btintel_delayed_hw_rfkill(data, true); bt_dev_dbg(data->hdev, "device entered into d0 state from d3 in %lld us", ktime_to_us(ktime_get() - start)); diff --git a/drivers/bluetooth/btintel_pcie.h b/drivers/bluetooth/btintel_pcie.h index 3030b4e8b750..fff31ac8f87a 100644 --- a/drivers/bluetooth/btintel_pcie.h +++ b/drivers/bluetooth/btintel_pcie.h @@ -6,6 +6,8 @@ * Copyright (C) 2024 Intel Corporation */ +#include "btintel_pcie_debug.h" + /* Control and Status Register(BTINTEL_PCIE_CSR) */ #define BTINTEL_PCIE_CSR_BASE (0x000) #define BTINTEL_PCIE_CSR_FUNC_CTRL_REG (BTINTEL_PCIE_CSR_BASE + 0x024) @@ -33,6 +35,7 @@ #define BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT (BIT(6)) #define BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_INIT (BIT(7)) #define BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_STS (BIT(20)) +#define BTINTEL_PCIE_CSR_FUNC_CTRL_HW_RFKILL (BIT(27)) #define BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_REQ (BIT(21)) @@ -40,6 +43,12 @@ #define BTINTEL_PCIE_CSR_FUNC_CTRL_BUS_MASTER_DISCON (BIT(29)) #define BTINTEL_PCIE_CSR_FUNC_CTRL_SW_RESET (BIT(31)) +/* BTINTEL PCIE CSR IPC Control Register */ +#define BTINTEL_PCIE_CSR_IPC_CONTROL_HW_RFKILL (BIT(7)) + +/* BTINTEL PCIE CSR IPC Status Register */ +#define BTINTEL_PCIE_CSR_IPC_STATUS_HW_RFKILL (BIT(7)) + /* Value for BTINTEL_PCIE_CSR_BOOT_STAGE register */ #define BTINTEL_PCIE_CSR_BOOT_STAGE_ROM (BIT(0)) #define BTINTEL_PCIE_CSR_BOOT_STAGE_IML (BIT(1)) @@ -53,6 +62,7 @@ #define BTINTEL_PCIE_CSR_BOOT_STAGE_ALIVE (BIT(23)) /* Reflects live D-state. Updated by hardware on every D-state transition. */ #define BTINTEL_PCIE_CSR_BOOT_STAGE_D3_STATE_READY (BIT(24)) +#define BTINTEL_PCIE_CSR_BOOT_STAGE_HW_RFKILL_STATE (BIT(25)) #define BTINTEL_PCIE_CSR_DOORBELL_MBOX_READ_CONFIRM (BIT(4)) @@ -135,8 +145,10 @@ enum msix_fh_int_causes { enum msix_hw_int_causes { BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0 = BIT(0), /* cause 32 */ BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP1 = BIT(1), /* cause 33 */ + BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP2 = BIT(2), /* cause 34 */ BTINTEL_PCIE_MSIX_HW_INT_CAUSES_HWEXP = BIT(3), /* cause 35 */ BTINTEL_PCIE_MSIX_HW_INT_CAUSES_FWTRIG = BIT(5), /* cause 37 */ + BTINTEL_PCIE_MSIX_HW_INT_CAUSES_HW_RFKILL = BIT(7), /* cause 39 */ }; /* PCIe device states @@ -155,6 +167,8 @@ enum { BTINTEL_PCIE_COREDUMP_INPROGRESS, BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, BTINTEL_PCIE_RECOVERY_IN_PROGRESS, + BTINTEL_PCIE_HWRFKILL_ON, + BTINTEL_PCIE_HW_RFKILL_STATE_CHECK, BTINTEL_PCIE_SETUP_DONE, BTINTEL_PCIE_MAIL_BOX_INTR, BTINTEL_PCIE_MBOX_PARSE_PENDING, @@ -215,6 +229,12 @@ enum btintel_pcie_mbox_msg { #define BTINTEL_PCIE_DX_TRANSITION_MAX_RETRIES 3 +/* HW rfkill interrupt timeout */ +#define BTINTEL_PCIE_HW_RFKILL_INTERRUPT_TIMEOUT 200 + +/* HW rfkill check timeout */ +#define BTINTEL_PCIE_HW_RFKILL_DELAY 1000 + /* The number of descriptors in TX queues */ #define BTINTEL_PCIE_TX_DESCS_COUNT 32 @@ -466,6 +486,7 @@ struct rxq { */ struct btintel_pcie_dbgc { u16 count; + u32 buf_size; void *frag_v_addr; dma_addr_t frag_p_addr; @@ -477,7 +498,12 @@ struct btintel_pcie_dbgc { }; struct btintel_pcie_mdbgc { - u32 count; + u32 buf1_count; + u32 buf1_size; + u32 buf2_count; + u32 buf2_size; + u32 buf3_count; + u32 buf3_size; void *frag_v_addr; dma_addr_t frag_p_addr; @@ -680,6 +706,7 @@ struct btintel_pcie_ini_dump_info { * @flags: driver state * @irq_lock: spinlock for MSI-X * @hci_rx_lock: spinlock for HCI RX flow + * @ipc_lock: protects IPC control writes and the rfkill wait state * @base_addr: pci base address (from BAR) * @msix_entries: array of MSI-X entries * @msix_enabled: true if MSI-X is enabled; @@ -696,6 +723,11 @@ struct btintel_pcie_ini_dump_info { * @gp0_wait_q: wait_q for gp0 interrupt * @tx_wait_done: condition for tx interrupt * @tx_wait_q: wait_q for tx interrupt + * @rfkill_wait_done: condition for HW rfkill GP2 interrupt + * @rfkill_wait_state: requested HW rfkill transition (set or clear) + * being waited on, used to validate the GP2 acknowledgment + * @rfkill_wait_q: wait_q for HW rfkill GP2 interrupt + * @rfkill_doorbell_lock: serializes HW rfkill doorbell transitions * @workqueue: workqueue for RX work * @rx_skb_q: SKB queue for RX packet * @rx_work: RX work struct to process the RX packet in @rx_skb_q @@ -723,6 +755,8 @@ struct btintel_pcie_data { spinlock_t irq_lock; /* lock to serialize rx events */ spinlock_t hci_rx_lock; + /* lock to serialize IPC control register updates */ + spinlock_t ipc_lock; void __iomem *base_addr; @@ -737,6 +771,8 @@ struct btintel_pcie_data { u32 boot_stage_cache; u32 img_resp_cache; u32 dbg_path_cache; + bool enable_ini; + struct btintel_pcie_yoyo_ctx yoyo; u32 cnvi; u32 cnvr; @@ -747,9 +783,16 @@ struct btintel_pcie_data { bool tx_wait_done; wait_queue_head_t tx_wait_q; + bool rfkill_wait_done; + bool rfkill_wait_state; + wait_queue_head_t rfkill_wait_q; + /* serializes HW rfkill doorbell transitions */ + struct mutex rfkill_doorbell_lock; + struct workqueue_struct *workqueue; struct sk_buff_head rx_skb_q; struct work_struct rx_work; + struct delayed_work hw_rfkill_work; struct work_struct reset_work; struct workqueue_struct *dump_workqueue; @@ -783,6 +826,7 @@ struct btintel_pcie_data { wait_queue_head_t mbox_parse_wait_q; /* Timestamp captured in GP1 handler when mbox interrupt is received */ ktime_t mbox_intr_ts; + bool pcie_alloc_init; }; static inline u32 btintel_pcie_rd_reg32(struct btintel_pcie_data *data, diff --git a/drivers/bluetooth/btintel_pcie_debug.c b/drivers/bluetooth/btintel_pcie_debug.c new file mode 100644 index 000000000000..9f2d3f32bd99 --- /dev/null +++ b/drivers/bluetooth/btintel_pcie_debug.c @@ -0,0 +1,331 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Intel Bluetooth YoYo Debug Framework + * + * Copyright (C) 2026 Intel Corporation + * + * Runtime-configurable TLV-based debug collection framework for loading and + * parsing the optional YoYo firmware configuration used to enable debug + * regions, triggers, HCI commands, and configuration sets. + */ + +#include <linux/errno.h> +#include <linux/module.h> +#include <linux/stddef.h> +#include <linux/string.h> +#include <linux/unaligned.h> +#include <net/bluetooth/bluetooth.h> +#include "btintel_pcie_debug.h" + +/* TLV-specific parser DEBUG_INFO TLV type */ +static int btintel_pcie_yoyo_parse_dbg_info(struct btintel_pcie_yoyo_ctx *ctx, + const struct btintel_pcie_tlv_dbg_info *info, + u32 len) +{ + const u8 *data = (const u8 *)info; + u32 domain, image_type, core_type, version; + + if (len != sizeof(*info) - sizeof(struct btintel_pcie_tlv_hdr)) + return -EBADMSG; + + image_type = get_unaligned_le32(data + + offsetof(struct btintel_pcie_tlv_dbg_info, + image_type)); + core_type = get_unaligned_le32(data + + offsetof(struct btintel_pcie_tlv_dbg_info, + core_type)); + domain = get_unaligned_le32(data + + offsetof(struct btintel_pcie_tlv_dbg_info, + dbg_hdr.domain)); + version = get_unaligned_le32(data + + offsetof(struct btintel_pcie_tlv_dbg_info, + dbg_hdr.tlv_data_version)); + + if (domain != BTINTEL_PCIE_DOMAIN_BT || + version != BTINTEL_PCIE_DBG_INFO_TLV_VERSION) { + BT_WARN("YoYo: unsupported domain/version (%u/%u), disabling", + domain, version); + return -EINVAL; + } + + if (image_type != BTINTEL_PCIE_IMAGE_TLV_TYPE_EXTERNAL) { + BT_WARN("YoYo: unsupported image_type 0x%x, disabling", image_type); + return -EINVAL; + } + + if (core_type != BTINTEL_PCIE_CORE_TYPE_BT) { + BT_WARN("YoYo: non BT core_type %u, disabling", core_type); + return -EINVAL; + } + + ctx->dbg_info_present = true; + BT_DBG("YoYo: config='%.64s' image=%u core=%u", + info->config_name, image_type, core_type); + return 0; +} + +static int btintel_pcie_yoyo_parse_buf_alloc(struct btintel_pcie_yoyo_ctx *ctx, + const struct btintel_pcie_tlv_buf_alloc *tlv, + u32 len) +{ + u32 alloc_id, buf_location, domain, idx, max_num_frags, min_buf_size; + u32 req_buf_size, version; + + if (len != sizeof(*tlv) - sizeof(struct btintel_pcie_tlv_hdr)) { + BT_WARN("YoYo: unexpected buf alloc TLV length %u", len); + return -EBADMSG; + } + + domain = get_unaligned_le32(&tlv->dbg_hdr.domain); + version = get_unaligned_le32(&tlv->dbg_hdr.tlv_data_version); + if (domain != BTINTEL_PCIE_DOMAIN_BT || + version != BTINTEL_PCIE_BUF_ALLOC_TLV_VERSION) { + BT_WARN("YoYo: unsupported buf allocation domain/version (%u/%u)", + domain, version); + return -EINVAL; + } + + alloc_id = get_unaligned_le32(&tlv->alloc_id); + if (alloc_id < BTINTEL_PCIE_ALLOC_ID_DBGC1 || + alloc_id > BTINTEL_PCIE_ALLOC_ID_DBGC3) { + BT_WARN("YoYo: invalid buf allocation id %u", alloc_id); + return -EINVAL; + } + + idx = alloc_id - BTINTEL_PCIE_ALLOC_ID_DBGC1; + buf_location = get_unaligned_le32(&tlv->buf_location); + max_num_frags = get_unaligned_le32(&tlv->max_num_frags); + min_buf_size = get_unaligned_le32(&tlv->min_buf_size); + req_buf_size = get_unaligned_le32(&tlv->req_buf_size); + + if (buf_location != BTINTEL_PCIE_BUF_LOC_DRAM) { + BT_WARN("YoYo: buf allocation id=%u unsupported buffer location %u", + alloc_id, buf_location); + return -EINVAL; + } + + if (!max_num_frags || max_num_frags > BTINTEL_PCIE_MAX_BUF_FRAGS || + min_buf_size < BTINTEL_PCIE_MIN_BUF_SIZE || + min_buf_size > BTINTEL_PCIE_MAX_BUF_SIZE || + req_buf_size > BTINTEL_PCIE_MAX_BUF_SIZE || + req_buf_size % max_num_frags || + req_buf_size / max_num_frags < min_buf_size) { + BT_WARN("YoYo: buf allocation id=%u req size=%u max frags=%u min size=%u", + alloc_id, req_buf_size, max_num_frags, min_buf_size); + return -EINVAL; + } + + ctx->buf_alloc[idx].alloc_id = alloc_id; + ctx->buf_alloc[idx].buf_location = buf_location; + ctx->buf_alloc[idx].req_buf_size = req_buf_size; + ctx->buf_alloc[idx].max_num_frags = max_num_frags; + ctx->buf_alloc[idx].min_buf_size = min_buf_size; + ctx->buf_alloc[idx].present = true; + + if (idx + 1 > ctx->num_buf_allocs) + ctx->num_buf_allocs = idx + 1; + + BT_DBG("YoYo: buf allocation id=%u loc=%u req size=%u max frags=%u min size=%u", + alloc_id, ctx->buf_alloc[idx].buf_location, + ctx->buf_alloc[idx].req_buf_size, + ctx->buf_alloc[idx].max_num_frags, + ctx->buf_alloc[idx].min_buf_size); + + return 0; +} + +/* + * Parse the optional YoYo firmware TLV stream and validate each record. + * This is the entry point for the runtime debug configuration payload. + */ +static int btintel_pcie_yoyo_parse_tlv_buffer(struct btintel_pcie_yoyo_ctx *ctx, + const u8 *buf, size_t buf_len) +{ + const struct btintel_pcie_tlv_hdr *tlv; + const u8 *ptr = buf; + size_t remaining = buf_len; + u32 count = 0; + int ret = 0; + + while (remaining >= sizeof(*tlv)) { + size_t tlv_size; + u32 type, len; + + tlv = (const struct btintel_pcie_tlv_hdr *)ptr; + type = get_unaligned_le32(&tlv->type); + len = get_unaligned_le32(&tlv->length); + + if (len > remaining - sizeof(*tlv)) { + BT_ERR("YoYo: tlv %u truncated (len=%u rem=%zu)", count, + len, remaining); + return -EBADMSG; + } + tlv_size = sizeof(*tlv) + len; + + switch (type) { + case BTINTEL_PCIE_TLV_TYPE_DBG_INFO: + ret = btintel_pcie_yoyo_parse_dbg_info(ctx, + (const void *)tlv, len); + if (ret) { + ctx->dbg_info_present = false; + } + break; + case BTINTEL_PCIE_TLV_TYPE_DBG_BUF_ALLOC: + ret = btintel_pcie_yoyo_parse_buf_alloc(ctx, + (const void *)tlv, len); + break; + case BTINTEL_PCIE_TLV_TYPE_DBG_REGION: + case BTINTEL_PCIE_TLV_TYPE_DBG_TRIGGER: + case BTINTEL_PCIE_TLV_TYPE_DBG_HCMD: + case BTINTEL_PCIE_TLV_TYPE_DBG_CONFIG_SET: + case BTINTEL_PCIE_TLV_TYPE_DBG_PRESET_OVERRIDE: + BT_DBG("YoYo: valid tlv type 0x%x len=%u", type, len); + break; + default: /* Log and continue, do not fail*/ + BT_DBG("YoYo: unknown tlv type 0x%x len=%u", type, len); + break; + } + + ptr += tlv_size; + remaining -= tlv_size; + + if (ret) { + BT_ERR("YoYo: error parsing tlv type 0x%x (ret=%d)", type, ret); + return ret; + } + + count++; + } + + /* If no TLVs were parsed, the YoYo binary is considered invalid */ + if (remaining || count == 0) { + BT_ERR("YoYo: trailing %zu bytes after tlv stream", remaining); + return -EBADMSG; + } + if (!ctx->num_buf_allocs) { + BT_ERR("YoYo: mandatory buffer allocation TLV missing"); + return -EBADMSG; + } + + BT_DBG("YoYo: parsed %u tlv's", count); + return 0; +} + +/** + * btintel_pcie_yoyo_init - Initialize the YoYo context + * @ctx: Pre-allocated context (typically embedded in driver data) + */ +int btintel_pcie_yoyo_init(struct btintel_pcie_yoyo_ctx *ctx) +{ + if (!ctx) + return -EINVAL; + + memset(ctx, 0, sizeof(*ctx)); + INIT_LIST_HEAD(&ctx->region_list); + INIT_LIST_HEAD(&ctx->trigger_list); + INIT_LIST_HEAD(&ctx->hcmd_list); + INIT_LIST_HEAD(&ctx->config_set_list); + + /* set it to true after successful TLV parsing */ + ctx->enabled = false; + + return 0; +} +EXPORT_SYMBOL_GPL(btintel_pcie_yoyo_init); + +/** + * btintel_pcie_yoyo_cleanup - Clean up the YoYo context + * @ctx: YoYo context to clean up + */ +void btintel_pcie_yoyo_cleanup(struct btintel_pcie_yoyo_ctx *ctx) +{ + if (!ctx) + return; + + ctx->enabled = false; + ctx->dbg_info_present = false; + ctx->num_buf_allocs = 0; + memset(ctx->buf_alloc, 0, sizeof(ctx->buf_alloc)); +} +EXPORT_SYMBOL_GPL(btintel_pcie_yoyo_cleanup); + +/** + * btintel_pcie_yoyo_load_and_parse - Load ibt_debug_yoyo.bin and parse TLVs + * @ctx: Initialized YoYo context + * @dev: Device for firmware loading (typically &pdev->dev) + * + * Uses request_firmware_direct, since the YoYo binary + * is optional. On success, sets ctx->enabled. + */ +int btintel_pcie_yoyo_load_and_parse(struct btintel_pcie_yoyo_ctx *ctx, + struct device *dev) +{ + const struct firmware *fw; + int ret; + + if (!ctx) + return -EINVAL; + + ret = request_firmware_direct(&fw, BTINTEL_PCIE_YOYO_FW_NAME, dev); + if (ret) { + BT_WARN("YoYo: failed to load %s (%d)", + BTINTEL_PCIE_YOYO_FW_NAME, ret); + return ret; + } + + /* Sanity check firmware size */ + if (fw->size < sizeof(struct btintel_pcie_tlv_hdr)) { + release_firmware(fw); + return -EBADMSG; + } + + BT_DBG("YoYo: loaded %s (%zu bytes)", BTINTEL_PCIE_YOYO_FW_NAME, + fw->size); + + ret = btintel_pcie_yoyo_parse_tlv_buffer(ctx, fw->data, fw->size); + release_firmware(fw); + + /* File Corruption / TLV validation failed */ + if (ret) { + BT_ERR("YoYo: tlv parsing failed (%d)", ret); + return ret; + } + if (!ctx->dbg_info_present) { + BT_ERR("YoYo: Invalid BT debug Info tlv, using legacy DBGC defaults"); + return -EBADMSG; + } + + ctx->enabled = true; + + BT_INFO("YoYo: feature enabled and configured"); + return 0; +} +EXPORT_SYMBOL_GPL(btintel_pcie_yoyo_load_and_parse); + +/** + * btintel_pcie_yoyo_get_buf_alloc - Query buffer allocation config for a DBGC + * @ctx: YoYo context + * @alloc_id: Allocation ID (1=DBGC1, 2=DBGC2, 3=DBGC3) + * + * Return the parsed configuration, or NULL if no matching TLV was present. + */ +const struct btintel_pcie_buf_alloc * +btintel_pcie_yoyo_get_buf_alloc(struct btintel_pcie_yoyo_ctx *ctx, u32 alloc_id) +{ + u32 idx; + + if (!ctx || !ctx->enabled || + alloc_id < BTINTEL_PCIE_ALLOC_ID_DBGC1 || + alloc_id > BTINTEL_PCIE_ALLOC_ID_DBGC3) + return NULL; + + idx = alloc_id - BTINTEL_PCIE_ALLOC_ID_DBGC1; + if (!ctx->buf_alloc[idx].present) + return NULL; + + return &ctx->buf_alloc[idx]; +} +EXPORT_SYMBOL_GPL(btintel_pcie_yoyo_get_buf_alloc); + +MODULE_DESCRIPTION("Intel Bluetooth yoyo debug framework"); +MODULE_LICENSE("GPL"); diff --git a/drivers/bluetooth/btintel_pcie_debug.h b/drivers/bluetooth/btintel_pcie_debug.h new file mode 100644 index 000000000000..5ed368fb13d1 --- /dev/null +++ b/drivers/bluetooth/btintel_pcie_debug.h @@ -0,0 +1,171 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Intel Bluetooth YoYo Debug Framework + * + * Copyright (C) 2026 Intel Corporation + * + */ + +#ifndef __BTINTEL_PCIE_DEBUG_H__ +#define __BTINTEL_PCIE_DEBUG_H__ + +#include <linux/list.h> +#include <linux/types.h> +#include <linux/device.h> +#include <linux/firmware.h> + +/* External YoYo binary file */ +#define BTINTEL_PCIE_YOYO_FW_NAME "intel/ibt_debug_yoyo.bin" + +/* TLV type codes */ +#define BTINTEL_PCIE_TLV_TYPE_DBG_INFO 0x1000005 +#define BTINTEL_PCIE_TLV_TYPE_DBG_BUF_ALLOC 0x1000006 +#define BTINTEL_PCIE_TLV_TYPE_DBG_HCMD 0x1000007 +#define BTINTEL_PCIE_TLV_TYPE_DBG_REGION 0x1000008 +#define BTINTEL_PCIE_TLV_TYPE_DBG_TRIGGER 0x1000009 +#define BTINTEL_PCIE_TLV_TYPE_DBG_CONFIG_SET 0x100000A +#define BTINTEL_PCIE_TLV_TYPE_DBG_PRESET_OVERRIDE 0x100000B + +/* Supported TLV type versions */ +#define BTINTEL_PCIE_DBG_INFO_TLV_VERSION 2 +#define BTINTEL_PCIE_BUF_ALLOC_TLV_VERSION 1 +/* Debug Info TLV */ +#define BTINTEL_PCIE_CONFIG_NAME_LEN 64 +#define BTINTEL_PCIE_DOMAIN_BT 0 +#define BTINTEL_PCIE_CORE_TYPE_BT 1 +/* Buffer allocation TLV */ +#define BTINTEL_PCIE_MAX_BUF_ALLOC 3 +#define BTINTEL_PCIE_MAX_BUF_FRAGS 16 +#define BTINTEL_PCIE_MIN_BUF_SIZE (32 * 1024) +#define BTINTEL_PCIE_MAX_BUF_SIZE (4 * 1024 * 1024) + +enum btintel_pcie_image_tlv_type { + BTINTEL_PCIE_IMAGE_TLV_TYPE_EXTERNAL = 0x1, + BTINTEL_PCIE_IMAGE_TLV_TYPE_INTERNAL = 0x2, + BTINTEL_PCIE_IMAGE_TLV_TYPE_UNKNOWN = 0xff, +}; + +/* Allocation IDs */ +enum btintel_dbg_alloc_id { + BTINTEL_PCIE_ALLOC_ID_INVALID = 0, + BTINTEL_PCIE_ALLOC_ID_DBGC1 = 1, + BTINTEL_PCIE_ALLOC_ID_DBGC2 = 2, + BTINTEL_PCIE_ALLOC_ID_DBGC3 = 3, + BTINTEL_PCIE_ALLOC_ID_MAX, +}; + +/* Buffer locations */ +enum btintel_dbg_buf_location { + BTINTEL_PCIE_BUF_LOC_INVALID = 0, + BTINTEL_PCIE_BUF_LOC_SRAM = 1, + BTINTEL_PCIE_BUF_LOC_DRAM = 2, + BTINTEL_PCIE_BUF_LOC_NPK = 3, + BTINTEL_PCIE_BUF_LOC_MAX, +}; + +/* TLV header */ +struct btintel_pcie_tlv_hdr { + __le32 type; + __le32 length; +} __packed; + +/* Debug header common to all debug TLVs */ +struct btintel_pcie_dbg_hdr { + __le32 tlv_data_version; + __le32 domain; +} __packed; + +/* Address/value pair */ +struct btintel_pcie_addr_value { + __le32 address; + __le32 value; +} __packed; + +/* + * struct btintel_pcie_tlv_dbg_info - YoYo DEBUG_INFO TLV + * @hdr: TLV type and payload length + * @dbg_hdr: Debug TLV version and domain + * @image_type: Firmware image type + * @core_type: Firmware core type + * @config_name: Fixed-size name of the firmware configuration + * + * Describes the firmware image targeted by the YoYo configuration. Fields + * are stored in little-endian format in the packed firmware TLV. + */ +struct btintel_pcie_tlv_dbg_info { + struct btintel_pcie_tlv_hdr hdr; + struct btintel_pcie_dbg_hdr dbg_hdr; + __le32 image_type; + __le32 core_type; + u8 config_name[BTINTEL_PCIE_CONFIG_NAME_LEN]; +} __packed; + +/* + * struct btintel_pcie_tlv_buf_alloc - YoYo buffer allocation TLV + * @hdr: Common TLV header + * @dbg_hdr: Debug TLV version and domain + * @alloc_id: DBGC allocation identifier (DBGC1..DBGC3) + * @buf_location: Requested buffer location (SRAM / DRAM / NPK) + * @req_buf_size: Total requested allocation size in bytes + * @max_num_frags: Maximum number of buffer fragments (1..16) + * @min_buf_size: Minimum buffer size in bytes + * + * Describes the buffer sizing override for one DBGC allocation. + */ +struct btintel_pcie_tlv_buf_alloc { + struct btintel_pcie_tlv_hdr hdr; + struct btintel_pcie_dbg_hdr dbg_hdr; + __le32 alloc_id; + __le32 buf_location; + __le32 req_buf_size; + __le32 max_num_frags; + __le32 min_buf_size; +} __packed; + +/* Parsed buffer allocation entry in the YoYo context */ +struct btintel_pcie_buf_alloc { + u32 alloc_id; + u32 buf_location; + u32 req_buf_size; + u32 max_num_frags; + u32 min_buf_size; + bool present; +}; + +/* + * struct btintel_pcie_yoyo_ctx- Runtime state for YoYo debug configuration + * @enabled: Whether the loaded YoYo configuration passed validation + * @region_list: Parsed debug-region entries + * @trigger_list: Parsed debug-trigger entries + * @hcmd_list: Parsed HCI command entries + * @config_set_list: Parsed configuration-set entries + * @buf_alloc: Parsed buffer allocation entries + * @num_buf_allocs: Number of parsed buffer allocation entries + * @hdev: Associated HCI device; NULL until successful HCI registration + * + * Stores the validation state and parsed TLV data for the optional YoYo + * firmware configuration. + */ +struct btintel_pcie_yoyo_ctx { + bool enabled; + bool dbg_info_present; + struct list_head region_list; + struct list_head trigger_list; + struct list_head hcmd_list; + struct list_head config_set_list; + struct btintel_pcie_buf_alloc buf_alloc[BTINTEL_PCIE_MAX_BUF_ALLOC]; + int num_buf_allocs; + struct hci_dev *hdev; +}; + +int btintel_pcie_yoyo_init(struct btintel_pcie_yoyo_ctx *ctx); +void btintel_pcie_yoyo_cleanup(struct btintel_pcie_yoyo_ctx *ctx); + +/* Load and parse the external .bin file */ +int btintel_pcie_yoyo_load_and_parse(struct btintel_pcie_yoyo_ctx *ctx, + struct device *dev); + +const struct btintel_pcie_buf_alloc * +btintel_pcie_yoyo_get_buf_alloc(struct btintel_pcie_yoyo_ctx *ctx, u32 alloc_id); + +#endif /* __BTINTEL_PCIE_DEBUG_H__ */ diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c index 75483d8230e1..bf9bfed3da23 100644 --- a/drivers/bluetooth/btmtk.c +++ b/drivers/bluetooth/btmtk.c @@ -7,6 +7,7 @@ #include <linux/usb.h> #include <linux/iopoll.h> #include <linux/overflow.h> +#include <linux/string.h> #include <linux/unaligned.h> #include <net/bluetooth/bluetooth.h> @@ -30,7 +31,7 @@ #define BTMTK_CBMCU_FLAG_ENABLE_PATCH 0xF1 /* It is for mt79xx iso data transmission setting */ -#define MTK_ISO_THRESHOLD 264 +#define MTK_ISO_THRESHOLD 342 struct btmtk_patch_header { u8 datetime[16]; @@ -1556,8 +1557,15 @@ static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count) struct btmtk_data *btmtk_data = hci_get_priv(hdev); struct sk_buff *skb; unsigned long flags; + unsigned int iso_mtu; int err = 0; + /* The controller reports the largest Data_Total_Length it will send in + * LE Read Buffer Size [v2]. Fall back to HCI_MAX_ISO_SIZE while that + * command has not completed yet. + */ + iso_mtu = hdev->iso_mtu ? hdev->iso_mtu : HCI_MAX_ISO_SIZE; + spin_lock_irqsave(&btmtk_data->isorxlock, flags); skb = btmtk_data->isopkt_skb; @@ -1565,7 +1573,16 @@ static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count) int len; if (!skb) { - skb = bt_skb_alloc(HCI_MAX_ISO_SIZE, GFP_ATOMIC); + /* Drop the endpoint's zero-filled padding before + * allocating an skb for it; a zero Data_Total_Length + * check below would miss a padding remainder + * shorter than an ISO header. + */ + if (mem_is_zero(buffer, count)) + break; + + skb = bt_skb_alloc(HCI_ISO_HDR_SIZE + iso_mtu, + GFP_ATOMIC); if (!skb) { err = -ENOMEM; break; @@ -1588,7 +1605,24 @@ static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count) /* Complete ISO header */ hci_skb_expect(skb) = __le16_to_cpu(dlen); - if (skb_tailroom(skb) < hci_skb_expect(skb)) { + if (!hci_skb_expect(skb)) { + /* Zero padding was ruled out above, so a + * zero Data_Total_Length here is invalid. + */ + kfree_skb(skb); + skb = NULL; + + err = -EILSEQ; + break; + } + + /* Reject a length the controller said it would never + * send. The skb_tailroom() test is kept because a + * fragment started before hdev->iso_mtu was populated + * sits in a smaller skb than iso_mtu now allows. + */ + if (hci_skb_expect(skb) > iso_mtu || + skb_tailroom(skb) < hci_skb_expect(skb)) { kfree_skb(skb); skb = NULL; @@ -1707,7 +1741,7 @@ static int btmtk_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags) static int btmtk_usb_isointf_init(struct hci_dev *hdev) { struct btmtk_data *btmtk_data = hci_get_priv(hdev); - u8 iso_param[2] = { 0x08, 0x01 }; + __le16 iso_param = cpu_to_le16(MTK_ISO_THRESHOLD); struct sk_buff *skb; int err; @@ -1722,7 +1756,7 @@ static int btmtk_usb_isointf_init(struct hci_dev *hdev) return err; } - skb = __hci_cmd_sync(hdev, 0xfd98, sizeof(iso_param), iso_param, + skb = __hci_cmd_sync(hdev, 0xfd98, sizeof(iso_param), &iso_param, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { bt_dev_err(hdev, "Failed to apply iso setting (%ld)", PTR_ERR(skb)); diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c index 22b08ab05b82..002307000d3c 100644 --- a/drivers/bluetooth/btqca.c +++ b/drivers/bluetooth/btqca.c @@ -426,7 +426,8 @@ static int qca_tlv_check_data(struct hci_dev *hdev, tlv_nvm->data[0] |= 0x80; /* UART Baud Rate */ - if (soc_type >= QCA_WCN3991) + if (soc_type == QCA_WCN3950 || + soc_type >= QCA_WCN3991) tlv_nvm->data[1] = nvm_baud_rate; else tlv_nvm->data[2] = nvm_baud_rate; diff --git a/drivers/bluetooth/hci_nokia.c b/drivers/bluetooth/hci_nokia.c index be2923231e71..2866d4b54a53 100644 --- a/drivers/bluetooth/hci_nokia.c +++ b/drivers/bluetooth/hci_nokia.c @@ -531,12 +531,9 @@ static int nokia_enqueue(struct hci_uart *hu, struct sk_buff *skb) memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); /* Packets must be word aligned */ - if (skb->len % 2) { - err = skb_pad(skb, 1); - if (err) - return err; - skb_put(skb, 1); - } + err = skb_put_padto(skb, round_up(skb->len, 2)); + if (err) + return err; skb_queue_tail(&btdev->txq, skb); diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 9dc714d9145e..1c992e87534d 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -473,6 +473,9 @@ enum { HCI_MESH, HCI_MESH_SENDING, + HCI_HW_RFKILLED, + HCI_SW_RFKILLED, + __HCI_NUM_FLAGS, }; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index aa04dec45153..9d5d3ab4a075 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -503,6 +503,7 @@ struct hci_dev { struct list_head cmd_sync_work_list; struct mutex cmd_sync_work_lock; struct mutex unregister_lock; + struct mutex rfkill_lock; struct work_struct cmd_sync_cancel_work; struct work_struct reenable_adv_work; @@ -586,6 +587,7 @@ struct hci_dev { struct device dev; struct rfkill *rfkill; + struct work_struct rfkill_block; DECLARE_BITMAP(dev_flags, __HCI_NUM_FLAGS); hci_conn_flags_t conn_flags; @@ -680,6 +682,45 @@ enum conn_reasons { CONN_REASON_ISO_CONNECT, }; +enum { + HCI_CONN_AUTH_PEND, + HCI_CONN_ENCRYPT_PEND, + HCI_CONN_RSWITCH_PEND, + HCI_CONN_MODE_CHANGE_PEND, + HCI_CONN_SCO_SETUP_PEND, + HCI_CONN_MGMT_CONNECTED, + HCI_CONN_SSP_ENABLED, + HCI_CONN_SC_ENABLED, + HCI_CONN_AES_CCM, + HCI_CONN_POWER_SAVE, + HCI_CONN_FLUSH_KEY, + HCI_CONN_ENCRYPT, + HCI_CONN_AUTH, + HCI_CONN_SECURE, + HCI_CONN_FIPS, + HCI_CONN_STK_ENCRYPT, + HCI_CONN_AUTH_INITIATOR, + HCI_CONN_DROP, + HCI_CONN_CANCEL, + HCI_CONN_PARAM_REMOVAL_PEND, + HCI_CONN_NEW_LINK_KEY, + HCI_CONN_SCANNING, + HCI_CONN_AUTH_FAILURE, + HCI_CONN_PER_ADV, + HCI_CONN_BIG_CREATED, + HCI_CONN_CREATE, + HCI_CONN_CREATE_CIS, + HCI_CONN_CREATE_BIG_SYNC, + HCI_CONN_BIG_SYNC, + HCI_CONN_BIG_SYNC_FAILED, + HCI_CONN_CREATE_PA_SYNC, + HCI_CONN_PA_SYNC, + HCI_CONN_PA_SYNC_FAILED, + HCI_CONN_ENC_KEY_SIZE_PEND, + + __HCI_CONN_NUM_FLAGS, +}; + struct hci_conn { struct list_head list; @@ -750,7 +791,7 @@ struct hci_conn { __u8 num_bis; __u8 bis[HCI_MAX_ISO_BIS]; - unsigned long flags; + DECLARE_BITMAP(flags, __HCI_CONN_NUM_FLAGS); enum conn_reasons conn_reason; __u8 abort_reason; @@ -980,55 +1021,18 @@ u32 hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, bool name_known); void hci_inquiry_cache_flush(struct hci_dev *hdev); -/* ----- HCI Connections ----- */ -enum { - HCI_CONN_AUTH_PEND, - HCI_CONN_ENCRYPT_PEND, - HCI_CONN_RSWITCH_PEND, - HCI_CONN_MODE_CHANGE_PEND, - HCI_CONN_SCO_SETUP_PEND, - HCI_CONN_MGMT_CONNECTED, - HCI_CONN_SSP_ENABLED, - HCI_CONN_SC_ENABLED, - HCI_CONN_AES_CCM, - HCI_CONN_POWER_SAVE, - HCI_CONN_FLUSH_KEY, - HCI_CONN_ENCRYPT, - HCI_CONN_AUTH, - HCI_CONN_SECURE, - HCI_CONN_FIPS, - HCI_CONN_STK_ENCRYPT, - HCI_CONN_AUTH_INITIATOR, - HCI_CONN_DROP, - HCI_CONN_CANCEL, - HCI_CONN_PARAM_REMOVAL_PEND, - HCI_CONN_NEW_LINK_KEY, - HCI_CONN_SCANNING, - HCI_CONN_AUTH_FAILURE, - HCI_CONN_PER_ADV, - HCI_CONN_BIG_CREATED, - HCI_CONN_CREATE, - HCI_CONN_CREATE_CIS, - HCI_CONN_CREATE_BIG_SYNC, - HCI_CONN_BIG_SYNC, - HCI_CONN_BIG_SYNC_FAILED, - HCI_CONN_CREATE_PA_SYNC, - HCI_CONN_PA_SYNC, - HCI_CONN_PA_SYNC_FAILED, -}; - static inline bool hci_conn_ssp_enabled(struct hci_conn *conn) { struct hci_dev *hdev = conn->hdev; return hci_dev_test_flag(hdev, HCI_SSP_ENABLED) && - test_bit(HCI_CONN_SSP_ENABLED, &conn->flags); + test_bit(HCI_CONN_SSP_ENABLED, conn->flags); } static inline bool hci_conn_sc_enabled(struct hci_conn *conn) { struct hci_dev *hdev = conn->hdev; return hci_dev_test_flag(hdev, HCI_SC_ENABLED) && - test_bit(HCI_CONN_SC_ENABLED, &conn->flags); + test_bit(HCI_CONN_SC_ENABLED, conn->flags); } static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c) @@ -1219,7 +1223,7 @@ hci_conn_hash_lookup_create_pa_sync(struct hci_dev *hdev) if (c->type != PA_LINK) continue; - if (!test_bit(HCI_CONN_CREATE_PA_SYNC, &c->flags)) + if (!test_bit(HCI_CONN_CREATE_PA_SYNC, c->flags)) continue; rcu_read_unlock(); @@ -1245,7 +1249,7 @@ hci_conn_hash_lookup_per_adv_bis(struct hci_dev *hdev, list_for_each_entry_rcu(c, &h->list, list) { if (bacmp(&c->dst, ba) || c->type != BIS_LINK || - !test_bit(HCI_CONN_PER_ADV, &c->flags)) + !test_bit(HCI_CONN_PER_ADV, c->flags)) continue; if (c->iso_qos.bcast.big == big && @@ -1502,7 +1506,7 @@ hci_conn_hash_lookup_pa_sync_big_handle(struct hci_dev *hdev, __u8 big) list_for_each_entry_rcu(c, &h->list, list) { if (c->type != BIS_LINK || - !test_bit(HCI_CONN_PA_SYNC, &c->flags)) + !test_bit(HCI_CONN_PA_SYNC, c->flags)) continue; if (c->iso_qos.bcast.big == big) { @@ -1580,7 +1584,7 @@ static inline void hci_conn_hash_list_flag(struct hci_dev *hdev, rcu_read_lock(); list_for_each_entry_rcu(c, &h->list, list) { - if (c->type == type && test_bit(flag, &c->flags)) + if (c->type == type && test_bit(flag, c->flags)) func(c, data); } @@ -1598,7 +1602,7 @@ static inline struct hci_conn *hci_lookup_le_connect(struct hci_dev *hdev) list_for_each_entry_rcu(c, &h->list, list) { if (c->type == LE_LINK && c->state == BT_CONNECT && - !test_bit(HCI_CONN_SCANNING, &c->flags)) { + !test_bit(HCI_CONN_SCANNING, c->flags)) { rcu_read_unlock(); return c; } @@ -1619,7 +1623,7 @@ static inline bool hci_is_le_conn_scanning(struct hci_dev *hdev) list_for_each_entry_rcu(c, &h->list, list) { if (c->type == LE_LINK && c->state == BT_CONNECT && - test_bit(HCI_CONN_SCANNING, &c->flags)) { + test_bit(HCI_CONN_SCANNING, c->flags)) { rcu_read_unlock(); return true; } @@ -1822,6 +1826,8 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src, u8 src_type); struct hci_dev *hci_alloc_dev_priv(int sizeof_priv); +void hci_rfkill_set_hw_state(struct hci_dev *hdev, bool blocked); + static inline struct hci_dev *hci_alloc_dev(void) { return hci_alloc_dev_priv(0); @@ -2239,10 +2245,10 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status) struct hci_cb *cb; __u8 encrypt; - if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) + if (test_bit(HCI_CONN_ENCRYPT_PEND, conn->flags)) return; - encrypt = test_bit(HCI_CONN_ENCRYPT, &conn->flags) ? 0x01 : 0x00; + encrypt = test_bit(HCI_CONN_ENCRYPT, conn->flags) ? 0x01 : 0x00; mutex_lock(&hci_cb_list_lock); list_for_each_entry(cb, &hci_cb_list, list) { @@ -2271,9 +2277,9 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status) return; } - if (!test_bit(HCI_CONN_ENCRYPT, &conn->flags)) + if (!test_bit(HCI_CONN_ENCRYPT, conn->flags)) encrypt = 0x00; - else if (test_bit(HCI_CONN_AES_CCM, &conn->flags)) + else if (test_bit(HCI_CONN_AES_CCM, conn->flags)) encrypt = 0x02; else encrypt = 0x01; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 29da3fe2b953..b007f623b2ec 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -138,10 +138,10 @@ static void hci_conn_cleanup(struct hci_conn *conn) { struct hci_dev *hdev = conn->hdev; - if (test_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags)) + if (test_bit(HCI_CONN_PARAM_REMOVAL_PEND, conn->flags)) hci_conn_params_del(conn->hdev, &conn->dst, conn->dst_type); - if (test_and_clear_bit(HCI_CONN_FLUSH_KEY, &conn->flags)) + if (test_and_clear_bit(HCI_CONN_FLUSH_KEY, conn->flags)) hci_remove_link_key(hdev, &conn->dst); hci_chan_list_flush(conn); @@ -685,7 +685,7 @@ static void hci_conn_idle(struct work_struct *work) hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp); } - if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) { + if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, conn->flags)) { struct hci_cp_sniff_mode cp; cp.handle = cpu_to_le16(conn->handle); cp.max_interval = cpu_to_le16(hdev->sniff_max_interval); @@ -814,7 +814,7 @@ static int hci_le_terminate_big(struct hci_dev *hdev, struct hci_conn *conn) d->big = conn->iso_qos.bcast.big; d->bis = conn->iso_qos.bcast.bis; - d->big_term = test_and_clear_bit(HCI_CONN_BIG_CREATED, &conn->flags); + d->big_term = test_and_clear_bit(HCI_CONN_BIG_CREATED, conn->flags); ret = hci_cmd_sync_queue(hdev, terminate_big_sync, d, terminate_big_destroy); @@ -867,7 +867,7 @@ static int hci_le_big_terminate(struct hci_dev *hdev, struct hci_conn *conn) d->sync_handle = conn->sync_handle; if (conn->type == PA_LINK && - test_and_clear_bit(HCI_CONN_PA_SYNC, &conn->flags)) { + test_and_clear_bit(HCI_CONN_PA_SYNC, conn->flags)) { hci_conn_hash_list_flag(hdev, find_bis, PA_LINK, HCI_CONN_PA_SYNC, d); @@ -877,7 +877,7 @@ static int hci_le_big_terminate(struct hci_dev *hdev, struct hci_conn *conn) d->count = 0; } - if (test_and_clear_bit(HCI_CONN_BIG_SYNC, &conn->flags)) { + if (test_and_clear_bit(HCI_CONN_BIG_SYNC, conn->flags)) { hci_conn_hash_list_flag(hdev, find_bis, BIS_LINK, HCI_CONN_BIG_SYNC, d); @@ -912,7 +912,7 @@ static void bis_cleanup(struct hci_conn *conn) bt_dev_dbg(hdev, "conn %p", conn); if (conn->role == HCI_ROLE_MASTER) { - if (!test_and_clear_bit(HCI_CONN_PER_ADV, &conn->flags)) + if (!test_and_clear_bit(HCI_CONN_PER_ADV, conn->flags)) return; /* Check if ISO connection is a BIS and terminate advertising @@ -1087,7 +1087,7 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type, conn->sync_handle = HCI_SYNC_HANDLE_INVALID; conn->sid = HCI_SID_INVALID; - set_bit(HCI_CONN_POWER_SAVE, &conn->flags); + set_bit(HCI_CONN_POWER_SAVE, conn->flags); conn->disc_timeout = HCI_DISCONN_TIMEOUT; /* Set Default Authenticated payload timeout to 30s */ @@ -1217,8 +1217,8 @@ static void hci_conn_cleanup_child(struct hci_conn *conn, u8 reason) case BIS_LINK: case PA_LINK: if ((conn->state != BT_CONNECTED && - !test_bit(HCI_CONN_CREATE_CIS, &conn->flags)) || - test_bit(HCI_CONN_BIG_CREATED, &conn->flags)) + !test_bit(HCI_CONN_CREATE_CIS, conn->flags)) || + test_bit(HCI_CONN_BIG_CREATED, conn->flags)) hci_conn_failed(conn, reason); break; } @@ -1234,8 +1234,8 @@ static void hci_conn_unlink(struct hci_conn *conn) struct hci_link *link, *t; conn->sec_level = BT_SECURITY_SDP; - clear_bit(HCI_CONN_ENCRYPT, &conn->flags); - clear_bit(HCI_CONN_AES_CCM, &conn->flags); + clear_bit(HCI_CONN_ENCRYPT, conn->flags); + clear_bit(HCI_CONN_AES_CCM, conn->flags); /* mgmt_security_level_changed() reports the reset only if * this connection was actually reported to userspace as * connected (it checks HCI_CONN_MGMT_CONNECTED itself), so it @@ -1254,7 +1254,7 @@ static void hci_conn_unlink(struct hci_conn *conn) */ if (test_bit(HCI_UP, &hdev->flags)) mgmt_security_level_changed(conn); - clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags); + clear_bit(HCI_CONN_MGMT_CONNECTED, conn->flags); list_for_each_entry_safe(link, t, &conn->link_list, list) { struct hci_conn *child = link->conn; @@ -1458,8 +1458,8 @@ void hci_conn_failed(struct hci_conn *conn, u8 status) /* In case of BIG/PA sync failed, clear conn flags so that * the conns will be correctly cleaned up by ISO layer */ - test_and_clear_bit(HCI_CONN_BIG_SYNC_FAILED, &conn->flags); - test_and_clear_bit(HCI_CONN_PA_SYNC_FAILED, &conn->flags); + test_and_clear_bit(HCI_CONN_BIG_SYNC_FAILED, conn->flags); + test_and_clear_bit(HCI_CONN_PA_SYNC_FAILED, conn->flags); conn->state = BT_CLOSED; hci_connect_cfm(conn, status); @@ -1524,9 +1524,8 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, * to connect. */ conn = hci_conn_hash_lookup_le(hdev, dst, dst_type); - if (conn && !test_bit(HCI_CONN_SCANNING, &conn->flags)) { + if (conn && !test_bit(HCI_CONN_SCANNING, conn->flags)) return ERR_PTR(-EBUSY); - } /* Check if the destination address has been resolved by the controller * since if it did then the identity address shall be used. @@ -1614,8 +1613,9 @@ static int hci_explicit_conn_params_set(struct hci_dev *hdev, if (!params) return -ENOMEM; - /* If we created new params, mark them to be deleted in - * hci_connect_le_scan_cleanup. It's different case than + /* If we created new params, mark them to be deleted once the + * explicit connect is done, see le_conn_complete_evt() and + * hci_connect_le_scan_cleanup(). It's different case than * existing disabled params, those will stay after cleanup. */ params->auto_connect = HCI_AUTO_CONN_EXPLICIT; @@ -1797,7 +1797,7 @@ struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst, } conn->state = BT_CONNECT; - set_bit(HCI_CONN_SCANNING, &conn->flags); + set_bit(HCI_CONN_SCANNING, conn->flags); conn->sec_level = BT_SECURITY_LOW; conn->pending_sec_level = sec_level; conn->conn_timeout = conn_timeout; @@ -1923,12 +1923,12 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, if (acl->state == BT_CONNECTED && (sco->state == BT_OPEN || sco->state == BT_CLOSED)) { - set_bit(HCI_CONN_POWER_SAVE, &acl->flags); + set_bit(HCI_CONN_POWER_SAVE, acl->flags); hci_conn_enter_active_mode(acl, BT_POWER_FORCE_ACTIVE_ON); - if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->flags)) { + if (test_bit(HCI_CONN_MODE_CHANGE_PEND, acl->flags)) { /* defer SCO setup until mode change completed */ - set_bit(HCI_CONN_SCO_SETUP_PEND, &acl->flags); + set_bit(HCI_CONN_SCO_SETUP_PEND, acl->flags); return sco; } @@ -2220,7 +2220,7 @@ int hci_le_create_cis_pending(struct hci_dev *hdev) rcu_read_lock(); list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) { - if (test_bit(HCI_CONN_CREATE_CIS, &conn->flags)) { + if (test_bit(HCI_CONN_CREATE_CIS, conn->flags)) { rcu_read_unlock(); return -EBUSY; } @@ -2448,7 +2448,7 @@ static void bis_mark_per_adv(struct hci_conn *conn, void *data) d->bis != conn->iso_qos.bcast.bis) return; - set_bit(HCI_CONN_PER_ADV, &conn->flags); + set_bit(HCI_CONN_PER_ADV, conn->flags); } struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst, @@ -2568,7 +2568,7 @@ int hci_conn_check_link_mode(struct hci_conn *conn) */ if (hci_dev_test_flag(conn->hdev, HCI_SC_ONLY)) { if (!hci_conn_sc_enabled(conn) || - !test_bit(HCI_CONN_AES_CCM, &conn->flags) || + !test_bit(HCI_CONN_AES_CCM, conn->flags) || conn->key_type != HCI_LK_AUTH_COMBINATION_P256) return 0; } @@ -2584,14 +2584,14 @@ int hci_conn_check_link_mode(struct hci_conn *conn) * not shortened) */ if (conn->sec_level == BT_SECURITY_FIPS && - !test_bit(HCI_CONN_AES_CCM, &conn->flags)) { + !test_bit(HCI_CONN_AES_CCM, conn->flags)) { bt_dev_err(conn->hdev, "Invalid security: Missing AES-CCM usage"); return 0; } if (hci_conn_ssp_enabled(conn) && - !test_bit(HCI_CONN_ENCRYPT, &conn->flags)) + !test_bit(HCI_CONN_ENCRYPT, conn->flags)) return 0; return 1; @@ -2607,7 +2607,7 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) if (sec_level > conn->sec_level) conn->pending_sec_level = sec_level; - else if (test_bit(HCI_CONN_AUTH, &conn->flags)) + else if (test_bit(HCI_CONN_AUTH, conn->flags)) return 1; /* Make sure we preserve an existing MITM requirement*/ @@ -2615,7 +2615,7 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) conn->auth_type = auth_type; - if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { + if (!test_and_set_bit(HCI_CONN_AUTH_PEND, conn->flags)) { struct hci_cp_auth_requested cp; cp.handle = cpu_to_le16(conn->handle); @@ -2625,8 +2625,8 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) /* Set the ENCRYPT_PEND to trigger encryption after * authentication. */ - if (!test_bit(HCI_CONN_ENCRYPT, &conn->flags)) - set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); + if (!test_bit(HCI_CONN_ENCRYPT, conn->flags)) + set_bit(HCI_CONN_ENCRYPT_PEND, conn->flags); } return 0; @@ -2637,7 +2637,7 @@ static void hci_conn_encrypt(struct hci_conn *conn) { BT_DBG("hcon %p", conn); - if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) { + if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, conn->flags)) { struct hci_cp_set_conn_encrypt cp; cp.handle = cpu_to_le16(conn->handle); cp.encrypt = 0x01; @@ -2665,7 +2665,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type, return 1; /* For other security levels we need the link key. */ - if (!test_bit(HCI_CONN_AUTH, &conn->flags)) + if (!test_bit(HCI_CONN_AUTH, conn->flags)) goto auth; switch (conn->key_type) { @@ -2705,17 +2705,17 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type, } auth: - if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) + if (test_bit(HCI_CONN_ENCRYPT_PEND, conn->flags)) return 0; if (initiator) - set_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags); + set_bit(HCI_CONN_AUTH_INITIATOR, conn->flags); if (!hci_conn_auth(conn, sec_level, auth_type)) return 0; encrypt: - if (test_bit(HCI_CONN_ENCRYPT, &conn->flags)) { + if (test_bit(HCI_CONN_ENCRYPT, conn->flags)) { /* Ensure that the encryption key size has been read, * otherwise stall the upper layer responses. */ @@ -2758,7 +2758,7 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role) if (role == conn->role) return 1; - if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->flags)) { + if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, conn->flags)) { struct hci_cp_switch_role cp; bacpy(&cp.bdaddr, &conn->dst); cp.role = role; @@ -2779,10 +2779,10 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active) if (conn->mode != HCI_CM_SNIFF) goto timer; - if (!test_bit(HCI_CONN_POWER_SAVE, &conn->flags) && !force_active) + if (!test_bit(HCI_CONN_POWER_SAVE, conn->flags) && !force_active) goto timer; - if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) { + if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, conn->flags)) { struct hci_cp_exit_sniff_mode cp; cp.handle = cpu_to_le16(conn->handle); hci_send_cmd(hdev, HCI_OP_EXIT_SNIFF_MODE, sizeof(cp), &cp); @@ -2822,16 +2822,16 @@ static u32 get_link_mode(struct hci_conn *conn) if (conn->role == HCI_ROLE_MASTER) link_mode |= HCI_LM_MASTER; - if (test_bit(HCI_CONN_ENCRYPT, &conn->flags)) + if (test_bit(HCI_CONN_ENCRYPT, conn->flags)) link_mode |= HCI_LM_ENCRYPT; - if (test_bit(HCI_CONN_AUTH, &conn->flags)) + if (test_bit(HCI_CONN_AUTH, conn->flags)) link_mode |= HCI_LM_AUTH; - if (test_bit(HCI_CONN_SECURE, &conn->flags)) + if (test_bit(HCI_CONN_SECURE, conn->flags)) link_mode |= HCI_LM_SECURE; - if (test_bit(HCI_CONN_FIPS, &conn->flags)) + if (test_bit(HCI_CONN_FIPS, conn->flags)) link_mode |= HCI_LM_FIPS; return link_mode; @@ -2945,7 +2945,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn) BT_DBG("%s hcon %p", hdev->name, conn); - if (test_bit(HCI_CONN_DROP, &conn->flags)) { + if (test_bit(HCI_CONN_DROP, conn->flags)) { BT_DBG("Refusing to create new hci_chan"); return NULL; } @@ -2975,7 +2975,7 @@ void hci_chan_del(struct hci_chan *chan) synchronize_rcu(); /* Prevent new hci_chan's to be created for this hci_conn */ - set_bit(HCI_CONN_DROP, &conn->flags); + set_bit(HCI_CONN_DROP, conn->flags); hci_conn_put(conn); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 209244fd9391..2a29cfdee972 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -863,15 +863,13 @@ static int hci_dev_do_poweroff(struct hci_dev *hdev) return err; } -static int hci_rfkill_set_block(void *data, bool blocked) +static int __hci_rfkill_set_block(struct hci_dev *hdev, bool blocked) { - struct hci_dev *hdev = data; int err; - BT_DBG("%p name %s blocked %d", hdev, hdev->name, blocked); + lockdep_assert_held(&hdev->rfkill_lock); - if (hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) - return -EBUSY; + BT_DBG("%p name %s blocked %d", hdev, hdev->name, blocked); if (blocked == hci_dev_test_flag(hdev, HCI_RFKILLED)) return 0; @@ -879,8 +877,17 @@ static int hci_rfkill_set_block(void *data, bool blocked) if (blocked) { hci_dev_set_flag(hdev, HCI_RFKILLED); + /* Leave a user channel up; it closes the device on release + * and HCI_RFKILLED then blocks the next power on. + * + * During setup/config, HCI_RFKILLED is checked by the power + * on path, which closes the device. A block between that + * check and clearing HCI_SETUP is not enforced, as for a + * soft block; changing that is left to the setup flow. + */ if (!hci_dev_test_flag(hdev, HCI_SETUP) && - !hci_dev_test_flag(hdev, HCI_CONFIG)) { + !hci_dev_test_flag(hdev, HCI_CONFIG) && + !hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) { err = hci_dev_do_poweroff(hdev); if (err) { bt_dev_err(hdev, "Error when powering off device on rfkill (%d)", @@ -894,12 +901,100 @@ static int hci_rfkill_set_block(void *data, bool blocked) } } } else { + /* Stay blocked while HW rfkill is still asserted. Do not use + * rfkill_blocked() here: inside set_block it still reports + * the soft block being removed. + */ + if (hci_dev_test_flag(hdev, HCI_HW_RFKILLED)) + return 0; + hci_dev_clear_flag(hdev, HCI_RFKILLED); } return 0; } +static int hci_rfkill_set_block(void *data, bool blocked) +{ + struct hci_dev *hdev = data; + int err; + + mutex_lock(&hdev->rfkill_lock); + /* A user channel owns the device, so refuse soft rfkill. HW rfkill + * cannot be refused and is applied by hdev->rfkill_block instead. + */ + if (hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) { + err = -EBUSY; + } else { + /* Track only accepted soft state; rfkill core reverts a + * refused one after this callback returns. + */ + if (blocked) + hci_dev_set_flag(hdev, HCI_SW_RFKILLED); + else + hci_dev_clear_flag(hdev, HCI_SW_RFKILLED); + err = __hci_rfkill_set_block(hdev, blocked); + } + mutex_unlock(&hdev->rfkill_lock); + + return err; +} + +/** + * hci_rfkill_set_hw_state - report a hardware rfkill switch change + * @hdev: HCI device + * @blocked: true if the hardware switch is asserted + * + * May sleep. Must not be called with hdev->req_lock held, as a block + * powers the device off under hdev->rfkill_lock. @hdev must have been + * registered with hci_register_dev(). + */ +void hci_rfkill_set_hw_state(struct hci_dev *hdev, bool blocked) +{ + mutex_lock(&hdev->rfkill_lock); + mutex_lock(&hdev->unregister_lock); + if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) + goto unlock; + + if (blocked) + hci_dev_set_flag(hdev, HCI_HW_RFKILLED); + else + hci_dev_clear_flag(hdev, HCI_HW_RFKILLED); + + if (!IS_ERR_OR_NULL(hdev->rfkill)) { + /* Clear HCI_RFKILLED before rfkill core notifies userspace, + * so a power-on triggered by the unblock event does not see + * a stale flag. + */ + if (!blocked && !hci_dev_test_flag(hdev, HCI_SW_RFKILLED)) + hci_dev_clear_flag(hdev, HCI_RFKILLED); + + rfkill_set_hw_state(hdev->rfkill, blocked); + } + + /* Enforce the hardware state even without an rfkill device */ + schedule_work(&hdev->rfkill_block); +unlock: + mutex_unlock(&hdev->unregister_lock); + mutex_unlock(&hdev->rfkill_lock); +} +EXPORT_SYMBOL(hci_rfkill_set_hw_state); + +static void hci_rfkill_block_work(struct work_struct *work) +{ + struct hci_dev *hdev = container_of(work, struct hci_dev, rfkill_block); + bool blocked; + + /* Use only state settled under rfkill_lock, not rfkill core's, + * which may hold a soft change that set_block is about to revert. + */ + mutex_lock(&hdev->rfkill_lock); + blocked = hci_dev_test_flag(hdev, HCI_HW_RFKILLED) || + hci_dev_test_flag(hdev, HCI_SW_RFKILLED); + __hci_rfkill_set_block(hdev, blocked); + mutex_unlock(&hdev->rfkill_lock); +} + static const struct rfkill_ops hci_rfkill_ops = { .set_block = hci_rfkill_set_block, }; @@ -1252,7 +1347,6 @@ struct link_key *hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, key = kzalloc_obj(*key); if (!key) return NULL; - list_add_rcu(&key->list, &hdev->link_keys); } BT_DBG("%s key for %pMR type %u", hdev->name, bdaddr, type); @@ -1276,6 +1370,9 @@ struct link_key *hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, else key->type = type; + if (!old_key) + list_add_rcu(&key->list, &hdev->link_keys); + if (persistent) *persistent = hci_persistent_key(hdev, conn, type, old_key_type); @@ -1297,7 +1394,6 @@ struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, key = kzalloc_obj(*key); if (!key) return NULL; - list_add_rcu(&key->list, &hdev->long_term_keys); } bacpy(&key->bdaddr, bdaddr); @@ -1309,15 +1405,19 @@ struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, key->enc_size = enc_size; key->type = type; + if (!old_key) + list_add_rcu(&key->list, &hdev->long_term_keys); + return key; } struct smp_irk *hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 val[16], bdaddr_t *rpa) { - struct smp_irk *irk; + struct smp_irk *irk, *old_irk; - irk = hci_find_irk_by_addr(hdev, bdaddr, addr_type); + old_irk = hci_find_irk_by_addr(hdev, bdaddr, addr_type); + irk = old_irk; if (!irk) { irk = kzalloc_obj(*irk); if (!irk) @@ -1326,12 +1426,14 @@ struct smp_irk *hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, bacpy(&irk->bdaddr, bdaddr); irk->addr_type = addr_type; - list_add_rcu(&irk->list, &hdev->identity_resolving_keys); } memcpy(irk->val, val, 16); bacpy(&irk->rpa, rpa); + if (!old_irk) + list_add_rcu(&irk->list, &hdev->identity_resolving_keys); + return irk; } @@ -2495,6 +2597,7 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv) mutex_init(&hdev->req_lock); mutex_init(&hdev->mgmt_pending_lock); mutex_init(&hdev->remote_oob_lock); + mutex_init(&hdev->rfkill_lock); ida_init(&hdev->unset_handle_ida); @@ -2518,6 +2621,7 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv) INIT_LIST_HEAD(&hdev->monitored_devices); INIT_LIST_HEAD(&hdev->local_codecs); + INIT_WORK(&hdev->rfkill_block, hci_rfkill_block_work); INIT_WORK(&hdev->rx_work, hci_rx_work); INIT_WORK(&hdev->cmd_work, hci_cmd_work); INIT_WORK(&hdev->tx_work, hci_tx_work); @@ -2683,6 +2787,7 @@ void hci_unregister_dev(struct hci_dev *hdev) disable_work_sync(&hdev->tx_work); disable_work_sync(&hdev->power_on); disable_work_sync(&hdev->error_reset); + disable_work_sync(&hdev->rfkill_block); disable_delayed_work_sync(&hdev->cmd_timer); disable_delayed_work_sync(&hdev->ncmd_timer); hci_devcd_shutdown(hdev); @@ -2897,8 +3002,14 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb) { u8 dev_pkt_type; + /* Pairs with synchronize_rcu() in hci_dev_close_sync(), so rx_work is + * not queued once the workqueue is being drained. + */ + rcu_read_lock(); + if (!hdev || (!test_bit(HCI_UP, &hdev->flags) && !test_bit(HCI_INIT, &hdev->flags))) { + rcu_read_unlock(); kfree_skb(skb); return -ENXIO; } @@ -2934,6 +3045,7 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb) case HCI_DRV_PKT: break; default: + rcu_read_unlock(); kfree_skb(skb); return -EINVAL; } @@ -2947,6 +3059,8 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb) skb_queue_tail(&hdev->rx_q, skb); queue_work(hdev->workqueue, &hdev->rx_work); + rcu_read_unlock(); + return 0; } EXPORT_SYMBOL(hci_recv_frame); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 1f80f2cf6b2c..d05934fef4d9 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -724,6 +724,8 @@ static u8 hci_cc_read_enc_key_size(struct hci_dev *hdev, void *data, goto done; } + clear_bit(HCI_CONN_ENC_KEY_SIZE_PEND, conn->flags); + /* While unexpected, the read_enc_key_size command may fail. The most * secure approach is to then assume the key size is 0 to force a * disconnection. @@ -732,8 +734,8 @@ static u8 hci_cc_read_enc_key_size(struct hci_dev *hdev, void *data, bt_dev_err(hdev, "failed to read key size for handle %u", handle); conn->enc_key_size = 0; - clear_bit(HCI_CONN_ENCRYPT, &conn->flags); - clear_bit(HCI_CONN_AES_CCM, &conn->flags); + clear_bit(HCI_CONN_ENCRYPT, conn->flags); + clear_bit(HCI_CONN_AES_CCM, conn->flags); /* Downgrade to reflect the connection no longer being * encrypted, instead of advertising a stale elevated * security level alongside MGMT_CONN_SEC_ENCRYPT_NONE. @@ -761,8 +763,8 @@ static u8 hci_cc_read_enc_key_size(struct hci_dev *hdev, void *data, * state at a later time. */ status = HCI_ERROR_AUTH_FAILURE; - clear_bit(HCI_CONN_ENCRYPT, &conn->flags); - clear_bit(HCI_CONN_AES_CCM, &conn->flags); + clear_bit(HCI_CONN_ENCRYPT, conn->flags); + clear_bit(HCI_CONN_AES_CCM, conn->flags); /* Downgrade to reflect the connection no longer being * encrypted, instead of advertising a stale elevated * security level alongside MGMT_CONN_SEC_ENCRYPT_NONE. @@ -2595,10 +2597,10 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status) if (!hci_outgoing_auth_needed(hdev, conn)) goto unlock; - if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { + if (!test_and_set_bit(HCI_CONN_AUTH_PEND, conn->flags)) { struct hci_cp_auth_requested auth_cp; - set_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags); + set_bit(HCI_CONN_AUTH_INITIATOR, conn->flags); auth_cp.handle = __cpu_to_le16(conn->handle); hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, @@ -2738,9 +2740,9 @@ static void hci_cs_sniff_mode(struct hci_dev *hdev, __u8 status) conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); if (conn) { - clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags); + clear_bit(HCI_CONN_MODE_CHANGE_PEND, conn->flags); - if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags)) + if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, conn->flags)) hci_sco_setup(conn, status); } @@ -2765,9 +2767,9 @@ static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status) conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); if (conn) { - clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags); + clear_bit(HCI_CONN_MODE_CHANGE_PEND, conn->flags); - if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags)) + if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, conn->flags)) hci_sco_setup(conn, status); } @@ -2824,10 +2826,10 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status) * still needs it set to know whether to report the security level * reset, so it is consumed there instead of here. */ - mgmt_conn = test_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags); + mgmt_conn = test_bit(HCI_CONN_MGMT_CONNECTED, conn->flags); if (conn->type == ACL_LINK) { - if (test_and_clear_bit(HCI_CONN_FLUSH_KEY, &conn->flags)) + if (test_and_clear_bit(HCI_CONN_FLUSH_KEY, conn->flags)) hci_remove_link_key(hdev, &conn->dst); } @@ -3078,7 +3080,7 @@ static void hci_cs_switch_role(struct hci_dev *hdev, u8 status) conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); if (conn) - clear_bit(HCI_CONN_RSWITCH_PEND, &conn->flags); + clear_bit(HCI_CONN_RSWITCH_PEND, conn->flags); hci_dev_unlock(hdev); } @@ -3190,6 +3192,7 @@ static int hci_read_enc_key_size(struct hci_dev *hdev, struct hci_conn *conn) { struct hci_cp_read_enc_key_size cp; u8 *key_enc_size = hci_conn_key_enc_size(conn); + int err; if (!read_key_size_capable(hdev)) { conn->enc_key_size = HCI_LINK_KEY_SIZE; @@ -3211,7 +3214,14 @@ static int hci_read_enc_key_size(struct hci_dev *hdev, struct hci_conn *conn) else conn->enc_key_size = hdev->min_enc_key_size; - return hci_send_cmd(hdev, HCI_OP_READ_ENC_KEY_SIZE, sizeof(cp), &cp); + /* L2CAP holds incoming data back until the key size is known */ + set_bit(HCI_CONN_ENC_KEY_SIZE_PEND, conn->flags); + + err = hci_send_cmd(hdev, HCI_OP_READ_ENC_KEY_SIZE, sizeof(cp), &cp); + if (err) + clear_bit(HCI_CONN_ENC_KEY_SIZE_PEND, conn->flags); + + return err; } static void hci_conn_complete_evt(struct hci_dev *hdev, void *data, @@ -3309,19 +3319,19 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data, hci_conn_add_sysfs(conn); if (test_bit(HCI_AUTH, &hdev->flags)) - set_bit(HCI_CONN_AUTH, &conn->flags); + set_bit(HCI_CONN_AUTH, conn->flags); if (test_bit(HCI_ENCRYPT, &hdev->flags)) - set_bit(HCI_CONN_ENCRYPT, &conn->flags); + set_bit(HCI_CONN_ENCRYPT, conn->flags); /* "Link key request" completed ahead of "connect request" completes */ - if (ev->encr_mode == 1 && !test_bit(HCI_CONN_ENCRYPT, &conn->flags) && + if (ev->encr_mode == 1 && !test_bit(HCI_CONN_ENCRYPT, conn->flags) && ev->link_type == ACL_LINK) { struct link_key *key; key = hci_find_link_key(hdev, &ev->bdaddr); if (key) { - set_bit(HCI_CONN_ENCRYPT, &conn->flags); + set_bit(HCI_CONN_ENCRYPT, conn->flags); hci_read_enc_key_size(hdev, conn); hci_encrypt_cfm(conn, ev->status); } @@ -3525,9 +3535,9 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, void *data, * still needs it set to know whether to report the security level * reset, so it is consumed there instead of here. */ - mgmt_connected = test_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags); + mgmt_connected = test_bit(HCI_CONN_MGMT_CONNECTED, conn->flags); - if (test_bit(HCI_CONN_AUTH_FAILURE, &conn->flags)) + if (test_bit(HCI_CONN_AUTH_FAILURE, conn->flags)) reason = MGMT_DEV_DISCONN_AUTH_FAILURE; else reason = hci_to_mgmt_reason(ev->reason); @@ -3536,7 +3546,7 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, void *data, reason, mgmt_connected); if (conn->type == ACL_LINK) { - if (test_and_clear_bit(HCI_CONN_FLUSH_KEY, &conn->flags)) + if (test_and_clear_bit(HCI_CONN_FLUSH_KEY, conn->flags)) hci_remove_link_key(hdev, &conn->dst); hci_update_scan(hdev); @@ -3607,8 +3617,8 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, void *data, goto unlock; if (!ev->status) { - clear_bit(HCI_CONN_AUTH_FAILURE, &conn->flags); - set_bit(HCI_CONN_AUTH, &conn->flags); + clear_bit(HCI_CONN_AUTH_FAILURE, conn->flags); + set_bit(HCI_CONN_AUTH, conn->flags); /* Authentication alone does not imply encryption: for SSP * capable devices, encryption is only requested below, and * for legacy devices it is requested by a separate @@ -3621,12 +3631,12 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, void *data, conn->sec_level = conn->pending_sec_level; } else { if (ev->status == HCI_ERROR_PIN_OR_KEY_MISSING) - set_bit(HCI_CONN_AUTH_FAILURE, &conn->flags); + set_bit(HCI_CONN_AUTH_FAILURE, conn->flags); mgmt_auth_failed(conn, ev->status); } - clear_bit(HCI_CONN_AUTH_PEND, &conn->flags); + clear_bit(HCI_CONN_AUTH_PEND, conn->flags); if (conn->state == BT_CONFIG) { if (!ev->status && hci_conn_ssp_enabled(conn)) { @@ -3648,7 +3658,7 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, void *data, hci_conn_drop(conn); } - if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) { + if (test_bit(HCI_CONN_ENCRYPT_PEND, conn->flags)) { if (!ev->status) { struct hci_cp_set_conn_encrypt cp; cp.handle = ev->handle; @@ -3656,7 +3666,7 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, void *data, hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), &cp); } else { - clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); + clear_bit(HCI_CONN_ENCRYPT_PEND, conn->flags); hci_encrypt_cfm(conn, ev->status); } } @@ -3693,10 +3703,10 @@ check_auth: if (!hci_outgoing_auth_needed(hdev, conn)) goto unlock; - if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { + if (!test_and_set_bit(HCI_CONN_AUTH_PEND, conn->flags)) { struct hci_cp_auth_requested cp; - set_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags); + set_bit(HCI_CONN_AUTH_INITIATOR, conn->flags); cp.handle = __cpu_to_le16(conn->handle); hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); @@ -3723,17 +3733,17 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, void *data, if (!ev->status) { if (ev->encrypt) { /* Encryption implies authentication */ - set_bit(HCI_CONN_AUTH, &conn->flags); - set_bit(HCI_CONN_ENCRYPT, &conn->flags); + set_bit(HCI_CONN_AUTH, conn->flags); + set_bit(HCI_CONN_ENCRYPT, conn->flags); conn->sec_level = conn->pending_sec_level; /* P-256 authentication key implies FIPS */ if (conn->key_type == HCI_LK_AUTH_COMBINATION_P256) - set_bit(HCI_CONN_FIPS, &conn->flags); + set_bit(HCI_CONN_FIPS, conn->flags); if ((conn->type == ACL_LINK && ev->encrypt == 0x02) || conn->type == LE_LINK) - set_bit(HCI_CONN_AES_CCM, &conn->flags); + set_bit(HCI_CONN_AES_CCM, conn->flags); /* For ACL links the encryption key size is still * validated below via hci_read_enc_key_size(). Its @@ -3745,8 +3755,8 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, void *data, if (conn->type != ACL_LINK) mgmt_security_level_changed(conn); } else { - clear_bit(HCI_CONN_ENCRYPT, &conn->flags); - clear_bit(HCI_CONN_AES_CCM, &conn->flags); + clear_bit(HCI_CONN_ENCRYPT, conn->flags); + clear_bit(HCI_CONN_AES_CCM, conn->flags); /* Elevated security levels (MEDIUM and above) require * encryption, so downgrade to reflect the connection * no longer being encrypted before reporting, instead @@ -3767,7 +3777,7 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, void *data, hci_adv_instances_set_rpa_expired(hdev, true); } - clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); + clear_bit(HCI_CONN_ENCRYPT_PEND, conn->flags); /* Check link security requirements are met */ if (!hci_conn_check_link_mode(conn)) @@ -3775,7 +3785,7 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, void *data, if (ev->status && conn->state == BT_CONNECTED) { if (ev->status == HCI_ERROR_PIN_OR_KEY_MISSING) - set_bit(HCI_CONN_AUTH_FAILURE, &conn->flags); + set_bit(HCI_CONN_AUTH_FAILURE, conn->flags); /* Notify upper layers so they can cleanup before * disconnecting. @@ -3813,8 +3823,8 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, void *data, * type can be either LE or ACL and controller must support LMP Ping. * Ensure for AES-CCM encryption as well. */ - if (test_bit(HCI_CONN_ENCRYPT, &conn->flags) && - test_bit(HCI_CONN_AES_CCM, &conn->flags) && + if (test_bit(HCI_CONN_ENCRYPT, conn->flags) && + test_bit(HCI_CONN_AES_CCM, conn->flags) && ((conn->type == ACL_LINK && lmp_ping_capable(hdev)) || (conn->type == LE_LINK && (hdev->le_features[0] & HCI_LE_PING)))) { struct hci_cp_write_auth_payload_to cp; @@ -3846,9 +3856,9 @@ static void hci_change_link_key_complete_evt(struct hci_dev *hdev, void *data, conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); if (conn) { if (!ev->status) - set_bit(HCI_CONN_SECURE, &conn->flags); + set_bit(HCI_CONN_SECURE, conn->flags); - clear_bit(HCI_CONN_AUTH_PEND, &conn->flags); + clear_bit(HCI_CONN_AUTH_PEND, conn->flags); hci_key_change_cfm(conn, ev->status); } @@ -4074,7 +4084,7 @@ static u8 hci_cc_le_setup_iso_path(struct hci_dev *hdev, void *data, hci_connect_cfm(conn, rp->status); /* Notify device connected in case it is a BIG Sync */ - if (!rp->status && test_bit(HCI_CONN_BIG_SYNC, &conn->flags)) + if (!rp->status && test_bit(HCI_CONN_BIG_SYNC, conn->flags)) mgmt_device_connected(hdev, conn, NULL, 0); break; @@ -4504,7 +4514,7 @@ static void hci_cs_le_create_cis(struct hci_dev *hdev, u8 status) conn = hci_conn_hash_lookup_handle(hdev, handle); if (conn) { if (test_and_clear_bit(HCI_CONN_CREATE_CIS, - &conn->flags)) + conn->flags)) pending = true; conn->state = BT_CLOSED; hci_connect_cfm(conn, status); @@ -4625,7 +4635,7 @@ static void hci_role_change_evt(struct hci_dev *hdev, void *data, if (!ev->status) conn->role = ev->role; - clear_bit(HCI_CONN_RSWITCH_PEND, &conn->flags); + clear_bit(HCI_CONN_RSWITCH_PEND, conn->flags); hci_role_switch_cfm(conn, ev->status, ev->role); } @@ -4737,12 +4747,12 @@ static void hci_mode_change_evt(struct hci_dev *hdev, void *data, conn->mode = ev->mode; if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, - &conn->flags)) { - assign_bit(HCI_CONN_POWER_SAVE, &conn->flags, + conn->flags)) { + assign_bit(HCI_CONN_POWER_SAVE, conn->flags, conn->mode == HCI_CM_ACTIVE); } - if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags)) + if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, conn->flags)) hci_sco_setup(conn, ev->status); } @@ -4770,7 +4780,7 @@ static void hci_pin_code_request_evt(struct hci_dev *hdev, void *data, } if (!hci_dev_test_flag(hdev, HCI_BONDABLE) && - !test_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags)) { + !test_bit(HCI_CONN_AUTH_INITIATOR, conn->flags)) { hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(ev->bdaddr), &ev->bdaddr); } else if (hci_dev_test_flag(hdev, HCI_MGMT)) { @@ -4845,7 +4855,7 @@ static void hci_link_key_request_evt(struct hci_dev *hdev, void *data, conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); if (conn) { - clear_bit(HCI_CONN_NEW_LINK_KEY, &conn->flags); + clear_bit(HCI_CONN_NEW_LINK_KEY, conn->flags); if ((key->type == HCI_LK_UNAUTH_COMBINATION_P192 || key->type == HCI_LK_UNAUTH_COMBINATION_P256) && @@ -4908,7 +4918,7 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, void *data, conn->disc_timeout = HCI_DISCONN_TIMEOUT; hci_conn_drop(conn); - set_bit(HCI_CONN_NEW_LINK_KEY, &conn->flags); + set_bit(HCI_CONN_NEW_LINK_KEY, conn->flags); conn_set_key(conn, ev->key_type, conn->pin_length); if (!hci_dev_test_flag(hdev, HCI_MGMT)) @@ -4939,7 +4949,7 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, void *data, goto unlock; } - assign_bit(HCI_CONN_FLUSH_KEY, &conn->flags, !persistent); + assign_bit(HCI_CONN_FLUSH_KEY, conn->flags, !persistent); unlock: hci_dev_unlock(hdev); @@ -5117,7 +5127,7 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev, void *data, ie->data.ssp_mode = (ev->features[0] & LMP_HOST_SSP); if (ev->features[0] & LMP_HOST_SSP) { - set_bit(HCI_CONN_SSP_ENABLED, &conn->flags); + set_bit(HCI_CONN_SSP_ENABLED, conn->flags); } else { /* It is mandatory by the Bluetooth specification that * Extended Inquiry Results are only used when Secure @@ -5127,17 +5137,17 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev, void *data, * To make these devices work, the internal SSP * enabled flag needs to be cleared if the remote host * features do not indicate SSP support */ - clear_bit(HCI_CONN_SSP_ENABLED, &conn->flags); + clear_bit(HCI_CONN_SSP_ENABLED, conn->flags); } if (ev->features[0] & LMP_HOST_SC) - set_bit(HCI_CONN_SC_ENABLED, &conn->flags); + set_bit(HCI_CONN_SC_ENABLED, conn->flags); } if (conn->state != BT_CONFIG) goto unlock; - if (!ev->status && !test_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) { + if (!ev->status && !test_bit(HCI_CONN_MGMT_CONNECTED, conn->flags)) { struct hci_cp_remote_name_req cp; memset(&cp, 0, sizeof(cp)); bacpy(&cp.bdaddr, &conn->dst); @@ -5373,7 +5383,7 @@ static void hci_key_refresh_complete_evt(struct hci_dev *hdev, void *data, mgmt_security_level_changed(conn); } - clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); + clear_bit(HCI_CONN_ENCRYPT_PEND, conn->flags); if (ev->status && conn->state == BT_CONNECTED) { hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE); @@ -5474,7 +5484,7 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, void *data, goto unlock; /* Assume remote supports SSP since it has triggered this event */ - set_bit(HCI_CONN_SSP_ENABLED, &conn->flags); + set_bit(HCI_CONN_SSP_ENABLED, conn->flags); hci_conn_hold(conn); @@ -5485,7 +5495,7 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, void *data, * pairing or if the remote is not requesting bonding. */ if (hci_dev_test_flag(hdev, HCI_BONDABLE) || - test_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags) || + test_bit(HCI_CONN_AUTH_INITIATOR, conn->flags) || (conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) { struct hci_cp_io_capability_reply cp; @@ -5595,7 +5605,7 @@ static void hci_user_confirm_request_evt(struct hci_dev *hdev, void *data, * local IO capability is not NoInputNoOutput, use JUST_WORKS * method (mgmt_user_confirm with confirm_hint set to 1). */ - if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && + if (!test_bit(HCI_CONN_AUTH_PEND, conn->flags) && conn->io_capability != HCI_IO_NO_INPUT_OUTPUT) { bt_dev_dbg(hdev, "Confirming auto-accept as acceptor"); confirm_hint = 1; @@ -5738,7 +5748,7 @@ static void hci_simple_pair_complete_evt(struct hci_dev *hdev, void *data, * initiated the authentication. A traditional auth_complete * event gets always produced as initiator and is also mapped to * the mgmt_auth_failed event */ - if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && ev->status) + if (!test_bit(HCI_CONN_AUTH_PEND, conn->flags) && ev->status) mgmt_auth_failed(conn, ev->status); hci_conn_drop(conn); @@ -5984,7 +5994,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status, goto unlock; /* Drop the connection if it has been aborted */ - if (test_bit(HCI_CONN_CANCEL, &conn->flags)) { + if (test_bit(HCI_CONN_CANCEL, conn->flags)) { hci_conn_drop(conn); goto unlock; } @@ -6041,6 +6051,28 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status, hci_conn_put(params->conn); params->conn = NULL; } + + /* An explicit connect request is complete once connected, so + * clean it up here: hci_connect_le_scan_cleanup() no longer + * finds the params since they have just been removed from + * pend_le_conns. + */ + if (params->explicit_connect) { + params->explicit_connect = false; + + switch (params->auto_connect) { + case HCI_AUTO_CONN_EXPLICIT: + hci_conn_params_del(hdev, &conn->dst, + conn->dst_type); + break; + case HCI_AUTO_CONN_REPORT: + hci_pend_le_list_add(params, + &hdev->pend_le_reports); + break; + default: + break; + } + } } /* If we are central and have subrate parameters stored, queue a @@ -6101,8 +6133,8 @@ static void hci_le_pa_sync_lost_evt(struct hci_dev *hdev, void *data, /* Delete the pa sync connection */ conn = hci_conn_hash_lookup_pa_sync_handle(hdev, handle); if (conn) { - clear_bit(HCI_CONN_BIG_SYNC, &conn->flags); - clear_bit(HCI_CONN_PA_SYNC, &conn->flags); + clear_bit(HCI_CONN_BIG_SYNC, conn->flags); + clear_bit(HCI_CONN_PA_SYNC, conn->flags); hci_disconn_cfm(conn, HCI_ERROR_REMOTE_USER_TERM); hci_conn_del(conn); } @@ -6236,7 +6268,7 @@ static void hci_le_past_received_evt(struct hci_dev *hdev, void *data, pa_sync->sync_handle = le16_to_cpu(ev->sync_handle); if (ev->status) { - set_bit(HCI_CONN_PA_SYNC_FAILED, &pa_sync->flags); + set_bit(HCI_CONN_PA_SYNC_FAILED, pa_sync->flags); /* Notify iso layer */ hci_connect_cfm(pa_sync, ev->status); @@ -6611,6 +6643,17 @@ static void hci_le_adv_report_evt(struct hci_dev *hdev, void *data, hci_store_wake_reason(hdev, &info->bdaddr, info->bdaddr_type); + /* Broadcom ROM firmware (BCM4364B3 on Apple T2 Macs, no + * patchram) sets vendor bits in the legacy Event_Type. + */ + if (hdev->manufacturer == 15 && info->type > LE_ADV_SCAN_RSP) { + /* 0x0f masks out upper vendor bits (0x10, 0x20, 0x80), + * extracting the standard legacy advertising type + * (0x00-0x04) stored in the low nibble (bits 0-3). + */ + info->type &= 0x0f; + } + if (info->length <= max_adv_len(hdev)) { rssi = info->data[info->length]; process_adv_report(hdev, info->type, &info->bdaddr, @@ -6758,7 +6801,7 @@ static void hci_le_pa_sync_established_evt(struct hci_dev *hdev, void *data, goto unlock; } - clear_bit(HCI_CONN_CREATE_PA_SYNC, &conn->flags); + clear_bit(HCI_CONN_CREATE_PA_SYNC, conn->flags); conn->sync_handle = le16_to_cpu(ev->handle); conn->sid = HCI_SID_INVALID; @@ -6783,7 +6826,7 @@ static void hci_le_pa_sync_established_evt(struct hci_dev *hdev, void *data, pa_sync->sync_handle = le16_to_cpu(ev->handle); if (ev->status) { - set_bit(HCI_CONN_PA_SYNC_FAILED, &pa_sync->flags); + set_bit(HCI_CONN_PA_SYNC_FAILED, pa_sync->flags); /* Notify iso layer */ hci_connect_cfm(pa_sync, ev->status); @@ -6827,7 +6870,7 @@ static void hci_le_per_adv_report_evt(struct hci_dev *hdev, void *data, goto unlock; if (ev->data_status == LE_PA_DATA_COMPLETE && - !test_and_set_bit(HCI_CONN_PA_SYNC, &pa_sync->flags)) { + !test_and_set_bit(HCI_CONN_PA_SYNC, pa_sync->flags)) { /* Notify iso layer */ hci_connect_cfm(pa_sync, 0); @@ -6940,11 +6983,11 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, void *data, * using a distributed LTK. */ if (ltk->type == SMP_STK) { - set_bit(HCI_CONN_STK_ENCRYPT, &conn->flags); + set_bit(HCI_CONN_STK_ENCRYPT, conn->flags); list_del_rcu(<k->list); kfree_rcu(ltk, rcu); } else { - clear_bit(HCI_CONN_STK_ENCRYPT, &conn->flags); + clear_bit(HCI_CONN_STK_ENCRYPT, conn->flags); } hci_dev_unlock(hdev); @@ -7140,7 +7183,7 @@ static void hci_le_cis_established_evt(struct hci_dev *hdev, void *data, qos = &conn->iso_qos; - pending = test_and_clear_bit(HCI_CONN_CREATE_CIS, &conn->flags); + pending = test_and_clear_bit(HCI_CONN_CREATE_CIS, conn->flags); /* BLUETOOTH CORE SPECIFICATION Version 5.4 | Vol 6, Part G * page 3075: @@ -7337,7 +7380,7 @@ static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data, } conn->state = BT_CONNECTED; - set_bit(HCI_CONN_BIG_CREATED, &conn->flags); + set_bit(HCI_CONN_BIG_CREATED, conn->flags); hci_debugfs_create_conn(conn); hci_conn_add_sysfs(conn); hci_iso_setup_path(conn); @@ -7382,7 +7425,7 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data, goto unlock; } - clear_bit(HCI_CONN_CREATE_BIG_SYNC, &conn->flags); + clear_bit(HCI_CONN_CREATE_BIG_SYNC, conn->flags); conn->num_bis = 0; memset(conn->bis, 0, sizeof(conn->bis)); @@ -7405,7 +7448,7 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data, if (ev->status != 0x42) /* Mark PA sync as established */ - set_bit(HCI_CONN_PA_SYNC, &bis->flags); + set_bit(HCI_CONN_PA_SYNC, bis->flags); bis->sync_handle = conn->sync_handle; bis->iso_qos.bcast.big = ev->handle; @@ -7418,7 +7461,7 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data, if (!ev->status) { bis->state = BT_CONNECTED; - set_bit(HCI_CONN_BIG_SYNC, &bis->flags); + set_bit(HCI_CONN_BIG_SYNC, bis->flags); hci_debugfs_create_conn(bis); hci_conn_add_sysfs(bis); hci_iso_setup_path(bis); @@ -7436,7 +7479,7 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data, if (!bis) continue; - set_bit(HCI_CONN_BIG_SYNC_FAILED, &bis->flags); + set_bit(HCI_CONN_BIG_SYNC_FAILED, bis->flags); hci_connect_cfm(bis, ev->status); } @@ -7466,13 +7509,13 @@ static void hci_le_big_sync_lost_evt(struct hci_dev *hdev, void *data, * it is consumed there instead of here. */ mgmt_conn = test_bit(HCI_CONN_MGMT_CONNECTED, - &bis->flags); + bis->flags); mgmt_device_disconnected(hdev, &bis->dst, bis->type, bis->dst_type, ev->reason, mgmt_conn); } - clear_bit(HCI_CONN_BIG_SYNC, &bis->flags); + clear_bit(HCI_CONN_BIG_SYNC, bis->flags); hci_disconn_cfm(bis, ev->reason); hci_conn_del(bis); } diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 03f706c1f815..9d71ce96bd8e 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -2448,15 +2448,17 @@ static int hci_le_del_resolve_list_sync(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type) { struct hci_cp_le_del_from_resolv_list cp; - struct bdaddr_list_with_irk *entry; + bool exists; if (!ll_privacy_capable(hdev)) return 0; /* Check if the IRK has been programmed */ - entry = hci_bdaddr_list_lookup_with_irk(&hdev->le_resolv_list, bdaddr, - bdaddr_type); - if (!entry) + hci_dev_lock(hdev); + exists = hci_bdaddr_list_lookup_with_irk(&hdev->le_resolv_list, + bdaddr, bdaddr_type); + hci_dev_unlock(hdev); + if (!exists) return 0; cp.bdaddr_type = bdaddr_type; @@ -2512,8 +2514,8 @@ static int hci_le_add_resolve_list_sync(struct hci_dev *hdev, { struct hci_cp_le_add_to_resolv_list cp; struct smp_irk *irk; - struct bdaddr_list_with_irk *entry; struct hci_conn_params *p; + bool exists; if (!ll_privacy_capable(hdev)) return 0; @@ -2536,10 +2538,11 @@ static int hci_le_add_resolve_list_sync(struct hci_dev *hdev, return 0; /* Check if the IK has _not_ been programmed yet. */ - entry = hci_bdaddr_list_lookup_with_irk(&hdev->le_resolv_list, - ¶ms->addr, - params->addr_type); - if (entry) + hci_dev_lock(hdev); + exists = hci_bdaddr_list_lookup_with_irk( + &hdev->le_resolv_list, ¶ms->addr, params->addr_type); + hci_dev_unlock(hdev); + if (exists) return 0; cp.bdaddr_type = params->addr_type; @@ -2733,7 +2736,7 @@ static int hci_pause_advertising_sync(struct hci_dev *hdev) static int hci_resume_advertising_sync(struct hci_dev *hdev) { struct adv_info *adv, *tmp; - int err; + int err = 0; /* If advertising has not been paused there is nothing to do. */ if (!hdev->advertising_paused) @@ -2766,13 +2769,19 @@ static int hci_resume_advertising_sync(struct hci_dev *hdev) */ if (hci_dev_test_and_clear_flag(hdev, HCI_LE_ADV_0)) err = hci_enable_ext_advertising_sync(hdev, 0x00); - } else { + } else if (hdev->cur_adv_instance) { /* Schedule for most recent instance to be restarted and begin * the software rotation loop */ err = hci_schedule_adv_instance_sync(hdev, hdev->cur_adv_instance, true); + } else if (hci_dev_test_flag(hdev, HCI_ADVERTISING) && + !hci_dev_test_flag(hdev, HCI_LE_ADV)) { + /* hci_schedule_adv_instance_sync() rejects instance 0x00 while + * HCI_ADVERTISING is set, so enable it directly. + */ + err = hci_start_adv_sync(hdev, 0x00); } hdev->advertising_paused = false; @@ -2879,6 +2888,31 @@ static struct conn_params *conn_params_copy(struct list_head *list, size_t *n) return p; } +static struct conn_params *le_accept_list_copy(struct hci_dev *hdev, + size_t *n) +{ + struct bdaddr_list *entry; + struct conn_params *params; + size_t i = 0; + + hci_dev_lock(hdev); + + *n = list_count_nodes(&hdev->le_accept_list); + params = kvzalloc_objs(struct conn_params, *n); + if (!params) + goto unlock; + + list_for_each_entry(entry, &hdev->le_accept_list, list) { + bacpy(¶ms[i].addr, &entry->bdaddr); + params[i].addr_type = entry->bdaddr_type; + i++; + } + +unlock: + hci_dev_unlock(hdev); + return params; +} + /* Clear LE Accept List */ static int hci_le_clear_accept_list_sync(struct hci_dev *hdev) { @@ -2909,7 +2943,6 @@ static int hci_le_clear_accept_list_sync(struct hci_dev *hdev) static u8 hci_update_accept_list_sync(struct hci_dev *hdev) { struct conn_params *params; - struct bdaddr_list *b, *t; u8 num_entries = 0; bool pend_conn, pend_report; u8 filter_policy; @@ -2974,20 +3007,27 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev) * report. If not present in either list, then remove it from * the controller. */ - list_for_each_entry_safe(b, t, &hdev->le_accept_list, list) { + params = le_accept_list_copy(hdev, &n); + if (!params) { + err = -ENOMEM; + goto done; + } + + for (i = 0; i < n; i++) { rcu_read_lock(); - if (hci_conn_hash_lookup_le(hdev, &b->bdaddr, b->bdaddr_type)) { + if (hci_conn_hash_lookup_le(hdev, ¶ms[i].addr, + params[i].addr_type)) { rcu_read_unlock(); continue; } pend_conn = hci_pend_le_action_lookup(&hdev->pend_le_conns, - &b->bdaddr, - b->bdaddr_type); - pend_report = hci_pend_le_action_lookup(&hdev->pend_le_reports, - &b->bdaddr, - b->bdaddr_type); + ¶ms[i].addr, + params[i].addr_type); + pend_report = hci_pend_le_action_lookup( + &hdev->pend_le_reports, ¶ms[i].addr, + params[i].addr_type); rcu_read_unlock(); @@ -2995,14 +3035,16 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev) * remove it from the acceptlist. */ if (!pend_conn && !pend_report) { - hci_le_del_accept_list_sync(hdev, &b->bdaddr, - b->bdaddr_type); + hci_le_del_accept_list_sync(hdev, ¶ms[i].addr, + params[i].addr_type); continue; } num_entries++; } + kvfree(params); + /* Since all no longer valid accept list entries have been * removed, walk through the list of pending connections * and ensure that any new device gets programmed into @@ -3505,9 +3547,13 @@ int hci_write_ssp_mode_sync(struct hci_dev *hdev, u8 mode) return hci_write_sc_support_sync(hdev, 0x01); } +static int hci_le_set_host_feature_sync(struct hci_dev *hdev, u16 bit, + u8 value); + int hci_write_le_host_supported_sync(struct hci_dev *hdev, u8 le, u8 simul) { struct hci_cp_write_le_host_supported cp; + int err; if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) || !lmp_bredr_capable(hdev)) @@ -3525,8 +3571,16 @@ int hci_write_le_host_supported_sync(struct hci_dev *hdev, u8 le, u8 simul) cp.le = le; cp.simul = simul; - return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, - sizeof(cp), &cp, HCI_CMD_TIMEOUT); + err = __hci_cmd_sync_status(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, + sizeof(cp), &cp, HCI_CMD_TIMEOUT); + if (err || !cis_capable(hdev)) + return err; + + /* The CIS host feature is set during init based on LE being enabled, + * which is not repeated when LE is enabled afterwards, e.g. while the + * controller is still auto powered on, so update it here. + */ + return hci_le_set_host_feature_sync(hdev, 32, iso_enabled(hdev)); } static int hci_powered_update_adv_sync(struct hci_dev *hdev) @@ -4828,6 +4882,9 @@ static int hci_le_set_def_rate_sync(struct hci_dev *hdev) struct hci_cp_le_set_def_rate cp; u16 interval_min = 0x000a; /* 1.25 ms */ u16 interval_max = 0x0078; /* 15 ms */ + u16 subrate_max = 0x0004; + u16 max_latency = 0x0000; + u32 supv_timeout; if (!le_sci_capable(hdev)) return 0; @@ -4852,10 +4909,31 @@ static int hci_le_set_def_rate_sync(struct hci_dev *hdev) cp.interval_min = cpu_to_le16(interval_min); cp.interval_max = cpu_to_le16(interval_max); cp.subrate_min = cpu_to_le16(0x0001); - cp.subrate_max = cpu_to_le16(0x0004); - cp.max_latency = cpu_to_le16(0x0000); + cp.subrate_max = cpu_to_le16(subrate_max); + cp.max_latency = cpu_to_le16(max_latency); cp.cont_num = cpu_to_le16(0x0001); - cp.supv_timeout = cpu_to_le16(0x000c); /* 120 ms */ + + /* HOGP v1.2 recommends a Supervision_Timeout greater than or equal to + * (1 + Max_Latency) x Subrate_Max x Connection_Interval_Max x 2, but + * the Core spec treats the equality as invalid: + * + * BLUETOOTH CORE SPECIFICATION Version 6.3 | Vol 4, Part E + * 7.8.158. LE Set Default Rate Parameters command + * + * If Connection_Interval_Max x Subrate_Max x (Max_Latency + 1) is + * greater than or equal to Supervision_Timeout x 40, the Controller + * shall return the error code Invalid HCI Command Parameters (0x12). + * + * So default to 2 s, 10x lower than the 20 s used for non-SCI + * connections while still well above the minimum required, but make + * sure it stays strictly above the minimum in case interval_max has + * been raised. + */ + supv_timeout = (u32)interval_max * subrate_max * (max_latency + 1); + supv_timeout = supv_timeout / 40 + 1; + supv_timeout = clamp_t(u32, max_t(u32, supv_timeout, 0x00c8), + 0x000a, 0x0c80); + cp.supv_timeout = cpu_to_le16(supv_timeout); /* The connection event length recommended in requests by a Peripheral * uses units of 125 us with a valid range of 0x0001 to 0x7CFF @@ -5637,6 +5715,11 @@ int hci_dev_close_sync(struct hci_dev *hdev) return err; } + /* Wait for hci_recv_frame() callers that still saw HCI_UP, so that + * none of them queues rx_work while the workqueue is drained below. + */ + synchronize_rcu(); + hci_leds_update_powered(hdev, false); /* Flush RX and TX works */ @@ -5913,11 +5996,11 @@ static int hci_le_connect_cancel_sync(struct hci_dev *hdev, /* Return reason if scanning since the connection shall probably be * cleanup directly. */ - if (test_bit(HCI_CONN_SCANNING, &conn->flags)) + if (test_bit(HCI_CONN_SCANNING, conn->flags)) return reason; if (conn->role == HCI_ROLE_SLAVE || - test_and_set_bit(HCI_CONN_CANCEL, &conn->flags)) + test_and_set_bit(HCI_CONN_CANCEL, conn->flags)) return 0; return __hci_cmd_sync_status(hdev, HCI_OP_LE_CREATE_CONN_CANCEL, @@ -5939,7 +6022,7 @@ static int hci_connect_cancel_sync(struct hci_dev *hdev, struct hci_conn *conn, * then an HCI_LE_CIS_Established event shall also be sent for * this CIS with the Status Operation Cancelled by Host (0x44). */ - if (test_bit(HCI_CONN_CREATE_CIS, &conn->flags)) + if (test_bit(HCI_CONN_CREATE_CIS, conn->flags)) return hci_disconnect_sync(hdev, conn, reason); /* CIS with no Create CIS sent have nothing to cancel */ @@ -6310,6 +6393,7 @@ static int hci_active_scan_sync(struct hci_dev *hdev, uint16_t interval) u8 filter_policy = 0x00; /* Default is to enable duplicates filter */ u8 filter_dup = LE_SCAN_FILTER_DUP_ENABLE; + bool paused; int err; bt_dev_dbg(hdev, ""); @@ -6333,6 +6417,12 @@ static int hci_active_scan_sync(struct hci_dev *hdev, uint16_t interval) if (err) goto failed; + /* LE Set Random Address is disallowed while advertising is enabled. */ + paused = !hdev->advertising_paused; + err = hci_pause_advertising_sync(hdev); + if (err) + goto failed; + /* All active scans will be done with either a resolvable private * address (when privacy feature has been enabled) or non-resolvable * private address. @@ -6342,6 +6432,9 @@ static int hci_active_scan_sync(struct hci_dev *hdev, uint16_t interval) if (err < 0) own_addr_type = ADDR_LE_DEV_PUBLIC; + if (paused) + hci_resume_advertising_sync(hdev); + if (hci_is_adv_monitoring(hdev) || (hci_test_quirk(hdev, HCI_QUIRK_STRICT_DUPLICATE_FILTER) && hdev->discovery.result_filtering)) { @@ -6365,9 +6458,8 @@ static int hci_active_scan_sync(struct hci_dev *hdev, uint16_t interval) return err; failed: - /* Resume advertising if it was paused */ - if (ll_privacy_capable(hdev)) - hci_resume_advertising_sync(hdev); + /* No-op when advertising was not paused. */ + hci_resume_advertising_sync(hdev); /* Resume passive scanning */ hci_update_passive_scan_sync(hdev); @@ -6928,7 +7020,7 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data) bt_dev_dbg(hdev, "conn %p", conn); - clear_bit(HCI_CONN_SCANNING, &conn->flags); + clear_bit(HCI_CONN_SCANNING, conn->flags); conn->state = BT_CONNECT; /* If requested to connect as peripheral use directed advertising */ @@ -6995,7 +7087,7 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data) /* Mark create connection in flight so hci_cancel_connect_sync() can * cancel it while blocking on the connection complete event. */ - set_bit(HCI_CONN_CREATE, &conn->flags); + set_bit(HCI_CONN_CREATE, conn->flags); /* Send command LE Extended Create Connection if supported */ if (use_ext_conn(hdev)) { @@ -7032,7 +7124,7 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data) conn->conn_timeout, NULL); done: - clear_bit(HCI_CONN_CREATE, &conn->flags); + clear_bit(HCI_CONN_CREATE, conn->flags); if (err == -ETIMEDOUT) hci_le_connect_cancel_sync(hdev, conn, 0x00); @@ -7079,7 +7171,7 @@ int hci_le_create_cis_sync(struct hci_dev *hdev) /* Wait until previous Create CIS has completed */ list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) { - if (test_bit(HCI_CONN_CREATE_CIS, &conn->flags)) + if (test_bit(HCI_CONN_CREATE_CIS, conn->flags)) goto done; } @@ -7115,7 +7207,7 @@ int hci_le_create_cis_sync(struct hci_dev *hdev) conn->iso_qos.ucast.cig != cig) continue; - set_bit(HCI_CONN_CREATE_CIS, &conn->flags); + set_bit(HCI_CONN_CREATE_CIS, conn->flags); cis->acl_handle = cpu_to_le16(conn->parent->handle); cis->cis_handle = cpu_to_le16(conn->handle); timeout = conn->conn_timeout; @@ -7318,14 +7410,14 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data) /* Mark create connection in flight so hci_cancel_connect_sync() can * cancel it while blocking on the connection complete event. */ - set_bit(HCI_CONN_CREATE, &conn->flags); + set_bit(HCI_CONN_CREATE, conn->flags); err = __hci_cmd_sync_status_sk(hdev, HCI_OP_CREATE_CONN, sizeof(cp), &cp, HCI_EV_CONN_COMPLETE, conn->conn_timeout, NULL); - clear_bit(HCI_CONN_CREATE, &conn->flags); + clear_bit(HCI_CONN_CREATE, conn->flags); return err; } @@ -7414,7 +7506,7 @@ static int hci_acl_cancel_create_conn_sync(struct hci_dev *hdev, mutex_lock(&hdev->cmd_sync_work_lock); /* In flight: this connection owns the pending request, cancel it. */ - if (test_bit(HCI_CONN_CREATE, &conn->flags)) { + if (test_bit(HCI_CONN_CREATE, conn->flags)) { hci_cmd_sync_cancel(hdev, ECANCELED); goto unlock; } @@ -7445,7 +7537,7 @@ static int hci_le_cancel_create_conn_sync(struct hci_dev *hdev, */ mutex_lock(&hdev->cmd_sync_work_lock); - if (test_bit(HCI_CONN_CREATE, &conn->flags)) { + if (test_bit(HCI_CONN_CREATE, conn->flags)) { hci_cmd_sync_cancel(hdev, ECANCELED); goto unlock; } @@ -7472,7 +7564,7 @@ static int hci_cis_cancel_create_conn_sync(struct hci_dev *hdev, */ mutex_lock(&hdev->cmd_sync_work_lock); - if (test_bit(HCI_CONN_CREATE_CIS, &conn->flags)) + if (test_bit(HCI_CONN_CREATE_CIS, conn->flags)) hci_cmd_sync_cancel(hdev, ECANCELED); mutex_unlock(&hdev->cmd_sync_work_lock); @@ -7609,7 +7701,7 @@ static void create_pa_complete(struct hci_dev *hdev, void *data, int err) hci_dev_lock(hdev); if (hci_conn_valid(hdev, conn)) - clear_bit(HCI_CONN_CREATE_PA_SYNC, &conn->flags); + clear_bit(HCI_CONN_CREATE_PA_SYNC, conn->flags); if (!err) goto unlock; @@ -7621,7 +7713,7 @@ static void create_pa_complete(struct hci_dev *hdev, void *data, int err) if (IS_ERR(pa_sync)) goto unlock; - set_bit(HCI_CONN_PA_SYNC_FAILED, &pa_sync->flags); + set_bit(HCI_CONN_PA_SYNC_FAILED, pa_sync->flags); /* Notify iso layer */ hci_connect_cfm(pa_sync, bt_status(err)); @@ -7694,7 +7786,7 @@ static int hci_le_pa_create_sync(struct hci_dev *hdev, void *data) * program the address in the allow list so PA advertisements can be * received. */ - set_bit(HCI_CONN_CREATE_PA_SYNC, &conn->flags); + set_bit(HCI_CONN_CREATE_PA_SYNC, conn->flags); hci_update_passive_scan_sync(hdev); @@ -7797,7 +7889,7 @@ static void create_big_complete(struct hci_dev *hdev, void *data, int err) if (err == -ECANCELED) goto done; - clear_bit(HCI_CONN_CREATE_BIG_SYNC, &conn->flags); + clear_bit(HCI_CONN_CREATE_BIG_SYNC, conn->flags); done: hci_conn_put(conn); @@ -7814,7 +7906,7 @@ static int hci_le_big_create_sync(struct hci_dev *hdev, void *data) if (!hci_conn_valid(hdev, conn)) return -ECANCELED; - set_bit(HCI_CONN_CREATE_BIG_SYNC, &conn->flags); + set_bit(HCI_CONN_CREATE_BIG_SYNC, conn->flags); memset(cp, 0, sizeof(*cp)); cp->handle = qos->bcast.big; diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c index c1fdd9846eeb..06f1e7ba2cb1 100644 --- a/net/bluetooth/iso.c +++ b/net/bluetooth/iso.c @@ -912,7 +912,7 @@ static void iso_sock_disconn(struct sock *sk) struct sock *bis_sk; struct hci_conn *hcon = iso_pi(sk)->conn->hcon; - if (test_bit(HCI_CONN_BIG_CREATED, &hcon->flags)) { + if (test_bit(HCI_CONN_BIG_CREATED, hcon->flags)) { bis_sk = iso_get_sock_big(sk, &iso_pi(sk)->src, &iso_pi(sk)->dst, iso_pi(sk)->qos.bcast.big); @@ -957,8 +957,8 @@ static void __iso_sock_close(struct sock *sk) case BT_CONNECT2: if (iso_pi(sk)->conn->hcon && - (test_bit(HCI_CONN_PA_SYNC, &iso_pi(sk)->conn->hcon->flags) || - test_bit(HCI_CONN_PA_SYNC_FAILED, &iso_pi(sk)->conn->hcon->flags))) + (test_bit(HCI_CONN_PA_SYNC, iso_pi(sk)->conn->hcon->flags) || + test_bit(HCI_CONN_PA_SYNC_FAILED, iso_pi(sk)->conn->hcon->flags))) iso_sock_disconn(sk); else iso_chan_del(sk, ECONNRESET); @@ -2289,7 +2289,7 @@ static void iso_conn_ready(struct iso_conn *conn) hdev = hcon->hdev; - if (test_bit(HCI_CONN_BIG_SYNC, &hcon->flags)) { + if (test_bit(HCI_CONN_BIG_SYNC, hcon->flags)) { /* A BIS slave hcon is notified to the ISO layer * after the Command Complete for the LE Setup * ISO Data Path command is received. Get the @@ -2298,7 +2298,7 @@ static void iso_conn_ready(struct iso_conn *conn) parent = iso_get_sock(hdev, &hcon->src, &hcon->dst, BT_LISTEN, iso_match_big_hcon, hcon); - } else if (test_bit(HCI_CONN_BIG_SYNC_FAILED, &hcon->flags)) { + } else if (test_bit(HCI_CONN_BIG_SYNC_FAILED, hcon->flags)) { ev = hci_recv_event_data(hcon->hdev, HCI_EVT_LE_BIG_SYNC_ESTABLISHED); @@ -2312,7 +2312,7 @@ static void iso_conn_ready(struct iso_conn *conn) &hcon->dst, BT_LISTEN, iso_match_big, ev); - } else if (test_bit(HCI_CONN_PA_SYNC_FAILED, &hcon->flags)) { + } else if (test_bit(HCI_CONN_PA_SYNC_FAILED, hcon->flags)) { ev2 = hci_recv_event_data(hcon->hdev, HCI_EV_LE_PA_SYNC_ESTABLISHED); if (ev2) @@ -2320,7 +2320,7 @@ static void iso_conn_ready(struct iso_conn *conn) &hcon->dst, BT_LISTEN, iso_match_sid, ev2); - } else if (test_bit(HCI_CONN_PA_SYNC, &hcon->flags)) { + } else if (test_bit(HCI_CONN_PA_SYNC, hcon->flags)) { ev3 = hci_recv_event_data(hcon->hdev, HCI_EV_LE_PER_ADV_REPORT); if (ev3) @@ -2376,7 +2376,7 @@ static void iso_conn_ready(struct iso_conn *conn) hcon->dst_type = le_addr_type(iso_pi(parent)->dst_type); } - if (test_bit(HCI_CONN_PA_SYNC, &hcon->flags)) { + if (test_bit(HCI_CONN_PA_SYNC, hcon->flags)) { iso_pi(sk)->qos = iso_pi(parent)->qos; hcon->iso_qos = iso_pi(sk)->qos; iso_pi(sk)->bc_sid = iso_pi(parent)->bc_sid; @@ -2676,8 +2676,8 @@ static void iso_connect_cfm(struct hci_conn *hcon, __u8 status) * into the accept queue of the listening socket and wake up * userspace, to inform the user about the event. */ - if (!status || test_bit(HCI_CONN_BIG_SYNC_FAILED, &hcon->flags) || - test_bit(HCI_CONN_PA_SYNC_FAILED, &hcon->flags)) { + if (!status || test_bit(HCI_CONN_BIG_SYNC_FAILED, hcon->flags) || + test_bit(HCI_CONN_PA_SYNC_FAILED, hcon->flags)) { struct iso_conn *conn; conn = iso_conn_add(hcon); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 4dd56e0074fd..83b622a42811 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1575,7 +1575,7 @@ static bool l2cap_check_enc_key_size(struct hci_conn *hcon, if (chan->sec_level == BT_SECURITY_FIPS) min_key_size = 16; - return (!test_bit(HCI_CONN_ENCRYPT, &hcon->flags) || + return (!test_bit(HCI_CONN_ENCRYPT, hcon->flags) || hcon->enc_key_size >= min_key_size); } @@ -7389,7 +7389,11 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) u16 cid, len; __le16 psm; - if (hcon->state != BT_CONNECTED) { + /* Also hold data back while the encryption key size is read, as + * the security of the link, e.g. for SMP over BR/EDR, depends on it. + */ + if (hcon->state != BT_CONNECTED || + test_bit(HCI_CONN_ENC_KEY_SIZE_PEND, hcon->flags)) { BT_DBG("queueing pending rx skb"); skb_queue_tail(&conn->pending_rx, skb); return; @@ -7452,7 +7456,11 @@ static void process_pending_rx(struct work_struct *work) mutex_lock(&conn->lock); - while ((skb = skb_dequeue(&conn->pending_rx))) + /* l2cap_recv_frame() would queue it all again while the encryption + * key size is read, l2cap_security_cfm() schedules this once known. + */ + while (!test_bit(HCI_CONN_ENC_KEY_SIZE_PEND, conn->hcon->flags) && + (skb = skb_dequeue(&conn->pending_rx))) l2cap_recv_frame(conn, skb); mutex_unlock(&conn->lock); @@ -8041,6 +8049,10 @@ static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) } mutex_unlock(&conn->lock); + + /* Process data held back while the encryption key size was read */ + if (!skb_queue_empty(&conn->pending_rx)) + queue_work(hcon->hdev->workqueue, &conn->pending_rx_work); } /* Append fragment into frame respecting the maximum len of rx_skb */ diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 3b9c82bd2f02..3cb4f9ece83c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -304,6 +304,8 @@ static u8 mgmt_errno_status(int err) return MGMT_STATUS_DISCONNECTED; case -ECANCELED: return MGMT_STATUS_CANCELLED; + case -ERFKILL: + return MGMT_STATUS_RFKILLED; } return MGMT_STATUS_FAILED; @@ -3241,7 +3243,7 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, /* Defer clearing up the connection parameters until closing to * give a chance of keeping them if a repairing happens. */ - set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags); + set_bit(HCI_CONN_PARAM_REMOVAL_PEND, conn->flags); /* Disable auto-connection parameters if present */ params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type); @@ -3416,7 +3418,7 @@ static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data, i = 0; list_for_each_entry(c, &hdev->conn_hash.list, list) { - if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags)) + if (test_bit(HCI_CONN_MGMT_CONNECTED, c->flags)) i++; } @@ -3428,7 +3430,7 @@ static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data, i = 0; list_for_each_entry(c, &hdev->conn_hash.list, list) { - if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags)) + if (!test_bit(HCI_CONN_MGMT_CONNECTED, c->flags)) continue; bacpy(&rp->addr[i].bdaddr, &c->dst); rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type); @@ -3628,7 +3630,7 @@ static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status) /* The device is paired so there is no need to remove * its connection parameters anymore. */ - clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags); + clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, conn->flags); hci_conn_put(conn); @@ -10128,7 +10130,7 @@ void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn, u16 eir_len = 0; u32 flags = 0; - if (test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) + if (test_and_set_bit(HCI_CONN_MGMT_CONNECTED, conn->flags)) return; /* allocate buff for LE or BR/EDR adv */ @@ -10177,7 +10179,7 @@ void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn, * since userspace did not know about them yet, so report it now. * Unencrypted connections have no change to report. */ - if (test_bit(HCI_CONN_ENCRYPT, &conn->flags)) + if (test_bit(HCI_CONN_ENCRYPT, conn->flags)) mgmt_security_level_changed(conn); } @@ -10289,7 +10291,7 @@ void mgmt_connect_failed(struct hci_dev *hdev, struct hci_conn *conn, u8 status) * still needs it set to know whether to report the security level * reset, so it is consumed there instead of here. */ - if (test_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) { + if (test_bit(HCI_CONN_MGMT_CONNECTED, conn->flags)) { mgmt_device_disconnected(hdev, &conn->dst, conn->type, conn->dst_type, hci_to_mgmt_reason(status), true); @@ -10930,7 +10932,7 @@ void mgmt_security_level_changed(struct hci_conn *conn) u8 *tlv_data; u8 tlv_len; - if (!test_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) + if (!test_bit(HCI_CONN_MGMT_CONNECTED, conn->flags)) return; /* Only ACL, LE and BIS links are tracked as mgmt connections, so @@ -10961,9 +10963,9 @@ void mgmt_security_level_changed(struct hci_conn *conn) tlv = (void *)tlv_data; tlv->type = cpu_to_le16(MGMT_SEC_LEVEL_CHANGED_PARAM_ENC_TYPE); tlv->length = sizeof(__u8); - if (!test_bit(HCI_CONN_ENCRYPT, &conn->flags)) + if (!test_bit(HCI_CONN_ENCRYPT, conn->flags)) tlv->value[0] = MGMT_CONN_SEC_ENCRYPT_NONE; - else if (test_bit(HCI_CONN_AES_CCM, &conn->flags)) + else if (test_bit(HCI_CONN_AES_CCM, conn->flags)) tlv->value[0] = MGMT_CONN_SEC_ENCRYPT_AES_CCM; else tlv->value[0] = MGMT_CONN_SEC_ENCRYPT_E0; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 5dac8b2eae42..984b2d0b5e3e 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -984,12 +984,12 @@ static u8 smp_random(struct smp_chan *smp) smp_s1(smp->tk, smp->rrnd, smp->prnd, stk); - if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) + if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, hcon->flags)) return SMP_UNSPECIFIED; hci_le_start_enc(hcon, ediv, rand, stk, smp->enc_key_size); hcon->enc_key_size = smp->enc_key_size; - set_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags); + set_bit(HCI_CONN_STK_ENCRYPT, hcon->flags); } else { u8 stk[16], auth; __le64 rand = 0; @@ -1028,7 +1028,7 @@ static void smp_notify_keys(struct l2cap_conn *conn) persistent = false; else persistent = !test_bit(HCI_CONN_FLUSH_KEY, - &hcon->flags); + hcon->flags); } else { /* The LTKs, IRKs and CSRKs should be persistent only if * both sides had the bonding bit set in their @@ -1753,7 +1753,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) /* SMP over BR/EDR requires special treatment */ if (conn->hcon->type == ACL_LINK) { /* We must have a BR/EDR SC link */ - if (!test_bit(HCI_CONN_AES_CCM, &conn->hcon->flags) && + if (!test_bit(HCI_CONN_AES_CCM, conn->hcon->flags) && !hci_dev_test_flag(hdev, HCI_FORCE_BREDR_SMP)) return SMP_CROSS_TRANSP_NOT_ALLOWED; @@ -2210,14 +2210,14 @@ static bool smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level) if (smp_ltk_sec_level(key) < sec_level) return false; - if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) + if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, hcon->flags)) return true; hci_le_start_enc(hcon, key->ediv, key->rand, key->val, key->enc_size); hcon->enc_key_size = key->enc_size; /* We never store STKs for initiator role, so clear this flag */ - clear_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags); + clear_bit(HCI_CONN_STK_ENCRYPT, hcon->flags); return true; } @@ -2235,7 +2235,7 @@ bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level, * don't have an LTK (e.g. because of key distribution bits). */ if (key_pref == SMP_USE_LTK && - test_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags) && + test_bit(HCI_CONN_STK_ENCRYPT, hcon->flags) && hci_find_ltk(hcon->hdev, &hcon->dst, hcon->dst_type, hcon->role)) return false; @@ -3084,11 +3084,11 @@ static void bredr_pairing(struct l2cap_chan *chan) bt_dev_dbg(hdev, "chan %p", chan); /* Only new pairings are interesting */ - if (!test_bit(HCI_CONN_NEW_LINK_KEY, &hcon->flags)) + if (!test_bit(HCI_CONN_NEW_LINK_KEY, hcon->flags)) return; /* Don't bother if we're not encrypted */ - if (!test_bit(HCI_CONN_ENCRYPT, &hcon->flags)) + if (!test_bit(HCI_CONN_ENCRYPT, hcon->flags)) return; /* Only initiator may initiate SMP over BR/EDR */ @@ -3100,7 +3100,7 @@ static void bredr_pairing(struct l2cap_chan *chan) return; /* BR/EDR must use Secure Connections for SMP */ - if (!test_bit(HCI_CONN_AES_CCM, &hcon->flags) && + if (!test_bit(HCI_CONN_AES_CCM, hcon->flags) && !hci_dev_test_flag(hdev, HCI_FORCE_BREDR_SMP)) return; @@ -3149,7 +3149,7 @@ static void smp_resume_cb(struct l2cap_chan *chan) if (!smp) return; - if (!test_bit(HCI_CONN_ENCRYPT, &hcon->flags)) + if (!test_bit(HCI_CONN_ENCRYPT, hcon->flags)) return; cancel_delayed_work(&smp->security_timer); @@ -3172,7 +3172,7 @@ static void smp_ready_cb(struct l2cap_chan *chan) */ conn->smp = chan; - if (hcon->type == ACL_LINK && test_bit(HCI_CONN_ENCRYPT, &hcon->flags)) + if (hcon->type == ACL_LINK && test_bit(HCI_CONN_ENCRYPT, hcon->flags)) bredr_pairing(chan); } |
