mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 08:44:41 +00:00 
			
		
		
		
	bluetooth pull request for net:
- Fix regression causing some HCI events to be discarded when they
    shouldn't.
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEE7E6oRXp8w05ovYr/9JCA4xAyCykFAmJp06sZHGx1aXoudm9u
 LmRlbnR6QGludGVsLmNvbQAKCRD0kIDjEDILKYIqD/9z5sdKwHfJCBhPA3f9RqrY
 uzJXaza10/rabRGj/sobWxbF662nvImUS9zXsyR1gH8BXG9yOiH/tL1vnP8+Hnze
 o0DHsD2iXOL1HDdt1ZXkyvkAoDlnV8pFyDuakeFG7ddOYIhoq12bMj7Tu8fGsei3
 miFFQwwHMvxPs77zJpkW0E5XqC1UI4LJA7a+ezpP+5Y7Oqzy7FJpv+RTjjtSxdKP
 kSlDUBuqzKuvXyeV4D6T0wyJFk4XFJVjyfwAtBiiXsADVCDSr+eJ6WUMixE04x35
 siykz7gu/Fl79SOJHmOm/ZnJDlO2GFoWmmXA2HomqT1N6CECA7CBfwOG/HQ8mETE
 z0TwYbwQbK4sewMWClz6InrPhfY2P6z47xsohY1DPWpJB+dsvYjLvqxnP7bnVxTc
 ZO3N8fNt3BDZnnqEaKXZyoIOwppS8+q0nGUAvi8nkhh3dMphYg6csDn8iNm0EdkI
 RGkiB+dgoTY9Wwe9GnVysBGC5rFV5uQBwKLkSZeBAgzE2zRVIJvn6RzmExVYDk/V
 nXaFmW8vG/rgXoOIfW1jO3YqgKOPgb+emX6ckmaFA+Z8ICUeYKazfLa2OUAsVILX
 S7LhP5aY9vPkaRr4iXXyt88nRl97NejSC4zc0iGJQijYwQKuClcUWy2fqzTSuUVv
 TrH8ti7QqGR4C+M0uV2N9Q==
 =sidM
 -----END PGP SIGNATURE-----
Merge tag 'for-net-2022-04-27' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth
Luiz Augusto von Dentz says:
====================
bluetooth pull request for net:
 - Fix regression causing some HCI events to be discarded when they
   shouldn't.
* tag 'for-net-2022-04-27' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth:
  Bluetooth: hci_sync: Cleanup hci_conn if it cannot be aborted
  Bluetooth: hci_event: Fix creating hci_conn object on error status
  Bluetooth: hci_event: Fix checking for invalid handle on error status
====================
Link: https://lore.kernel.org/r/20220427234031.1257281-1-luiz.dentz@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
			
			
This commit is contained in:
		
						commit
						febb2d2fa5
					
				
					 5 changed files with 83 additions and 43 deletions
				
			
		|  | @ -578,6 +578,7 @@ enum { | |||
| #define HCI_ERROR_CONNECTION_TIMEOUT	0x08 | ||||
| #define HCI_ERROR_REJ_LIMITED_RESOURCES	0x0d | ||||
| #define HCI_ERROR_REJ_BAD_ADDR		0x0f | ||||
| #define HCI_ERROR_INVALID_PARAMETERS	0x12 | ||||
| #define HCI_ERROR_REMOTE_USER_TERM	0x13 | ||||
| #define HCI_ERROR_REMOTE_LOW_RESOURCES	0x14 | ||||
| #define HCI_ERROR_REMOTE_POWER_OFF	0x15 | ||||
|  |  | |||
|  | @ -1156,7 +1156,7 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role); | |||
| 
 | ||||
| void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active); | ||||
| 
 | ||||
| void hci_le_conn_failed(struct hci_conn *conn, u8 status); | ||||
| void hci_conn_failed(struct hci_conn *conn, u8 status); | ||||
| 
 | ||||
| /*
 | ||||
|  * hci_conn_get() and hci_conn_put() are used to control the life-time of an | ||||
|  |  | |||
|  | @ -670,7 +670,7 @@ static void le_conn_timeout(struct work_struct *work) | |||
| 		/* Disable LE Advertising */ | ||||
| 		le_disable_advertising(hdev); | ||||
| 		hci_dev_lock(hdev); | ||||
| 		hci_le_conn_failed(conn, HCI_ERROR_ADVERTISING_TIMEOUT); | ||||
| 		hci_conn_failed(conn, HCI_ERROR_ADVERTISING_TIMEOUT); | ||||
| 		hci_dev_unlock(hdev); | ||||
| 		return; | ||||
| 	} | ||||
|  | @ -873,7 +873,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src, uint8_t src_type) | |||
| EXPORT_SYMBOL(hci_get_route); | ||||
| 
 | ||||
| /* This function requires the caller holds hdev->lock */ | ||||
| void hci_le_conn_failed(struct hci_conn *conn, u8 status) | ||||
| static void hci_le_conn_failed(struct hci_conn *conn, u8 status) | ||||
| { | ||||
| 	struct hci_dev *hdev = conn->hdev; | ||||
| 	struct hci_conn_params *params; | ||||
|  | @ -886,8 +886,6 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status) | |||
| 		params->conn = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	conn->state = BT_CLOSED; | ||||
| 
 | ||||
| 	/* If the status indicates successful cancellation of
 | ||||
| 	 * the attempt (i.e. Unknown Connection Id) there's no point of | ||||
| 	 * notifying failure since we'll go back to keep trying to | ||||
|  | @ -899,10 +897,6 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status) | |||
| 		mgmt_connect_failed(hdev, &conn->dst, conn->type, | ||||
| 				    conn->dst_type, status); | ||||
| 
 | ||||
| 	hci_connect_cfm(conn, status); | ||||
| 
 | ||||
| 	hci_conn_del(conn); | ||||
| 
 | ||||
| 	/* Since we may have temporarily stopped the background scanning in
 | ||||
| 	 * favor of connection establishment, we should restart it. | ||||
| 	 */ | ||||
|  | @ -914,6 +908,28 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status) | |||
| 	hci_enable_advertising(hdev); | ||||
| } | ||||
| 
 | ||||
| /* This function requires the caller holds hdev->lock */ | ||||
| void hci_conn_failed(struct hci_conn *conn, u8 status) | ||||
| { | ||||
| 	struct hci_dev *hdev = conn->hdev; | ||||
| 
 | ||||
| 	bt_dev_dbg(hdev, "status 0x%2.2x", status); | ||||
| 
 | ||||
| 	switch (conn->type) { | ||||
| 	case LE_LINK: | ||||
| 		hci_le_conn_failed(conn, status); | ||||
| 		break; | ||||
| 	case ACL_LINK: | ||||
| 		mgmt_connect_failed(hdev, &conn->dst, conn->type, | ||||
| 				    conn->dst_type, status); | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	conn->state = BT_CLOSED; | ||||
| 	hci_connect_cfm(conn, status); | ||||
| 	hci_conn_del(conn); | ||||
| } | ||||
| 
 | ||||
| static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err) | ||||
| { | ||||
| 	struct hci_conn *conn = data; | ||||
|  |  | |||
|  | @ -2834,7 +2834,7 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, u8 status) | |||
| 	bt_dev_dbg(hdev, "status 0x%2.2x", status); | ||||
| 
 | ||||
| 	/* All connection failure handling is taken care of by the
 | ||||
| 	 * hci_le_conn_failed function which is triggered by the HCI | ||||
| 	 * hci_conn_failed function which is triggered by the HCI | ||||
| 	 * request completion callbacks used for connecting. | ||||
| 	 */ | ||||
| 	if (status) | ||||
|  | @ -2859,7 +2859,7 @@ static void hci_cs_le_ext_create_conn(struct hci_dev *hdev, u8 status) | |||
| 	bt_dev_dbg(hdev, "status 0x%2.2x", status); | ||||
| 
 | ||||
| 	/* All connection failure handling is taken care of by the
 | ||||
| 	 * hci_le_conn_failed function which is triggered by the HCI | ||||
| 	 * hci_conn_failed function which is triggered by the HCI | ||||
| 	 * request completion callbacks used for connecting. | ||||
| 	 */ | ||||
| 	if (status) | ||||
|  | @ -3067,18 +3067,20 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data, | |||
| { | ||||
| 	struct hci_ev_conn_complete *ev = data; | ||||
| 	struct hci_conn *conn; | ||||
| 	u8 status = ev->status; | ||||
| 
 | ||||
| 	if (__le16_to_cpu(ev->handle) > HCI_CONN_HANDLE_MAX) { | ||||
| 		bt_dev_err(hdev, "Ignoring HCI_Connection_Complete for invalid handle"); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	bt_dev_dbg(hdev, "status 0x%2.2x", ev->status); | ||||
| 	bt_dev_dbg(hdev, "status 0x%2.2x", status); | ||||
| 
 | ||||
| 	hci_dev_lock(hdev); | ||||
| 
 | ||||
| 	conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr); | ||||
| 	if (!conn) { | ||||
| 		/* In case of error status and there is no connection pending
 | ||||
| 		 * just unlock as there is nothing to cleanup. | ||||
| 		 */ | ||||
| 		if (ev->status) | ||||
| 			goto unlock; | ||||
| 
 | ||||
| 		/* Connection may not exist if auto-connected. Check the bredr
 | ||||
| 		 * allowlist to see if this device is allowed to auto connect. | ||||
| 		 * If link is an ACL type, create a connection class | ||||
|  | @ -3122,8 +3124,14 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data, | |||
| 		goto unlock; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!ev->status) { | ||||
| 	if (!status) { | ||||
| 		conn->handle = __le16_to_cpu(ev->handle); | ||||
| 		if (conn->handle > HCI_CONN_HANDLE_MAX) { | ||||
| 			bt_dev_err(hdev, "Invalid handle: 0x%4.4x > 0x%4.4x", | ||||
| 				   conn->handle, HCI_CONN_HANDLE_MAX); | ||||
| 			status = HCI_ERROR_INVALID_PARAMETERS; | ||||
| 			goto done; | ||||
| 		} | ||||
| 
 | ||||
| 		if (conn->type == ACL_LINK) { | ||||
| 			conn->state = BT_CONFIG; | ||||
|  | @ -3164,19 +3172,14 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data, | |||
| 			hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE, sizeof(cp), | ||||
| 				     &cp); | ||||
| 		} | ||||
| 	} else { | ||||
| 		conn->state = BT_CLOSED; | ||||
| 		if (conn->type == ACL_LINK) | ||||
| 			mgmt_connect_failed(hdev, &conn->dst, conn->type, | ||||
| 					    conn->dst_type, ev->status); | ||||
| 	} | ||||
| 
 | ||||
| 	if (conn->type == ACL_LINK) | ||||
| 		hci_sco_setup(conn, ev->status); | ||||
| 
 | ||||
| 	if (ev->status) { | ||||
| 		hci_connect_cfm(conn, ev->status); | ||||
| 		hci_conn_del(conn); | ||||
| done: | ||||
| 	if (status) { | ||||
| 		hci_conn_failed(conn, status); | ||||
| 	} else if (ev->link_type == SCO_LINK) { | ||||
| 		switch (conn->setting & SCO_AIRMODE_MASK) { | ||||
| 		case SCO_AIRMODE_CVSD: | ||||
|  | @ -3185,7 +3188,7 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data, | |||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		hci_connect_cfm(conn, ev->status); | ||||
| 		hci_connect_cfm(conn, status); | ||||
| 	} | ||||
| 
 | ||||
| unlock: | ||||
|  | @ -4676,6 +4679,7 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev, void *data, | |||
| { | ||||
| 	struct hci_ev_sync_conn_complete *ev = data; | ||||
| 	struct hci_conn *conn; | ||||
| 	u8 status = ev->status; | ||||
| 
 | ||||
| 	switch (ev->link_type) { | ||||
| 	case SCO_LINK: | ||||
|  | @ -4690,12 +4694,7 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev, void *data, | |||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	if (__le16_to_cpu(ev->handle) > HCI_CONN_HANDLE_MAX) { | ||||
| 		bt_dev_err(hdev, "Ignoring HCI_Sync_Conn_Complete for invalid handle"); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	bt_dev_dbg(hdev, "status 0x%2.2x", ev->status); | ||||
| 	bt_dev_dbg(hdev, "status 0x%2.2x", status); | ||||
| 
 | ||||
| 	hci_dev_lock(hdev); | ||||
| 
 | ||||
|  | @ -4729,9 +4728,17 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev, void *data, | |||
| 		goto unlock; | ||||
| 	} | ||||
| 
 | ||||
| 	switch (ev->status) { | ||||
| 	switch (status) { | ||||
| 	case 0x00: | ||||
| 		conn->handle = __le16_to_cpu(ev->handle); | ||||
| 		if (conn->handle > HCI_CONN_HANDLE_MAX) { | ||||
| 			bt_dev_err(hdev, "Invalid handle: 0x%4.4x > 0x%4.4x", | ||||
| 				   conn->handle, HCI_CONN_HANDLE_MAX); | ||||
| 			status = HCI_ERROR_INVALID_PARAMETERS; | ||||
| 			conn->state = BT_CLOSED; | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		conn->state  = BT_CONNECTED; | ||||
| 		conn->type   = ev->link_type; | ||||
| 
 | ||||
|  | @ -4775,8 +4782,8 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev, void *data, | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	hci_connect_cfm(conn, ev->status); | ||||
| 	if (ev->status) | ||||
| 	hci_connect_cfm(conn, status); | ||||
| 	if (status) | ||||
| 		hci_conn_del(conn); | ||||
| 
 | ||||
| unlock: | ||||
|  | @ -5527,11 +5534,6 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status, | |||
| 	struct smp_irk *irk; | ||||
| 	u8 addr_type; | ||||
| 
 | ||||
| 	if (handle > HCI_CONN_HANDLE_MAX) { | ||||
| 		bt_dev_err(hdev, "Ignoring HCI_LE_Connection_Complete for invalid handle"); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	hci_dev_lock(hdev); | ||||
| 
 | ||||
| 	/* All controllers implicitly stop advertising in the event of a
 | ||||
|  | @ -5541,6 +5543,12 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status, | |||
| 
 | ||||
| 	conn = hci_lookup_le_connect(hdev); | ||||
| 	if (!conn) { | ||||
| 		/* In case of error status and there is no connection pending
 | ||||
| 		 * just unlock as there is nothing to cleanup. | ||||
| 		 */ | ||||
| 		if (status) | ||||
| 			goto unlock; | ||||
| 
 | ||||
| 		conn = hci_conn_add(hdev, LE_LINK, bdaddr, role); | ||||
| 		if (!conn) { | ||||
| 			bt_dev_err(hdev, "no memory for new connection"); | ||||
|  | @ -5603,8 +5611,14 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status, | |||
| 
 | ||||
| 	conn->dst_type = ev_bdaddr_type(hdev, conn->dst_type, NULL); | ||||
| 
 | ||||
| 	if (handle > HCI_CONN_HANDLE_MAX) { | ||||
| 		bt_dev_err(hdev, "Invalid handle: 0x%4.4x > 0x%4.4x", handle, | ||||
| 			   HCI_CONN_HANDLE_MAX); | ||||
| 		status = HCI_ERROR_INVALID_PARAMETERS; | ||||
| 	} | ||||
| 
 | ||||
| 	if (status) { | ||||
| 		hci_le_conn_failed(conn, status); | ||||
| 		hci_conn_failed(conn, status); | ||||
| 		goto unlock; | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -4408,12 +4408,21 @@ static int hci_reject_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, | |||
| static int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, | ||||
| 			       u8 reason) | ||||
| { | ||||
| 	int err; | ||||
| 
 | ||||
| 	switch (conn->state) { | ||||
| 	case BT_CONNECTED: | ||||
| 	case BT_CONFIG: | ||||
| 		return hci_disconnect_sync(hdev, conn, reason); | ||||
| 	case BT_CONNECT: | ||||
| 		return hci_connect_cancel_sync(hdev, conn); | ||||
| 		err = hci_connect_cancel_sync(hdev, conn); | ||||
| 		/* Cleanup hci_conn object if it cannot be cancelled as it
 | ||||
| 		 * likelly means the controller and host stack are out of sync. | ||||
| 		 */ | ||||
| 		if (err) | ||||
| 			hci_conn_failed(conn, err); | ||||
| 
 | ||||
| 		return err; | ||||
| 	case BT_CONNECT2: | ||||
| 		return hci_reject_conn_sync(hdev, conn, reason); | ||||
| 	default: | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Paolo Abeni
						Paolo Abeni