mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	Bluetooth: hci_conn: Always allocate unique handles
This attempts to always allocate a unique handle for connections so they can be properly aborted by the likes of hci_abort_conn, so this uses the invalid range as a pool of unset handles that way if userspace is trying to create multiple connections at once each will be given a unique handle which will be considered unset. Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
		
							parent
							
								
									04a51d6169
								
							
						
					
					
						commit
						9f78191cc9
					
				
					 3 changed files with 26 additions and 7 deletions
				
			
		| 
						 | 
				
			
			@ -321,8 +321,8 @@ struct adv_monitor {
 | 
			
		|||
 | 
			
		||||
#define HCI_MAX_SHORT_NAME_LENGTH	10
 | 
			
		||||
 | 
			
		||||
#define HCI_CONN_HANDLE_UNSET		0xffff
 | 
			
		||||
#define HCI_CONN_HANDLE_MAX		0x0eff
 | 
			
		||||
#define HCI_CONN_HANDLE_UNSET(_handle)	(_handle > HCI_CONN_HANDLE_MAX)
 | 
			
		||||
 | 
			
		||||
/* Min encryption key size to match with SMP */
 | 
			
		||||
#define HCI_MIN_ENC_KEY_SIZE		7
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -932,6 +932,25 @@ static void cis_cleanup(struct hci_conn *conn)
 | 
			
		|||
	hci_le_remove_cig(hdev, conn->iso_qos.ucast.cig);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static u16 hci_conn_hash_alloc_unset(struct hci_dev *hdev)
 | 
			
		||||
{
 | 
			
		||||
	struct hci_conn_hash *h = &hdev->conn_hash;
 | 
			
		||||
	struct hci_conn  *c;
 | 
			
		||||
	u16 handle = HCI_CONN_HANDLE_MAX + 1;
 | 
			
		||||
 | 
			
		||||
	rcu_read_lock();
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry_rcu(c, &h->list, list) {
 | 
			
		||||
		/* Find the first unused handle */
 | 
			
		||||
		if (handle == 0xffff || c->handle != handle)
 | 
			
		||||
			break;
 | 
			
		||||
		handle++;
 | 
			
		||||
	}
 | 
			
		||||
	rcu_read_unlock();
 | 
			
		||||
 | 
			
		||||
	return handle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
 | 
			
		||||
			      u8 role)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -945,7 +964,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
 | 
			
		|||
 | 
			
		||||
	bacpy(&conn->dst, dst);
 | 
			
		||||
	bacpy(&conn->src, &hdev->bdaddr);
 | 
			
		||||
	conn->handle = HCI_CONN_HANDLE_UNSET;
 | 
			
		||||
	conn->handle = hci_conn_hash_alloc_unset(hdev);
 | 
			
		||||
	conn->hdev  = hdev;
 | 
			
		||||
	conn->type  = type;
 | 
			
		||||
	conn->role  = role;
 | 
			
		||||
| 
						 | 
				
			
			@ -1057,7 +1076,7 @@ static void hci_conn_unlink(struct hci_conn *conn)
 | 
			
		|||
			 */
 | 
			
		||||
			if ((child->type == SCO_LINK ||
 | 
			
		||||
			     child->type == ESCO_LINK) &&
 | 
			
		||||
			    child->handle == HCI_CONN_HANDLE_UNSET)
 | 
			
		||||
			    HCI_CONN_HANDLE_UNSET(child->handle))
 | 
			
		||||
				hci_conn_del(child);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1943,7 +1962,7 @@ int hci_conn_check_create_cis(struct hci_conn *conn)
 | 
			
		|||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	if (!conn->parent || conn->parent->state != BT_CONNECTED ||
 | 
			
		||||
	    conn->state != BT_CONNECT || conn->handle == HCI_CONN_HANDLE_UNSET)
 | 
			
		||||
	    conn->state != BT_CONNECT || HCI_CONN_HANDLE_UNSET(conn->handle))
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3173,7 +3173,7 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data,
 | 
			
		|||
	 * As the connection handle is set here for the first time, it indicates
 | 
			
		||||
	 * whether the connection is already set up.
 | 
			
		||||
	 */
 | 
			
		||||
	if (conn->handle != HCI_CONN_HANDLE_UNSET) {
 | 
			
		||||
	if (!HCI_CONN_HANDLE_UNSET(conn->handle)) {
 | 
			
		||||
		bt_dev_err(hdev, "Ignoring HCI_Connection_Complete for existing connection");
 | 
			
		||||
		goto unlock;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -5032,7 +5032,7 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev, void *data,
 | 
			
		|||
	 * As the connection handle is set here for the first time, it indicates
 | 
			
		||||
	 * whether the connection is already set up.
 | 
			
		||||
	 */
 | 
			
		||||
	if (conn->handle != HCI_CONN_HANDLE_UNSET) {
 | 
			
		||||
	if (!HCI_CONN_HANDLE_UNSET(conn->handle)) {
 | 
			
		||||
		bt_dev_err(hdev, "Ignoring HCI_Sync_Conn_Complete event for existing connection");
 | 
			
		||||
		goto unlock;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -5896,7 +5896,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
 | 
			
		|||
	 * As the connection handle is set here for the first time, it indicates
 | 
			
		||||
	 * whether the connection is already set up.
 | 
			
		||||
	 */
 | 
			
		||||
	if (conn->handle != HCI_CONN_HANDLE_UNSET) {
 | 
			
		||||
	if (!HCI_CONN_HANDLE_UNSET(conn->handle)) {
 | 
			
		||||
		bt_dev_err(hdev, "Ignoring HCI_Connection_Complete for existing connection");
 | 
			
		||||
		goto unlock;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue