diff options
Diffstat (limited to 'net/bluetooth/smp.c')
| -rw-r--r-- | net/bluetooth/smp.c | 68 | 
1 files changed, 47 insertions, 21 deletions
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index ae91e2d40056..a1c1b7e8a45c 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -83,13 +83,11 @@ enum {  struct smp_dev {  	/* Secure Connections OOB data */ +	bool			local_oob;  	u8			local_pk[64];  	u8			local_rand[16];  	bool			debug_key; -	u8			min_key_size; -	u8			max_key_size; -  	struct crypto_cipher	*tfm_aes;  	struct crypto_shash	*tfm_cmac;  	struct crypto_kpp	*tfm_ecdh; @@ -599,6 +597,8 @@ int smp_generate_oob(struct hci_dev *hdev, u8 hash[16], u8 rand[16])  	memcpy(rand, smp->local_rand, 16); +	smp->local_oob = true; +  	return 0;  } @@ -717,7 +717,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,  	if (rsp == NULL) {  		req->io_capability = conn->hcon->io_capability;  		req->oob_flag = oob_flag; -		req->max_key_size = SMP_DEV(hdev)->max_key_size; +		req->max_key_size = hdev->le_max_key_size;  		req->init_key_dist = local_dist;  		req->resp_key_dist = remote_dist;  		req->auth_req = (authreq & AUTH_REQ_MASK(hdev)); @@ -728,7 +728,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,  	rsp->io_capability = conn->hcon->io_capability;  	rsp->oob_flag = oob_flag; -	rsp->max_key_size = SMP_DEV(hdev)->max_key_size; +	rsp->max_key_size = hdev->le_max_key_size;  	rsp->init_key_dist = req->init_key_dist & remote_dist;  	rsp->resp_key_dist = req->resp_key_dist & local_dist;  	rsp->auth_req = (authreq & AUTH_REQ_MASK(hdev)); @@ -742,7 +742,7 @@ static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)  	struct hci_dev *hdev = conn->hcon->hdev;  	struct smp_chan *smp = chan->data; -	if (max_key_size > SMP_DEV(hdev)->max_key_size || +	if (max_key_size > hdev->le_max_key_size ||  	    max_key_size < SMP_MIN_ENC_KEY_SIZE)  		return SMP_ENC_KEY_SIZE; @@ -1785,7 +1785,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)  	 * successfully received our local OOB data - therefore set the  	 * flag to indicate that local OOB is in use.  	 */ -	if (req->oob_flag == SMP_OOB_PRESENT) +	if (req->oob_flag == SMP_OOB_PRESENT && SMP_DEV(hdev)->local_oob)  		set_bit(SMP_FLAG_LOCAL_OOB, &smp->flags);  	/* SMP over BR/EDR requires special treatment */ @@ -1967,7 +1967,7 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)  	 * successfully received our local OOB data - therefore set the  	 * flag to indicate that local OOB is in use.  	 */ -	if (rsp->oob_flag == SMP_OOB_PRESENT) +	if (rsp->oob_flag == SMP_OOB_PRESENT && SMP_DEV(hdev)->local_oob)  		set_bit(SMP_FLAG_LOCAL_OOB, &smp->flags);  	smp->prsp[0] = SMP_CMD_PAIRING_RSP; @@ -2419,30 +2419,51 @@ unlock:  	return ret;  } -void smp_cancel_pairing(struct hci_conn *hcon) +int smp_cancel_and_remove_pairing(struct hci_dev *hdev, bdaddr_t *bdaddr, +				  u8 addr_type)  { -	struct l2cap_conn *conn = hcon->l2cap_data; +	struct hci_conn *hcon; +	struct l2cap_conn *conn;  	struct l2cap_chan *chan;  	struct smp_chan *smp; +	int err; + +	err = hci_remove_ltk(hdev, bdaddr, addr_type); +	hci_remove_irk(hdev, bdaddr, addr_type); +	hcon = hci_conn_hash_lookup_le(hdev, bdaddr, addr_type); +	if (!hcon) +		goto done; + +	conn = hcon->l2cap_data;  	if (!conn) -		return; +		goto done;  	chan = conn->smp;  	if (!chan) -		return; +		goto done;  	l2cap_chan_lock(chan);  	smp = chan->data;  	if (smp) { +		/* Set keys to NULL to make sure smp_failure() does not try to +		 * remove and free already invalidated rcu list entries. */ +		smp->ltk = NULL; +		smp->slave_ltk = NULL; +		smp->remote_irk = NULL; +  		if (test_bit(SMP_FLAG_COMPLETE, &smp->flags))  			smp_failure(conn, 0);  		else  			smp_failure(conn, SMP_UNSPECIFIED); +		err = 0;  	}  	l2cap_chan_unlock(chan); + +done: +	return err;  }  static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb) @@ -2697,7 +2718,13 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)  	 * key was set/generated.  	 */  	if (test_bit(SMP_FLAG_LOCAL_OOB, &smp->flags)) { -		struct smp_dev *smp_dev = chan->data; +		struct l2cap_chan *hchan = hdev->smp_data; +		struct smp_dev *smp_dev; + +		if (!hchan || !hchan->data) +			return SMP_UNSPECIFIED; + +		smp_dev = hchan->data;  		tfm_ecdh = smp_dev->tfm_ecdh;  	} else { @@ -3230,11 +3257,10 @@ static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid)  		return ERR_CAST(tfm_ecdh);  	} +	smp->local_oob = false;  	smp->tfm_aes = tfm_aes;  	smp->tfm_cmac = tfm_cmac;  	smp->tfm_ecdh = tfm_ecdh; -	smp->min_key_size = SMP_MIN_ENC_KEY_SIZE; -	smp->max_key_size = SMP_MAX_ENC_KEY_SIZE;  create_chan:  	chan = l2cap_chan_create(); @@ -3360,7 +3386,7 @@ static ssize_t le_min_key_size_read(struct file *file,  	struct hci_dev *hdev = file->private_data;  	char buf[4]; -	snprintf(buf, sizeof(buf), "%2u\n", SMP_DEV(hdev)->min_key_size); +	snprintf(buf, sizeof(buf), "%2u\n", hdev->le_min_key_size);  	return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));  } @@ -3381,11 +3407,11 @@ static ssize_t le_min_key_size_write(struct file *file,  	sscanf(buf, "%hhu", &key_size); -	if (key_size > SMP_DEV(hdev)->max_key_size || +	if (key_size > hdev->le_max_key_size ||  	    key_size < SMP_MIN_ENC_KEY_SIZE)  		return -EINVAL; -	SMP_DEV(hdev)->min_key_size = key_size; +	hdev->le_min_key_size = key_size;  	return count;  } @@ -3404,7 +3430,7 @@ static ssize_t le_max_key_size_read(struct file *file,  	struct hci_dev *hdev = file->private_data;  	char buf[4]; -	snprintf(buf, sizeof(buf), "%2u\n", SMP_DEV(hdev)->max_key_size); +	snprintf(buf, sizeof(buf), "%2u\n", hdev->le_max_key_size);  	return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));  } @@ -3426,10 +3452,10 @@ static ssize_t le_max_key_size_write(struct file *file,  	sscanf(buf, "%hhu", &key_size);  	if (key_size > SMP_MAX_ENC_KEY_SIZE || -	    key_size < SMP_DEV(hdev)->min_key_size) +	    key_size < hdev->le_min_key_size)  		return -EINVAL; -	SMP_DEV(hdev)->max_key_size = key_size; +	hdev->le_max_key_size = key_size;  	return count;  }  | 
