diff options
| author | Jakub Kicinski <kuba@kernel.org> | 2024-03-08 20:37:32 -0800 | 
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2024-03-08 20:37:32 -0800 | 
| commit | 2f901582f032bed47907a20f77fb44b3532b4762 (patch) | |
| tree | bd6ed56abfba275a26b4106d063808d701cca6c6 | |
| parent | 2612b9f10c5f184a1e5e4cf16ce2de9e615ed104 (diff) | |
| parent | 3d1c16e920c88eb5e583e1b4a10b95a5dc97ec22 (diff) | |
Merge tag 'for-net-next-2024-03-08' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
Luiz Augusto von Dentz says:
====================
bluetooth-next pull request for net-next:
 - hci_conn: Only do ACL connections sequentially
 - hci_core: Cancel request on command timeout
 - Remove CONFIG_BT_HS
 - btrtl: Add the support for RTL8852BT/RTL8852BE-VT
 - btusb: Add support Mediatek MT7920
 - btusb: Add new VID/PID 13d3/3602 for MT7925
 - Add new quirk for broken read key length on ATS2851
* tag 'for-net-next-2024-03-08' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next: (52 commits)
  Bluetooth: hci_sync: Fix UAF in hci_acl_create_conn_sync
  Bluetooth: Fix eir name length
  Bluetooth: ISO: Align broadcast sync_timeout with connection timeout
  Bluetooth: Add new quirk for broken read key length on ATS2851
  Bluetooth: mgmt: remove NULL check in add_ext_adv_params_complete()
  Bluetooth: mgmt: remove NULL check in mgmt_set_connectable_complete()
  Bluetooth: btusb: Add support Mediatek MT7920
  Bluetooth: btmtk: Add MODULE_FIRMWARE() for MT7922
  Bluetooth: btnxpuart: Fix btnxpuart_close
  Bluetooth: ISO: Clean up returns values in iso_connect_ind()
  Bluetooth: fix use-after-free in accessing skb after sending it
  Bluetooth: af_bluetooth: Fix deadlock
  Bluetooth: bnep: Fix out-of-bound access
  Bluetooth: btusb: Fix memory leak
  Bluetooth: msft: Fix memory leak
  Bluetooth: hci_core: Fix possible buffer overflow
  Bluetooth: btrtl: fix out of bounds memory access
  Bluetooth: hci_h5: Add ability to allocate memory for private data
  Bluetooth: hci_sync: Fix overwriting request callback
  Bluetooth: hci_sync: Use QoS to determine which PHY to scan
  ...
====================
Link: https://lore.kernel.org/r/20240308181056.120547-1-luiz.dentz@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
38 files changed, 1028 insertions, 3623 deletions
| diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c index 0a5445ac5e1b..f9a7c790d7e2 100644 --- a/drivers/bluetooth/btbcm.c +++ b/drivers/bluetooth/btbcm.c @@ -11,6 +11,7 @@  #include <linux/firmware.h>  #include <linux/dmi.h>  #include <linux/of.h> +#include <linux/string.h>  #include <asm/unaligned.h>  #include <net/bluetooth/bluetooth.h> @@ -543,8 +544,6 @@ static const char *btbcm_get_board_name(struct device *dev)  	struct device_node *root;  	char *board_type;  	const char *tmp; -	int len; -	int i;  	root = of_find_node_by_path("/");  	if (!root) @@ -554,13 +553,8 @@ static const char *btbcm_get_board_name(struct device *dev)  		return NULL;  	/* get rid of any '/' in the compatible string */ -	len = strlen(tmp) + 1; -	board_type = devm_kzalloc(dev, len, GFP_KERNEL); -	strscpy(board_type, tmp, len); -	for (i = 0; i < len; i++) { -		if (board_type[i] == '/') -			board_type[i] = '-'; -	} +	board_type = devm_kstrdup(dev, tmp, GFP_KERNEL); +	strreplace(board_type, '/', '-');  	of_node_put(root);  	return board_type; diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index cdc5c08824a0..6ba7f5d1b837 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -441,7 +441,7 @@ int btintel_read_version(struct hci_dev *hdev, struct intel_version *ver)  		return PTR_ERR(skb);  	} -	if (skb->len != sizeof(*ver)) { +	if (!skb || skb->len != sizeof(*ver)) {  		bt_dev_err(hdev, "Intel version event size mismatch");  		kfree_skb(skb);  		return -EILSEQ; @@ -2670,6 +2670,119 @@ static void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant)  	}  } +static void btintel_print_fseq_info(struct hci_dev *hdev) +{ +	struct sk_buff *skb; +	u8 *p; +	u32 val; +	const char *str; + +	skb = __hci_cmd_sync(hdev, 0xfcb3, 0, NULL, HCI_CMD_TIMEOUT); +	if (IS_ERR(skb)) { +		bt_dev_dbg(hdev, "Reading fseq status command failed (%ld)", +			   PTR_ERR(skb)); +		return; +	} + +	if (skb->len < (sizeof(u32) * 16 + 2)) { +		bt_dev_dbg(hdev, "Malformed packet of length %u received", +			   skb->len); +		kfree_skb(skb); +		return; +	} + +	p = skb_pull_data(skb, 1); +	if (*p) { +		bt_dev_dbg(hdev, "Failed to get fseq status (0x%2.2x)", *p); +		kfree_skb(skb); +		return; +	} + +	p = skb_pull_data(skb, 1); +	switch (*p) { +	case 0: +		str = "Success"; +		break; +	case 1: +		str = "Fatal error"; +		break; +	case 2: +		str = "Semaphore acquire error"; +		break; +	default: +		str = "Unknown error"; +		break; +	} + +	if (*p) { +		bt_dev_err(hdev, "Fseq status: %s (0x%2.2x)", str, *p); +		kfree_skb(skb); +		return; +	} + +	bt_dev_info(hdev, "Fseq status: %s (0x%2.2x)", str, *p); + +	val = get_unaligned_le32(skb_pull_data(skb, 4)); +	bt_dev_dbg(hdev, "Reason: 0x%8.8x", val); + +	val = get_unaligned_le32(skb_pull_data(skb, 4)); +	bt_dev_dbg(hdev, "Global version: 0x%8.8x", val); + +	val = get_unaligned_le32(skb_pull_data(skb, 4)); +	bt_dev_dbg(hdev, "Installed version: 0x%8.8x", val); + +	p = skb->data; +	skb_pull_data(skb, 4); +	bt_dev_info(hdev, "Fseq executed: %2.2u.%2.2u.%2.2u.%2.2u", p[0], p[1], +		    p[2], p[3]); + +	p = skb->data; +	skb_pull_data(skb, 4); +	bt_dev_info(hdev, "Fseq BT Top: %2.2u.%2.2u.%2.2u.%2.2u", p[0], p[1], +		    p[2], p[3]); + +	val = get_unaligned_le32(skb_pull_data(skb, 4)); +	bt_dev_dbg(hdev, "Fseq Top init version: 0x%8.8x", val); + +	val = get_unaligned_le32(skb_pull_data(skb, 4)); +	bt_dev_dbg(hdev, "Fseq Cnvio init version: 0x%8.8x", val); + +	val = get_unaligned_le32(skb_pull_data(skb, 4)); +	bt_dev_dbg(hdev, "Fseq MBX Wifi file version: 0x%8.8x", val); + +	val = get_unaligned_le32(skb_pull_data(skb, 4)); +	bt_dev_dbg(hdev, "Fseq BT version: 0x%8.8x", val); + +	val = get_unaligned_le32(skb_pull_data(skb, 4)); +	bt_dev_dbg(hdev, "Fseq Top reset address: 0x%8.8x", val); + +	val = get_unaligned_le32(skb_pull_data(skb, 4)); +	bt_dev_dbg(hdev, "Fseq MBX timeout: 0x%8.8x", val); + +	val = get_unaligned_le32(skb_pull_data(skb, 4)); +	bt_dev_dbg(hdev, "Fseq MBX ack: 0x%8.8x", val); + +	val = get_unaligned_le32(skb_pull_data(skb, 4)); +	bt_dev_dbg(hdev, "Fseq CNVi id: 0x%8.8x", val); + +	val = get_unaligned_le32(skb_pull_data(skb, 4)); +	bt_dev_dbg(hdev, "Fseq CNVr id: 0x%8.8x", val); + +	val = get_unaligned_le32(skb_pull_data(skb, 4)); +	bt_dev_dbg(hdev, "Fseq Error handle: 0x%8.8x", val); + +	val = get_unaligned_le32(skb_pull_data(skb, 4)); +	bt_dev_dbg(hdev, "Fseq Magic noalive indication: 0x%8.8x", val); + +	val = get_unaligned_le32(skb_pull_data(skb, 4)); +	bt_dev_dbg(hdev, "Fseq OTP version: 0x%8.8x", val); + +	val = get_unaligned_le32(skb_pull_data(skb, 4)); +	bt_dev_dbg(hdev, "Fseq MBX otp version: 0x%8.8x", val); + +	kfree_skb(skb); +} +  static int btintel_setup_combined(struct hci_dev *hdev)  {  	const u8 param[1] = { 0xFF }; @@ -2902,6 +3015,7 @@ static int btintel_setup_combined(struct hci_dev *hdev)  		err = btintel_bootloader_setup_tlv(hdev, &ver_tlv);  		btintel_register_devcoredump_support(hdev); +		btintel_print_fseq_info(hdev);  		break;  	default:  		bt_dev_err(hdev, "Unsupported Intel hw variant (%u)", diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c index aaabb732082c..ac8ebccd3507 100644 --- a/drivers/bluetooth/btmtk.c +++ b/drivers/bluetooth/btmtk.c @@ -372,8 +372,10 @@ int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb)  	struct btmediatek_data *data = hci_get_priv(hdev);  	int err; -	if (!IS_ENABLED(CONFIG_DEV_COREDUMP)) +	if (!IS_ENABLED(CONFIG_DEV_COREDUMP)) { +		kfree_skb(skb);  		return 0; +	}  	switch (data->cd_info.state) {  	case HCI_DEVCOREDUMP_IDLE: @@ -420,5 +422,6 @@ MODULE_LICENSE("GPL");  MODULE_FIRMWARE(FIRMWARE_MT7622);  MODULE_FIRMWARE(FIRMWARE_MT7663);  MODULE_FIRMWARE(FIRMWARE_MT7668); +MODULE_FIRMWARE(FIRMWARE_MT7922);  MODULE_FIRMWARE(FIRMWARE_MT7961);  MODULE_FIRMWARE(FIRMWARE_MT7925); diff --git a/drivers/bluetooth/btmtk.h b/drivers/bluetooth/btmtk.h index 56f5502baadf..cbcdb99a22e6 100644 --- a/drivers/bluetooth/btmtk.h +++ b/drivers/bluetooth/btmtk.h @@ -4,6 +4,7 @@  #define FIRMWARE_MT7622		"mediatek/mt7622pr2h.bin"  #define FIRMWARE_MT7663		"mediatek/mt7663pr2h.bin"  #define FIRMWARE_MT7668		"mediatek/mt7668pr2h.bin" +#define FIRMWARE_MT7922		"mediatek/BT_RAM_CODE_MT7922_1_1_hdr.bin"  #define FIRMWARE_MT7961		"mediatek/BT_RAM_CODE_MT7961_1_2_hdr.bin"  #define FIRMWARE_MT7925		"mediatek/mt7925/BT_RAM_CODE_MT7925_1_1_hdr.bin" diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c index 1d592ac413d1..0b93c2ff29e4 100644 --- a/drivers/bluetooth/btnxpuart.c +++ b/drivers/bluetooth/btnxpuart.c @@ -126,6 +126,7 @@ struct ps_data {  	struct hci_dev *hdev;  	struct work_struct work;  	struct timer_list ps_timer; +	struct mutex ps_lock;  };  struct wakeup_cmd_payload { @@ -317,6 +318,9 @@ static void ps_start_timer(struct btnxpuart_dev *nxpdev)  	if (psdata->cur_psmode == PS_MODE_ENABLE)  		mod_timer(&psdata->ps_timer, jiffies + msecs_to_jiffies(psdata->h2c_ps_interval)); + +	if (psdata->ps_state == PS_STATE_AWAKE && psdata->ps_cmd == PS_CMD_ENTER_PS) +		cancel_work_sync(&psdata->work);  }  static void ps_cancel_timer(struct btnxpuart_dev *nxpdev) @@ -337,6 +341,7 @@ static void ps_control(struct hci_dev *hdev, u8 ps_state)  	    !test_bit(BTNXPUART_SERDEV_OPEN, &nxpdev->tx_state))  		return; +	mutex_lock(&psdata->ps_lock);  	switch (psdata->cur_h2c_wakeupmode) {  	case WAKEUP_METHOD_DTR:  		if (ps_state == PS_STATE_AWAKE) @@ -350,12 +355,15 @@ static void ps_control(struct hci_dev *hdev, u8 ps_state)  			status = serdev_device_break_ctl(nxpdev->serdev, 0);  		else  			status = serdev_device_break_ctl(nxpdev->serdev, -1); +		msleep(20); /* Allow chip to detect UART-break and enter sleep */  		bt_dev_dbg(hdev, "Set UART break: %s, status=%d",  			   str_on_off(ps_state == PS_STATE_SLEEP), status);  		break;  	}  	if (!status)  		psdata->ps_state = ps_state; +	mutex_unlock(&psdata->ps_lock); +  	if (ps_state == PS_STATE_AWAKE)  		btnxpuart_tx_wakeup(nxpdev);  } @@ -391,17 +399,25 @@ static void ps_setup(struct hci_dev *hdev)  	psdata->hdev = hdev;  	INIT_WORK(&psdata->work, ps_work_func); +	mutex_init(&psdata->ps_lock);  	timer_setup(&psdata->ps_timer, ps_timeout_func, 0);  } -static void ps_wakeup(struct btnxpuart_dev *nxpdev) +static bool ps_wakeup(struct btnxpuart_dev *nxpdev)  {  	struct ps_data *psdata = &nxpdev->psdata; +	u8 ps_state; + +	mutex_lock(&psdata->ps_lock); +	ps_state = psdata->ps_state; +	mutex_unlock(&psdata->ps_lock); -	if (psdata->ps_state != PS_STATE_AWAKE) { +	if (ps_state != PS_STATE_AWAKE) {  		psdata->ps_cmd = PS_CMD_EXIT_PS;  		schedule_work(&psdata->work); +		return true;  	} +	return false;  }  static int send_ps_cmd(struct hci_dev *hdev, void *data) @@ -1171,7 +1187,6 @@ static struct sk_buff *nxp_dequeue(void *data)  {  	struct btnxpuart_dev *nxpdev = (struct btnxpuart_dev *)data; -	ps_wakeup(nxpdev);  	ps_start_timer(nxpdev);  	return skb_dequeue(&nxpdev->txq);  } @@ -1186,6 +1201,9 @@ static void btnxpuart_tx_work(struct work_struct *work)  	struct sk_buff *skb;  	int len; +	if (ps_wakeup(nxpdev)) +		return; +  	while ((skb = nxp_dequeue(nxpdev))) {  		len = serdev_device_write_buf(serdev, skb->data, skb->len);  		hdev->stat.byte_tx += len; @@ -1234,6 +1252,9 @@ static int btnxpuart_close(struct hci_dev *hdev)  	ps_wakeup(nxpdev);  	serdev_device_close(nxpdev->serdev); +	skb_queue_purge(&nxpdev->txq); +	kfree_skb(nxpdev->rx_skb); +	nxpdev->rx_skb = NULL;  	clear_bit(BTNXPUART_SERDEV_OPEN, &nxpdev->tx_state);  	return 0;  } diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c index 277d039ecbb4..cc50de69e8dc 100644 --- a/drivers/bluetooth/btrtl.c +++ b/drivers/bluetooth/btrtl.c @@ -69,6 +69,7 @@ enum btrtl_chip_id {  	CHIP_ID_8852B = 20,  	CHIP_ID_8852C = 25,  	CHIP_ID_8851B = 36, +	CHIP_ID_8852BT = 47,  };  struct id_table { @@ -307,6 +308,15 @@ static const struct id_table ic_id_table[] = {  	  .fw_name  = "rtl_bt/rtl8851bu_fw",  	  .cfg_name = "rtl_bt/rtl8851bu_config",  	  .hw_info  = "rtl8851bu" }, + +	/* 8852BT/8852BE-VT */ +	{ IC_INFO(RTL_ROM_LMP_8852A, 0x87, 0xc, HCI_USB), +	  .config_needed = false, +	  .has_rom_version = true, +	  .has_msft_ext = true, +	  .fw_name  = "rtl_bt/rtl8852btu_fw", +	  .cfg_name = "rtl_bt/rtl8852btu_config", +	  .hw_info  = "rtl8852btu" },  	};  static const struct id_table *btrtl_match_ic(u16 lmp_subver, u16 hci_rev, @@ -645,6 +655,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev,  		{ RTL_ROM_LMP_8852A, 20 },	/* 8852B */  		{ RTL_ROM_LMP_8852A, 25 },	/* 8852C */  		{ RTL_ROM_LMP_8851B, 36 },	/* 8851B */ +		{ RTL_ROM_LMP_8852A, 47 },	/* 8852BT */  	};  	if (btrtl_dev->fw_len <= 8) @@ -1275,6 +1286,7 @@ void btrtl_set_quirks(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev)  	case CHIP_ID_8852B:  	case CHIP_ID_8852C:  	case CHIP_ID_8851B: +	case CHIP_ID_8852BT:  		set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);  		set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks); @@ -1505,6 +1517,8 @@ MODULE_FIRMWARE("rtl_bt/rtl8852bs_fw.bin");  MODULE_FIRMWARE("rtl_bt/rtl8852bs_config.bin");  MODULE_FIRMWARE("rtl_bt/rtl8852bu_fw.bin");  MODULE_FIRMWARE("rtl_bt/rtl8852bu_config.bin"); +MODULE_FIRMWARE("rtl_bt/rtl8852btu_fw.bin"); +MODULE_FIRMWARE("rtl_bt/rtl8852btu_config.bin");  MODULE_FIRMWARE("rtl_bt/rtl8852cu_fw.bin");  MODULE_FIRMWARE("rtl_bt/rtl8852cu_fw_v2.bin");  MODULE_FIRMWARE("rtl_bt/rtl8852cu_config.bin"); diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index d31edad7a056..06e915b57283 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -553,6 +553,9 @@ static const struct usb_device_id quirks_table[] = {  	{ USB_DEVICE(0x13d3, 0x3572), .driver_info = BTUSB_REALTEK |  						     BTUSB_WIDEBAND_SPEECH }, +	/* Realtek 8852BT/8852BE-VT Bluetooth devices */ +	{ USB_DEVICE(0x0bda, 0x8520), .driver_info = BTUSB_REALTEK | +						     BTUSB_WIDEBAND_SPEECH },  	/* Realtek Bluetooth devices */  	{ USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01),  	  .driver_info = BTUSB_REALTEK }, @@ -655,6 +658,11 @@ static const struct usb_device_id quirks_table[] = {  						     BTUSB_WIDEBAND_SPEECH |  						     BTUSB_VALID_LE_STATES }, +	/* Additional MediaTek MT7925 Bluetooth devices */ +	{ USB_DEVICE(0x13d3, 0x3602), .driver_info = BTUSB_MEDIATEK | +						     BTUSB_WIDEBAND_SPEECH | +						     BTUSB_VALID_LE_STATES }, +  	/* Additional Realtek 8723AE Bluetooth devices */  	{ USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK },  	{ USB_DEVICE(0x13d3, 0x3394), .driver_info = BTUSB_REALTEK }, @@ -3080,7 +3088,7 @@ static int btusb_mtk_setup(struct hci_dev *hdev)  	int err, status;  	u32 dev_id = 0;  	char fw_bin_name[64]; -	u32 fw_version = 0; +	u32 fw_version = 0, fw_flavor = 0;  	u8 param;  	struct btmediatek_data *mediatek; @@ -3103,6 +3111,11 @@ static int btusb_mtk_setup(struct hci_dev *hdev)  			bt_dev_err(hdev, "Failed to get fw version (%d)", err);  			return err;  		} +		err = btusb_mtk_id_get(data, 0x70010020, &fw_flavor); +		if (err < 0) { +			bt_dev_err(hdev, "Failed to get fw flavor (%d)", err); +			return err; +		}  	}  	mediatek = hci_get_priv(hdev); @@ -3127,6 +3140,10 @@ static int btusb_mtk_setup(struct hci_dev *hdev)  			snprintf(fw_bin_name, sizeof(fw_bin_name),  				 "mediatek/mt%04x/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",  				 dev_id & 0xffff, dev_id & 0xffff, (fw_version & 0xff) + 1); +		else if (dev_id == 0x7961 && fw_flavor) +			snprintf(fw_bin_name, sizeof(fw_bin_name), +				 "mediatek/BT_RAM_CODE_MT%04x_1a_%x_hdr.bin", +				 dev_id & 0xffff, (fw_version & 0xff) + 1);  		else  			snprintf(fw_bin_name, sizeof(fw_bin_name),  				 "mediatek/BT_RAM_CODE_MT%04x_1_%x_hdr.bin", @@ -3273,7 +3290,6 @@ static int btusb_recv_acl_mtk(struct hci_dev *hdev, struct sk_buff *skb)  {  	struct btusb_data *data = hci_get_drvdata(hdev);  	u16 handle = le16_to_cpu(hci_acl_hdr(skb)->handle); -	struct sk_buff *skb_cd;  	switch (handle) {  	case 0xfc6f:		/* Firmware dump from device */ @@ -3286,9 +3302,12 @@ static int btusb_recv_acl_mtk(struct hci_dev *hdev, struct sk_buff *skb)  		 * for backward compatibility, so we have to clone the packet  		 * extraly for the in-kernel coredump support.  		 */ -		skb_cd = skb_clone(skb, GFP_ATOMIC); -		if (skb_cd) -			btmtk_process_coredump(hdev, skb_cd); +		if (IS_ENABLED(CONFIG_DEV_COREDUMP)) { +			struct sk_buff *skb_cd = skb_clone(skb, GFP_ATOMIC); + +			if (skb_cd) +				btmtk_process_coredump(hdev, skb_cd); +		}  		fallthrough;  	case 0x05ff:		/* Firmware debug logging 1 */ @@ -4481,6 +4500,7 @@ static int btusb_probe(struct usb_interface *intf,  		set_bit(HCI_QUIRK_BROKEN_READ_TRANSMIT_POWER, &hdev->quirks);  		set_bit(HCI_QUIRK_BROKEN_SET_RPA_TIMEOUT, &hdev->quirks);  		set_bit(HCI_QUIRK_BROKEN_EXT_SCAN, &hdev->quirks); +		set_bit(HCI_QUIRK_BROKEN_READ_ENC_KEY_SIZE, &hdev->quirks);  	}  	if (!reset) diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index 71e748a9477e..c0436881a533 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -113,6 +113,7 @@ struct h5_vnd {  	int (*suspend)(struct h5 *h5);  	int (*resume)(struct h5 *h5);  	const struct acpi_gpio_mapping *acpi_gpio_map; +	int sizeof_priv;  };  struct h5_device_data { @@ -863,7 +864,8 @@ static int h5_serdev_probe(struct serdev_device *serdev)  	if (IS_ERR(h5->device_wake_gpio))  		return PTR_ERR(h5->device_wake_gpio); -	return hci_uart_register_device(&h5->serdev_hu, &h5p); +	return hci_uart_register_device_priv(&h5->serdev_hu, &h5p, +					     h5->vnd->sizeof_priv);  }  static void h5_serdev_remove(struct serdev_device *serdev) @@ -1070,6 +1072,7 @@ static struct h5_vnd rtl_vnd = {  	.suspend	= h5_btrtl_suspend,  	.resume		= h5_btrtl_resume,  	.acpi_gpio_map	= acpi_btrtl_gpios, +	.sizeof_priv    = sizeof(struct btrealtek_data),  };  static const struct h5_device_data h5_data_rtl8822cs = { diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index edd2a81b4d5e..8a60ad7acd70 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -2326,7 +2326,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)  		qcadev->bt_en = devm_gpiod_get_optional(&serdev->dev, "enable",  					       GPIOD_OUT_LOW); -		if (IS_ERR_OR_NULL(qcadev->bt_en) && +		if (IS_ERR(qcadev->bt_en) &&  		    (data->soc_type == QCA_WCN6750 ||  		     data->soc_type == QCA_WCN6855)) {  			dev_err(&serdev->dev, "failed to acquire BT_EN gpio\n"); @@ -2335,7 +2335,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)  		qcadev->sw_ctrl = devm_gpiod_get_optional(&serdev->dev, "swctrl",  					       GPIOD_IN); -		if (IS_ERR_OR_NULL(qcadev->sw_ctrl) && +		if (IS_ERR(qcadev->sw_ctrl) &&  		    (data->soc_type == QCA_WCN6750 ||  		     data->soc_type == QCA_WCN6855 ||  		     data->soc_type == QCA_WCN7850)) @@ -2357,7 +2357,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)  	default:  		qcadev->bt_en = devm_gpiod_get_optional(&serdev->dev, "enable",  					       GPIOD_OUT_LOW); -		if (IS_ERR_OR_NULL(qcadev->bt_en)) { +		if (IS_ERR(qcadev->bt_en)) {  			dev_warn(&serdev->dev, "failed to acquire enable gpio\n");  			power_ctrl_enabled = false;  		} diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c index 39c8b567da3c..214fff876eae 100644 --- a/drivers/bluetooth/hci_serdev.c +++ b/drivers/bluetooth/hci_serdev.c @@ -300,8 +300,9 @@ static const struct serdev_device_ops hci_serdev_client_ops = {  	.write_wakeup = hci_uart_write_wakeup,  }; -int hci_uart_register_device(struct hci_uart *hu, -			     const struct hci_uart_proto *p) +int hci_uart_register_device_priv(struct hci_uart *hu, +			     const struct hci_uart_proto *p, +			     int sizeof_priv)  {  	int err;  	struct hci_dev *hdev; @@ -325,7 +326,7 @@ int hci_uart_register_device(struct hci_uart *hu,  	set_bit(HCI_UART_PROTO_READY, &hu->flags);  	/* Initialize and register HCI device */ -	hdev = hci_alloc_dev(); +	hdev = hci_alloc_dev_priv(sizeof_priv);  	if (!hdev) {  		BT_ERR("Can't allocate HCI device");  		err = -ENOMEM; @@ -394,7 +395,7 @@ err_rwsem:  	percpu_free_rwsem(&hu->proto_lock);  	return err;  } -EXPORT_SYMBOL_GPL(hci_uart_register_device); +EXPORT_SYMBOL_GPL(hci_uart_register_device_priv);  void hci_uart_unregister_device(struct hci_uart *hu)  { diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index fb4a2d0d8cc8..68c8c7e95d64 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -97,7 +97,17 @@ struct hci_uart {  int hci_uart_register_proto(const struct hci_uart_proto *p);  int hci_uart_unregister_proto(const struct hci_uart_proto *p); -int hci_uart_register_device(struct hci_uart *hu, const struct hci_uart_proto *p); + +int hci_uart_register_device_priv(struct hci_uart *hu, +				  const struct hci_uart_proto *p, +				  int sizeof_priv); + +static inline int hci_uart_register_device(struct hci_uart *hu, +					   const struct hci_uart_proto *p) +{ +	return hci_uart_register_device_priv(hu, p, 0); +} +  void hci_uart_unregister_device(struct hci_uart *hu);  int hci_uart_tx_wakeup(struct hci_uart *hu); diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 7ffa8c192c3f..9fe95a22abeb 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -164,6 +164,8 @@ struct bt_voice {  #define BT_ISO_QOS_BIG_UNSET	0xff  #define BT_ISO_QOS_BIS_UNSET	0xff +#define BT_ISO_SYNC_TIMEOUT	0x07d0 /* 20 secs */ +  struct bt_iso_io_qos {  	__u32 interval;  	__u16 latency; diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index bdee5d649cc6..8701ca5f31ee 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -330,6 +330,14 @@ enum {  	 * during the hdev->setup vendor callback.  	 */  	HCI_QUIRK_BROKEN_LE_CODED, + +	/* +	 * When this quirk is set, the HCI_OP_READ_ENC_KEY_SIZE command is +	 * skipped during an HCI_EV_ENCRYPT_CHANGE event. This is required +	 * for Actions Semiconductor ATS2851 based controllers, which erroneously +	 * claim to support it. +	 */ +	HCI_QUIRK_BROKEN_READ_ENC_KEY_SIZE,  };  /* HCI device flags */ @@ -372,6 +380,7 @@ enum {  	HCI_SETUP,  	HCI_CONFIG,  	HCI_DEBUGFS_CREATED, +	HCI_POWERING_DOWN,  	HCI_AUTO_OFF,  	HCI_RFKILLED,  	HCI_MGMT, @@ -393,7 +402,6 @@ enum {  	HCI_LIMITED_PRIVACY,  	HCI_RPA_EXPIRED,  	HCI_RPA_RESOLVING, -	HCI_HS_ENABLED,  	HCI_LE_ENABLED,  	HCI_ADVERTISING,  	HCI_ADVERTISING_CONNECTABLE, @@ -437,7 +445,7 @@ enum {  #define HCI_NCMD_TIMEOUT	msecs_to_jiffies(4000)	/* 4 seconds */  #define HCI_ACL_TX_TIMEOUT	msecs_to_jiffies(45000)	/* 45 seconds */  #define HCI_AUTO_OFF_TIMEOUT	msecs_to_jiffies(2000)	/* 2 seconds */ -#define HCI_POWER_OFF_TIMEOUT	msecs_to_jiffies(5000)	/* 5 seconds */ +#define HCI_ACL_CONN_TIMEOUT	msecs_to_jiffies(20000)	/* 20 seconds */  #define HCI_LE_CONN_TIMEOUT	msecs_to_jiffies(20000)	/* 20 seconds */  #define HCI_LE_AUTOCONN_TIMEOUT	msecs_to_jiffies(4000)	/* 4 seconds */ @@ -653,6 +661,7 @@ enum {  #define HCI_ERROR_PIN_OR_KEY_MISSING	0x06  #define HCI_ERROR_MEMORY_EXCEEDED	0x07  #define HCI_ERROR_CONNECTION_TIMEOUT	0x08 +#define HCI_ERROR_COMMAND_DISALLOWED	0x0c  #define HCI_ERROR_REJ_LIMITED_RESOURCES	0x0d  #define HCI_ERROR_REJ_BAD_ADDR		0x0f  #define HCI_ERROR_INVALID_PARAMETERS	0x12 @@ -661,6 +670,7 @@ enum {  #define HCI_ERROR_REMOTE_POWER_OFF	0x15  #define HCI_ERROR_LOCAL_HOST_TERM	0x16  #define HCI_ERROR_PAIRING_NOT_ALLOWED	0x18 +#define HCI_ERROR_UNSUPPORTED_REMOTE_FEATURE	0x1e  #define HCI_ERROR_INVALID_LL_PARAMS	0x1e  #define HCI_ERROR_UNSPECIFIED		0x1f  #define HCI_ERROR_ADVERTISING_TIMEOUT	0x3c @@ -2035,6 +2045,7 @@ struct hci_cp_le_set_per_adv_params {  } __packed;  #define HCI_MAX_PER_AD_LENGTH	252 +#define HCI_MAX_PER_AD_TOT_LEN	1650  #define HCI_OP_LE_SET_PER_ADV_DATA		0x203f  struct hci_cp_le_set_per_adv_data { @@ -2795,6 +2806,10 @@ struct hci_ev_le_per_adv_report {  	__u8     data[];  } __packed; +#define LE_PA_DATA_COMPLETE	0x00 +#define LE_PA_DATA_MORE_TO_COME	0x01 +#define LE_PA_DATA_TRUNCATED	0x02 +  #define HCI_EV_LE_EXT_ADV_SET_TERM	0x12  struct hci_evt_le_ext_adv_set_term {  	__u8	status; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 8f8dd9173714..56fb42df44a3 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1,7 +1,7 @@  /*     BlueZ - Bluetooth protocol stack for Linux     Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved. -   Copyright 2023 NXP +   Copyright 2023-2024 NXP     Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> @@ -552,6 +552,7 @@ struct hci_dev {  	__u32			req_status;  	__u32			req_result;  	struct sk_buff		*req_skb; +	struct sk_buff		*req_rsp;  	void			*smp_data;  	void			*smp_bredr_data; @@ -734,8 +735,9 @@ struct hci_conn {  	__u16		le_supv_timeout;  	__u8		le_adv_data[HCI_MAX_EXT_AD_LENGTH];  	__u8		le_adv_data_len; -	__u8		le_per_adv_data[HCI_MAX_PER_AD_LENGTH]; -	__u8		le_per_adv_data_len; +	__u8		le_per_adv_data[HCI_MAX_PER_AD_TOT_LEN]; +	__u16		le_per_adv_data_len; +	__u16		le_per_adv_data_offset;  	__u8		le_tx_phy;  	__u8		le_rx_phy;  	__s8		rssi; @@ -1083,6 +1085,24 @@ static inline unsigned int hci_conn_count(struct hci_dev *hdev)  	return c->acl_num + c->amp_num + c->sco_num + c->le_num + c->iso_num;  } +static inline bool hci_conn_valid(struct hci_dev *hdev, struct hci_conn *conn) +{ +	struct hci_conn_hash *h = &hdev->conn_hash; +	struct hci_conn  *c; + +	rcu_read_lock(); + +	list_for_each_entry_rcu(c, &h->list, list) { +		if (c == conn) { +			rcu_read_unlock(); +			return true; +		} +	} +	rcu_read_unlock(); + +	return false; +} +  static inline __u8 hci_conn_lookup_type(struct hci_dev *hdev, __u16 handle)  {  	struct hci_conn_hash *h = &hdev->conn_hash; @@ -1480,7 +1500,6 @@ struct hci_conn *hci_conn_add_unset(struct hci_dev *hdev, int type,  				    bdaddr_t *dst, u8 role);  void hci_conn_del(struct hci_conn *conn);  void hci_conn_hash_flush(struct hci_dev *hdev); -void hci_conn_check_pending(struct hci_dev *hdev);  struct hci_chan *hci_chan_create(struct hci_conn *conn);  void hci_chan_del(struct hci_chan *chan); @@ -1494,11 +1513,13 @@ struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst,  struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,  				u8 dst_type, bool dst_resolved, u8 sec_level,  				u16 conn_timeout, u8 role); +void hci_connect_le_scan_cleanup(struct hci_conn *conn, u8 status);  struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,  				 u8 sec_level, u8 auth_type, -				 enum conn_reasons conn_reason); +				 enum conn_reasons conn_reason, u16 timeout);  struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, -				 __u16 setting, struct bt_codec *codec); +				 __u16 setting, struct bt_codec *codec, +				 u16 timeout);  struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst,  			      __u8 dst_type, struct bt_iso_qos *qos);  struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, @@ -1509,8 +1530,8 @@ struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst,  struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst,  				 __u8 dst_type, struct bt_iso_qos *qos,  				 __u8 data_len, __u8 *data); -int hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type, -		       __u8 sid, struct bt_iso_qos *qos); +struct hci_conn *hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst, +		       __u8 dst_type, __u8 sid, struct bt_iso_qos *qos);  int hci_le_big_create_sync(struct hci_dev *hdev, struct hci_conn *hcon,  			   struct bt_iso_qos *qos,  			   __u16 sync_handle, __u8 num_bis, __u8 bis[]); diff --git a/include/net/bluetooth/hci_sync.h b/include/net/bluetooth/hci_sync.h index 6efbc2152146..6a9d063e9f47 100644 --- a/include/net/bluetooth/hci_sync.h +++ b/include/net/bluetooth/hci_sync.h @@ -42,12 +42,24 @@ int __hci_cmd_sync_status_sk(struct hci_dev *hdev, u16 opcode, u32 plen,  void hci_cmd_sync_init(struct hci_dev *hdev);  void hci_cmd_sync_clear(struct hci_dev *hdev);  void hci_cmd_sync_cancel(struct hci_dev *hdev, int err); -void __hci_cmd_sync_cancel(struct hci_dev *hdev, int err); +void hci_cmd_sync_cancel_sync(struct hci_dev *hdev, int err);  int hci_cmd_sync_submit(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,  			void *data, hci_cmd_sync_work_destroy_t destroy);  int hci_cmd_sync_queue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,  		       void *data, hci_cmd_sync_work_destroy_t destroy); +int hci_cmd_sync_queue_once(struct hci_dev *hdev, hci_cmd_sync_work_func_t func, +			    void *data, hci_cmd_sync_work_destroy_t destroy); +struct hci_cmd_sync_work_entry * +hci_cmd_sync_lookup_entry(struct hci_dev *hdev, hci_cmd_sync_work_func_t func, +			  void *data, hci_cmd_sync_work_destroy_t destroy); +void hci_cmd_sync_cancel_entry(struct hci_dev *hdev, +			       struct hci_cmd_sync_work_entry *entry); +bool hci_cmd_sync_dequeue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func, +			  void *data, hci_cmd_sync_work_destroy_t destroy); +bool hci_cmd_sync_dequeue_once(struct hci_dev *hdev, +			      hci_cmd_sync_work_func_t func, void *data, +			      hci_cmd_sync_work_destroy_t destroy);  int hci_update_eir_sync(struct hci_dev *hdev);  int hci_update_class_sync(struct hci_dev *hdev); @@ -127,8 +139,6 @@ struct hci_conn;  int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason); -int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn); -  int hci_le_create_cis_sync(struct hci_dev *hdev);  int hci_le_remove_cig_sync(struct hci_dev *hdev, u8 handle); @@ -138,3 +148,9 @@ int hci_le_terminate_big_sync(struct hci_dev *hdev, u8 handle, u8 reason);  int hci_le_big_terminate_sync(struct hci_dev *hdev, u8 handle);  int hci_le_pa_terminate_sync(struct hci_dev *hdev, u16 handle); + +int hci_connect_acl_sync(struct hci_dev *hdev, struct hci_conn *conn); + +int hci_connect_le_sync(struct hci_dev *hdev, struct hci_conn *conn); + +int hci_cancel_connect_sync(struct hci_dev *hdev, struct hci_conn *conn); diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index cf393e72d6ed..a4278aa618ab 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -59,8 +59,6 @@  #define L2CAP_WAIT_ACK_POLL_PERIOD	msecs_to_jiffies(200)  #define L2CAP_WAIT_ACK_TIMEOUT		msecs_to_jiffies(10000) -#define L2CAP_A2MP_DEFAULT_MTU		670 -  /* L2CAP socket address */  struct sockaddr_l2 {  	sa_family_t	l2_family; @@ -109,12 +107,6 @@ struct l2cap_conninfo {  #define L2CAP_ECHO_RSP		0x09  #define L2CAP_INFO_REQ		0x0a  #define L2CAP_INFO_RSP		0x0b -#define L2CAP_CREATE_CHAN_REQ	0x0c -#define L2CAP_CREATE_CHAN_RSP	0x0d -#define L2CAP_MOVE_CHAN_REQ	0x0e -#define L2CAP_MOVE_CHAN_RSP	0x0f -#define L2CAP_MOVE_CHAN_CFM	0x10 -#define L2CAP_MOVE_CHAN_CFM_RSP	0x11  #define L2CAP_CONN_PARAM_UPDATE_REQ	0x12  #define L2CAP_CONN_PARAM_UPDATE_RSP	0x13  #define L2CAP_LE_CONN_REQ	0x14 @@ -144,7 +136,6 @@ struct l2cap_conninfo {  /* L2CAP fixed channels */  #define L2CAP_FC_SIG_BREDR	0x02  #define L2CAP_FC_CONNLESS	0x04 -#define L2CAP_FC_A2MP		0x08  #define L2CAP_FC_ATT		0x10  #define L2CAP_FC_SIG_LE		0x20  #define L2CAP_FC_SMP_LE		0x40 @@ -267,7 +258,6 @@ struct l2cap_conn_rsp {  /* channel identifier */  #define L2CAP_CID_SIGNALING	0x0001  #define L2CAP_CID_CONN_LESS	0x0002 -#define L2CAP_CID_A2MP		0x0003  #define L2CAP_CID_ATT		0x0004  #define L2CAP_CID_LE_SIGNALING	0x0005  #define L2CAP_CID_SMP		0x0006 @@ -282,7 +272,6 @@ struct l2cap_conn_rsp {  #define L2CAP_CR_BAD_PSM	0x0002  #define L2CAP_CR_SEC_BLOCK	0x0003  #define L2CAP_CR_NO_MEM		0x0004 -#define L2CAP_CR_BAD_AMP	0x0005  #define L2CAP_CR_INVALID_SCID	0x0006  #define L2CAP_CR_SCID_IN_USE	0x0007 @@ -404,29 +393,6 @@ struct l2cap_info_rsp {  	__u8        data[];  } __packed; -struct l2cap_create_chan_req { -	__le16      psm; -	__le16      scid; -	__u8        amp_id; -} __packed; - -struct l2cap_create_chan_rsp { -	__le16      dcid; -	__le16      scid; -	__le16      result; -	__le16      status; -} __packed; - -struct l2cap_move_chan_req { -	__le16      icid; -	__u8        dest_amp_id; -} __packed; - -struct l2cap_move_chan_rsp { -	__le16      icid; -	__le16      result; -} __packed; -  #define L2CAP_MR_SUCCESS	0x0000  #define L2CAP_MR_PEND		0x0001  #define L2CAP_MR_BAD_ID		0x0002 @@ -539,8 +505,6 @@ struct l2cap_seq_list {  struct l2cap_chan {  	struct l2cap_conn	*conn; -	struct hci_conn		*hs_hcon; -	struct hci_chan		*hs_hchan;  	struct kref	kref;  	atomic_t	nesting; @@ -591,12 +555,6 @@ struct l2cap_chan {  	unsigned long	conn_state;  	unsigned long	flags; -	__u8		remote_amp_id; -	__u8		local_amp_id; -	__u8		move_id; -	__u8		move_state; -	__u8		move_role; -  	__u16		next_tx_seq;  	__u16		expected_ack_seq;  	__u16		expected_tx_seq; @@ -981,7 +939,7 @@ int l2cap_add_scid(struct l2cap_chan *chan,  __u16 scid);  struct l2cap_chan *l2cap_chan_create(void);  void l2cap_chan_close(struct l2cap_chan *chan, int reason);  int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, -		       bdaddr_t *dst, u8 dst_type); +		       bdaddr_t *dst, u8 dst_type, u16 timeout);  int l2cap_chan_reconfigure(struct l2cap_chan *chan, __u16 mtu);  int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len);  void l2cap_chan_busy(struct l2cap_chan *chan, int busy); diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index 4eb1b3ced0d2..27520a8a486f 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -572,7 +572,7 @@ static void netdev_setup(struct net_device *dev)  	dev->needs_free_netdev	= true;  } -static struct device_type bt_type = { +static const struct device_type bt_type = {  	.name	= "bluetooth",  }; @@ -892,7 +892,7 @@ static int bt_6lowpan_connect(bdaddr_t *addr, u8 dst_type)  	chan->ops = &bt_6lowpan_chan_ops;  	err = l2cap_chan_connect(chan, cpu_to_le16(L2CAP_PSM_IPSP), 0, -				 addr, dst_type); +				 addr, dst_type, L2CAP_CONN_TIMEOUT);  	BT_DBG("chan %p err %d", chan, err);  	if (err < 0) diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index da7cac0a1b71..6b2b65a66700 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -62,14 +62,6 @@ source "net/bluetooth/cmtp/Kconfig"  source "net/bluetooth/hidp/Kconfig" -config BT_HS -	bool "Bluetooth High Speed (HS) features" -	depends on BT_BREDR -	help -	  Bluetooth High Speed includes support for off-loading -	  Bluetooth connections via 802.11 (wifi) physical layer -	  available with Bluetooth version 3.0 or later. -  config BT_LE  	bool "Bluetooth Low Energy (LE) features"  	depends on BT diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile index 141ac1fda0bf..628d448d78be 100644 --- a/net/bluetooth/Makefile +++ b/net/bluetooth/Makefile @@ -21,7 +21,6 @@ bluetooth-$(CONFIG_DEV_COREDUMP) += coredump.o  bluetooth-$(CONFIG_BT_BREDR) += sco.o  bluetooth-$(CONFIG_BT_LE) += iso.o -bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o  bluetooth-$(CONFIG_BT_LEDS) += leds.o  bluetooth-$(CONFIG_BT_MSFTEXT) += msft.o  bluetooth-$(CONFIG_BT_AOSPEXT) += aosp.o diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c deleted file mode 100644 index e7adb8a98cf9..000000000000 --- a/net/bluetooth/a2mp.c +++ /dev/null @@ -1,1054 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* -   Copyright (c) 2010,2011 Code Aurora Forum.  All rights reserved. -   Copyright (c) 2011,2012 Intel Corp. - -*/ - -#include <net/bluetooth/bluetooth.h> -#include <net/bluetooth/hci_core.h> -#include <net/bluetooth/l2cap.h> - -#include "hci_request.h" -#include "a2mp.h" -#include "amp.h" - -#define A2MP_FEAT_EXT	0x8000 - -/* Global AMP Manager list */ -static LIST_HEAD(amp_mgr_list); -static DEFINE_MUTEX(amp_mgr_list_lock); - -/* A2MP build & send command helper functions */ -static struct a2mp_cmd *__a2mp_build(u8 code, u8 ident, u16 len, void *data) -{ -	struct a2mp_cmd *cmd; -	int plen; - -	plen = sizeof(*cmd) + len; -	cmd = kzalloc(plen, GFP_KERNEL); -	if (!cmd) -		return NULL; - -	cmd->code = code; -	cmd->ident = ident; -	cmd->len = cpu_to_le16(len); - -	memcpy(cmd->data, data, len); - -	return cmd; -} - -static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data) -{ -	struct l2cap_chan *chan = mgr->a2mp_chan; -	struct a2mp_cmd *cmd; -	u16 total_len = len + sizeof(*cmd); -	struct kvec iv; -	struct msghdr msg; - -	cmd = __a2mp_build(code, ident, len, data); -	if (!cmd) -		return; - -	iv.iov_base = cmd; -	iv.iov_len = total_len; - -	memset(&msg, 0, sizeof(msg)); - -	iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, &iv, 1, total_len); - -	l2cap_chan_send(chan, &msg, total_len); - -	kfree(cmd); -} - -static u8 __next_ident(struct amp_mgr *mgr) -{ -	if (++mgr->ident == 0) -		mgr->ident = 1; - -	return mgr->ident; -} - -static struct amp_mgr *amp_mgr_lookup_by_state(u8 state) -{ -	struct amp_mgr *mgr; - -	mutex_lock(&_mgr_list_lock); -	list_for_each_entry(mgr, &_mgr_list, list) { -		if (test_and_clear_bit(state, &mgr->state)) { -			amp_mgr_get(mgr); -			mutex_unlock(&_mgr_list_lock); -			return mgr; -		} -	} -	mutex_unlock(&_mgr_list_lock); - -	return NULL; -} - -/* hci_dev_list shall be locked */ -static void __a2mp_add_cl(struct amp_mgr *mgr, struct a2mp_cl *cl) -{ -	struct hci_dev *hdev; -	int i = 1; - -	cl[0].id = AMP_ID_BREDR; -	cl[0].type = AMP_TYPE_BREDR; -	cl[0].status = AMP_STATUS_BLUETOOTH_ONLY; - -	list_for_each_entry(hdev, &hci_dev_list, list) { -		if (hdev->dev_type == HCI_AMP) { -			cl[i].id = hdev->id; -			cl[i].type = hdev->amp_type; -			if (test_bit(HCI_UP, &hdev->flags)) -				cl[i].status = hdev->amp_status; -			else -				cl[i].status = AMP_STATUS_POWERED_DOWN; -			i++; -		} -	} -} - -/* Processing A2MP messages */ -static int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb, -			    struct a2mp_cmd *hdr) -{ -	struct a2mp_cmd_rej *rej = (void *) skb->data; - -	if (le16_to_cpu(hdr->len) < sizeof(*rej)) -		return -EINVAL; - -	BT_DBG("ident %u reason %d", hdr->ident, le16_to_cpu(rej->reason)); - -	skb_pull(skb, sizeof(*rej)); - -	return 0; -} - -static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb, -			     struct a2mp_cmd *hdr) -{ -	struct a2mp_discov_req *req = (void *) skb->data; -	u16 len = le16_to_cpu(hdr->len); -	struct a2mp_discov_rsp *rsp; -	u16 ext_feat; -	u8 num_ctrl; -	struct hci_dev *hdev; - -	if (len < sizeof(*req)) -		return -EINVAL; - -	skb_pull(skb, sizeof(*req)); - -	ext_feat = le16_to_cpu(req->ext_feat); - -	BT_DBG("mtu %d efm 0x%4.4x", le16_to_cpu(req->mtu), ext_feat); - -	/* check that packet is not broken for now */ -	while (ext_feat & A2MP_FEAT_EXT) { -		if (len < sizeof(ext_feat)) -			return -EINVAL; - -		ext_feat = get_unaligned_le16(skb->data); -		BT_DBG("efm 0x%4.4x", ext_feat); -		len -= sizeof(ext_feat); -		skb_pull(skb, sizeof(ext_feat)); -	} - -	read_lock(&hci_dev_list_lock); - -	/* at minimum the BR/EDR needs to be listed */ -	num_ctrl = 1; - -	list_for_each_entry(hdev, &hci_dev_list, list) { -		if (hdev->dev_type == HCI_AMP) -			num_ctrl++; -	} - -	len = struct_size(rsp, cl, num_ctrl); -	rsp = kmalloc(len, GFP_ATOMIC); -	if (!rsp) { -		read_unlock(&hci_dev_list_lock); -		return -ENOMEM; -	} - -	rsp->mtu = cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU); -	rsp->ext_feat = 0; - -	__a2mp_add_cl(mgr, rsp->cl); - -	read_unlock(&hci_dev_list_lock); - -	a2mp_send(mgr, A2MP_DISCOVER_RSP, hdr->ident, len, rsp); - -	kfree(rsp); -	return 0; -} - -static int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb, -			     struct a2mp_cmd *hdr) -{ -	struct a2mp_discov_rsp *rsp = (void *) skb->data; -	u16 len = le16_to_cpu(hdr->len); -	struct a2mp_cl *cl; -	u16 ext_feat; -	bool found = false; - -	if (len < sizeof(*rsp)) -		return -EINVAL; - -	len -= sizeof(*rsp); -	skb_pull(skb, sizeof(*rsp)); - -	ext_feat = le16_to_cpu(rsp->ext_feat); - -	BT_DBG("mtu %d efm 0x%4.4x", le16_to_cpu(rsp->mtu), ext_feat); - -	/* check that packet is not broken for now */ -	while (ext_feat & A2MP_FEAT_EXT) { -		if (len < sizeof(ext_feat)) -			return -EINVAL; - -		ext_feat = get_unaligned_le16(skb->data); -		BT_DBG("efm 0x%4.4x", ext_feat); -		len -= sizeof(ext_feat); -		skb_pull(skb, sizeof(ext_feat)); -	} - -	cl = (void *) skb->data; -	while (len >= sizeof(*cl)) { -		BT_DBG("Remote AMP id %u type %u status %u", cl->id, cl->type, -		       cl->status); - -		if (cl->id != AMP_ID_BREDR && cl->type != AMP_TYPE_BREDR) { -			struct a2mp_info_req req; - -			found = true; - -			memset(&req, 0, sizeof(req)); - -			req.id = cl->id; -			a2mp_send(mgr, A2MP_GETINFO_REQ, __next_ident(mgr), -				  sizeof(req), &req); -		} - -		len -= sizeof(*cl); -		cl = skb_pull(skb, sizeof(*cl)); -	} - -	/* Fall back to L2CAP init sequence */ -	if (!found) { -		struct l2cap_conn *conn = mgr->l2cap_conn; -		struct l2cap_chan *chan; - -		mutex_lock(&conn->chan_lock); - -		list_for_each_entry(chan, &conn->chan_l, list) { - -			BT_DBG("chan %p state %s", chan, -			       state_to_string(chan->state)); - -			if (chan->scid == L2CAP_CID_A2MP) -				continue; - -			l2cap_chan_lock(chan); - -			if (chan->state == BT_CONNECT) -				l2cap_send_conn_req(chan); - -			l2cap_chan_unlock(chan); -		} - -		mutex_unlock(&conn->chan_lock); -	} - -	return 0; -} - -static int a2mp_change_notify(struct amp_mgr *mgr, struct sk_buff *skb, -			      struct a2mp_cmd *hdr) -{ -	struct a2mp_cl *cl = (void *) skb->data; - -	while (skb->len >= sizeof(*cl)) { -		BT_DBG("Controller id %u type %u status %u", cl->id, cl->type, -		       cl->status); -		cl = skb_pull(skb, sizeof(*cl)); -	} - -	/* TODO send A2MP_CHANGE_RSP */ - -	return 0; -} - -static void read_local_amp_info_complete(struct hci_dev *hdev, u8 status, -					 u16 opcode) -{ -	BT_DBG("%s status 0x%2.2x", hdev->name, status); - -	a2mp_send_getinfo_rsp(hdev); -} - -static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb, -			    struct a2mp_cmd *hdr) -{ -	struct a2mp_info_req *req  = (void *) skb->data; -	struct hci_dev *hdev; -	struct hci_request hreq; -	int err = 0; - -	if (le16_to_cpu(hdr->len) < sizeof(*req)) -		return -EINVAL; - -	BT_DBG("id %u", req->id); - -	hdev = hci_dev_get(req->id); -	if (!hdev || hdev->dev_type != HCI_AMP) { -		struct a2mp_info_rsp rsp; - -		memset(&rsp, 0, sizeof(rsp)); - -		rsp.id = req->id; -		rsp.status = A2MP_STATUS_INVALID_CTRL_ID; - -		a2mp_send(mgr, A2MP_GETINFO_RSP, hdr->ident, sizeof(rsp), -			  &rsp); - -		goto done; -	} - -	set_bit(READ_LOC_AMP_INFO, &mgr->state); -	hci_req_init(&hreq, hdev); -	hci_req_add(&hreq, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL); -	err = hci_req_run(&hreq, read_local_amp_info_complete); -	if (err < 0) -		a2mp_send_getinfo_rsp(hdev); - -done: -	if (hdev) -		hci_dev_put(hdev); - -	skb_pull(skb, sizeof(*req)); -	return 0; -} - -static int a2mp_getinfo_rsp(struct amp_mgr *mgr, struct sk_buff *skb, -			    struct a2mp_cmd *hdr) -{ -	struct a2mp_info_rsp *rsp = (struct a2mp_info_rsp *) skb->data; -	struct a2mp_amp_assoc_req req; -	struct amp_ctrl *ctrl; - -	if (le16_to_cpu(hdr->len) < sizeof(*rsp)) -		return -EINVAL; - -	BT_DBG("id %u status 0x%2.2x", rsp->id, rsp->status); - -	if (rsp->status) -		return -EINVAL; - -	ctrl = amp_ctrl_add(mgr, rsp->id); -	if (!ctrl) -		return -ENOMEM; - -	memset(&req, 0, sizeof(req)); - -	req.id = rsp->id; -	a2mp_send(mgr, A2MP_GETAMPASSOC_REQ, __next_ident(mgr), sizeof(req), -		  &req); - -	skb_pull(skb, sizeof(*rsp)); -	return 0; -} - -static int a2mp_getampassoc_req(struct amp_mgr *mgr, struct sk_buff *skb, -				struct a2mp_cmd *hdr) -{ -	struct a2mp_amp_assoc_req *req = (void *) skb->data; -	struct hci_dev *hdev; -	struct amp_mgr *tmp; - -	if (le16_to_cpu(hdr->len) < sizeof(*req)) -		return -EINVAL; - -	BT_DBG("id %u", req->id); - -	/* Make sure that other request is not processed */ -	tmp = amp_mgr_lookup_by_state(READ_LOC_AMP_ASSOC); - -	hdev = hci_dev_get(req->id); -	if (!hdev || hdev->amp_type == AMP_TYPE_BREDR || tmp) { -		struct a2mp_amp_assoc_rsp rsp; - -		memset(&rsp, 0, sizeof(rsp)); -		rsp.id = req->id; - -		if (tmp) { -			rsp.status = A2MP_STATUS_COLLISION_OCCURED; -			amp_mgr_put(tmp); -		} else { -			rsp.status = A2MP_STATUS_INVALID_CTRL_ID; -		} - -		a2mp_send(mgr, A2MP_GETAMPASSOC_RSP, hdr->ident, sizeof(rsp), -			  &rsp); - -		goto done; -	} - -	amp_read_loc_assoc(hdev, mgr); - -done: -	if (hdev) -		hci_dev_put(hdev); - -	skb_pull(skb, sizeof(*req)); -	return 0; -} - -static int a2mp_getampassoc_rsp(struct amp_mgr *mgr, struct sk_buff *skb, -				struct a2mp_cmd *hdr) -{ -	struct a2mp_amp_assoc_rsp *rsp = (void *) skb->data; -	u16 len = le16_to_cpu(hdr->len); -	struct hci_dev *hdev; -	struct amp_ctrl *ctrl; -	struct hci_conn *hcon; -	size_t assoc_len; - -	if (len < sizeof(*rsp)) -		return -EINVAL; - -	assoc_len = len - sizeof(*rsp); - -	BT_DBG("id %u status 0x%2.2x assoc len %zu", rsp->id, rsp->status, -	       assoc_len); - -	if (rsp->status) -		return -EINVAL; - -	/* Save remote ASSOC data */ -	ctrl = amp_ctrl_lookup(mgr, rsp->id); -	if (ctrl) { -		u8 *assoc; - -		assoc = kmemdup(rsp->amp_assoc, assoc_len, GFP_KERNEL); -		if (!assoc) { -			amp_ctrl_put(ctrl); -			return -ENOMEM; -		} - -		ctrl->assoc = assoc; -		ctrl->assoc_len = assoc_len; -		ctrl->assoc_rem_len = assoc_len; -		ctrl->assoc_len_so_far = 0; - -		amp_ctrl_put(ctrl); -	} - -	/* Create Phys Link */ -	hdev = hci_dev_get(rsp->id); -	if (!hdev) -		return -EINVAL; - -	hcon = phylink_add(hdev, mgr, rsp->id, true); -	if (!hcon) -		goto done; - -	BT_DBG("Created hcon %p: loc:%u -> rem:%u", hcon, hdev->id, rsp->id); - -	mgr->bredr_chan->remote_amp_id = rsp->id; - -	amp_create_phylink(hdev, mgr, hcon); - -done: -	hci_dev_put(hdev); -	skb_pull(skb, len); -	return 0; -} - -static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb, -				   struct a2mp_cmd *hdr) -{ -	struct a2mp_physlink_req *req = (void *) skb->data; -	struct a2mp_physlink_rsp rsp; -	struct hci_dev *hdev; -	struct hci_conn *hcon; -	struct amp_ctrl *ctrl; - -	if (le16_to_cpu(hdr->len) < sizeof(*req)) -		return -EINVAL; - -	BT_DBG("local_id %u, remote_id %u", req->local_id, req->remote_id); - -	memset(&rsp, 0, sizeof(rsp)); - -	rsp.local_id = req->remote_id; -	rsp.remote_id = req->local_id; - -	hdev = hci_dev_get(req->remote_id); -	if (!hdev || hdev->amp_type == AMP_TYPE_BREDR) { -		rsp.status = A2MP_STATUS_INVALID_CTRL_ID; -		goto send_rsp; -	} - -	ctrl = amp_ctrl_lookup(mgr, rsp.remote_id); -	if (!ctrl) { -		ctrl = amp_ctrl_add(mgr, rsp.remote_id); -		if (ctrl) { -			amp_ctrl_get(ctrl); -		} else { -			rsp.status = A2MP_STATUS_UNABLE_START_LINK_CREATION; -			goto send_rsp; -		} -	} - -	if (ctrl) { -		size_t assoc_len = le16_to_cpu(hdr->len) - sizeof(*req); -		u8 *assoc; - -		assoc = kmemdup(req->amp_assoc, assoc_len, GFP_KERNEL); -		if (!assoc) { -			amp_ctrl_put(ctrl); -			hci_dev_put(hdev); -			return -ENOMEM; -		} - -		ctrl->assoc = assoc; -		ctrl->assoc_len = assoc_len; -		ctrl->assoc_rem_len = assoc_len; -		ctrl->assoc_len_so_far = 0; - -		amp_ctrl_put(ctrl); -	} - -	hcon = phylink_add(hdev, mgr, req->local_id, false); -	if (hcon) { -		amp_accept_phylink(hdev, mgr, hcon); -		rsp.status = A2MP_STATUS_SUCCESS; -	} else { -		rsp.status = A2MP_STATUS_UNABLE_START_LINK_CREATION; -	} - -send_rsp: -	if (hdev) -		hci_dev_put(hdev); - -	/* Reply error now and success after HCI Write Remote AMP Assoc -	   command complete with success status -	 */ -	if (rsp.status != A2MP_STATUS_SUCCESS) { -		a2mp_send(mgr, A2MP_CREATEPHYSLINK_RSP, hdr->ident, -			  sizeof(rsp), &rsp); -	} else { -		set_bit(WRITE_REMOTE_AMP_ASSOC, &mgr->state); -		mgr->ident = hdr->ident; -	} - -	skb_pull(skb, le16_to_cpu(hdr->len)); -	return 0; -} - -static int a2mp_discphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb, -				 struct a2mp_cmd *hdr) -{ -	struct a2mp_physlink_req *req = (void *) skb->data; -	struct a2mp_physlink_rsp rsp; -	struct hci_dev *hdev; -	struct hci_conn *hcon; - -	if (le16_to_cpu(hdr->len) < sizeof(*req)) -		return -EINVAL; - -	BT_DBG("local_id %u remote_id %u", req->local_id, req->remote_id); - -	memset(&rsp, 0, sizeof(rsp)); - -	rsp.local_id = req->remote_id; -	rsp.remote_id = req->local_id; -	rsp.status = A2MP_STATUS_SUCCESS; - -	hdev = hci_dev_get(req->remote_id); -	if (!hdev) { -		rsp.status = A2MP_STATUS_INVALID_CTRL_ID; -		goto send_rsp; -	} - -	hcon = hci_conn_hash_lookup_ba(hdev, AMP_LINK, -				       &mgr->l2cap_conn->hcon->dst); -	if (!hcon) { -		bt_dev_err(hdev, "no phys link exist"); -		rsp.status = A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS; -		goto clean; -	} - -	/* TODO Disconnect Phys Link here */ - -clean: -	hci_dev_put(hdev); - -send_rsp: -	a2mp_send(mgr, A2MP_DISCONNPHYSLINK_RSP, hdr->ident, sizeof(rsp), &rsp); - -	skb_pull(skb, sizeof(*req)); -	return 0; -} - -static inline int a2mp_cmd_rsp(struct amp_mgr *mgr, struct sk_buff *skb, -			       struct a2mp_cmd *hdr) -{ -	BT_DBG("ident %u code 0x%2.2x", hdr->ident, hdr->code); - -	skb_pull(skb, le16_to_cpu(hdr->len)); -	return 0; -} - -/* Handle A2MP signalling */ -static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) -{ -	struct a2mp_cmd *hdr; -	struct amp_mgr *mgr = chan->data; -	int err = 0; - -	amp_mgr_get(mgr); - -	while (skb->len >= sizeof(*hdr)) { -		u16 len; - -		hdr = (void *) skb->data; -		len = le16_to_cpu(hdr->len); - -		BT_DBG("code 0x%2.2x id %u len %u", hdr->code, hdr->ident, len); - -		skb_pull(skb, sizeof(*hdr)); - -		if (len > skb->len || !hdr->ident) { -			err = -EINVAL; -			break; -		} - -		mgr->ident = hdr->ident; - -		switch (hdr->code) { -		case A2MP_COMMAND_REJ: -			a2mp_command_rej(mgr, skb, hdr); -			break; - -		case A2MP_DISCOVER_REQ: -			err = a2mp_discover_req(mgr, skb, hdr); -			break; - -		case A2MP_CHANGE_NOTIFY: -			err = a2mp_change_notify(mgr, skb, hdr); -			break; - -		case A2MP_GETINFO_REQ: -			err = a2mp_getinfo_req(mgr, skb, hdr); -			break; - -		case A2MP_GETAMPASSOC_REQ: -			err = a2mp_getampassoc_req(mgr, skb, hdr); -			break; - -		case A2MP_CREATEPHYSLINK_REQ: -			err = a2mp_createphyslink_req(mgr, skb, hdr); -			break; - -		case A2MP_DISCONNPHYSLINK_REQ: -			err = a2mp_discphyslink_req(mgr, skb, hdr); -			break; - -		case A2MP_DISCOVER_RSP: -			err = a2mp_discover_rsp(mgr, skb, hdr); -			break; - -		case A2MP_GETINFO_RSP: -			err = a2mp_getinfo_rsp(mgr, skb, hdr); -			break; - -		case A2MP_GETAMPASSOC_RSP: -			err = a2mp_getampassoc_rsp(mgr, skb, hdr); -			break; - -		case A2MP_CHANGE_RSP: -		case A2MP_CREATEPHYSLINK_RSP: -		case A2MP_DISCONNPHYSLINK_RSP: -			err = a2mp_cmd_rsp(mgr, skb, hdr); -			break; - -		default: -			BT_ERR("Unknown A2MP sig cmd 0x%2.2x", hdr->code); -			err = -EINVAL; -			break; -		} -	} - -	if (err) { -		struct a2mp_cmd_rej rej; - -		memset(&rej, 0, sizeof(rej)); - -		rej.reason = cpu_to_le16(0); -		hdr = (void *) skb->data; - -		BT_DBG("Send A2MP Rej: cmd 0x%2.2x err %d", hdr->code, err); - -		a2mp_send(mgr, A2MP_COMMAND_REJ, hdr->ident, sizeof(rej), -			  &rej); -	} - -	/* Always free skb and return success error code to prevent -	   from sending L2CAP Disconnect over A2MP channel */ -	kfree_skb(skb); - -	amp_mgr_put(mgr); - -	return 0; -} - -static void a2mp_chan_close_cb(struct l2cap_chan *chan) -{ -	l2cap_chan_put(chan); -} - -static void a2mp_chan_state_change_cb(struct l2cap_chan *chan, int state, -				      int err) -{ -	struct amp_mgr *mgr = chan->data; - -	if (!mgr) -		return; - -	BT_DBG("chan %p state %s", chan, state_to_string(state)); - -	chan->state = state; - -	switch (state) { -	case BT_CLOSED: -		if (mgr) -			amp_mgr_put(mgr); -		break; -	} -} - -static struct sk_buff *a2mp_chan_alloc_skb_cb(struct l2cap_chan *chan, -					      unsigned long hdr_len, -					      unsigned long len, int nb) -{ -	struct sk_buff *skb; - -	skb = bt_skb_alloc(hdr_len + len, GFP_KERNEL); -	if (!skb) -		return ERR_PTR(-ENOMEM); - -	return skb; -} - -static const struct l2cap_ops a2mp_chan_ops = { -	.name = "L2CAP A2MP channel", -	.recv = a2mp_chan_recv_cb, -	.close = a2mp_chan_close_cb, -	.state_change = a2mp_chan_state_change_cb, -	.alloc_skb = a2mp_chan_alloc_skb_cb, - -	/* Not implemented for A2MP */ -	.new_connection = l2cap_chan_no_new_connection, -	.teardown = l2cap_chan_no_teardown, -	.ready = l2cap_chan_no_ready, -	.defer = l2cap_chan_no_defer, -	.resume = l2cap_chan_no_resume, -	.set_shutdown = l2cap_chan_no_set_shutdown, -	.get_sndtimeo = l2cap_chan_no_get_sndtimeo, -}; - -static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn, bool locked) -{ -	struct l2cap_chan *chan; -	int err; - -	chan = l2cap_chan_create(); -	if (!chan) -		return NULL; - -	BT_DBG("chan %p", chan); - -	chan->chan_type = L2CAP_CHAN_FIXED; -	chan->scid = L2CAP_CID_A2MP; -	chan->dcid = L2CAP_CID_A2MP; -	chan->omtu = L2CAP_A2MP_DEFAULT_MTU; -	chan->imtu = L2CAP_A2MP_DEFAULT_MTU; -	chan->flush_to = L2CAP_DEFAULT_FLUSH_TO; - -	chan->ops = &a2mp_chan_ops; - -	l2cap_chan_set_defaults(chan); -	chan->remote_max_tx = chan->max_tx; -	chan->remote_tx_win = chan->tx_win; - -	chan->retrans_timeout = L2CAP_DEFAULT_RETRANS_TO; -	chan->monitor_timeout = L2CAP_DEFAULT_MONITOR_TO; - -	skb_queue_head_init(&chan->tx_q); - -	chan->mode = L2CAP_MODE_ERTM; - -	err = l2cap_ertm_init(chan); -	if (err < 0) { -		l2cap_chan_del(chan, 0); -		return NULL; -	} - -	chan->conf_state = 0; - -	if (locked) -		__l2cap_chan_add(conn, chan); -	else -		l2cap_chan_add(conn, chan); - -	chan->remote_mps = chan->omtu; -	chan->mps = chan->omtu; - -	chan->state = BT_CONNECTED; - -	return chan; -} - -/* AMP Manager functions */ -struct amp_mgr *amp_mgr_get(struct amp_mgr *mgr) -{ -	BT_DBG("mgr %p orig refcnt %d", mgr, kref_read(&mgr->kref)); - -	kref_get(&mgr->kref); - -	return mgr; -} - -static void amp_mgr_destroy(struct kref *kref) -{ -	struct amp_mgr *mgr = container_of(kref, struct amp_mgr, kref); - -	BT_DBG("mgr %p", mgr); - -	mutex_lock(&_mgr_list_lock); -	list_del(&mgr->list); -	mutex_unlock(&_mgr_list_lock); - -	amp_ctrl_list_flush(mgr); -	kfree(mgr); -} - -int amp_mgr_put(struct amp_mgr *mgr) -{ -	BT_DBG("mgr %p orig refcnt %d", mgr, kref_read(&mgr->kref)); - -	return kref_put(&mgr->kref, &_mgr_destroy); -} - -static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn, bool locked) -{ -	struct amp_mgr *mgr; -	struct l2cap_chan *chan; - -	mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); -	if (!mgr) -		return NULL; - -	BT_DBG("conn %p mgr %p", conn, mgr); - -	mgr->l2cap_conn = conn; - -	chan = a2mp_chan_open(conn, locked); -	if (!chan) { -		kfree(mgr); -		return NULL; -	} - -	mgr->a2mp_chan = chan; -	chan->data = mgr; - -	conn->hcon->amp_mgr = mgr; - -	kref_init(&mgr->kref); - -	/* Remote AMP ctrl list initialization */ -	INIT_LIST_HEAD(&mgr->amp_ctrls); -	mutex_init(&mgr->amp_ctrls_lock); - -	mutex_lock(&_mgr_list_lock); -	list_add(&mgr->list, &_mgr_list); -	mutex_unlock(&_mgr_list_lock); - -	return mgr; -} - -struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn, -				       struct sk_buff *skb) -{ -	struct amp_mgr *mgr; - -	if (conn->hcon->type != ACL_LINK) -		return NULL; - -	mgr = amp_mgr_create(conn, false); -	if (!mgr) { -		BT_ERR("Could not create AMP manager"); -		return NULL; -	} - -	BT_DBG("mgr: %p chan %p", mgr, mgr->a2mp_chan); - -	return mgr->a2mp_chan; -} - -void a2mp_send_getinfo_rsp(struct hci_dev *hdev) -{ -	struct amp_mgr *mgr; -	struct a2mp_info_rsp rsp; - -	mgr = amp_mgr_lookup_by_state(READ_LOC_AMP_INFO); -	if (!mgr) -		return; - -	BT_DBG("%s mgr %p", hdev->name, mgr); - -	memset(&rsp, 0, sizeof(rsp)); - -	rsp.id = hdev->id; -	rsp.status = A2MP_STATUS_INVALID_CTRL_ID; - -	if (hdev->amp_type != AMP_TYPE_BREDR) { -		rsp.status = 0; -		rsp.total_bw = cpu_to_le32(hdev->amp_total_bw); -		rsp.max_bw = cpu_to_le32(hdev->amp_max_bw); -		rsp.min_latency = cpu_to_le32(hdev->amp_min_latency); -		rsp.pal_cap = cpu_to_le16(hdev->amp_pal_cap); -		rsp.assoc_size = cpu_to_le16(hdev->amp_assoc_size); -	} - -	a2mp_send(mgr, A2MP_GETINFO_RSP, mgr->ident, sizeof(rsp), &rsp); -	amp_mgr_put(mgr); -} - -void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status) -{ -	struct amp_mgr *mgr; -	struct amp_assoc *loc_assoc = &hdev->loc_assoc; -	struct a2mp_amp_assoc_rsp *rsp; -	size_t len; - -	mgr = amp_mgr_lookup_by_state(READ_LOC_AMP_ASSOC); -	if (!mgr) -		return; - -	BT_DBG("%s mgr %p", hdev->name, mgr); - -	len = sizeof(struct a2mp_amp_assoc_rsp) + loc_assoc->len; -	rsp = kzalloc(len, GFP_KERNEL); -	if (!rsp) { -		amp_mgr_put(mgr); -		return; -	} - -	rsp->id = hdev->id; - -	if (status) { -		rsp->status = A2MP_STATUS_INVALID_CTRL_ID; -	} else { -		rsp->status = A2MP_STATUS_SUCCESS; -		memcpy(rsp->amp_assoc, loc_assoc->data, loc_assoc->len); -	} - -	a2mp_send(mgr, A2MP_GETAMPASSOC_RSP, mgr->ident, len, rsp); -	amp_mgr_put(mgr); -	kfree(rsp); -} - -void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status) -{ -	struct amp_mgr *mgr; -	struct amp_assoc *loc_assoc = &hdev->loc_assoc; -	struct a2mp_physlink_req *req; -	struct l2cap_chan *bredr_chan; -	size_t len; - -	mgr = amp_mgr_lookup_by_state(READ_LOC_AMP_ASSOC_FINAL); -	if (!mgr) -		return; - -	len = sizeof(*req) + loc_assoc->len; - -	BT_DBG("%s mgr %p assoc_len %zu", hdev->name, mgr, len); - -	req = kzalloc(len, GFP_KERNEL); -	if (!req) { -		amp_mgr_put(mgr); -		return; -	} - -	bredr_chan = mgr->bredr_chan; -	if (!bredr_chan) -		goto clean; - -	req->local_id = hdev->id; -	req->remote_id = bredr_chan->remote_amp_id; -	memcpy(req->amp_assoc, loc_assoc->data, loc_assoc->len); - -	a2mp_send(mgr, A2MP_CREATEPHYSLINK_REQ, __next_ident(mgr), len, req); - -clean: -	amp_mgr_put(mgr); -	kfree(req); -} - -void a2mp_send_create_phy_link_rsp(struct hci_dev *hdev, u8 status) -{ -	struct amp_mgr *mgr; -	struct a2mp_physlink_rsp rsp; -	struct hci_conn *hs_hcon; - -	mgr = amp_mgr_lookup_by_state(WRITE_REMOTE_AMP_ASSOC); -	if (!mgr) -		return; - -	memset(&rsp, 0, sizeof(rsp)); - -	hs_hcon = hci_conn_hash_lookup_state(hdev, AMP_LINK, BT_CONNECT); -	if (!hs_hcon) { -		rsp.status = A2MP_STATUS_UNABLE_START_LINK_CREATION; -	} else { -		rsp.remote_id = hs_hcon->remote_id; -		rsp.status = A2MP_STATUS_SUCCESS; -	} - -	BT_DBG("%s mgr %p hs_hcon %p status %u", hdev->name, mgr, hs_hcon, -	       status); - -	rsp.local_id = hdev->id; -	a2mp_send(mgr, A2MP_CREATEPHYSLINK_RSP, mgr->ident, sizeof(rsp), &rsp); -	amp_mgr_put(mgr); -} - -void a2mp_discover_amp(struct l2cap_chan *chan) -{ -	struct l2cap_conn *conn = chan->conn; -	struct amp_mgr *mgr = conn->hcon->amp_mgr; -	struct a2mp_discov_req req; - -	BT_DBG("chan %p conn %p mgr %p", chan, conn, mgr); - -	if (!mgr) { -		mgr = amp_mgr_create(conn, true); -		if (!mgr) -			return; -	} - -	mgr->bredr_chan = chan; - -	memset(&req, 0, sizeof(req)); - -	req.mtu = cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU); -	req.ext_feat = 0; -	a2mp_send(mgr, A2MP_DISCOVER_REQ, 1, sizeof(req), &req); -} diff --git a/net/bluetooth/a2mp.h b/net/bluetooth/a2mp.h deleted file mode 100644 index 2fd253a61a2a..000000000000 --- a/net/bluetooth/a2mp.h +++ /dev/null @@ -1,154 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* -   Copyright (c) 2010,2011 Code Aurora Forum.  All rights reserved. -   Copyright (c) 2011,2012 Intel Corp. - -*/ - -#ifndef __A2MP_H -#define __A2MP_H - -#include <net/bluetooth/l2cap.h> - -enum amp_mgr_state { -	READ_LOC_AMP_INFO, -	READ_LOC_AMP_ASSOC, -	READ_LOC_AMP_ASSOC_FINAL, -	WRITE_REMOTE_AMP_ASSOC, -}; - -struct amp_mgr { -	struct list_head	list; -	struct l2cap_conn	*l2cap_conn; -	struct l2cap_chan	*a2mp_chan; -	struct l2cap_chan	*bredr_chan; -	struct kref		kref; -	__u8			ident; -	__u8			handle; -	unsigned long		state; -	unsigned long		flags; - -	struct list_head	amp_ctrls; -	struct mutex		amp_ctrls_lock; -}; - -struct a2mp_cmd { -	__u8	code; -	__u8	ident; -	__le16	len; -	__u8	data[]; -} __packed; - -/* A2MP command codes */ -#define A2MP_COMMAND_REJ         0x01 -struct a2mp_cmd_rej { -	__le16	reason; -	__u8	data[]; -} __packed; - -#define A2MP_DISCOVER_REQ        0x02 -struct a2mp_discov_req { -	__le16	mtu; -	__le16	ext_feat; -} __packed; - -struct a2mp_cl { -	__u8	id; -	__u8	type; -	__u8	status; -} __packed; - -#define A2MP_DISCOVER_RSP        0x03 -struct a2mp_discov_rsp { -	__le16     mtu; -	__le16     ext_feat; -	struct a2mp_cl cl[]; -} __packed; - -#define A2MP_CHANGE_NOTIFY       0x04 -#define A2MP_CHANGE_RSP          0x05 - -#define A2MP_GETINFO_REQ         0x06 -struct a2mp_info_req { -	__u8       id; -} __packed; - -#define A2MP_GETINFO_RSP         0x07 -struct a2mp_info_rsp { -	__u8	id; -	__u8	status; -	__le32	total_bw; -	__le32	max_bw; -	__le32	min_latency; -	__le16	pal_cap; -	__le16	assoc_size; -} __packed; - -#define A2MP_GETAMPASSOC_REQ     0x08 -struct a2mp_amp_assoc_req { -	__u8	id; -} __packed; - -#define A2MP_GETAMPASSOC_RSP     0x09 -struct a2mp_amp_assoc_rsp { -	__u8	id; -	__u8	status; -	__u8	amp_assoc[]; -} __packed; - -#define A2MP_CREATEPHYSLINK_REQ  0x0A -#define A2MP_DISCONNPHYSLINK_REQ 0x0C -struct a2mp_physlink_req { -	__u8	local_id; -	__u8	remote_id; -	__u8	amp_assoc[]; -} __packed; - -#define A2MP_CREATEPHYSLINK_RSP  0x0B -#define A2MP_DISCONNPHYSLINK_RSP 0x0D -struct a2mp_physlink_rsp { -	__u8	local_id; -	__u8	remote_id; -	__u8	status; -} __packed; - -/* A2MP response status */ -#define A2MP_STATUS_SUCCESS			0x00 -#define A2MP_STATUS_INVALID_CTRL_ID		0x01 -#define A2MP_STATUS_UNABLE_START_LINK_CREATION	0x02 -#define A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS	0x02 -#define A2MP_STATUS_COLLISION_OCCURED		0x03 -#define A2MP_STATUS_DISCONN_REQ_RECVD		0x04 -#define A2MP_STATUS_PHYS_LINK_EXISTS		0x05 -#define A2MP_STATUS_SECURITY_VIOLATION		0x06 - -struct amp_mgr *amp_mgr_get(struct amp_mgr *mgr); - -#if IS_ENABLED(CONFIG_BT_HS) -int amp_mgr_put(struct amp_mgr *mgr); -struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn, -				       struct sk_buff *skb); -void a2mp_discover_amp(struct l2cap_chan *chan); -#else -static inline int amp_mgr_put(struct amp_mgr *mgr) -{ -	return 0; -} - -static inline struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn, -						     struct sk_buff *skb) -{ -	return NULL; -} - -static inline void a2mp_discover_amp(struct l2cap_chan *chan) -{ -} -#endif - -void a2mp_send_getinfo_rsp(struct hci_dev *hdev); -void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status); -void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status); -void a2mp_send_create_phy_link_rsp(struct hci_dev *hdev, u8 status); - -#endif /* __A2MP_H */ diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index b93464ac3517..67604ccec2f4 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -309,14 +309,11 @@ int bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,  	if (flags & MSG_OOB)  		return -EOPNOTSUPP; -	lock_sock(sk); -  	skb = skb_recv_datagram(sk, flags, &err);  	if (!skb) {  		if (sk->sk_shutdown & RCV_SHUTDOWN)  			err = 0; -		release_sock(sk);  		return err;  	} @@ -346,8 +343,6 @@ int bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,  	skb_free_datagram(sk, skb); -	release_sock(sk); -  	if (flags & MSG_TRUNC)  		copied = skblen; @@ -570,10 +565,11 @@ int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)  		if (sk->sk_state == BT_LISTEN)  			return -EINVAL; -		lock_sock(sk); +		spin_lock(&sk->sk_receive_queue.lock);  		skb = skb_peek(&sk->sk_receive_queue);  		amount = skb ? skb->len : 0; -		release_sock(sk); +		spin_unlock(&sk->sk_receive_queue.lock); +  		err = put_user(amount, (int __user *)arg);  		break; diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c deleted file mode 100644 index 5d698f19868c..000000000000 --- a/net/bluetooth/amp.c +++ /dev/null @@ -1,590 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* -   Copyright (c) 2011,2012 Intel Corp. - -*/ - -#include <net/bluetooth/bluetooth.h> -#include <net/bluetooth/hci.h> -#include <net/bluetooth/hci_core.h> -#include <crypto/hash.h> - -#include "hci_request.h" -#include "a2mp.h" -#include "amp.h" - -/* Remote AMP Controllers interface */ -void amp_ctrl_get(struct amp_ctrl *ctrl) -{ -	BT_DBG("ctrl %p orig refcnt %d", ctrl, -	       kref_read(&ctrl->kref)); - -	kref_get(&ctrl->kref); -} - -static void amp_ctrl_destroy(struct kref *kref) -{ -	struct amp_ctrl *ctrl = container_of(kref, struct amp_ctrl, kref); - -	BT_DBG("ctrl %p", ctrl); - -	kfree(ctrl->assoc); -	kfree(ctrl); -} - -int amp_ctrl_put(struct amp_ctrl *ctrl) -{ -	BT_DBG("ctrl %p orig refcnt %d", ctrl, -	       kref_read(&ctrl->kref)); - -	return kref_put(&ctrl->kref, &_ctrl_destroy); -} - -struct amp_ctrl *amp_ctrl_add(struct amp_mgr *mgr, u8 id) -{ -	struct amp_ctrl *ctrl; - -	ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); -	if (!ctrl) -		return NULL; - -	kref_init(&ctrl->kref); -	ctrl->id = id; - -	mutex_lock(&mgr->amp_ctrls_lock); -	list_add(&ctrl->list, &mgr->amp_ctrls); -	mutex_unlock(&mgr->amp_ctrls_lock); - -	BT_DBG("mgr %p ctrl %p", mgr, ctrl); - -	return ctrl; -} - -void amp_ctrl_list_flush(struct amp_mgr *mgr) -{ -	struct amp_ctrl *ctrl, *n; - -	BT_DBG("mgr %p", mgr); - -	mutex_lock(&mgr->amp_ctrls_lock); -	list_for_each_entry_safe(ctrl, n, &mgr->amp_ctrls, list) { -		list_del(&ctrl->list); -		amp_ctrl_put(ctrl); -	} -	mutex_unlock(&mgr->amp_ctrls_lock); -} - -struct amp_ctrl *amp_ctrl_lookup(struct amp_mgr *mgr, u8 id) -{ -	struct amp_ctrl *ctrl; - -	BT_DBG("mgr %p id %u", mgr, id); - -	mutex_lock(&mgr->amp_ctrls_lock); -	list_for_each_entry(ctrl, &mgr->amp_ctrls, list) { -		if (ctrl->id == id) { -			amp_ctrl_get(ctrl); -			mutex_unlock(&mgr->amp_ctrls_lock); -			return ctrl; -		} -	} -	mutex_unlock(&mgr->amp_ctrls_lock); - -	return NULL; -} - -/* Physical Link interface */ -static u8 __next_handle(struct amp_mgr *mgr) -{ -	if (++mgr->handle == 0) -		mgr->handle = 1; - -	return mgr->handle; -} - -struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr, -			     u8 remote_id, bool out) -{ -	bdaddr_t *dst = &mgr->l2cap_conn->hcon->dst; -	struct hci_conn *hcon; -	u8 role = out ? HCI_ROLE_MASTER : HCI_ROLE_SLAVE; - -	hcon = hci_conn_add(hdev, AMP_LINK, dst, role, __next_handle(mgr)); -	if (!hcon) -		return NULL; - -	BT_DBG("hcon %p dst %pMR", hcon, dst); - -	hcon->state = BT_CONNECT; -	hcon->attempt++; -	hcon->remote_id = remote_id; -	hcon->amp_mgr = amp_mgr_get(mgr); - -	return hcon; -} - -/* AMP crypto key generation interface */ -static int hmac_sha256(u8 *key, u8 ksize, char *plaintext, u8 psize, u8 *output) -{ -	struct crypto_shash *tfm; -	struct shash_desc *shash; -	int ret; - -	if (!ksize) -		return -EINVAL; - -	tfm = crypto_alloc_shash("hmac(sha256)", 0, 0); -	if (IS_ERR(tfm)) { -		BT_DBG("crypto_alloc_ahash failed: err %ld", PTR_ERR(tfm)); -		return PTR_ERR(tfm); -	} - -	ret = crypto_shash_setkey(tfm, key, ksize); -	if (ret) { -		BT_DBG("crypto_ahash_setkey failed: err %d", ret); -		goto failed; -	} - -	shash = kzalloc(sizeof(*shash) + crypto_shash_descsize(tfm), -			GFP_KERNEL); -	if (!shash) { -		ret = -ENOMEM; -		goto failed; -	} - -	shash->tfm = tfm; - -	ret = crypto_shash_digest(shash, plaintext, psize, output); - -	kfree(shash); - -failed: -	crypto_free_shash(tfm); -	return ret; -} - -int phylink_gen_key(struct hci_conn *conn, u8 *data, u8 *len, u8 *type) -{ -	struct hci_dev *hdev = conn->hdev; -	struct link_key *key; -	u8 keybuf[HCI_AMP_LINK_KEY_SIZE]; -	u8 gamp_key[HCI_AMP_LINK_KEY_SIZE]; -	int err; - -	if (!hci_conn_check_link_mode(conn)) -		return -EACCES; - -	BT_DBG("conn %p key_type %d", conn, conn->key_type); - -	/* Legacy key */ -	if (conn->key_type < 3) { -		bt_dev_err(hdev, "legacy key type %u", conn->key_type); -		return -EACCES; -	} - -	*type = conn->key_type; -	*len = HCI_AMP_LINK_KEY_SIZE; - -	key = hci_find_link_key(hdev, &conn->dst); -	if (!key) { -		BT_DBG("No Link key for conn %p dst %pMR", conn, &conn->dst); -		return -EACCES; -	} - -	/* BR/EDR Link Key concatenated together with itself */ -	memcpy(&keybuf[0], key->val, HCI_LINK_KEY_SIZE); -	memcpy(&keybuf[HCI_LINK_KEY_SIZE], key->val, HCI_LINK_KEY_SIZE); - -	/* Derive Generic AMP Link Key (gamp) */ -	err = hmac_sha256(keybuf, HCI_AMP_LINK_KEY_SIZE, "gamp", 4, gamp_key); -	if (err) { -		bt_dev_err(hdev, "could not derive Generic AMP Key: err %d", err); -		return err; -	} - -	if (conn->key_type == HCI_LK_DEBUG_COMBINATION) { -		BT_DBG("Use Generic AMP Key (gamp)"); -		memcpy(data, gamp_key, HCI_AMP_LINK_KEY_SIZE); -		return err; -	} - -	/* Derive Dedicated AMP Link Key: "802b" is 802.11 PAL keyID */ -	return hmac_sha256(gamp_key, HCI_AMP_LINK_KEY_SIZE, "802b", 4, data); -} - -static void read_local_amp_assoc_complete(struct hci_dev *hdev, u8 status, -					  u16 opcode, struct sk_buff *skb) -{ -	struct hci_rp_read_local_amp_assoc *rp = (void *)skb->data; -	struct amp_assoc *assoc = &hdev->loc_assoc; -	size_t rem_len, frag_len; - -	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); - -	if (rp->status) -		goto send_rsp; - -	frag_len = skb->len - sizeof(*rp); -	rem_len = __le16_to_cpu(rp->rem_len); - -	if (rem_len > frag_len) { -		BT_DBG("frag_len %zu rem_len %zu", frag_len, rem_len); - -		memcpy(assoc->data + assoc->offset, rp->frag, frag_len); -		assoc->offset += frag_len; - -		/* Read other fragments */ -		amp_read_loc_assoc_frag(hdev, rp->phy_handle); - -		return; -	} - -	memcpy(assoc->data + assoc->offset, rp->frag, rem_len); -	assoc->len = assoc->offset + rem_len; -	assoc->offset = 0; - -send_rsp: -	/* Send A2MP Rsp when all fragments are received */ -	a2mp_send_getampassoc_rsp(hdev, rp->status); -	a2mp_send_create_phy_link_req(hdev, rp->status); -} - -void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle) -{ -	struct hci_cp_read_local_amp_assoc cp; -	struct amp_assoc *loc_assoc = &hdev->loc_assoc; -	struct hci_request req; -	int err; - -	BT_DBG("%s handle %u", hdev->name, phy_handle); - -	cp.phy_handle = phy_handle; -	cp.max_len = cpu_to_le16(hdev->amp_assoc_size); -	cp.len_so_far = cpu_to_le16(loc_assoc->offset); - -	hci_req_init(&req, hdev); -	hci_req_add(&req, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); -	err = hci_req_run_skb(&req, read_local_amp_assoc_complete); -	if (err < 0) -		a2mp_send_getampassoc_rsp(hdev, A2MP_STATUS_INVALID_CTRL_ID); -} - -void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr) -{ -	struct hci_cp_read_local_amp_assoc cp; -	struct hci_request req; -	int err; - -	memset(&hdev->loc_assoc, 0, sizeof(struct amp_assoc)); -	memset(&cp, 0, sizeof(cp)); - -	cp.max_len = cpu_to_le16(hdev->amp_assoc_size); - -	set_bit(READ_LOC_AMP_ASSOC, &mgr->state); -	hci_req_init(&req, hdev); -	hci_req_add(&req, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); -	err = hci_req_run_skb(&req, read_local_amp_assoc_complete); -	if (err < 0) -		a2mp_send_getampassoc_rsp(hdev, A2MP_STATUS_INVALID_CTRL_ID); -} - -void amp_read_loc_assoc_final_data(struct hci_dev *hdev, -				   struct hci_conn *hcon) -{ -	struct hci_cp_read_local_amp_assoc cp; -	struct amp_mgr *mgr = hcon->amp_mgr; -	struct hci_request req; -	int err; - -	if (!mgr) -		return; - -	cp.phy_handle = hcon->handle; -	cp.len_so_far = cpu_to_le16(0); -	cp.max_len = cpu_to_le16(hdev->amp_assoc_size); - -	set_bit(READ_LOC_AMP_ASSOC_FINAL, &mgr->state); - -	/* Read Local AMP Assoc final link information data */ -	hci_req_init(&req, hdev); -	hci_req_add(&req, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); -	err = hci_req_run_skb(&req, read_local_amp_assoc_complete); -	if (err < 0) -		a2mp_send_getampassoc_rsp(hdev, A2MP_STATUS_INVALID_CTRL_ID); -} - -static void write_remote_amp_assoc_complete(struct hci_dev *hdev, u8 status, -					    u16 opcode, struct sk_buff *skb) -{ -	struct hci_rp_write_remote_amp_assoc *rp = (void *)skb->data; - -	BT_DBG("%s status 0x%2.2x phy_handle 0x%2.2x", -	       hdev->name, rp->status, rp->phy_handle); - -	if (rp->status) -		return; - -	amp_write_rem_assoc_continue(hdev, rp->phy_handle); -} - -/* Write AMP Assoc data fragments, returns true with last fragment written*/ -static bool amp_write_rem_assoc_frag(struct hci_dev *hdev, -				     struct hci_conn *hcon) -{ -	struct hci_cp_write_remote_amp_assoc *cp; -	struct amp_mgr *mgr = hcon->amp_mgr; -	struct amp_ctrl *ctrl; -	struct hci_request req; -	u16 frag_len, len; - -	ctrl = amp_ctrl_lookup(mgr, hcon->remote_id); -	if (!ctrl) -		return false; - -	if (!ctrl->assoc_rem_len) { -		BT_DBG("all fragments are written"); -		ctrl->assoc_rem_len = ctrl->assoc_len; -		ctrl->assoc_len_so_far = 0; - -		amp_ctrl_put(ctrl); -		return true; -	} - -	frag_len = min_t(u16, 248, ctrl->assoc_rem_len); -	len = frag_len + sizeof(*cp); - -	cp = kzalloc(len, GFP_KERNEL); -	if (!cp) { -		amp_ctrl_put(ctrl); -		return false; -	} - -	BT_DBG("hcon %p ctrl %p frag_len %u assoc_len %u rem_len %u", -	       hcon, ctrl, frag_len, ctrl->assoc_len, ctrl->assoc_rem_len); - -	cp->phy_handle = hcon->handle; -	cp->len_so_far = cpu_to_le16(ctrl->assoc_len_so_far); -	cp->rem_len = cpu_to_le16(ctrl->assoc_rem_len); -	memcpy(cp->frag, ctrl->assoc, frag_len); - -	ctrl->assoc_len_so_far += frag_len; -	ctrl->assoc_rem_len -= frag_len; - -	amp_ctrl_put(ctrl); - -	hci_req_init(&req, hdev); -	hci_req_add(&req, HCI_OP_WRITE_REMOTE_AMP_ASSOC, len, cp); -	hci_req_run_skb(&req, write_remote_amp_assoc_complete); - -	kfree(cp); - -	return false; -} - -void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle) -{ -	struct hci_conn *hcon; - -	BT_DBG("%s phy handle 0x%2.2x", hdev->name, handle); - -	hcon = hci_conn_hash_lookup_handle(hdev, handle); -	if (!hcon) -		return; - -	/* Send A2MP create phylink rsp when all fragments are written */ -	if (amp_write_rem_assoc_frag(hdev, hcon)) -		a2mp_send_create_phy_link_rsp(hdev, 0); -} - -void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle) -{ -	struct hci_conn *hcon; - -	BT_DBG("%s phy handle 0x%2.2x", hdev->name, handle); - -	hcon = hci_conn_hash_lookup_handle(hdev, handle); -	if (!hcon) -		return; - -	BT_DBG("%s phy handle 0x%2.2x hcon %p", hdev->name, handle, hcon); - -	amp_write_rem_assoc_frag(hdev, hcon); -} - -static void create_phylink_complete(struct hci_dev *hdev, u8 status, -				    u16 opcode) -{ -	struct hci_cp_create_phy_link *cp; - -	BT_DBG("%s status 0x%2.2x", hdev->name, status); - -	cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_PHY_LINK); -	if (!cp) -		return; - -	hci_dev_lock(hdev); - -	if (status) { -		struct hci_conn *hcon; - -		hcon = hci_conn_hash_lookup_handle(hdev, cp->phy_handle); -		if (hcon) -			hci_conn_del(hcon); -	} else { -		amp_write_remote_assoc(hdev, cp->phy_handle); -	} - -	hci_dev_unlock(hdev); -} - -void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, -			struct hci_conn *hcon) -{ -	struct hci_cp_create_phy_link cp; -	struct hci_request req; - -	cp.phy_handle = hcon->handle; - -	BT_DBG("%s hcon %p phy handle 0x%2.2x", hdev->name, hcon, -	       hcon->handle); - -	if (phylink_gen_key(mgr->l2cap_conn->hcon, cp.key, &cp.key_len, -			    &cp.key_type)) { -		BT_DBG("Cannot create link key"); -		return; -	} - -	hci_req_init(&req, hdev); -	hci_req_add(&req, HCI_OP_CREATE_PHY_LINK, sizeof(cp), &cp); -	hci_req_run(&req, create_phylink_complete); -} - -static void accept_phylink_complete(struct hci_dev *hdev, u8 status, -				    u16 opcode) -{ -	struct hci_cp_accept_phy_link *cp; - -	BT_DBG("%s status 0x%2.2x", hdev->name, status); - -	if (status) -		return; - -	cp = hci_sent_cmd_data(hdev, HCI_OP_ACCEPT_PHY_LINK); -	if (!cp) -		return; - -	amp_write_remote_assoc(hdev, cp->phy_handle); -} - -void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, -			struct hci_conn *hcon) -{ -	struct hci_cp_accept_phy_link cp; -	struct hci_request req; - -	cp.phy_handle = hcon->handle; - -	BT_DBG("%s hcon %p phy handle 0x%2.2x", hdev->name, hcon, -	       hcon->handle); - -	if (phylink_gen_key(mgr->l2cap_conn->hcon, cp.key, &cp.key_len, -			    &cp.key_type)) { -		BT_DBG("Cannot create link key"); -		return; -	} - -	hci_req_init(&req, hdev); -	hci_req_add(&req, HCI_OP_ACCEPT_PHY_LINK, sizeof(cp), &cp); -	hci_req_run(&req, accept_phylink_complete); -} - -void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon) -{ -	struct hci_dev *bredr_hdev = hci_dev_hold(bredr_hcon->hdev); -	struct amp_mgr *mgr = hs_hcon->amp_mgr; -	struct l2cap_chan *bredr_chan; - -	BT_DBG("bredr_hcon %p hs_hcon %p mgr %p", bredr_hcon, hs_hcon, mgr); - -	if (!bredr_hdev || !mgr || !mgr->bredr_chan) -		return; - -	bredr_chan = mgr->bredr_chan; - -	l2cap_chan_lock(bredr_chan); - -	set_bit(FLAG_EFS_ENABLE, &bredr_chan->flags); -	bredr_chan->remote_amp_id = hs_hcon->remote_id; -	bredr_chan->local_amp_id = hs_hcon->hdev->id; -	bredr_chan->hs_hcon = hs_hcon; -	bredr_chan->conn->mtu = hs_hcon->hdev->block_mtu; - -	__l2cap_physical_cfm(bredr_chan, 0); - -	l2cap_chan_unlock(bredr_chan); - -	hci_dev_put(bredr_hdev); -} - -void amp_create_logical_link(struct l2cap_chan *chan) -{ -	struct hci_conn *hs_hcon = chan->hs_hcon; -	struct hci_cp_create_accept_logical_link cp; -	struct hci_dev *hdev; - -	BT_DBG("chan %p hs_hcon %p dst %pMR", chan, hs_hcon, -	       &chan->conn->hcon->dst); - -	if (!hs_hcon) -		return; - -	hdev = hci_dev_hold(chan->hs_hcon->hdev); -	if (!hdev) -		return; - -	cp.phy_handle = hs_hcon->handle; - -	cp.tx_flow_spec.id = chan->local_id; -	cp.tx_flow_spec.stype = chan->local_stype; -	cp.tx_flow_spec.msdu = cpu_to_le16(chan->local_msdu); -	cp.tx_flow_spec.sdu_itime = cpu_to_le32(chan->local_sdu_itime); -	cp.tx_flow_spec.acc_lat = cpu_to_le32(chan->local_acc_lat); -	cp.tx_flow_spec.flush_to = cpu_to_le32(chan->local_flush_to); - -	cp.rx_flow_spec.id = chan->remote_id; -	cp.rx_flow_spec.stype = chan->remote_stype; -	cp.rx_flow_spec.msdu = cpu_to_le16(chan->remote_msdu); -	cp.rx_flow_spec.sdu_itime = cpu_to_le32(chan->remote_sdu_itime); -	cp.rx_flow_spec.acc_lat = cpu_to_le32(chan->remote_acc_lat); -	cp.rx_flow_spec.flush_to = cpu_to_le32(chan->remote_flush_to); - -	if (hs_hcon->out) -		hci_send_cmd(hdev, HCI_OP_CREATE_LOGICAL_LINK, sizeof(cp), -			     &cp); -	else -		hci_send_cmd(hdev, HCI_OP_ACCEPT_LOGICAL_LINK, sizeof(cp), -			     &cp); - -	hci_dev_put(hdev); -} - -void amp_disconnect_logical_link(struct hci_chan *hchan) -{ -	struct hci_conn *hcon = hchan->conn; -	struct hci_cp_disconn_logical_link cp; - -	if (hcon->state != BT_CONNECTED) { -		BT_DBG("hchan %p not connected", hchan); -		return; -	} - -	cp.log_handle = cpu_to_le16(hchan->handle); -	hci_send_cmd(hcon->hdev, HCI_OP_DISCONN_LOGICAL_LINK, sizeof(cp), &cp); -} - -void amp_destroy_logical_link(struct hci_chan *hchan, u8 reason) -{ -	BT_DBG("hchan %p", hchan); - -	hci_chan_del(hchan); -} diff --git a/net/bluetooth/amp.h b/net/bluetooth/amp.h deleted file mode 100644 index 97c87abd129f..000000000000 --- a/net/bluetooth/amp.h +++ /dev/null @@ -1,60 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* -   Copyright (c) 2011,2012 Intel Corp. - -*/ - -#ifndef __AMP_H -#define __AMP_H - -struct amp_ctrl { -	struct list_head	list; -	struct kref		kref; -	__u8			id; -	__u16			assoc_len_so_far; -	__u16			assoc_rem_len; -	__u16			assoc_len; -	__u8			*assoc; -}; - -int amp_ctrl_put(struct amp_ctrl *ctrl); -void amp_ctrl_get(struct amp_ctrl *ctrl); -struct amp_ctrl *amp_ctrl_add(struct amp_mgr *mgr, u8 id); -struct amp_ctrl *amp_ctrl_lookup(struct amp_mgr *mgr, u8 id); -void amp_ctrl_list_flush(struct amp_mgr *mgr); - -struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr, -			     u8 remote_id, bool out); - -int phylink_gen_key(struct hci_conn *hcon, u8 *data, u8 *len, u8 *type); - -void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle); -void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr); -void amp_read_loc_assoc_final_data(struct hci_dev *hdev, -				   struct hci_conn *hcon); -void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, -			struct hci_conn *hcon); -void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, -			struct hci_conn *hcon); - -#if IS_ENABLED(CONFIG_BT_HS) -void amp_create_logical_link(struct l2cap_chan *chan); -void amp_disconnect_logical_link(struct hci_chan *hchan); -#else -static inline void amp_create_logical_link(struct l2cap_chan *chan) -{ -} - -static inline void amp_disconnect_logical_link(struct hci_chan *hchan) -{ -} -#endif - -void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle); -void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle); -void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon); -void amp_create_logical_link(struct l2cap_chan *chan); -void amp_disconnect_logical_link(struct hci_chan *hchan); -void amp_destroy_logical_link(struct hci_chan *hchan, u8 reason); - -#endif /* __AMP_H */ diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index 5a6a49885ab6..ec45f77fce21 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -385,7 +385,8 @@ static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)  	case BNEP_COMPRESSED_DST_ONLY:  		__skb_put_data(nskb, skb_mac_header(skb), ETH_ALEN); -		__skb_put_data(nskb, s->eh.h_source, ETH_ALEN + 2); +		__skb_put_data(nskb, s->eh.h_source, ETH_ALEN); +		put_unaligned(s->eh.h_proto, (__be16 *)__skb_put(nskb, 2));  		break;  	case BNEP_GENERAL: @@ -549,7 +550,7 @@ static struct device *bnep_get_device(struct bnep_session *session)  	return &conn->hcon->dev;  } -static struct device_type bnep_type = { +static const struct device_type bnep_type = {  	.name	= "bluetooth",  }; diff --git a/net/bluetooth/eir.c b/net/bluetooth/eir.c index 9214189279e8..1bc51e2b05a3 100644 --- a/net/bluetooth/eir.c +++ b/net/bluetooth/eir.c @@ -13,48 +13,33 @@  #define PNP_INFO_SVCLASS_ID		0x1200 -static u8 eir_append_name(u8 *eir, u16 eir_len, u8 type, u8 *data, u8 data_len) -{ -	u8 name[HCI_MAX_SHORT_NAME_LENGTH + 1]; - -	/* If data is already NULL terminated just pass it directly */ -	if (data[data_len - 1] == '\0') -		return eir_append_data(eir, eir_len, type, data, data_len); - -	memcpy(name, data, HCI_MAX_SHORT_NAME_LENGTH); -	name[HCI_MAX_SHORT_NAME_LENGTH] = '\0'; - -	return eir_append_data(eir, eir_len, type, name, sizeof(name)); -} -  u8 eir_append_local_name(struct hci_dev *hdev, u8 *ptr, u8 ad_len)  {  	size_t short_len;  	size_t complete_len; -	/* no space left for name (+ NULL + type + len) */ -	if ((max_adv_len(hdev) - ad_len) < HCI_MAX_SHORT_NAME_LENGTH + 3) +	/* no space left for name (+ type + len) */ +	if ((max_adv_len(hdev) - ad_len) < HCI_MAX_SHORT_NAME_LENGTH + 2)  		return ad_len;  	/* use complete name if present and fits */  	complete_len = strnlen(hdev->dev_name, sizeof(hdev->dev_name));  	if (complete_len && complete_len <= HCI_MAX_SHORT_NAME_LENGTH) -		return eir_append_name(ptr, ad_len, EIR_NAME_COMPLETE, -				       hdev->dev_name, complete_len + 1); +		return eir_append_data(ptr, ad_len, EIR_NAME_COMPLETE, +				       hdev->dev_name, complete_len);  	/* use short name if present */  	short_len = strnlen(hdev->short_name, sizeof(hdev->short_name));  	if (short_len) -		return eir_append_name(ptr, ad_len, EIR_NAME_SHORT, +		return eir_append_data(ptr, ad_len, EIR_NAME_SHORT,  				       hdev->short_name, -				       short_len == HCI_MAX_SHORT_NAME_LENGTH ? -				       short_len : short_len + 1); +				       short_len);  	/* use shortened full name if present, we already know that name  	 * is longer then HCI_MAX_SHORT_NAME_LENGTH  	 */  	if (complete_len) -		return eir_append_name(ptr, ad_len, EIR_NAME_SHORT, +		return eir_append_data(ptr, ad_len, EIR_NAME_SHORT,  				       hdev->dev_name,  				       HCI_MAX_SHORT_NAME_LENGTH); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index a41d2693f4d8..3ad74f76983b 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -1,7 +1,7 @@  /*     BlueZ - Bluetooth protocol stack for Linux     Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved. -   Copyright 2023 NXP +   Copyright 2023-2024 NXP     Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> @@ -36,7 +36,6 @@  #include "hci_request.h"  #include "smp.h" -#include "a2mp.h"  #include "eir.h"  struct sco_param { @@ -69,7 +68,7 @@ static const struct sco_param esco_param_msbc[] = {  };  /* This function requires the caller holds hdev->lock */ -static void hci_connect_le_scan_cleanup(struct hci_conn *conn, u8 status) +void hci_connect_le_scan_cleanup(struct hci_conn *conn, u8 status)  {  	struct hci_conn_params *params;  	struct hci_dev *hdev = conn->hdev; @@ -179,64 +178,6 @@ static void hci_conn_cleanup(struct hci_conn *conn)  	hci_dev_put(hdev);  } -static void hci_acl_create_connection(struct hci_conn *conn) -{ -	struct hci_dev *hdev = conn->hdev; -	struct inquiry_entry *ie; -	struct hci_cp_create_conn cp; - -	BT_DBG("hcon %p", conn); - -	/* Many controllers disallow HCI Create Connection while it is doing -	 * HCI Inquiry. So we cancel the Inquiry first before issuing HCI Create -	 * Connection. This may cause the MGMT discovering state to become false -	 * without user space's request but it is okay since the MGMT Discovery -	 * APIs do not promise that discovery should be done forever. Instead, -	 * the user space monitors the status of MGMT discovering and it may -	 * request for discovery again when this flag becomes false. -	 */ -	if (test_bit(HCI_INQUIRY, &hdev->flags)) { -		/* Put this connection to "pending" state so that it will be -		 * executed after the inquiry cancel command complete event. -		 */ -		conn->state = BT_CONNECT2; -		hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL); -		return; -	} - -	conn->state = BT_CONNECT; -	conn->out = true; -	conn->role = HCI_ROLE_MASTER; - -	conn->attempt++; - -	conn->link_policy = hdev->link_policy; - -	memset(&cp, 0, sizeof(cp)); -	bacpy(&cp.bdaddr, &conn->dst); -	cp.pscan_rep_mode = 0x02; - -	ie = hci_inquiry_cache_lookup(hdev, &conn->dst); -	if (ie) { -		if (inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) { -			cp.pscan_rep_mode = ie->data.pscan_rep_mode; -			cp.pscan_mode     = ie->data.pscan_mode; -			cp.clock_offset   = ie->data.clock_offset | -					    cpu_to_le16(0x8000); -		} - -		memcpy(conn->dev_class, ie->data.dev_class, 3); -	} - -	cp.pkt_type = cpu_to_le16(conn->pkt_type); -	if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER)) -		cp.role_switch = 0x01; -	else -		cp.role_switch = 0x00; - -	hci_send_cmd(hdev, HCI_OP_CREATE_CONN, sizeof(cp), &cp); -} -  int hci_disconnect(struct hci_conn *conn, __u8 reason)  {  	BT_DBG("hcon %p", conn); @@ -1175,9 +1116,6 @@ void hci_conn_del(struct hci_conn *conn)  		}  	} -	if (conn->amp_mgr) -		amp_mgr_put(conn->amp_mgr); -  	skb_queue_purge(&conn->data_q);  	/* Remove the connection from the list and cleanup its remaining @@ -1186,6 +1124,9 @@ void hci_conn_del(struct hci_conn *conn)  	 * rest of hci_conn_del.  	 */  	hci_conn_cleanup(conn); + +	/* Dequeue callbacks using connection pointer as data */ +	hci_cmd_sync_dequeue(hdev, NULL, conn, NULL);  }  struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src, uint8_t src_type) @@ -1320,53 +1261,6 @@ u8 hci_conn_set_handle(struct hci_conn *conn, u16 handle)  	return 0;  } -static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err) -{ -	struct hci_conn *conn; -	u16 handle = PTR_UINT(data); - -	conn = hci_conn_hash_lookup_handle(hdev, handle); -	if (!conn) -		return; - -	bt_dev_dbg(hdev, "err %d", err); - -	hci_dev_lock(hdev); - -	if (!err) { -		hci_connect_le_scan_cleanup(conn, 0x00); -		goto done; -	} - -	/* Check if connection is still pending */ -	if (conn != hci_lookup_le_connect(hdev)) -		goto done; - -	/* Flush to make sure we send create conn cancel command if needed */ -	flush_delayed_work(&conn->le_conn_timeout); -	hci_conn_failed(conn, bt_status(err)); - -done: -	hci_dev_unlock(hdev); -} - -static int hci_connect_le_sync(struct hci_dev *hdev, void *data) -{ -	struct hci_conn *conn; -	u16 handle = PTR_UINT(data); - -	conn = hci_conn_hash_lookup_handle(hdev, handle); -	if (!conn) -		return 0; - -	bt_dev_dbg(hdev, "conn %p", conn); - -	clear_bit(HCI_CONN_SCANNING, &conn->flags); -	conn->state = BT_CONNECT; - -	return hci_le_create_conn_sync(hdev, conn); -} -  struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,  				u8 dst_type, bool dst_resolved, u8 sec_level,  				u16 conn_timeout, u8 role) @@ -1433,9 +1327,7 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,  	conn->sec_level = BT_SECURITY_LOW;  	conn->conn_timeout = conn_timeout; -	err = hci_cmd_sync_queue(hdev, hci_connect_le_sync, -				 UINT_PTR(conn->handle), -				 create_le_conn_complete); +	err = hci_connect_le_sync(hdev, conn);  	if (err) {  		hci_conn_del(conn);  		return ERR_PTR(err); @@ -1669,7 +1561,7 @@ done:  struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,  				 u8 sec_level, u8 auth_type, -				 enum conn_reasons conn_reason) +				 enum conn_reasons conn_reason, u16 timeout)  {  	struct hci_conn *acl; @@ -1700,10 +1592,18 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,  	acl->conn_reason = conn_reason;  	if (acl->state == BT_OPEN || acl->state == BT_CLOSED) { +		int err; +  		acl->sec_level = BT_SECURITY_LOW;  		acl->pending_sec_level = sec_level;  		acl->auth_type = auth_type; -		hci_acl_create_connection(acl); +		acl->conn_timeout = timeout; + +		err = hci_connect_acl_sync(hdev, acl); +		if (err) { +			hci_conn_del(acl); +			return ERR_PTR(err); +		}  	}  	return acl; @@ -1738,14 +1638,15 @@ static struct hci_link *hci_conn_link(struct hci_conn *parent,  }  struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, -				 __u16 setting, struct bt_codec *codec) +				 __u16 setting, struct bt_codec *codec, +				 u16 timeout)  {  	struct hci_conn *acl;  	struct hci_conn *sco;  	struct hci_link *link;  	acl = hci_connect_acl(hdev, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING, -			      CONN_REASON_SCO_CONNECT); +			      CONN_REASON_SCO_CONNECT, timeout);  	if (IS_ERR(acl))  		return acl; @@ -2156,18 +2057,31 @@ static int create_pa_sync(struct hci_dev *hdev, void *data)  	return hci_update_passive_scan_sync(hdev);  } -int hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type, -		       __u8 sid, struct bt_iso_qos *qos) +struct hci_conn *hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst, +				    __u8 dst_type, __u8 sid, +				    struct bt_iso_qos *qos)  {  	struct hci_cp_le_pa_create_sync *cp; +	struct hci_conn *conn; +	int err;  	if (hci_dev_test_and_set_flag(hdev, HCI_PA_SYNC)) -		return -EBUSY; +		return ERR_PTR(-EBUSY); + +	conn = hci_conn_add_unset(hdev, ISO_LINK, dst, HCI_ROLE_SLAVE); +	if (!conn) +		return ERR_PTR(-ENOMEM); + +	conn->iso_qos = *qos; +	conn->state = BT_LISTEN; + +	hci_conn_hold(conn);  	cp = kzalloc(sizeof(*cp), GFP_KERNEL);  	if (!cp) {  		hci_dev_clear_flag(hdev, HCI_PA_SYNC); -		return -ENOMEM; +		hci_conn_drop(conn); +		return ERR_PTR(-ENOMEM);  	}  	cp->options = qos->bcast.options; @@ -2179,7 +2093,14 @@ int hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type,  	cp->sync_cte_type = qos->bcast.sync_cte_type;  	/* Queue start pa_create_sync and scan */ -	return hci_cmd_sync_queue(hdev, create_pa_sync, cp, create_pa_complete); +	err = hci_cmd_sync_queue(hdev, create_pa_sync, cp, create_pa_complete); +	if (err < 0) { +		hci_conn_drop(conn); +		kfree(cp); +		return ERR_PTR(err); +	} + +	return conn;  }  int hci_le_big_create_sync(struct hci_dev *hdev, struct hci_conn *hcon, @@ -2647,22 +2568,6 @@ void hci_conn_hash_flush(struct hci_dev *hdev)  	}  } -/* Check pending connect attempts */ -void hci_conn_check_pending(struct hci_dev *hdev) -{ -	struct hci_conn *conn; - -	BT_DBG("hdev %s", hdev->name); - -	hci_dev_lock(hdev); - -	conn = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2); -	if (conn) -		hci_acl_create_connection(conn); - -	hci_dev_unlock(hdev); -} -  static u32 get_link_mode(struct hci_conn *conn)  {  	u32 link_mode = 0; @@ -2978,12 +2883,10 @@ u32 hci_conn_get_phy(struct hci_conn *conn)  static int abort_conn_sync(struct hci_dev *hdev, void *data)  { -	struct hci_conn *conn; -	u16 handle = PTR_UINT(data); +	struct hci_conn *conn = data; -	conn = hci_conn_hash_lookup_handle(hdev, handle); -	if (!conn) -		return 0; +	if (!hci_conn_valid(hdev, conn)) +		return -ECANCELED;  	return hci_abort_conn_sync(hdev, conn, conn->abort_reason);  } @@ -3011,14 +2914,17 @@ int hci_abort_conn(struct hci_conn *conn, u8 reason)  	 */  	if (conn->state == BT_CONNECT && hdev->req_status == HCI_REQ_PEND) {  		switch (hci_skb_event(hdev->sent_cmd)) { +		case HCI_EV_CONN_COMPLETE:  		case HCI_EV_LE_CONN_COMPLETE:  		case HCI_EV_LE_ENHANCED_CONN_COMPLETE:  		case HCI_EVT_LE_CIS_ESTABLISHED: -			hci_cmd_sync_cancel(hdev, -ECANCELED); +			hci_cmd_sync_cancel(hdev, ECANCELED);  			break;  		} +	/* Cancel connect attempt if still queued/pending */ +	} else if (!hci_cancel_connect_sync(hdev, conn)) { +		return 0;  	} -	return hci_cmd_sync_queue(hdev, abort_conn_sync, UINT_PTR(conn->handle), -				  NULL); +	return hci_cmd_sync_queue_once(hdev, abort_conn_sync, conn, NULL);  } diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 2821a42cefdc..1690ae57a09d 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -908,7 +908,7 @@ int hci_get_dev_info(void __user *arg)  	else  		flags = hdev->flags; -	strcpy(di.name, hdev->name); +	strscpy(di.name, hdev->name, sizeof(di.name));  	di.bdaddr   = hdev->bdaddr;  	di.type     = (hdev->bus & 0x0f) | ((hdev->dev_type & 0x03) << 4);  	di.flags    = flags; @@ -940,20 +940,51 @@ int hci_get_dev_info(void __user *arg)  /* ---- Interface to HCI drivers ---- */ +static int hci_dev_do_poweroff(struct hci_dev *hdev) +{ +	int err; + +	BT_DBG("%s %p", hdev->name, hdev); + +	hci_req_sync_lock(hdev); + +	err = hci_set_powered_sync(hdev, false); + +	hci_req_sync_unlock(hdev); + +	return err; +} +  static int hci_rfkill_set_block(void *data, bool blocked)  {  	struct hci_dev *hdev = data; +	int err;  	BT_DBG("%p name %s blocked %d", hdev, hdev->name, blocked);  	if (hci_dev_test_flag(hdev, HCI_USER_CHANNEL))  		return -EBUSY; +	if (blocked == hci_dev_test_flag(hdev, HCI_RFKILLED)) +		return 0; +  	if (blocked) {  		hci_dev_set_flag(hdev, HCI_RFKILLED); +  		if (!hci_dev_test_flag(hdev, HCI_SETUP) && -		    !hci_dev_test_flag(hdev, HCI_CONFIG)) -			hci_dev_do_close(hdev); +		    !hci_dev_test_flag(hdev, HCI_CONFIG)) { +			err = hci_dev_do_poweroff(hdev); +			if (err) { +				bt_dev_err(hdev, "Error when powering off device on rfkill (%d)", +					   err); + +				/* Make sure the device is still closed even if +				 * anything during power off sequence (eg. +				 * disconnecting devices) failed. +				 */ +				hci_dev_do_close(hdev); +			} +		}  	} else {  		hci_dev_clear_flag(hdev, HCI_RFKILLED);  	} @@ -1491,11 +1522,12 @@ static void hci_cmd_timeout(struct work_struct *work)  	struct hci_dev *hdev = container_of(work, struct hci_dev,  					    cmd_timer.work); -	if (hdev->sent_cmd) { -		struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data; -		u16 opcode = __le16_to_cpu(sent->opcode); +	if (hdev->req_skb) { +		u16 opcode = hci_skb_opcode(hdev->req_skb);  		bt_dev_err(hdev, "command 0x%4.4x tx timeout", opcode); + +		hci_cmd_sync_cancel_sync(hdev, ETIMEDOUT);  	} else {  		bt_dev_err(hdev, "command tx timeout");  	} @@ -2608,10 +2640,11 @@ int hci_register_dev(struct hci_dev *hdev)  	 */  	switch (hdev->dev_type) {  	case HCI_PRIMARY: -		id = ida_simple_get(&hci_index_ida, 0, HCI_MAX_ID, GFP_KERNEL); +		id = ida_alloc_max(&hci_index_ida, HCI_MAX_ID - 1, GFP_KERNEL);  		break;  	case HCI_AMP: -		id = ida_simple_get(&hci_index_ida, 1, HCI_MAX_ID, GFP_KERNEL); +		id = ida_alloc_range(&hci_index_ida, 1, HCI_MAX_ID - 1, +				     GFP_KERNEL);  		break;  	default:  		return -EINVAL; @@ -2710,7 +2743,7 @@ err_wqueue:  	destroy_workqueue(hdev->workqueue);  	destroy_workqueue(hdev->req_workqueue);  err: -	ida_simple_remove(&hci_index_ida, hdev->id); +	ida_free(&hci_index_ida, hdev->id);  	return error;  } @@ -2793,8 +2826,9 @@ void hci_release_dev(struct hci_dev *hdev)  	hci_dev_unlock(hdev);  	ida_destroy(&hdev->unset_handle_ida); -	ida_simple_remove(&hci_index_ida, hdev->id); +	ida_free(&hci_index_ida, hdev->id);  	kfree_skb(hdev->sent_cmd); +	kfree_skb(hdev->req_skb);  	kfree_skb(hdev->recv_event);  	kfree(hdev);  } @@ -2826,6 +2860,23 @@ int hci_unregister_suspend_notifier(struct hci_dev *hdev)  	return ret;  } +/* Cancel ongoing command synchronously: + * + * - Cancel command timer + * - Reset command counter + * - Cancel command request + */ +static void hci_cancel_cmd_sync(struct hci_dev *hdev, int err) +{ +	bt_dev_dbg(hdev, "err 0x%2.2x", err); + +	cancel_delayed_work_sync(&hdev->cmd_timer); +	cancel_delayed_work_sync(&hdev->ncmd_timer); +	atomic_set(&hdev->cmd_cnt, 1); + +	hci_cmd_sync_cancel_sync(hdev, -err); +} +  /* Suspend HCI device */  int hci_suspend_dev(struct hci_dev *hdev)  { @@ -2843,7 +2894,7 @@ int hci_suspend_dev(struct hci_dev *hdev)  		return 0;  	/* Cancel potentially blocking sync operation before suspend */ -	__hci_cmd_sync_cancel(hdev, -EHOSTDOWN); +	hci_cancel_cmd_sync(hdev, -EHOSTDOWN);  	hci_req_sync_lock(hdev);  	ret = hci_suspend_sync(hdev); @@ -3107,21 +3158,33 @@ int __hci_cmd_send(struct hci_dev *hdev, u16 opcode, u32 plen,  EXPORT_SYMBOL(__hci_cmd_send);  /* Get data from the previously sent command */ -void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode) +static void *hci_cmd_data(struct sk_buff *skb, __u16 opcode)  {  	struct hci_command_hdr *hdr; -	if (!hdev->sent_cmd) +	if (!skb || skb->len < HCI_COMMAND_HDR_SIZE)  		return NULL; -	hdr = (void *) hdev->sent_cmd->data; +	hdr = (void *)skb->data;  	if (hdr->opcode != cpu_to_le16(opcode))  		return NULL; -	BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode); +	return skb->data + HCI_COMMAND_HDR_SIZE; +} -	return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE; +/* Get data from the previously sent command */ +void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode) +{ +	void *data; + +	/* Check if opcode matches last sent command */ +	data = hci_cmd_data(hdev->sent_cmd, opcode); +	if (!data) +		/* Check if opcode matches last request */ +		data = hci_cmd_data(hdev->req_skb, opcode); + +	return data;  }  /* Get data from last received event */ @@ -4022,17 +4085,19 @@ void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status,  	if (!status && !hci_req_is_complete(hdev))  		return; +	skb = hdev->req_skb; +  	/* If this was the last command in a request the complete -	 * callback would be found in hdev->sent_cmd instead of the +	 * callback would be found in hdev->req_skb instead of the  	 * command queue (hdev->cmd_q).  	 */ -	if (bt_cb(hdev->sent_cmd)->hci.req_flags & HCI_REQ_SKB) { -		*req_complete_skb = bt_cb(hdev->sent_cmd)->hci.req_complete_skb; +	if (skb && bt_cb(skb)->hci.req_flags & HCI_REQ_SKB) { +		*req_complete_skb = bt_cb(skb)->hci.req_complete_skb;  		return;  	} -	if (bt_cb(hdev->sent_cmd)->hci.req_complete) { -		*req_complete = bt_cb(hdev->sent_cmd)->hci.req_complete; +	if (skb && bt_cb(skb)->hci.req_complete) { +		*req_complete = bt_cb(skb)->hci.req_complete;  		return;  	} @@ -4128,6 +4193,36 @@ static void hci_rx_work(struct work_struct *work)  	}  } +static void hci_send_cmd_sync(struct hci_dev *hdev, struct sk_buff *skb) +{ +	int err; + +	bt_dev_dbg(hdev, "skb %p", skb); + +	kfree_skb(hdev->sent_cmd); + +	hdev->sent_cmd = skb_clone(skb, GFP_KERNEL); +	if (!hdev->sent_cmd) { +		skb_queue_head(&hdev->cmd_q, skb); +		queue_work(hdev->workqueue, &hdev->cmd_work); +		return; +	} + +	err = hci_send_frame(hdev, skb); +	if (err < 0) { +		hci_cmd_sync_cancel_sync(hdev, err); +		return; +	} + +	if (hci_req_status_pend(hdev) && +	    !hci_dev_test_and_set_flag(hdev, HCI_CMD_PENDING)) { +		kfree_skb(hdev->req_skb); +		hdev->req_skb = skb_clone(hdev->sent_cmd, GFP_KERNEL); +	} + +	atomic_dec(&hdev->cmd_cnt); +} +  static void hci_cmd_work(struct work_struct *work)  {  	struct hci_dev *hdev = container_of(work, struct hci_dev, cmd_work); @@ -4142,30 +4237,15 @@ static void hci_cmd_work(struct work_struct *work)  		if (!skb)  			return; -		kfree_skb(hdev->sent_cmd); - -		hdev->sent_cmd = skb_clone(skb, GFP_KERNEL); -		if (hdev->sent_cmd) { -			int res; -			if (hci_req_status_pend(hdev)) -				hci_dev_set_flag(hdev, HCI_CMD_PENDING); -			atomic_dec(&hdev->cmd_cnt); +		hci_send_cmd_sync(hdev, skb); -			res = hci_send_frame(hdev, skb); -			if (res < 0) -				__hci_cmd_sync_cancel(hdev, -res); - -			rcu_read_lock(); -			if (test_bit(HCI_RESET, &hdev->flags) || -			    hci_dev_test_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE)) -				cancel_delayed_work(&hdev->cmd_timer); -			else -				queue_delayed_work(hdev->workqueue, &hdev->cmd_timer, -						   HCI_CMD_TIMEOUT); -			rcu_read_unlock(); -		} else { -			skb_queue_head(&hdev->cmd_q, skb); -			queue_work(hdev->workqueue, &hdev->cmd_work); -		} +		rcu_read_lock(); +		if (test_bit(HCI_RESET, &hdev->flags) || +		    hci_dev_test_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE)) +			cancel_delayed_work(&hdev->cmd_timer); +		else +			queue_delayed_work(hdev->workqueue, &hdev->cmd_timer, +					   HCI_CMD_TIMEOUT); +		rcu_read_unlock();  	}  } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 2a5f5a7d2412..4ae224824012 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -36,8 +36,6 @@  #include "hci_request.h"  #include "hci_debugfs.h"  #include "hci_codec.h" -#include "a2mp.h" -#include "amp.h"  #include "smp.h"  #include "msft.h"  #include "eir.h" @@ -95,11 +93,11 @@ static u8 hci_cc_inquiry_cancel(struct hci_dev *hdev, void *data,  	/* It is possible that we receive Inquiry Complete event right  	 * before we receive Inquiry Cancel Command Complete event, in  	 * which case the latter event should have status of Command -	 * Disallowed (0x0c). This should not be treated as error, since +	 * Disallowed. This should not be treated as error, since  	 * we actually achieve what Inquiry Cancel wants to achieve,  	 * which is to end the last Inquiry session.  	 */ -	if (rp->status == 0x0c && !test_bit(HCI_INQUIRY, &hdev->flags)) { +	if (rp->status == HCI_ERROR_COMMAND_DISALLOWED && !test_bit(HCI_INQUIRY, &hdev->flags)) {  		bt_dev_warn(hdev, "Ignoring error of Inquiry Cancel command");  		rp->status = 0x00;  	} @@ -120,8 +118,6 @@ static u8 hci_cc_inquiry_cancel(struct hci_dev *hdev, void *data,  		hci_discovery_set_state(hdev, DISCOVERY_STOPPED);  	hci_dev_unlock(hdev); -	hci_conn_check_pending(hdev); -  	return rp->status;  } @@ -152,8 +148,6 @@ static u8 hci_cc_exit_periodic_inq(struct hci_dev *hdev, void *data,  	hci_dev_clear_flag(hdev, HCI_PERIODIC_INQ); -	hci_conn_check_pending(hdev); -  	return rp->status;  } @@ -2314,10 +2308,8 @@ static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)  {  	bt_dev_dbg(hdev, "status 0x%2.2x", status); -	if (status) { -		hci_conn_check_pending(hdev); +	if (status)  		return; -	}  	if (hci_sent_cmd_data(hdev, HCI_OP_INQUIRY))  		set_bit(HCI_INQUIRY, &hdev->flags); @@ -2342,12 +2334,9 @@ static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)  	if (status) {  		if (conn && conn->state == BT_CONNECT) { -			if (status != 0x0c || conn->attempt > 2) { -				conn->state = BT_CLOSED; -				hci_connect_cfm(conn, status); -				hci_conn_del(conn); -			} else -				conn->state = BT_CONNECT2; +			conn->state = BT_CLOSED; +			hci_connect_cfm(conn, status); +			hci_conn_del(conn);  		}  	} else {  		if (!conn) { @@ -2526,9 +2515,7 @@ static void hci_check_pending_name(struct hci_dev *hdev, struct hci_conn *conn,  	 * Only those in BT_CONFIG or BT_CONNECTED states can be  	 * considered connected.  	 */ -	if (conn && -	    (conn->state == BT_CONFIG || conn->state == BT_CONNECTED) && -	    !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) +	if (conn && (conn->state == BT_CONFIG || conn->state == BT_CONNECTED))  		mgmt_device_connected(hdev, conn, name, name_len);  	if (discov->state == DISCOVERY_STOPPED) @@ -3039,8 +3026,6 @@ static void hci_inquiry_complete_evt(struct hci_dev *hdev, void *data,  	bt_dev_dbg(hdev, "status 0x%2.2x", ev->status); -	hci_conn_check_pending(hdev); -  	if (!test_and_clear_bit(HCI_INQUIRY, &hdev->flags))  		return; @@ -3262,8 +3247,6 @@ done:  unlock:  	hci_dev_unlock(hdev); - -	hci_conn_check_pending(hdev);  }  static void hci_reject_conn(struct hci_dev *hdev, bdaddr_t *bdaddr) @@ -3556,8 +3539,6 @@ static void hci_remote_name_evt(struct hci_dev *hdev, void *data,  	bt_dev_dbg(hdev, "status 0x%2.2x", ev->status); -	hci_conn_check_pending(hdev); -  	hci_dev_lock(hdev);  	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); @@ -3660,7 +3641,8 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, void *data,  		 * controller really supports it. If it doesn't, assume  		 * the default size (16).  		 */ -		if (!(hdev->commands[20] & 0x10)) { +		if (!(hdev->commands[20] & 0x10) || +		    test_bit(HCI_QUIRK_BROKEN_READ_ENC_KEY_SIZE, &hdev->quirks)) {  			conn->enc_key_size = HCI_LINK_KEY_SIZE;  			goto notify;  		} @@ -3762,8 +3744,9 @@ static void hci_remote_features_evt(struct hci_dev *hdev, void *data,  		bacpy(&cp.bdaddr, &conn->dst);  		cp.pscan_rep_mode = 0x02;  		hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp); -	} else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) +	} else {  		mgmt_device_connected(hdev, conn, NULL, 0); +	}  	if (!hci_outgoing_auth_needed(hdev, conn)) {  		conn->state = BT_CONNECTED; @@ -3936,6 +3919,11 @@ static u8 hci_cc_le_setup_iso_path(struct hci_dev *hdev, void *data,  		 * last.  		 */  		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)) +			mgmt_device_connected(hdev, conn, NULL, 0); +  		break;  	} @@ -4381,7 +4369,7 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, void *data,  	 * (since for this kind of commands there will not be a command  	 * complete event).  	 */ -	if (ev->status || (hdev->sent_cmd && !hci_skb_event(hdev->sent_cmd))) { +	if (ev->status || (hdev->req_skb && !hci_skb_event(hdev->req_skb))) {  		hci_req_cmd_complete(hdev, *opcode, ev->status, req_complete,  				     req_complete_skb);  		if (hci_dev_test_flag(hdev, HCI_CMD_PENDING)) { @@ -5010,8 +4998,9 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev, void *data,  		bacpy(&cp.bdaddr, &conn->dst);  		cp.pscan_rep_mode = 0x02;  		hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp); -	} else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) +	} else {  		mgmt_device_connected(hdev, conn, NULL, 0); +	}  	if (!hci_outgoing_auth_needed(hdev, conn)) {  		conn->state = BT_CONNECTED; @@ -5675,150 +5664,6 @@ unlock:  	hci_dev_unlock(hdev);  } -#if IS_ENABLED(CONFIG_BT_HS) -static void hci_chan_selected_evt(struct hci_dev *hdev, void *data, -				  struct sk_buff *skb) -{ -	struct hci_ev_channel_selected *ev = data; -	struct hci_conn *hcon; - -	bt_dev_dbg(hdev, "handle 0x%2.2x", ev->phy_handle); - -	hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle); -	if (!hcon) -		return; - -	amp_read_loc_assoc_final_data(hdev, hcon); -} - -static void hci_phy_link_complete_evt(struct hci_dev *hdev, void *data, -				      struct sk_buff *skb) -{ -	struct hci_ev_phy_link_complete *ev = data; -	struct hci_conn *hcon, *bredr_hcon; - -	bt_dev_dbg(hdev, "handle 0x%2.2x status 0x%2.2x", ev->phy_handle, -		   ev->status); - -	hci_dev_lock(hdev); - -	hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle); -	if (!hcon) -		goto unlock; - -	if (!hcon->amp_mgr) -		goto unlock; - -	if (ev->status) { -		hci_conn_del(hcon); -		goto unlock; -	} - -	bredr_hcon = hcon->amp_mgr->l2cap_conn->hcon; - -	hcon->state = BT_CONNECTED; -	bacpy(&hcon->dst, &bredr_hcon->dst); - -	hci_conn_hold(hcon); -	hcon->disc_timeout = HCI_DISCONN_TIMEOUT; -	hci_conn_drop(hcon); - -	hci_debugfs_create_conn(hcon); -	hci_conn_add_sysfs(hcon); - -	amp_physical_cfm(bredr_hcon, hcon); - -unlock: -	hci_dev_unlock(hdev); -} - -static void hci_loglink_complete_evt(struct hci_dev *hdev, void *data, -				     struct sk_buff *skb) -{ -	struct hci_ev_logical_link_complete *ev = data; -	struct hci_conn *hcon; -	struct hci_chan *hchan; -	struct amp_mgr *mgr; - -	bt_dev_dbg(hdev, "log_handle 0x%4.4x phy_handle 0x%2.2x status 0x%2.2x", -		   le16_to_cpu(ev->handle), ev->phy_handle, ev->status); - -	hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle); -	if (!hcon) -		return; - -	/* Create AMP hchan */ -	hchan = hci_chan_create(hcon); -	if (!hchan) -		return; - -	hchan->handle = le16_to_cpu(ev->handle); -	hchan->amp = true; - -	BT_DBG("hcon %p mgr %p hchan %p", hcon, hcon->amp_mgr, hchan); - -	mgr = hcon->amp_mgr; -	if (mgr && mgr->bredr_chan) { -		struct l2cap_chan *bredr_chan = mgr->bredr_chan; - -		l2cap_chan_lock(bredr_chan); - -		bredr_chan->conn->mtu = hdev->block_mtu; -		l2cap_logical_cfm(bredr_chan, hchan, 0); -		hci_conn_hold(hcon); - -		l2cap_chan_unlock(bredr_chan); -	} -} - -static void hci_disconn_loglink_complete_evt(struct hci_dev *hdev, void *data, -					     struct sk_buff *skb) -{ -	struct hci_ev_disconn_logical_link_complete *ev = data; -	struct hci_chan *hchan; - -	bt_dev_dbg(hdev, "handle 0x%4.4x status 0x%2.2x", -		   le16_to_cpu(ev->handle), ev->status); - -	if (ev->status) -		return; - -	hci_dev_lock(hdev); - -	hchan = hci_chan_lookup_handle(hdev, le16_to_cpu(ev->handle)); -	if (!hchan || !hchan->amp) -		goto unlock; - -	amp_destroy_logical_link(hchan, ev->reason); - -unlock: -	hci_dev_unlock(hdev); -} - -static void hci_disconn_phylink_complete_evt(struct hci_dev *hdev, void *data, -					     struct sk_buff *skb) -{ -	struct hci_ev_disconn_phy_link_complete *ev = data; -	struct hci_conn *hcon; - -	bt_dev_dbg(hdev, "status 0x%2.2x", ev->status); - -	if (ev->status) -		return; - -	hci_dev_lock(hdev); - -	hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle); -	if (hcon && hcon->type == AMP_LINK) { -		hcon->state = BT_CLOSED; -		hci_disconn_cfm(hcon, ev->reason); -		hci_conn_del(hcon); -	} - -	hci_dev_unlock(hdev); -} -#endif -  static void le_conn_update_addr(struct hci_conn *conn, bdaddr_t *bdaddr,  				u8 bdaddr_type, bdaddr_t *local_rpa)  { @@ -5984,8 +5829,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,  		goto unlock;  	} -	if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) -		mgmt_device_connected(hdev, conn, NULL, 0); +	mgmt_device_connected(hdev, conn, NULL, 0);  	conn->sec_level = BT_SECURITY_LOW;  	conn->state = BT_CONFIG; @@ -6684,7 +6528,7 @@ static void hci_le_remote_feat_complete_evt(struct hci_dev *hdev, void *data,  			 * transition into connected state and mark it as  			 * successful.  			 */ -			if (!conn->out && ev->status == 0x1a && +			if (!conn->out && ev->status == HCI_ERROR_UNSUPPORTED_REMOTE_FEATURE &&  			    (hdev->le_features[0] & HCI_LE_PERIPHERAL_FEATURES))  				status = 0x00;  			else @@ -7214,6 +7058,9 @@ static void hci_le_big_info_adv_report_evt(struct hci_dev *hdev, void *data,  	/* Notify iso layer */  	hci_connect_cfm(pa_sync, 0x00); +	/* Notify MGMT layer */ +	mgmt_device_connected(hdev, pa_sync, NULL, 0); +  unlock:  	hci_dev_unlock(hdev);  } @@ -7324,10 +7171,10 @@ static void hci_le_meta_evt(struct hci_dev *hdev, void *data,  	bt_dev_dbg(hdev, "subevent 0x%2.2x", ev->subevent);  	/* Only match event if command OGF is for LE */ -	if (hdev->sent_cmd && -	    hci_opcode_ogf(hci_skb_opcode(hdev->sent_cmd)) == 0x08 && -	    hci_skb_event(hdev->sent_cmd) == ev->subevent) { -		*opcode = hci_skb_opcode(hdev->sent_cmd); +	if (hdev->req_skb && +	    hci_opcode_ogf(hci_skb_opcode(hdev->req_skb)) == 0x08 && +	    hci_skb_event(hdev->req_skb) == ev->subevent) { +		*opcode = hci_skb_opcode(hdev->req_skb);  		hci_req_cmd_complete(hdev, *opcode, 0x00, req_complete,  				     req_complete_skb);  	} @@ -7626,25 +7473,6 @@ static const struct hci_ev {  	/* [0x3e = HCI_EV_LE_META] */  	HCI_EV_REQ_VL(HCI_EV_LE_META, hci_le_meta_evt,  		      sizeof(struct hci_ev_le_meta), HCI_MAX_EVENT_SIZE), -#if IS_ENABLED(CONFIG_BT_HS) -	/* [0x40 = HCI_EV_PHY_LINK_COMPLETE] */ -	HCI_EV(HCI_EV_PHY_LINK_COMPLETE, hci_phy_link_complete_evt, -	       sizeof(struct hci_ev_phy_link_complete)), -	/* [0x41 = HCI_EV_CHANNEL_SELECTED] */ -	HCI_EV(HCI_EV_CHANNEL_SELECTED, hci_chan_selected_evt, -	       sizeof(struct hci_ev_channel_selected)), -	/* [0x42 = HCI_EV_DISCONN_PHY_LINK_COMPLETE] */ -	HCI_EV(HCI_EV_DISCONN_LOGICAL_LINK_COMPLETE, -	       hci_disconn_loglink_complete_evt, -	       sizeof(struct hci_ev_disconn_logical_link_complete)), -	/* [0x45 = HCI_EV_LOGICAL_LINK_COMPLETE] */ -	HCI_EV(HCI_EV_LOGICAL_LINK_COMPLETE, hci_loglink_complete_evt, -	       sizeof(struct hci_ev_logical_link_complete)), -	/* [0x46 = HCI_EV_DISCONN_LOGICAL_LINK_COMPLETE] */ -	HCI_EV(HCI_EV_DISCONN_PHY_LINK_COMPLETE, -	       hci_disconn_phylink_complete_evt, -	       sizeof(struct hci_ev_disconn_phy_link_complete)), -#endif  	/* [0x48 = HCI_EV_NUM_COMP_BLOCKS] */  	HCI_EV(HCI_EV_NUM_COMP_BLOCKS, hci_num_comp_blocks_evt,  	       sizeof(struct hci_ev_num_comp_blocks)), @@ -7714,10 +7542,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)  	}  	/* Only match event if command OGF is not for LE */ -	if (hdev->sent_cmd && -	    hci_opcode_ogf(hci_skb_opcode(hdev->sent_cmd)) != 0x08 && -	    hci_skb_event(hdev->sent_cmd) == event) { -		hci_req_cmd_complete(hdev, hci_skb_opcode(hdev->sent_cmd), +	if (hdev->req_skb && +	    hci_opcode_ogf(hci_skb_opcode(hdev->req_skb)) != 0x08 && +	    hci_skb_event(hdev->req_skb) == event) { +		hci_req_cmd_complete(hdev, hci_skb_opcode(hdev->req_skb),  				     status, &req_complete, &req_complete_skb);  		req_evt = event;  	} diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index 6e023b0104b0..00e02138003e 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -895,7 +895,7 @@ void hci_request_setup(struct hci_dev *hdev)  void hci_request_cancel_all(struct hci_dev *hdev)  { -	__hci_cmd_sync_cancel(hdev, ENODEV); +	hci_cmd_sync_cancel_sync(hdev, ENODEV);  	cancel_interleave_scan(hdev);  } diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 3e7cd330d731..4ee1b976678b 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -101,7 +101,7 @@ static bool hci_sock_gen_cookie(struct sock *sk)  	int id = hci_pi(sk)->cookie;  	if (!id) { -		id = ida_simple_get(&sock_cookie_ida, 1, 0, GFP_KERNEL); +		id = ida_alloc_min(&sock_cookie_ida, 1, GFP_KERNEL);  		if (id < 0)  			id = 0xffffffff; @@ -119,7 +119,7 @@ static void hci_sock_free_cookie(struct sock *sk)  	if (id) {  		hci_pi(sk)->cookie = 0xffffffff; -		ida_simple_remove(&sock_cookie_ida, id); +		ida_free(&sock_cookie_ida, id);  	}  } diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 5716345a26df..f6b662369322 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -32,6 +32,10 @@ static void hci_cmd_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode,  	hdev->req_result = result;  	hdev->req_status = HCI_REQ_DONE; +	/* Free the request command so it is not used as response */ +	kfree_skb(hdev->req_skb); +	hdev->req_skb = NULL; +  	if (skb) {  		struct sock *sk = hci_skb_sk(skb); @@ -39,7 +43,7 @@ static void hci_cmd_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode,  		if (sk)  			sock_put(sk); -		hdev->req_skb = skb_get(skb); +		hdev->req_rsp = skb_get(skb);  	}  	wake_up_interruptible(&hdev->req_wait_q); @@ -187,8 +191,8 @@ struct sk_buff *__hci_cmd_sync_sk(struct hci_dev *hdev, u16 opcode, u32 plen,  	hdev->req_status = 0;  	hdev->req_result = 0; -	skb = hdev->req_skb; -	hdev->req_skb = NULL; +	skb = hdev->req_rsp; +	hdev->req_rsp = NULL;  	bt_dev_dbg(hdev, "end: err %d", err); @@ -566,6 +570,17 @@ void hci_cmd_sync_init(struct hci_dev *hdev)  	INIT_DELAYED_WORK(&hdev->adv_instance_expire, adv_timeout_expire);  } +static void _hci_cmd_sync_cancel_entry(struct hci_dev *hdev, +				       struct hci_cmd_sync_work_entry *entry, +				       int err) +{ +	if (entry->destroy) +		entry->destroy(hdev, entry->data, err); + +	list_del(&entry->list); +	kfree(entry); +} +  void hci_cmd_sync_clear(struct hci_dev *hdev)  {  	struct hci_cmd_sync_work_entry *entry, *tmp; @@ -574,17 +589,12 @@ void hci_cmd_sync_clear(struct hci_dev *hdev)  	cancel_work_sync(&hdev->reenable_adv_work);  	mutex_lock(&hdev->cmd_sync_work_lock); -	list_for_each_entry_safe(entry, tmp, &hdev->cmd_sync_work_list, list) { -		if (entry->destroy) -			entry->destroy(hdev, entry->data, -ECANCELED); - -		list_del(&entry->list); -		kfree(entry); -	} +	list_for_each_entry_safe(entry, tmp, &hdev->cmd_sync_work_list, list) +		_hci_cmd_sync_cancel_entry(hdev, entry, -ECANCELED);  	mutex_unlock(&hdev->cmd_sync_work_lock);  } -void __hci_cmd_sync_cancel(struct hci_dev *hdev, int err) +void hci_cmd_sync_cancel(struct hci_dev *hdev, int err)  {  	bt_dev_dbg(hdev, "err 0x%2.2x", err); @@ -592,15 +602,17 @@ void __hci_cmd_sync_cancel(struct hci_dev *hdev, int err)  		hdev->req_result = err;  		hdev->req_status = HCI_REQ_CANCELED; -		cancel_delayed_work_sync(&hdev->cmd_timer); -		cancel_delayed_work_sync(&hdev->ncmd_timer); -		atomic_set(&hdev->cmd_cnt, 1); - -		wake_up_interruptible(&hdev->req_wait_q); +		queue_work(hdev->workqueue, &hdev->cmd_sync_cancel_work);  	}  } +EXPORT_SYMBOL(hci_cmd_sync_cancel); -void hci_cmd_sync_cancel(struct hci_dev *hdev, int err) +/* Cancel ongoing command request synchronously: + * + * - Set result and mark status to HCI_REQ_CANCELED + * - Wakeup command sync thread + */ +void hci_cmd_sync_cancel_sync(struct hci_dev *hdev, int err)  {  	bt_dev_dbg(hdev, "err 0x%2.2x", err); @@ -608,10 +620,10 @@ void hci_cmd_sync_cancel(struct hci_dev *hdev, int err)  		hdev->req_result = err;  		hdev->req_status = HCI_REQ_CANCELED; -		queue_work(hdev->workqueue, &hdev->cmd_sync_cancel_work); +		wake_up_interruptible(&hdev->req_wait_q);  	}  } -EXPORT_SYMBOL(hci_cmd_sync_cancel); +EXPORT_SYMBOL(hci_cmd_sync_cancel_sync);  /* Submit HCI command to be run in as cmd_sync_work:   * @@ -667,6 +679,115 @@ int hci_cmd_sync_queue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,  }  EXPORT_SYMBOL(hci_cmd_sync_queue); +static struct hci_cmd_sync_work_entry * +_hci_cmd_sync_lookup_entry(struct hci_dev *hdev, hci_cmd_sync_work_func_t func, +			   void *data, hci_cmd_sync_work_destroy_t destroy) +{ +	struct hci_cmd_sync_work_entry *entry, *tmp; + +	list_for_each_entry_safe(entry, tmp, &hdev->cmd_sync_work_list, list) { +		if (func && entry->func != func) +			continue; + +		if (data && entry->data != data) +			continue; + +		if (destroy && entry->destroy != destroy) +			continue; + +		return entry; +	} + +	return NULL; +} + +/* Queue HCI command entry once: + * + * - Lookup if an entry already exist and only if it doesn't creates a new entry + *   and queue it. + */ +int hci_cmd_sync_queue_once(struct hci_dev *hdev, hci_cmd_sync_work_func_t func, +			    void *data, hci_cmd_sync_work_destroy_t destroy) +{ +	if (hci_cmd_sync_lookup_entry(hdev, func, data, destroy)) +		return 0; + +	return hci_cmd_sync_queue(hdev, func, data, destroy); +} +EXPORT_SYMBOL(hci_cmd_sync_queue_once); + +/* Lookup HCI command entry: + * + * - Return first entry that matches by function callback or data or + *   destroy callback. + */ +struct hci_cmd_sync_work_entry * +hci_cmd_sync_lookup_entry(struct hci_dev *hdev, hci_cmd_sync_work_func_t func, +			  void *data, hci_cmd_sync_work_destroy_t destroy) +{ +	struct hci_cmd_sync_work_entry *entry; + +	mutex_lock(&hdev->cmd_sync_work_lock); +	entry = _hci_cmd_sync_lookup_entry(hdev, func, data, destroy); +	mutex_unlock(&hdev->cmd_sync_work_lock); + +	return entry; +} +EXPORT_SYMBOL(hci_cmd_sync_lookup_entry); + +/* Cancel HCI command entry */ +void hci_cmd_sync_cancel_entry(struct hci_dev *hdev, +			       struct hci_cmd_sync_work_entry *entry) +{ +	mutex_lock(&hdev->cmd_sync_work_lock); +	_hci_cmd_sync_cancel_entry(hdev, entry, -ECANCELED); +	mutex_unlock(&hdev->cmd_sync_work_lock); +} +EXPORT_SYMBOL(hci_cmd_sync_cancel_entry); + +/* Dequeue one HCI command entry: + * + * - Lookup and cancel first entry that matches. + */ +bool hci_cmd_sync_dequeue_once(struct hci_dev *hdev, +			       hci_cmd_sync_work_func_t func, +			       void *data, hci_cmd_sync_work_destroy_t destroy) +{ +	struct hci_cmd_sync_work_entry *entry; + +	entry = hci_cmd_sync_lookup_entry(hdev, func, data, destroy); +	if (!entry) +		return false; + +	hci_cmd_sync_cancel_entry(hdev, entry); + +	return true; +} +EXPORT_SYMBOL(hci_cmd_sync_dequeue_once); + +/* Dequeue HCI command entry: + * + * - Lookup and cancel any entry that matches by function callback or data or + *   destroy callback. + */ +bool hci_cmd_sync_dequeue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func, +			  void *data, hci_cmd_sync_work_destroy_t destroy) +{ +	struct hci_cmd_sync_work_entry *entry; +	bool ret = false; + +	mutex_lock(&hdev->cmd_sync_work_lock); +	while ((entry = _hci_cmd_sync_lookup_entry(hdev, func, data, +						   destroy))) { +		_hci_cmd_sync_cancel_entry(hdev, entry, -ECANCELED); +		ret = true; +	} +	mutex_unlock(&hdev->cmd_sync_work_lock); + +	return ret; +} +EXPORT_SYMBOL(hci_cmd_sync_dequeue); +  int hci_update_eir_sync(struct hci_dev *hdev)  {  	struct hci_cp_write_eir cp; @@ -2445,6 +2566,16 @@ static struct conn_params *conn_params_copy(struct list_head *list, size_t *n)  	return p;  } +/* Clear LE Accept List */ +static int hci_le_clear_accept_list_sync(struct hci_dev *hdev) +{ +	if (!(hdev->commands[26] & 0x80)) +		return 0; + +	return __hci_cmd_sync_status(hdev, HCI_OP_LE_CLEAR_ACCEPT_LIST, 0, NULL, +				     HCI_CMD_TIMEOUT); +} +  /* Device must not be scanning when updating the accept list.   *   * Update is done using the following sequence: @@ -2493,6 +2624,31 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)  		goto done;  	} +	/* Force address filtering if PA Sync is in progress */ +	if (hci_dev_test_flag(hdev, HCI_PA_SYNC)) { +		struct hci_cp_le_pa_create_sync *sent; + +		sent = hci_sent_cmd_data(hdev, HCI_OP_LE_PA_CREATE_SYNC); +		if (sent) { +			struct conn_params pa; + +			memset(&pa, 0, sizeof(pa)); + +			bacpy(&pa.addr, &sent->addr); +			pa.addr_type = sent->addr_type; + +			/* Clear first since there could be addresses left +			 * behind. +			 */ +			hci_le_clear_accept_list_sync(hdev); + +			num_entries = 1; +			err = hci_le_add_accept_list_sync(hdev, &pa, +							  &num_entries); +			goto done; +		} +	} +  	/* Go through the current accept list programmed into the  	 * controller one by one and check if that address is connected or is  	 * still in the list of pending connections or list of devices to @@ -2602,6 +2758,14 @@ done:  	return filter_policy;  } +static void hci_le_scan_phy_params(struct hci_cp_le_scan_phy_params *cp, +				   u8 type, u16 interval, u16 window) +{ +	cp->type = type; +	cp->interval = cpu_to_le16(interval); +	cp->window = cpu_to_le16(window); +} +  static int hci_le_set_ext_scan_param_sync(struct hci_dev *hdev, u8 type,  					  u16 interval, u16 window,  					  u8 own_addr_type, u8 filter_policy) @@ -2609,7 +2773,7 @@ static int hci_le_set_ext_scan_param_sync(struct hci_dev *hdev, u8 type,  	struct hci_cp_le_set_ext_scan_params *cp;  	struct hci_cp_le_scan_phy_params *phy;  	u8 data[sizeof(*cp) + sizeof(*phy) * 2]; -	u8 num_phy = 0; +	u8 num_phy = 0x00;  	cp = (void *)data;  	phy = (void *)cp->data; @@ -2619,28 +2783,64 @@ static int hci_le_set_ext_scan_param_sync(struct hci_dev *hdev, u8 type,  	cp->own_addr_type = own_addr_type;  	cp->filter_policy = filter_policy; +	/* Check if PA Sync is in progress then select the PHY based on the +	 * hci_conn.iso_qos. +	 */ +	if (hci_dev_test_flag(hdev, HCI_PA_SYNC)) { +		struct hci_cp_le_add_to_accept_list *sent; + +		sent = hci_sent_cmd_data(hdev, HCI_OP_LE_ADD_TO_ACCEPT_LIST); +		if (sent) { +			struct hci_conn *conn; + +			conn = hci_conn_hash_lookup_ba(hdev, ISO_LINK, +						       &sent->bdaddr); +			if (conn) { +				struct bt_iso_qos *qos = &conn->iso_qos; + +				if (qos->bcast.in.phy & BT_ISO_PHY_1M || +				    qos->bcast.in.phy & BT_ISO_PHY_2M) { +					cp->scanning_phys |= LE_SCAN_PHY_1M; +					hci_le_scan_phy_params(phy, type, +							       interval, +							       window); +					num_phy++; +					phy++; +				} + +				if (qos->bcast.in.phy & BT_ISO_PHY_CODED) { +					cp->scanning_phys |= LE_SCAN_PHY_CODED; +					hci_le_scan_phy_params(phy, type, +							       interval, +							       window); +					num_phy++; +					phy++; +				} + +				if (num_phy) +					goto done; +			} +		} +	} +  	if (scan_1m(hdev) || scan_2m(hdev)) {  		cp->scanning_phys |= LE_SCAN_PHY_1M; - -		phy->type = type; -		phy->interval = cpu_to_le16(interval); -		phy->window = cpu_to_le16(window); - +		hci_le_scan_phy_params(phy, type, interval, window);  		num_phy++;  		phy++;  	}  	if (scan_coded(hdev)) {  		cp->scanning_phys |= LE_SCAN_PHY_CODED; - -		phy->type = type; -		phy->interval = cpu_to_le16(interval); -		phy->window = cpu_to_le16(window); - +		hci_le_scan_phy_params(phy, type, interval, window);  		num_phy++;  		phy++;  	} +done: +	if (!num_phy) +		return -EINVAL; +  	return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_SCAN_PARAMS,  				     sizeof(*cp) + sizeof(*phy) * num_phy,  				     data, HCI_CMD_TIMEOUT); @@ -2879,7 +3079,8 @@ int hci_update_passive_scan(struct hci_dev *hdev)  	    hci_dev_test_flag(hdev, HCI_UNREGISTER))  		return 0; -	return hci_cmd_sync_queue(hdev, update_passive_scan_sync, NULL, NULL); +	return hci_cmd_sync_queue_once(hdev, update_passive_scan_sync, NULL, +				       NULL);  }  int hci_write_sc_support_sync(struct hci_dev *hdev, u8 val) @@ -4098,16 +4299,6 @@ static int hci_le_read_accept_list_size_sync(struct hci_dev *hdev)  				     0, NULL, HCI_CMD_TIMEOUT);  } -/* Clear LE Accept List */ -static int hci_le_clear_accept_list_sync(struct hci_dev *hdev) -{ -	if (!(hdev->commands[26] & 0x80)) -		return 0; - -	return __hci_cmd_sync_status(hdev, HCI_OP_LE_CLEAR_ACCEPT_LIST, 0, NULL, -				     HCI_CMD_TIMEOUT); -} -  /* Read LE Resolving List Size */  static int hci_le_read_resolv_list_size_sync(struct hci_dev *hdev)  { @@ -4834,6 +5025,11 @@ int hci_dev_open_sync(struct hci_dev *hdev)  			hdev->sent_cmd = NULL;  		} +		if (hdev->req_skb) { +			kfree_skb(hdev->req_skb); +			hdev->req_skb = NULL; +		} +  		clear_bit(HCI_RUNNING, &hdev->flags);  		hci_sock_dev_event(hdev, HCI_DEV_CLOSE); @@ -4994,6 +5190,12 @@ int hci_dev_close_sync(struct hci_dev *hdev)  		hdev->sent_cmd = NULL;  	} +	/* Drop last request */ +	if (hdev->req_skb) { +		kfree_skb(hdev->req_skb); +		hdev->req_skb = NULL; +	} +  	clear_bit(HCI_RUNNING, &hdev->flags);  	hci_sock_dev_event(hdev, HCI_DEV_CLOSE); @@ -5403,27 +5605,33 @@ static int hci_power_off_sync(struct hci_dev *hdev)  	if (!test_bit(HCI_UP, &hdev->flags))  		return 0; +	hci_dev_set_flag(hdev, HCI_POWERING_DOWN); +  	if (test_bit(HCI_ISCAN, &hdev->flags) ||  	    test_bit(HCI_PSCAN, &hdev->flags)) {  		err = hci_write_scan_enable_sync(hdev, 0x00);  		if (err) -			return err; +			goto out;  	}  	err = hci_clear_adv_sync(hdev, NULL, false);  	if (err) -		return err; +		goto out;  	err = hci_stop_discovery_sync(hdev);  	if (err) -		return err; +		goto out;  	/* Terminated due to Power Off */  	err = hci_disconnect_all_sync(hdev, HCI_ERROR_REMOTE_POWER_OFF);  	if (err) -		return err; +		goto out; + +	err = hci_dev_close_sync(hdev); -	return hci_dev_close_sync(hdev); +out: +	hci_dev_clear_flag(hdev, HCI_POWERING_DOWN); +	return err;  }  int hci_set_powered_sync(struct hci_dev *hdev, u8 val) @@ -6161,12 +6369,21 @@ static int hci_le_ext_create_conn_sync(struct hci_dev *hdev,  					conn->conn_timeout, NULL);  } -int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn) +static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)  {  	struct hci_cp_le_create_conn cp;  	struct hci_conn_params *params;  	u8 own_addr_type;  	int err; +	struct hci_conn *conn = data; + +	if (!hci_conn_valid(hdev, conn)) +		return -ECANCELED; + +	bt_dev_dbg(hdev, "conn %p", conn); + +	clear_bit(HCI_CONN_SCANNING, &conn->flags); +	conn->state = BT_CONNECT;  	/* If requested to connect as peripheral use directed advertising */  	if (conn->role == HCI_ROLE_SLAVE) { @@ -6484,3 +6701,125 @@ int hci_update_adv_data(struct hci_dev *hdev, u8 instance)  	return hci_cmd_sync_queue(hdev, _update_adv_data_sync,  				  UINT_PTR(instance), NULL);  } + +static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data) +{ +	struct hci_conn *conn = data; +	struct inquiry_entry *ie; +	struct hci_cp_create_conn cp; +	int err; + +	if (!hci_conn_valid(hdev, conn)) +		return -ECANCELED; + +	/* Many controllers disallow HCI Create Connection while it is doing +	 * HCI Inquiry. So we cancel the Inquiry first before issuing HCI Create +	 * Connection. This may cause the MGMT discovering state to become false +	 * without user space's request but it is okay since the MGMT Discovery +	 * APIs do not promise that discovery should be done forever. Instead, +	 * the user space monitors the status of MGMT discovering and it may +	 * request for discovery again when this flag becomes false. +	 */ +	if (test_bit(HCI_INQUIRY, &hdev->flags)) { +		err = __hci_cmd_sync_status(hdev, HCI_OP_INQUIRY_CANCEL, 0, +					    NULL, HCI_CMD_TIMEOUT); +		if (err) +			bt_dev_warn(hdev, "Failed to cancel inquiry %d", err); +	} + +	conn->state = BT_CONNECT; +	conn->out = true; +	conn->role = HCI_ROLE_MASTER; + +	conn->attempt++; + +	conn->link_policy = hdev->link_policy; + +	memset(&cp, 0, sizeof(cp)); +	bacpy(&cp.bdaddr, &conn->dst); +	cp.pscan_rep_mode = 0x02; + +	ie = hci_inquiry_cache_lookup(hdev, &conn->dst); +	if (ie) { +		if (inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) { +			cp.pscan_rep_mode = ie->data.pscan_rep_mode; +			cp.pscan_mode     = ie->data.pscan_mode; +			cp.clock_offset   = ie->data.clock_offset | +					    cpu_to_le16(0x8000); +		} + +		memcpy(conn->dev_class, ie->data.dev_class, 3); +	} + +	cp.pkt_type = cpu_to_le16(conn->pkt_type); +	if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER)) +		cp.role_switch = 0x01; +	else +		cp.role_switch = 0x00; + +	return __hci_cmd_sync_status_sk(hdev, HCI_OP_CREATE_CONN, +					sizeof(cp), &cp, +					HCI_EV_CONN_COMPLETE, +					conn->conn_timeout, NULL); +} + +int hci_connect_acl_sync(struct hci_dev *hdev, struct hci_conn *conn) +{ +	return hci_cmd_sync_queue_once(hdev, hci_acl_create_conn_sync, conn, +				       NULL); +} + +static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err) +{ +	struct hci_conn *conn = data; + +	bt_dev_dbg(hdev, "err %d", err); + +	if (err == -ECANCELED) +		return; + +	hci_dev_lock(hdev); + +	if (!hci_conn_valid(hdev, conn)) +		goto done; + +	if (!err) { +		hci_connect_le_scan_cleanup(conn, 0x00); +		goto done; +	} + +	/* Check if connection is still pending */ +	if (conn != hci_lookup_le_connect(hdev)) +		goto done; + +	/* Flush to make sure we send create conn cancel command if needed */ +	flush_delayed_work(&conn->le_conn_timeout); +	hci_conn_failed(conn, bt_status(err)); + +done: +	hci_dev_unlock(hdev); +} + +int hci_connect_le_sync(struct hci_dev *hdev, struct hci_conn *conn) +{ +	return hci_cmd_sync_queue_once(hdev, hci_le_create_conn_sync, conn, +				       create_le_conn_complete); +} + +int hci_cancel_connect_sync(struct hci_dev *hdev, struct hci_conn *conn) +{ +	if (conn->state != BT_OPEN) +		return -EINVAL; + +	switch (conn->type) { +	case ACL_LINK: +		return !hci_cmd_sync_dequeue_once(hdev, +						  hci_acl_create_conn_sync, +						  conn, NULL); +	case LE_LINK: +		return !hci_cmd_sync_dequeue_once(hdev, hci_le_create_conn_sync, +						  conn, create_le_conn_complete); +	} + +	return -ENOENT; +} diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c index 04f6572d35f1..c8793e57f4b5 100644 --- a/net/bluetooth/iso.c +++ b/net/bluetooth/iso.c @@ -3,7 +3,7 @@   * BlueZ - Bluetooth protocol stack for Linux   *   * Copyright (C) 2022 Intel Corporation - * Copyright 2023 NXP + * Copyright 2023-2024 NXP   */  #include <linux/module.h> @@ -690,11 +690,8 @@ static void iso_sock_cleanup_listen(struct sock *parent)  		iso_sock_kill(sk);  	} -	/* If listening socket stands for a PA sync connection, -	 * properly disconnect the hcon and socket. -	 */ -	if (iso_pi(parent)->conn && iso_pi(parent)->conn->hcon && -	    test_bit(HCI_CONN_PA_SYNC, &iso_pi(parent)->conn->hcon->flags)) { +	/* If listening socket has a hcon, properly disconnect it */ +	if (iso_pi(parent)->conn && iso_pi(parent)->conn->hcon) {  		iso_sock_disconn(parent);  		return;  	} @@ -837,10 +834,10 @@ static struct bt_iso_qos default_qos = {  		.bcode			= {0x00},  		.options		= 0x00,  		.skip			= 0x0000, -		.sync_timeout		= 0x4000, +		.sync_timeout		= BT_ISO_SYNC_TIMEOUT,  		.sync_cte_type		= 0x00,  		.mse			= 0x00, -		.timeout		= 0x4000, +		.timeout		= BT_ISO_SYNC_TIMEOUT,  	},  }; @@ -1076,6 +1073,8 @@ static int iso_listen_bis(struct sock *sk)  {  	struct hci_dev *hdev;  	int err = 0; +	struct iso_conn *conn; +	struct hci_conn *hcon;  	BT_DBG("%pMR -> %pMR (SID 0x%2.2x)", &iso_pi(sk)->src,  	       &iso_pi(sk)->dst, iso_pi(sk)->bc_sid); @@ -1096,18 +1095,40 @@ static int iso_listen_bis(struct sock *sk)  	if (!hdev)  		return -EHOSTUNREACH; +	hci_dev_lock(hdev); +  	/* Fail if user set invalid QoS */  	if (iso_pi(sk)->qos_user_set && !check_bcast_qos(&iso_pi(sk)->qos)) {  		iso_pi(sk)->qos = default_qos; -		return -EINVAL; +		err = -EINVAL; +		goto unlock; +	} + +	hcon = hci_pa_create_sync(hdev, &iso_pi(sk)->dst, +				  le_addr_type(iso_pi(sk)->dst_type), +				  iso_pi(sk)->bc_sid, &iso_pi(sk)->qos); +	if (IS_ERR(hcon)) { +		err = PTR_ERR(hcon); +		goto unlock;  	} -	err = hci_pa_create_sync(hdev, &iso_pi(sk)->dst, -				 le_addr_type(iso_pi(sk)->dst_type), -				 iso_pi(sk)->bc_sid, &iso_pi(sk)->qos); +	conn = iso_conn_add(hcon); +	if (!conn) { +		hci_conn_drop(hcon); +		err = -ENOMEM; +		goto unlock; +	} + +	err = iso_chan_add(conn, sk, NULL); +	if (err) { +		hci_conn_drop(hcon); +		goto unlock; +	}  	hci_dev_put(hdev); +unlock: +	hci_dev_unlock(hdev);  	return err;  } @@ -1889,7 +1910,6 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)  	struct hci_evt_le_big_info_adv_report *ev2;  	struct hci_ev_le_per_adv_report *ev3;  	struct sock *sk; -	int lm = 0;  	bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr); @@ -1933,7 +1953,7 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)  			if (sk && test_bit(BT_SK_PA_SYNC_TERM,  					   &iso_pi(sk)->flags)) -				return lm; +				return 0;  		}  		if (sk) { @@ -1961,16 +1981,58 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)  	ev3 = hci_recv_event_data(hdev, HCI_EV_LE_PER_ADV_REPORT);  	if (ev3) { -		size_t base_len = ev3->length; +		size_t base_len = 0;  		u8 *base; +		struct hci_conn *hcon;  		sk = iso_get_sock_listen(&hdev->bdaddr, bdaddr,  					 iso_match_sync_handle_pa_report, ev3); -		base = eir_get_service_data(ev3->data, ev3->length, -					    EIR_BAA_SERVICE_UUID, &base_len); -		if (base && sk && base_len <= sizeof(iso_pi(sk)->base)) { +		if (!sk) +			goto done; + +		hcon = iso_pi(sk)->conn->hcon; +		if (!hcon) +			goto done; + +		if (ev3->data_status == LE_PA_DATA_TRUNCATED) { +			/* The controller was unable to retrieve PA data. */ +			memset(hcon->le_per_adv_data, 0, +			       HCI_MAX_PER_AD_TOT_LEN); +			hcon->le_per_adv_data_len = 0; +			hcon->le_per_adv_data_offset = 0; +			goto done; +		} + +		if (hcon->le_per_adv_data_offset + ev3->length > +		    HCI_MAX_PER_AD_TOT_LEN) +			goto done; + +		memcpy(hcon->le_per_adv_data + hcon->le_per_adv_data_offset, +		       ev3->data, ev3->length); +		hcon->le_per_adv_data_offset += ev3->length; + +		if (ev3->data_status == LE_PA_DATA_COMPLETE) { +			/* All PA data has been received. */ +			hcon->le_per_adv_data_len = +				hcon->le_per_adv_data_offset; +			hcon->le_per_adv_data_offset = 0; + +			/* Extract BASE */ +			base = eir_get_service_data(hcon->le_per_adv_data, +						    hcon->le_per_adv_data_len, +						    EIR_BAA_SERVICE_UUID, +						    &base_len); + +			if (!base || base_len > BASE_MAX_LENGTH) +				goto done; +  			memcpy(iso_pi(sk)->base, base, base_len);  			iso_pi(sk)->base_len = base_len; +		} else { +			/* This is a PA data fragment. Keep pa_data_len set to 0 +			 * until all data has been reassembled. +			 */ +			hcon->le_per_adv_data_len = 0;  		}  	} else {  		sk = iso_get_sock_listen(&hdev->bdaddr, BDADDR_ANY, NULL, NULL); @@ -1978,16 +2040,14 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)  done:  	if (!sk) -		return lm; - -	lm |= HCI_LM_ACCEPT; +		return 0;  	if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags))  		*flags |= HCI_PROTO_DEFER;  	sock_put(sk); -	return lm; +	return HCI_LM_ACCEPT;  }  static void iso_connect_cfm(struct hci_conn *hcon, __u8 status) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 656f49b299d2..467b242d8be0 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -39,8 +39,6 @@  #include <net/bluetooth/l2cap.h>  #include "smp.h" -#include "a2mp.h" -#include "amp.h"  #define LE_FLOWCTL_MAX_CREDITS 65535 @@ -167,24 +165,6 @@ static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn,  	return NULL;  } -static struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, -						  u8 ident) -{ -	struct l2cap_chan *c; - -	mutex_lock(&conn->chan_lock); -	c = __l2cap_get_chan_by_ident(conn, ident); -	if (c) { -		/* Only lock if chan reference is not 0 */ -		c = l2cap_chan_hold_unless_zero(c); -		if (c) -			l2cap_chan_lock(c); -	} -	mutex_unlock(&conn->chan_lock); - -	return c; -} -  static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src,  						      u8 src_type)  { @@ -651,7 +631,6 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)  	chan->ops->teardown(chan, err);  	if (conn) { -		struct amp_mgr *mgr = conn->hcon->amp_mgr;  		/* Delete from channel list */  		list_del(&chan->list); @@ -666,16 +645,6 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)  		if (chan->chan_type != L2CAP_CHAN_FIXED ||  		    test_bit(FLAG_HOLD_HCI_CONN, &chan->flags))  			hci_conn_drop(conn->hcon); - -		if (mgr && mgr->bredr_chan == chan) -			mgr->bredr_chan = NULL; -	} - -	if (chan->hs_hchan) { -		struct hci_chan *hs_hchan = chan->hs_hchan; - -		BT_DBG("chan %p disconnect hs_hchan %p", chan, hs_hchan); -		amp_disconnect_logical_link(hs_hchan);  	}  	if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state)) @@ -977,12 +946,6 @@ static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,  	hci_send_acl(conn->hchan, skb, flags);  } -static bool __chan_is_moving(struct l2cap_chan *chan) -{ -	return chan->move_state != L2CAP_MOVE_STABLE && -	       chan->move_state != L2CAP_MOVE_WAIT_PREPARE; -} -  static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)  {  	struct hci_conn *hcon = chan->conn->hcon; @@ -991,15 +954,6 @@ static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)  	BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,  	       skb->priority); -	if (chan->hs_hcon && !__chan_is_moving(chan)) { -		if (chan->hs_hchan) -			hci_send_acl(chan->hs_hchan, skb, ACL_COMPLETE); -		else -			kfree_skb(skb); - -		return; -	} -  	/* Use NO_FLUSH for LE links (where this is the only option) or  	 * if the BR/EDR link supports it and flushing has not been  	 * explicitly requested (through FLAG_FLUSHABLE). @@ -1180,9 +1134,6 @@ static void l2cap_send_sframe(struct l2cap_chan *chan,  	if (!control->sframe)  		return; -	if (__chan_is_moving(chan)) -		return; -  	if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state) &&  	    !control->poll)  		control->final = 1; @@ -1237,40 +1188,6 @@ static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)  	return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);  } -static bool __amp_capable(struct l2cap_chan *chan) -{ -	struct l2cap_conn *conn = chan->conn; -	struct hci_dev *hdev; -	bool amp_available = false; - -	if (!(conn->local_fixed_chan & L2CAP_FC_A2MP)) -		return false; - -	if (!(conn->remote_fixed_chan & L2CAP_FC_A2MP)) -		return false; - -	read_lock(&hci_dev_list_lock); -	list_for_each_entry(hdev, &hci_dev_list, list) { -		if (hdev->amp_type != AMP_TYPE_BREDR && -		    test_bit(HCI_UP, &hdev->flags)) { -			amp_available = true; -			break; -		} -	} -	read_unlock(&hci_dev_list_lock); - -	if (chan->chan_policy == BT_CHANNEL_POLICY_AMP_PREFERRED) -		return amp_available; - -	return false; -} - -static bool l2cap_check_efs(struct l2cap_chan *chan) -{ -	/* Check EFS parameters */ -	return true; -} -  void l2cap_send_conn_req(struct l2cap_chan *chan)  {  	struct l2cap_conn *conn = chan->conn; @@ -1286,76 +1203,6 @@ void l2cap_send_conn_req(struct l2cap_chan *chan)  	l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req);  } -static void l2cap_send_create_chan_req(struct l2cap_chan *chan, u8 amp_id) -{ -	struct l2cap_create_chan_req req; -	req.scid = cpu_to_le16(chan->scid); -	req.psm  = chan->psm; -	req.amp_id = amp_id; - -	chan->ident = l2cap_get_ident(chan->conn); - -	l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CREATE_CHAN_REQ, -		       sizeof(req), &req); -} - -static void l2cap_move_setup(struct l2cap_chan *chan) -{ -	struct sk_buff *skb; - -	BT_DBG("chan %p", chan); - -	if (chan->mode != L2CAP_MODE_ERTM) -		return; - -	__clear_retrans_timer(chan); -	__clear_monitor_timer(chan); -	__clear_ack_timer(chan); - -	chan->retry_count = 0; -	skb_queue_walk(&chan->tx_q, skb) { -		if (bt_cb(skb)->l2cap.retries) -			bt_cb(skb)->l2cap.retries = 1; -		else -			break; -	} - -	chan->expected_tx_seq = chan->buffer_seq; - -	clear_bit(CONN_REJ_ACT, &chan->conn_state); -	clear_bit(CONN_SREJ_ACT, &chan->conn_state); -	l2cap_seq_list_clear(&chan->retrans_list); -	l2cap_seq_list_clear(&chan->srej_list); -	skb_queue_purge(&chan->srej_q); - -	chan->tx_state = L2CAP_TX_STATE_XMIT; -	chan->rx_state = L2CAP_RX_STATE_MOVE; - -	set_bit(CONN_REMOTE_BUSY, &chan->conn_state); -} - -static void l2cap_move_done(struct l2cap_chan *chan) -{ -	u8 move_role = chan->move_role; -	BT_DBG("chan %p", chan); - -	chan->move_state = L2CAP_MOVE_STABLE; -	chan->move_role = L2CAP_MOVE_ROLE_NONE; - -	if (chan->mode != L2CAP_MODE_ERTM) -		return; - -	switch (move_role) { -	case L2CAP_MOVE_ROLE_INITIATOR: -		l2cap_tx(chan, NULL, NULL, L2CAP_EV_EXPLICIT_POLL); -		chan->rx_state = L2CAP_RX_STATE_WAIT_F; -		break; -	case L2CAP_MOVE_ROLE_RESPONDER: -		chan->rx_state = L2CAP_RX_STATE_WAIT_P; -		break; -	} -} -  static void l2cap_chan_ready(struct l2cap_chan *chan)  {  	/* The channel may have already been flagged as connected in @@ -1505,10 +1352,7 @@ static void l2cap_le_start(struct l2cap_chan *chan)  static void l2cap_start_connection(struct l2cap_chan *chan)  { -	if (__amp_capable(chan)) { -		BT_DBG("chan %p AMP capable: discover AMPs", chan); -		a2mp_discover_amp(chan); -	} else if (chan->conn->hcon->type == LE_LINK) { +	if (chan->conn->hcon->type == LE_LINK) {  		l2cap_le_start(chan);  	} else {  		l2cap_send_conn_req(chan); @@ -1611,11 +1455,6 @@ static void l2cap_send_disconn_req(struct l2cap_chan *chan, int err)  		__clear_ack_timer(chan);  	} -	if (chan->scid == L2CAP_CID_A2MP) { -		l2cap_state_change(chan, BT_DISCONN); -		return; -	} -  	req.dcid = cpu_to_le16(chan->dcid);  	req.scid = cpu_to_le16(chan->scid);  	l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_DISCONN_REQ, @@ -1754,11 +1593,6 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)  		l2cap_chan_lock(chan); -		if (chan->scid == L2CAP_CID_A2MP) { -			l2cap_chan_unlock(chan); -			continue; -		} -  		if (hcon->type == LE_LINK) {  			l2cap_le_start(chan);  		} else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { @@ -2067,9 +1901,6 @@ static void l2cap_streaming_send(struct l2cap_chan *chan,  	BT_DBG("chan %p, skbs %p", chan, skbs); -	if (__chan_is_moving(chan)) -		return; -  	skb_queue_splice_tail_init(skbs, &chan->tx_q);  	while (!skb_queue_empty(&chan->tx_q)) { @@ -2112,9 +1943,6 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)  	if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))  		return 0; -	if (__chan_is_moving(chan)) -		return 0; -  	while (chan->tx_send_head &&  	       chan->unacked_frames < chan->remote_tx_win &&  	       chan->tx_state == L2CAP_TX_STATE_XMIT) { @@ -2180,9 +2008,6 @@ static void l2cap_ertm_resend(struct l2cap_chan *chan)  	if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))  		return; -	if (__chan_is_moving(chan)) -		return; -  	while (chan->retrans_list.head != L2CAP_SEQ_LIST_CLEAR) {  		seq = l2cap_seq_list_pop(&chan->retrans_list); @@ -2522,8 +2347,7 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan,  	pdu_len = chan->conn->mtu;  	/* Constrain PDU size for BR/EDR connections */ -	if (!chan->hs_hcon) -		pdu_len = min_t(size_t, pdu_len, L2CAP_BREDR_MAX_PAYLOAD); +	pdu_len = min_t(size_t, pdu_len, L2CAP_BREDR_MAX_PAYLOAD);  	/* Adjust for largest possible L2CAP overhead. */  	if (chan->fcs) @@ -3287,11 +3111,6 @@ int l2cap_ertm_init(struct l2cap_chan *chan)  	skb_queue_head_init(&chan->tx_q); -	chan->local_amp_id = AMP_ID_BREDR; -	chan->move_id = AMP_ID_BREDR; -	chan->move_state = L2CAP_MOVE_STABLE; -	chan->move_role = L2CAP_MOVE_ROLE_NONE; -  	if (chan->mode != L2CAP_MODE_ERTM)  		return 0; @@ -3326,52 +3145,19 @@ static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)  static inline bool __l2cap_ews_supported(struct l2cap_conn *conn)  { -	return ((conn->local_fixed_chan & L2CAP_FC_A2MP) && -		(conn->feat_mask & L2CAP_FEAT_EXT_WINDOW)); +	return (conn->feat_mask & L2CAP_FEAT_EXT_WINDOW);  }  static inline bool __l2cap_efs_supported(struct l2cap_conn *conn)  { -	return ((conn->local_fixed_chan & L2CAP_FC_A2MP) && -		(conn->feat_mask & L2CAP_FEAT_EXT_FLOW)); +	return (conn->feat_mask & L2CAP_FEAT_EXT_FLOW);  }  static void __l2cap_set_ertm_timeouts(struct l2cap_chan *chan,  				      struct l2cap_conf_rfc *rfc)  { -	if (chan->local_amp_id != AMP_ID_BREDR && chan->hs_hcon) { -		u64 ertm_to = chan->hs_hcon->hdev->amp_be_flush_to; - -		/* Class 1 devices have must have ERTM timeouts -		 * exceeding the Link Supervision Timeout.  The -		 * default Link Supervision Timeout for AMP -		 * controllers is 10 seconds. -		 * -		 * Class 1 devices use 0xffffffff for their -		 * best-effort flush timeout, so the clamping logic -		 * will result in a timeout that meets the above -		 * requirement.  ERTM timeouts are 16-bit values, so -		 * the maximum timeout is 65.535 seconds. -		 */ - -		/* Convert timeout to milliseconds and round */ -		ertm_to = DIV_ROUND_UP_ULL(ertm_to, 1000); - -		/* This is the recommended formula for class 2 devices -		 * that start ERTM timers when packets are sent to the -		 * controller. -		 */ -		ertm_to = 3 * ertm_to + 500; - -		if (ertm_to > 0xffff) -			ertm_to = 0xffff; - -		rfc->retrans_timeout = cpu_to_le16((u16) ertm_to); -		rfc->monitor_timeout = rfc->retrans_timeout; -	} else { -		rfc->retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); -		rfc->monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); -	} +	rfc->retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); +	rfc->monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);  }  static inline void l2cap_txwin_setup(struct l2cap_chan *chan) @@ -3623,13 +3409,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data  		case L2CAP_CONF_EWS:  			if (olen != 2)  				break; -			if (!(chan->conn->local_fixed_chan & L2CAP_FC_A2MP)) -				return -ECONNREFUSED; -			set_bit(FLAG_EXT_CTRL, &chan->flags); -			set_bit(CONF_EWS_RECV, &chan->conf_state); -			chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW; -			chan->remote_tx_win = val; -			break; +			return -ECONNREFUSED;  		default:  			if (hint) @@ -4027,11 +3807,7 @@ void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)  	rsp.dcid   = cpu_to_le16(chan->scid);  	rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);  	rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); - -	if (chan->hs_hcon) -		rsp_code = L2CAP_CREATE_CHAN_RSP; -	else -		rsp_code = L2CAP_CONN_RSP; +	rsp_code = L2CAP_CONN_RSP;  	BT_DBG("chan %p rsp_code %u", chan, rsp_code); @@ -4190,7 +3966,6 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,  	chan->dst_type = bdaddr_dst_type(conn->hcon);  	chan->psm  = psm;  	chan->dcid = scid; -	chan->local_amp_id = amp_id;  	__l2cap_chan_add(conn, chan); @@ -4516,10 +4291,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,  		/* check compatibility */  		/* Send rsp for BR/EDR channel */ -		if (!chan->hs_hcon) -			l2cap_send_efs_conf_rsp(chan, rsp, cmd->ident, flags); -		else -			chan->ident = cmd->ident; +		l2cap_send_efs_conf_rsp(chan, rsp, cmd->ident, flags);  	}  unlock: @@ -4571,15 +4343,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,  				goto done;  			} -			if (!chan->hs_hcon) { -				l2cap_send_efs_conf_rsp(chan, buf, cmd->ident, -							0); -			} else { -				if (l2cap_check_efs(chan)) { -					amp_create_logical_link(chan); -					chan->ident = cmd->ident; -				} -			} +			l2cap_send_efs_conf_rsp(chan, buf, cmd->ident, 0);  		}  		goto done; @@ -4750,9 +4514,6 @@ static inline int l2cap_information_req(struct l2cap_conn *conn,  		if (!disable_ertm)  			feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING  				| L2CAP_FEAT_FCS; -		if (conn->local_fixed_chan & L2CAP_FC_A2MP) -			feat_mask |= L2CAP_FEAT_EXT_FLOW -				| L2CAP_FEAT_EXT_WINDOW;  		put_unaligned_le32(feat_mask, rsp->data);  		l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(buf), @@ -4841,751 +4602,6 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn,  	return 0;  } -static int l2cap_create_channel_req(struct l2cap_conn *conn, -				    struct l2cap_cmd_hdr *cmd, -				    u16 cmd_len, void *data) -{ -	struct l2cap_create_chan_req *req = data; -	struct l2cap_create_chan_rsp rsp; -	struct l2cap_chan *chan; -	struct hci_dev *hdev; -	u16 psm, scid; - -	if (cmd_len != sizeof(*req)) -		return -EPROTO; - -	if (!(conn->local_fixed_chan & L2CAP_FC_A2MP)) -		return -EINVAL; - -	psm = le16_to_cpu(req->psm); -	scid = le16_to_cpu(req->scid); - -	BT_DBG("psm 0x%2.2x, scid 0x%4.4x, amp_id %d", psm, scid, req->amp_id); - -	/* For controller id 0 make BR/EDR connection */ -	if (req->amp_id == AMP_ID_BREDR) { -		l2cap_connect(conn, cmd, data, L2CAP_CREATE_CHAN_RSP, -			      req->amp_id); -		return 0; -	} - -	/* Validate AMP controller id */ -	hdev = hci_dev_get(req->amp_id); -	if (!hdev) -		goto error; - -	if (hdev->dev_type != HCI_AMP || !test_bit(HCI_UP, &hdev->flags)) { -		hci_dev_put(hdev); -		goto error; -	} - -	chan = l2cap_connect(conn, cmd, data, L2CAP_CREATE_CHAN_RSP, -			     req->amp_id); -	if (chan) { -		struct amp_mgr *mgr = conn->hcon->amp_mgr; -		struct hci_conn *hs_hcon; - -		hs_hcon = hci_conn_hash_lookup_ba(hdev, AMP_LINK, -						  &conn->hcon->dst); -		if (!hs_hcon) { -			hci_dev_put(hdev); -			cmd_reject_invalid_cid(conn, cmd->ident, chan->scid, -					       chan->dcid); -			return 0; -		} - -		BT_DBG("mgr %p bredr_chan %p hs_hcon %p", mgr, chan, hs_hcon); - -		mgr->bredr_chan = chan; -		chan->hs_hcon = hs_hcon; -		chan->fcs = L2CAP_FCS_NONE; -		conn->mtu = hdev->block_mtu; -	} - -	hci_dev_put(hdev); - -	return 0; - -error: -	rsp.dcid = 0; -	rsp.scid = cpu_to_le16(scid); -	rsp.result = cpu_to_le16(L2CAP_CR_BAD_AMP); -	rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); - -	l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP, -		       sizeof(rsp), &rsp); - -	return 0; -} - -static void l2cap_send_move_chan_req(struct l2cap_chan *chan, u8 dest_amp_id) -{ -	struct l2cap_move_chan_req req; -	u8 ident; - -	BT_DBG("chan %p, dest_amp_id %d", chan, dest_amp_id); - -	ident = l2cap_get_ident(chan->conn); -	chan->ident = ident; - -	req.icid = cpu_to_le16(chan->scid); -	req.dest_amp_id = dest_amp_id; - -	l2cap_send_cmd(chan->conn, ident, L2CAP_MOVE_CHAN_REQ, sizeof(req), -		       &req); - -	__set_chan_timer(chan, L2CAP_MOVE_TIMEOUT); -} - -static void l2cap_send_move_chan_rsp(struct l2cap_chan *chan, u16 result) -{ -	struct l2cap_move_chan_rsp rsp; - -	BT_DBG("chan %p, result 0x%4.4x", chan, result); - -	rsp.icid = cpu_to_le16(chan->dcid); -	rsp.result = cpu_to_le16(result); - -	l2cap_send_cmd(chan->conn, chan->ident, L2CAP_MOVE_CHAN_RSP, -		       sizeof(rsp), &rsp); -} - -static void l2cap_send_move_chan_cfm(struct l2cap_chan *chan, u16 result) -{ -	struct l2cap_move_chan_cfm cfm; - -	BT_DBG("chan %p, result 0x%4.4x", chan, result); - -	chan->ident = l2cap_get_ident(chan->conn); - -	cfm.icid = cpu_to_le16(chan->scid); -	cfm.result = cpu_to_le16(result); - -	l2cap_send_cmd(chan->conn, chan->ident, L2CAP_MOVE_CHAN_CFM, -		       sizeof(cfm), &cfm); - -	__set_chan_timer(chan, L2CAP_MOVE_TIMEOUT); -} - -static void l2cap_send_move_chan_cfm_icid(struct l2cap_conn *conn, u16 icid) -{ -	struct l2cap_move_chan_cfm cfm; - -	BT_DBG("conn %p, icid 0x%4.4x", conn, icid); - -	cfm.icid = cpu_to_le16(icid); -	cfm.result = cpu_to_le16(L2CAP_MC_UNCONFIRMED); - -	l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_MOVE_CHAN_CFM, -		       sizeof(cfm), &cfm); -} - -static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident, -					 u16 icid) -{ -	struct l2cap_move_chan_cfm_rsp rsp; - -	BT_DBG("icid 0x%4.4x", icid); - -	rsp.icid = cpu_to_le16(icid); -	l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp); -} - -static void __release_logical_link(struct l2cap_chan *chan) -{ -	chan->hs_hchan = NULL; -	chan->hs_hcon = NULL; - -	/* Placeholder - release the logical link */ -} - -static void l2cap_logical_fail(struct l2cap_chan *chan) -{ -	/* Logical link setup failed */ -	if (chan->state != BT_CONNECTED) { -		/* Create channel failure, disconnect */ -		l2cap_send_disconn_req(chan, ECONNRESET); -		return; -	} - -	switch (chan->move_role) { -	case L2CAP_MOVE_ROLE_RESPONDER: -		l2cap_move_done(chan); -		l2cap_send_move_chan_rsp(chan, L2CAP_MR_NOT_SUPP); -		break; -	case L2CAP_MOVE_ROLE_INITIATOR: -		if (chan->move_state == L2CAP_MOVE_WAIT_LOGICAL_COMP || -		    chan->move_state == L2CAP_MOVE_WAIT_LOGICAL_CFM) { -			/* Remote has only sent pending or -			 * success responses, clean up -			 */ -			l2cap_move_done(chan); -		} - -		/* Other amp move states imply that the move -		 * has already aborted -		 */ -		l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED); -		break; -	} -} - -static void l2cap_logical_finish_create(struct l2cap_chan *chan, -					struct hci_chan *hchan) -{ -	struct l2cap_conf_rsp rsp; - -	chan->hs_hchan = hchan; -	chan->hs_hcon->l2cap_data = chan->conn; - -	l2cap_send_efs_conf_rsp(chan, &rsp, chan->ident, 0); - -	if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) { -		int err; - -		set_default_fcs(chan); - -		err = l2cap_ertm_init(chan); -		if (err < 0) -			l2cap_send_disconn_req(chan, -err); -		else -			l2cap_chan_ready(chan); -	} -} - -static void l2cap_logical_finish_move(struct l2cap_chan *chan, -				      struct hci_chan *hchan) -{ -	chan->hs_hcon = hchan->conn; -	chan->hs_hcon->l2cap_data = chan->conn; - -	BT_DBG("move_state %d", chan->move_state); - -	switch (chan->move_state) { -	case L2CAP_MOVE_WAIT_LOGICAL_COMP: -		/* Move confirm will be sent after a success -		 * response is received -		 */ -		chan->move_state = L2CAP_MOVE_WAIT_RSP_SUCCESS; -		break; -	case L2CAP_MOVE_WAIT_LOGICAL_CFM: -		if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { -			chan->move_state = L2CAP_MOVE_WAIT_LOCAL_BUSY; -		} else if (chan->move_role == L2CAP_MOVE_ROLE_INITIATOR) { -			chan->move_state = L2CAP_MOVE_WAIT_CONFIRM_RSP; -			l2cap_send_move_chan_cfm(chan, L2CAP_MC_CONFIRMED); -		} else if (chan->move_role == L2CAP_MOVE_ROLE_RESPONDER) { -			chan->move_state = L2CAP_MOVE_WAIT_CONFIRM; -			l2cap_send_move_chan_rsp(chan, L2CAP_MR_SUCCESS); -		} -		break; -	default: -		/* Move was not in expected state, free the channel */ -		__release_logical_link(chan); - -		chan->move_state = L2CAP_MOVE_STABLE; -	} -} - -/* Call with chan locked */ -void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan, -		       u8 status) -{ -	BT_DBG("chan %p, hchan %p, status %d", chan, hchan, status); - -	if (status) { -		l2cap_logical_fail(chan); -		__release_logical_link(chan); -		return; -	} - -	if (chan->state != BT_CONNECTED) { -		/* Ignore logical link if channel is on BR/EDR */ -		if (chan->local_amp_id != AMP_ID_BREDR) -			l2cap_logical_finish_create(chan, hchan); -	} else { -		l2cap_logical_finish_move(chan, hchan); -	} -} - -void l2cap_move_start(struct l2cap_chan *chan) -{ -	BT_DBG("chan %p", chan); - -	if (chan->local_amp_id == AMP_ID_BREDR) { -		if (chan->chan_policy != BT_CHANNEL_POLICY_AMP_PREFERRED) -			return; -		chan->move_role = L2CAP_MOVE_ROLE_INITIATOR; -		chan->move_state = L2CAP_MOVE_WAIT_PREPARE; -		/* Placeholder - start physical link setup */ -	} else { -		chan->move_role = L2CAP_MOVE_ROLE_INITIATOR; -		chan->move_state = L2CAP_MOVE_WAIT_RSP_SUCCESS; -		chan->move_id = 0; -		l2cap_move_setup(chan); -		l2cap_send_move_chan_req(chan, 0); -	} -} - -static void l2cap_do_create(struct l2cap_chan *chan, int result, -			    u8 local_amp_id, u8 remote_amp_id) -{ -	BT_DBG("chan %p state %s %u -> %u", chan, state_to_string(chan->state), -	       local_amp_id, remote_amp_id); - -	chan->fcs = L2CAP_FCS_NONE; - -	/* Outgoing channel on AMP */ -	if (chan->state == BT_CONNECT) { -		if (result == L2CAP_CR_SUCCESS) { -			chan->local_amp_id = local_amp_id; -			l2cap_send_create_chan_req(chan, remote_amp_id); -		} else { -			/* Revert to BR/EDR connect */ -			l2cap_send_conn_req(chan); -		} - -		return; -	} - -	/* Incoming channel on AMP */ -	if (__l2cap_no_conn_pending(chan)) { -		struct l2cap_conn_rsp rsp; -		char buf[128]; -		rsp.scid = cpu_to_le16(chan->dcid); -		rsp.dcid = cpu_to_le16(chan->scid); - -		if (result == L2CAP_CR_SUCCESS) { -			/* Send successful response */ -			rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); -			rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); -		} else { -			/* Send negative response */ -			rsp.result = cpu_to_le16(L2CAP_CR_NO_MEM); -			rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); -		} - -		l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CREATE_CHAN_RSP, -			       sizeof(rsp), &rsp); - -		if (result == L2CAP_CR_SUCCESS) { -			l2cap_state_change(chan, BT_CONFIG); -			set_bit(CONF_REQ_SENT, &chan->conf_state); -			l2cap_send_cmd(chan->conn, l2cap_get_ident(chan->conn), -				       L2CAP_CONF_REQ, -				       l2cap_build_conf_req(chan, buf, sizeof(buf)), buf); -			chan->num_conf_req++; -		} -	} -} - -static void l2cap_do_move_initiate(struct l2cap_chan *chan, u8 local_amp_id, -				   u8 remote_amp_id) -{ -	l2cap_move_setup(chan); -	chan->move_id = local_amp_id; -	chan->move_state = L2CAP_MOVE_WAIT_RSP; - -	l2cap_send_move_chan_req(chan, remote_amp_id); -} - -static void l2cap_do_move_respond(struct l2cap_chan *chan, int result) -{ -	struct hci_chan *hchan = NULL; - -	/* Placeholder - get hci_chan for logical link */ - -	if (hchan) { -		if (hchan->state == BT_CONNECTED) { -			/* Logical link is ready to go */ -			chan->hs_hcon = hchan->conn; -			chan->hs_hcon->l2cap_data = chan->conn; -			chan->move_state = L2CAP_MOVE_WAIT_CONFIRM; -			l2cap_send_move_chan_rsp(chan, L2CAP_MR_SUCCESS); - -			l2cap_logical_cfm(chan, hchan, L2CAP_MR_SUCCESS); -		} else { -			/* Wait for logical link to be ready */ -			chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_CFM; -		} -	} else { -		/* Logical link not available */ -		l2cap_send_move_chan_rsp(chan, L2CAP_MR_NOT_ALLOWED); -	} -} - -static void l2cap_do_move_cancel(struct l2cap_chan *chan, int result) -{ -	if (chan->move_role == L2CAP_MOVE_ROLE_RESPONDER) { -		u8 rsp_result; -		if (result == -EINVAL) -			rsp_result = L2CAP_MR_BAD_ID; -		else -			rsp_result = L2CAP_MR_NOT_ALLOWED; - -		l2cap_send_move_chan_rsp(chan, rsp_result); -	} - -	chan->move_role = L2CAP_MOVE_ROLE_NONE; -	chan->move_state = L2CAP_MOVE_STABLE; - -	/* Restart data transmission */ -	l2cap_ertm_send(chan); -} - -/* Invoke with locked chan */ -void __l2cap_physical_cfm(struct l2cap_chan *chan, int result) -{ -	u8 local_amp_id = chan->local_amp_id; -	u8 remote_amp_id = chan->remote_amp_id; - -	BT_DBG("chan %p, result %d, local_amp_id %d, remote_amp_id %d", -	       chan, result, local_amp_id, remote_amp_id); - -	if (chan->state == BT_DISCONN || chan->state == BT_CLOSED) -		return; - -	if (chan->state != BT_CONNECTED) { -		l2cap_do_create(chan, result, local_amp_id, remote_amp_id); -	} else if (result != L2CAP_MR_SUCCESS) { -		l2cap_do_move_cancel(chan, result); -	} else { -		switch (chan->move_role) { -		case L2CAP_MOVE_ROLE_INITIATOR: -			l2cap_do_move_initiate(chan, local_amp_id, -					       remote_amp_id); -			break; -		case L2CAP_MOVE_ROLE_RESPONDER: -			l2cap_do_move_respond(chan, result); -			break; -		default: -			l2cap_do_move_cancel(chan, result); -			break; -		} -	} -} - -static inline int l2cap_move_channel_req(struct l2cap_conn *conn, -					 struct l2cap_cmd_hdr *cmd, -					 u16 cmd_len, void *data) -{ -	struct l2cap_move_chan_req *req = data; -	struct l2cap_move_chan_rsp rsp; -	struct l2cap_chan *chan; -	u16 icid = 0; -	u16 result = L2CAP_MR_NOT_ALLOWED; - -	if (cmd_len != sizeof(*req)) -		return -EPROTO; - -	icid = le16_to_cpu(req->icid); - -	BT_DBG("icid 0x%4.4x, dest_amp_id %d", icid, req->dest_amp_id); - -	if (!(conn->local_fixed_chan & L2CAP_FC_A2MP)) -		return -EINVAL; - -	chan = l2cap_get_chan_by_dcid(conn, icid); -	if (!chan) { -		rsp.icid = cpu_to_le16(icid); -		rsp.result = cpu_to_le16(L2CAP_MR_NOT_ALLOWED); -		l2cap_send_cmd(conn, cmd->ident, L2CAP_MOVE_CHAN_RSP, -			       sizeof(rsp), &rsp); -		return 0; -	} - -	chan->ident = cmd->ident; - -	if (chan->scid < L2CAP_CID_DYN_START || -	    chan->chan_policy == BT_CHANNEL_POLICY_BREDR_ONLY || -	    (chan->mode != L2CAP_MODE_ERTM && -	     chan->mode != L2CAP_MODE_STREAMING)) { -		result = L2CAP_MR_NOT_ALLOWED; -		goto send_move_response; -	} - -	if (chan->local_amp_id == req->dest_amp_id) { -		result = L2CAP_MR_SAME_ID; -		goto send_move_response; -	} - -	if (req->dest_amp_id != AMP_ID_BREDR) { -		struct hci_dev *hdev; -		hdev = hci_dev_get(req->dest_amp_id); -		if (!hdev || hdev->dev_type != HCI_AMP || -		    !test_bit(HCI_UP, &hdev->flags)) { -			if (hdev) -				hci_dev_put(hdev); - -			result = L2CAP_MR_BAD_ID; -			goto send_move_response; -		} -		hci_dev_put(hdev); -	} - -	/* Detect a move collision.  Only send a collision response -	 * if this side has "lost", otherwise proceed with the move. -	 * The winner has the larger bd_addr. -	 */ -	if ((__chan_is_moving(chan) || -	     chan->move_role != L2CAP_MOVE_ROLE_NONE) && -	    bacmp(&conn->hcon->src, &conn->hcon->dst) > 0) { -		result = L2CAP_MR_COLLISION; -		goto send_move_response; -	} - -	chan->move_role = L2CAP_MOVE_ROLE_RESPONDER; -	l2cap_move_setup(chan); -	chan->move_id = req->dest_amp_id; - -	if (req->dest_amp_id == AMP_ID_BREDR) { -		/* Moving to BR/EDR */ -		if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { -			chan->move_state = L2CAP_MOVE_WAIT_LOCAL_BUSY; -			result = L2CAP_MR_PEND; -		} else { -			chan->move_state = L2CAP_MOVE_WAIT_CONFIRM; -			result = L2CAP_MR_SUCCESS; -		} -	} else { -		chan->move_state = L2CAP_MOVE_WAIT_PREPARE; -		/* Placeholder - uncomment when amp functions are available */ -		/*amp_accept_physical(chan, req->dest_amp_id);*/ -		result = L2CAP_MR_PEND; -	} - -send_move_response: -	l2cap_send_move_chan_rsp(chan, result); - -	l2cap_chan_unlock(chan); -	l2cap_chan_put(chan); - -	return 0; -} - -static void l2cap_move_continue(struct l2cap_conn *conn, u16 icid, u16 result) -{ -	struct l2cap_chan *chan; -	struct hci_chan *hchan = NULL; - -	chan = l2cap_get_chan_by_scid(conn, icid); -	if (!chan) { -		l2cap_send_move_chan_cfm_icid(conn, icid); -		return; -	} - -	__clear_chan_timer(chan); -	if (result == L2CAP_MR_PEND) -		__set_chan_timer(chan, L2CAP_MOVE_ERTX_TIMEOUT); - -	switch (chan->move_state) { -	case L2CAP_MOVE_WAIT_LOGICAL_COMP: -		/* Move confirm will be sent when logical link -		 * is complete. -		 */ -		chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_CFM; -		break; -	case L2CAP_MOVE_WAIT_RSP_SUCCESS: -		if (result == L2CAP_MR_PEND) { -			break; -		} else if (test_bit(CONN_LOCAL_BUSY, -				    &chan->conn_state)) { -			chan->move_state = L2CAP_MOVE_WAIT_LOCAL_BUSY; -		} else { -			/* Logical link is up or moving to BR/EDR, -			 * proceed with move -			 */ -			chan->move_state = L2CAP_MOVE_WAIT_CONFIRM_RSP; -			l2cap_send_move_chan_cfm(chan, L2CAP_MC_CONFIRMED); -		} -		break; -	case L2CAP_MOVE_WAIT_RSP: -		/* Moving to AMP */ -		if (result == L2CAP_MR_SUCCESS) { -			/* Remote is ready, send confirm immediately -			 * after logical link is ready -			 */ -			chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_CFM; -		} else { -			/* Both logical link and move success -			 * are required to confirm -			 */ -			chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_COMP; -		} - -		/* Placeholder - get hci_chan for logical link */ -		if (!hchan) { -			/* Logical link not available */ -			l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED); -			break; -		} - -		/* If the logical link is not yet connected, do not -		 * send confirmation. -		 */ -		if (hchan->state != BT_CONNECTED) -			break; - -		/* Logical link is already ready to go */ - -		chan->hs_hcon = hchan->conn; -		chan->hs_hcon->l2cap_data = chan->conn; - -		if (result == L2CAP_MR_SUCCESS) { -			/* Can confirm now */ -			l2cap_send_move_chan_cfm(chan, L2CAP_MC_CONFIRMED); -		} else { -			/* Now only need move success -			 * to confirm -			 */ -			chan->move_state = L2CAP_MOVE_WAIT_RSP_SUCCESS; -		} - -		l2cap_logical_cfm(chan, hchan, L2CAP_MR_SUCCESS); -		break; -	default: -		/* Any other amp move state means the move failed. */ -		chan->move_id = chan->local_amp_id; -		l2cap_move_done(chan); -		l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED); -	} - -	l2cap_chan_unlock(chan); -	l2cap_chan_put(chan); -} - -static void l2cap_move_fail(struct l2cap_conn *conn, u8 ident, u16 icid, -			    u16 result) -{ -	struct l2cap_chan *chan; - -	chan = l2cap_get_chan_by_ident(conn, ident); -	if (!chan) { -		/* Could not locate channel, icid is best guess */ -		l2cap_send_move_chan_cfm_icid(conn, icid); -		return; -	} - -	__clear_chan_timer(chan); - -	if (chan->move_role == L2CAP_MOVE_ROLE_INITIATOR) { -		if (result == L2CAP_MR_COLLISION) { -			chan->move_role = L2CAP_MOVE_ROLE_RESPONDER; -		} else { -			/* Cleanup - cancel move */ -			chan->move_id = chan->local_amp_id; -			l2cap_move_done(chan); -		} -	} - -	l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED); - -	l2cap_chan_unlock(chan); -	l2cap_chan_put(chan); -} - -static int l2cap_move_channel_rsp(struct l2cap_conn *conn, -				  struct l2cap_cmd_hdr *cmd, -				  u16 cmd_len, void *data) -{ -	struct l2cap_move_chan_rsp *rsp = data; -	u16 icid, result; - -	if (cmd_len != sizeof(*rsp)) -		return -EPROTO; - -	icid = le16_to_cpu(rsp->icid); -	result = le16_to_cpu(rsp->result); - -	BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); - -	if (result == L2CAP_MR_SUCCESS || result == L2CAP_MR_PEND) -		l2cap_move_continue(conn, icid, result); -	else -		l2cap_move_fail(conn, cmd->ident, icid, result); - -	return 0; -} - -static int l2cap_move_channel_confirm(struct l2cap_conn *conn, -				      struct l2cap_cmd_hdr *cmd, -				      u16 cmd_len, void *data) -{ -	struct l2cap_move_chan_cfm *cfm = data; -	struct l2cap_chan *chan; -	u16 icid, result; - -	if (cmd_len != sizeof(*cfm)) -		return -EPROTO; - -	icid = le16_to_cpu(cfm->icid); -	result = le16_to_cpu(cfm->result); - -	BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); - -	chan = l2cap_get_chan_by_dcid(conn, icid); -	if (!chan) { -		/* Spec requires a response even if the icid was not found */ -		l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid); -		return 0; -	} - -	if (chan->move_state == L2CAP_MOVE_WAIT_CONFIRM) { -		if (result == L2CAP_MC_CONFIRMED) { -			chan->local_amp_id = chan->move_id; -			if (chan->local_amp_id == AMP_ID_BREDR) -				__release_logical_link(chan); -		} else { -			chan->move_id = chan->local_amp_id; -		} - -		l2cap_move_done(chan); -	} - -	l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid); - -	l2cap_chan_unlock(chan); -	l2cap_chan_put(chan); - -	return 0; -} - -static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn, -						 struct l2cap_cmd_hdr *cmd, -						 u16 cmd_len, void *data) -{ -	struct l2cap_move_chan_cfm_rsp *rsp = data; -	struct l2cap_chan *chan; -	u16 icid; - -	if (cmd_len != sizeof(*rsp)) -		return -EPROTO; - -	icid = le16_to_cpu(rsp->icid); - -	BT_DBG("icid 0x%4.4x", icid); - -	chan = l2cap_get_chan_by_scid(conn, icid); -	if (!chan) -		return 0; - -	__clear_chan_timer(chan); - -	if (chan->move_state == L2CAP_MOVE_WAIT_CONFIRM_RSP) { -		chan->local_amp_id = chan->move_id; - -		if (chan->local_amp_id == AMP_ID_BREDR && chan->hs_hchan) -			__release_logical_link(chan); - -		l2cap_move_done(chan); -	} - -	l2cap_chan_unlock(chan); -	l2cap_chan_put(chan); - -	return 0; -} -  static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,  					      struct l2cap_cmd_hdr *cmd,  					      u16 cmd_len, u8 *data) @@ -5745,7 +4761,6 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,  		break;  	case L2CAP_CONN_RSP: -	case L2CAP_CREATE_CHAN_RSP:  		l2cap_connect_create_rsp(conn, cmd, cmd_len, data);  		break; @@ -5780,26 +4795,6 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,  		l2cap_information_rsp(conn, cmd, cmd_len, data);  		break; -	case L2CAP_CREATE_CHAN_REQ: -		err = l2cap_create_channel_req(conn, cmd, cmd_len, data); -		break; - -	case L2CAP_MOVE_CHAN_REQ: -		err = l2cap_move_channel_req(conn, cmd, cmd_len, data); -		break; - -	case L2CAP_MOVE_CHAN_RSP: -		l2cap_move_channel_rsp(conn, cmd, cmd_len, data); -		break; - -	case L2CAP_MOVE_CHAN_CFM: -		err = l2cap_move_channel_confirm(conn, cmd, cmd_len, data); -		break; - -	case L2CAP_MOVE_CHAN_CFM_RSP: -		l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data); -		break; -  	default:  		BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);  		err = -EINVAL; @@ -7051,8 +6046,8 @@ static int l2cap_rx_state_recv(struct l2cap_chan *chan,  		if (control->final) {  			clear_bit(CONN_REMOTE_BUSY, &chan->conn_state); -			if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state) && -			    !__chan_is_moving(chan)) { +			if (!test_and_clear_bit(CONN_REJ_ACT, +						&chan->conn_state)) {  				control->final = 0;  				l2cap_retransmit_all(chan, control);  			} @@ -7245,11 +6240,7 @@ static int l2cap_finish_move(struct l2cap_chan *chan)  	BT_DBG("chan %p", chan);  	chan->rx_state = L2CAP_RX_STATE_RECV; - -	if (chan->hs_hcon) -		chan->conn->mtu = chan->hs_hcon->hdev->block_mtu; -	else -		chan->conn->mtu = chan->conn->hcon->hdev->acl_mtu; +	chan->conn->mtu = chan->conn->hcon->hdev->acl_mtu;  	return l2cap_resegment(chan);  } @@ -7316,11 +6307,7 @@ static int l2cap_rx_state_wait_f(struct l2cap_chan *chan,  	 */  	chan->next_tx_seq = control->reqseq;  	chan->unacked_frames = 0; - -	if (chan->hs_hcon) -		chan->conn->mtu = chan->hs_hcon->hdev->block_mtu; -	else -		chan->conn->mtu = chan->conn->hcon->hdev->acl_mtu; +	chan->conn->mtu = chan->conn->hcon->hdev->acl_mtu;  	err = l2cap_resegment(chan); @@ -7672,21 +6659,10 @@ static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid,  	chan = l2cap_get_chan_by_scid(conn, cid);  	if (!chan) { -		if (cid == L2CAP_CID_A2MP) { -			chan = a2mp_channel_create(conn, skb); -			if (!chan) { -				kfree_skb(skb); -				return; -			} - -			l2cap_chan_hold(chan); -			l2cap_chan_lock(chan); -		} else { -			BT_DBG("unknown cid 0x%4.4x", cid); -			/* Drop packet and return */ -			kfree_skb(skb); -			return; -		} +		BT_DBG("unknown cid 0x%4.4x", cid); +		/* Drop packet and return */ +		kfree_skb(skb); +		return;  	}  	BT_DBG("chan %p, len %d", chan, skb->len); @@ -7887,10 +6863,6 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)  	conn->local_fixed_chan = L2CAP_FC_SIG_BREDR | L2CAP_FC_CONNLESS; -	if (hcon->type == ACL_LINK && -	    hci_dev_test_flag(hcon->hdev, HCI_HS_ENABLED)) -		conn->local_fixed_chan |= L2CAP_FC_A2MP; -  	if (hci_dev_test_flag(hcon->hdev, HCI_LE_ENABLED) &&  	    (bredr_sc_enabled(hcon->hdev) ||  	     hci_dev_test_flag(hcon->hdev, HCI_FORCE_BREDR_SMP))) @@ -7953,7 +6925,7 @@ static void l2cap_chan_by_pid(struct l2cap_chan *chan, void *data)  }  int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, -		       bdaddr_t *dst, u8 dst_type) +		       bdaddr_t *dst, u8 dst_type, u16 timeout)  {  	struct l2cap_conn *conn;  	struct hci_conn *hcon; @@ -8046,19 +7018,17 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,  		if (hci_dev_test_flag(hdev, HCI_ADVERTISING))  			hcon = hci_connect_le(hdev, dst, dst_type, false, -					      chan->sec_level, -					      HCI_LE_CONN_TIMEOUT, +					      chan->sec_level, timeout,  					      HCI_ROLE_SLAVE);  		else  			hcon = hci_connect_le_scan(hdev, dst, dst_type, -						   chan->sec_level, -						   HCI_LE_CONN_TIMEOUT, +						   chan->sec_level, timeout,  						   CONN_REASON_L2CAP_CHAN);  	} else {  		u8 auth_type = l2cap_get_auth_type(chan);  		hcon = hci_connect_acl(hdev, dst, chan->sec_level, auth_type, -				       CONN_REASON_L2CAP_CHAN); +				       CONN_REASON_L2CAP_CHAN, timeout);  	}  	if (IS_ERR(hcon)) { @@ -8355,11 +7325,6 @@ static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)  		BT_DBG("chan %p scid 0x%4.4x state %s", chan, chan->scid,  		       state_to_string(chan->state)); -		if (chan->scid == L2CAP_CID_A2MP) { -			l2cap_chan_unlock(chan); -			continue; -		} -  		if (!status && encrypt)  			chan->sec_level = hcon->sec_level; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index e50d3d102078..4287aa6cc988 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -254,7 +254,8 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr,  		chan->mode = L2CAP_MODE_LE_FLOWCTL;  	err = l2cap_chan_connect(chan, la.l2_psm, __le16_to_cpu(la.l2_cid), -				 &la.l2_bdaddr, la.l2_bdaddr_type); +				 &la.l2_bdaddr, la.l2_bdaddr_type, +				 sk->sk_sndtimeo);  	if (err)  		return err; @@ -1027,23 +1028,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,  			break;  		} -		if (opt > BT_CHANNEL_POLICY_AMP_PREFERRED) { -			err = -EINVAL; -			break; -		} - -		if (chan->mode != L2CAP_MODE_ERTM && -		    chan->mode != L2CAP_MODE_STREAMING) { -			err = -EOPNOTSUPP; -			break; -		} - -		chan->chan_policy = (u8) opt; - -		if (sk->sk_state == BT_CONNECTED && -		    chan->move_role == L2CAP_MOVE_ROLE_NONE) -			l2cap_move_start(chan); - +		err = -EOPNOTSUPP;  		break;  	case BT_SNDMTU: diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ee3b4aad8bd8..32ed6e9245a3 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -835,8 +835,6 @@ static u32 get_supported_settings(struct hci_dev *hdev)  		if (lmp_ssp_capable(hdev)) {  			settings |= MGMT_SETTING_SSP; -			if (IS_ENABLED(CONFIG_BT_HS)) -				settings |= MGMT_SETTING_HS;  		}  		if (lmp_sc_capable(hdev)) @@ -901,9 +899,6 @@ static u32 get_current_settings(struct hci_dev *hdev)  	if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))  		settings |= MGMT_SETTING_SSP; -	if (hci_dev_test_flag(hdev, HCI_HS_ENABLED)) -		settings |= MGMT_SETTING_HS; -  	if (hci_dev_test_flag(hdev, HCI_ADVERTISING))  		settings |= MGMT_SETTING_ADVERTISING; @@ -1390,6 +1385,14 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,  	hci_dev_lock(hdev); +	if (!cp->val) { +		if (hci_dev_test_flag(hdev, HCI_POWERING_DOWN)) { +			err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED, +					      MGMT_STATUS_BUSY); +			goto failed; +		} +	} +  	if (pending_find(MGMT_OP_SET_POWERED, hdev)) {  		err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,  				      MGMT_STATUS_BUSY); @@ -1409,7 +1412,7 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,  	/* Cancel potentially blocking sync operation before power off */  	if (cp->val == 0x00) { -		__hci_cmd_sync_cancel(hdev, -EHOSTDOWN); +		hci_cmd_sync_cancel_sync(hdev, -EHOSTDOWN);  		err = hci_cmd_sync_queue(hdev, set_powered_sync, cmd,  					 mgmt_set_powered_complete);  	} else { @@ -1704,8 +1707,7 @@ static void mgmt_set_connectable_complete(struct hci_dev *hdev, void *data,  	new_settings(hdev, cmd->sk);  done: -	if (cmd) -		mgmt_pending_remove(cmd); +	mgmt_pending_remove(cmd);  	hci_dev_unlock(hdev);  } @@ -1930,7 +1932,6 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)  		if (enable && hci_dev_test_and_clear_flag(hdev,  							  HCI_SSP_ENABLED)) { -			hci_dev_clear_flag(hdev, HCI_HS_ENABLED);  			new_settings(hdev, NULL);  		} @@ -1943,12 +1944,6 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)  		changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);  	} else {  		changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED); - -		if (!changed) -			changed = hci_dev_test_and_clear_flag(hdev, -							      HCI_HS_ENABLED); -		else -			hci_dev_clear_flag(hdev, HCI_HS_ENABLED);  	}  	mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match); @@ -2012,11 +2007,6 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)  		} else {  			changed = hci_dev_test_and_clear_flag(hdev,  							      HCI_SSP_ENABLED); -			if (!changed) -				changed = hci_dev_test_and_clear_flag(hdev, -								      HCI_HS_ENABLED); -			else -				hci_dev_clear_flag(hdev, HCI_HS_ENABLED);  		}  		err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev); @@ -2062,63 +2052,10 @@ failed:  static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)  { -	struct mgmt_mode *cp = data; -	bool changed; -	u8 status; -	int err; -  	bt_dev_dbg(hdev, "sock %p", sk); -	if (!IS_ENABLED(CONFIG_BT_HS)) -		return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, +	return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,  				       MGMT_STATUS_NOT_SUPPORTED); - -	status = mgmt_bredr_support(hdev); -	if (status) -		return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status); - -	if (!lmp_ssp_capable(hdev)) -		return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, -				       MGMT_STATUS_NOT_SUPPORTED); - -	if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) -		return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, -				       MGMT_STATUS_REJECTED); - -	if (cp->val != 0x00 && cp->val != 0x01) -		return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, -				       MGMT_STATUS_INVALID_PARAMS); - -	hci_dev_lock(hdev); - -	if (pending_find(MGMT_OP_SET_SSP, hdev)) { -		err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, -				      MGMT_STATUS_BUSY); -		goto unlock; -	} - -	if (cp->val) { -		changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED); -	} else { -		if (hdev_is_powered(hdev)) { -			err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, -					      MGMT_STATUS_REJECTED); -			goto unlock; -		} - -		changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED); -	} - -	err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev); -	if (err < 0) -		goto unlock; - -	if (changed) -		err = new_settings(hdev, sk); - -unlock: -	hci_dev_unlock(hdev); -	return err;  }  static void set_le_complete(struct hci_dev *hdev, void *data, int err) @@ -3188,6 +3125,7 @@ failed:  static u8 link_to_bdaddr(u8 link_type, u8 addr_type)  {  	switch (link_type) { +	case ISO_LINK:  	case LE_LINK:  		switch (addr_type) {  		case ADDR_LE_DEV_PUBLIC: @@ -3505,7 +3443,8 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,  	if (cp->addr.type == BDADDR_BREDR) {  		conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level, -				       auth_type, CONN_REASON_PAIR_DEVICE); +				       auth_type, CONN_REASON_PAIR_DEVICE, +				       HCI_ACL_CONN_TIMEOUT);  	} else {  		u8 addr_type = le_addr_type(cp->addr.type);  		struct hci_conn_params *p; @@ -6766,7 +6705,6 @@ static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)  			hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);  			hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);  			hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE); -			hci_dev_clear_flag(hdev, HCI_HS_ENABLED);  		}  		hci_dev_change_flag(hdev, HCI_BREDR_ENABLED); @@ -8470,7 +8408,7 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,  static u8 calculate_name_len(struct hci_dev *hdev)  { -	u8 buf[HCI_MAX_SHORT_NAME_LENGTH + 3]; +	u8 buf[HCI_MAX_SHORT_NAME_LENGTH + 2]; /* len + type + name */  	return eir_append_local_name(hdev, buf, 0);  } @@ -8829,8 +8767,7 @@ static void add_ext_adv_params_complete(struct hci_dev *hdev, void *data,  	}  unlock: -	if (cmd) -		mgmt_pending_free(cmd); +	mgmt_pending_free(cmd);  	hci_dev_unlock(hdev);  } @@ -9681,6 +9618,9 @@ 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)) +		return; +  	/* allocate buff for LE or BR/EDR adv */  	if (conn->le_adv_data_len > 0)  		skb = mgmt_alloc_skb(hdev, MGMT_EV_DEVICE_CONNECTED, @@ -9748,6 +9688,9 @@ bool mgmt_powering_down(struct hci_dev *hdev)  	struct mgmt_pending_cmd *cmd;  	struct mgmt_mode *cp; +	if (hci_dev_test_flag(hdev, HCI_POWERING_DOWN)) +		return true; +  	cmd = pending_find(MGMT_OP_SET_POWERED, hdev);  	if (!cmd)  		return false; @@ -9766,14 +9709,6 @@ void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,  	struct mgmt_ev_device_disconnected ev;  	struct sock *sk = NULL; -	/* The connection is still in hci_conn_hash so test for 1 -	 * instead of 0 to know if this is the last one. -	 */ -	if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) { -		cancel_delayed_work(&hdev->power_off); -		queue_work(hdev->req_workqueue, &hdev->power_off.work); -	} -  	if (!mgmt_connected)  		return; @@ -9830,14 +9765,6 @@ void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,  {  	struct mgmt_ev_connect_failed ev; -	/* The connection is still in hci_conn_hash so test for 1 -	 * instead of 0 to know if this is the last one. -	 */ -	if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) { -		cancel_delayed_work(&hdev->power_off); -		queue_work(hdev->req_workqueue, &hdev->power_off.work); -	} -  	bacpy(&ev.addr.bdaddr, bdaddr);  	ev.addr.type = link_to_bdaddr(link_type, addr_type);  	ev.status = mgmt_status(status); @@ -10071,6 +9998,9 @@ void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)  		/* If this is a HCI command related to powering on the  		 * HCI dev don't send any mgmt signals.  		 */ +		if (hci_dev_test_flag(hdev, HCI_POWERING_DOWN)) +			return; +  		if (pending_find(MGMT_OP_SET_POWERED, hdev))  			return;  	} diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c index 630e3023273b..9612c5d1b13f 100644 --- a/net/bluetooth/msft.c +++ b/net/bluetooth/msft.c @@ -875,6 +875,7 @@ static int msft_add_address_filter_sync(struct hci_dev *hdev, void *data)  		remove = true;  		goto done;  	} +  	cp->sub_opcode           = MSFT_OP_LE_MONITOR_ADVERTISEMENT;  	cp->rssi_high		 = address_filter->rssi_high;  	cp->rssi_low		 = address_filter->rssi_low; @@ -887,6 +888,8 @@ static int msft_add_address_filter_sync(struct hci_dev *hdev, void *data)  	skb = __hci_cmd_sync(hdev, hdev->msft_opcode, size, cp,  			     HCI_CMD_TIMEOUT); +	kfree(cp); +  	if (IS_ERR(skb)) {  		bt_dev_err(hdev, "Failed to enable address %pMR filter",  			   &address_filter->bdaddr); diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index c736186aba26..43daf965a01e 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -264,7 +264,8 @@ static int sco_connect(struct sock *sk)  	}  	hcon = hci_connect_sco(hdev, type, &sco_pi(sk)->dst, -			       sco_pi(sk)->setting, &sco_pi(sk)->codec); +			       sco_pi(sk)->setting, &sco_pi(sk)->codec, +			       sk->sk_sndtimeo);  	if (IS_ERR(hcon)) {  		err = PTR_ERR(hcon);  		goto unlock; | 
