diff options
Diffstat (limited to 'net/bluetooth/hci_event.c')
| -rw-r--r-- | net/bluetooth/hci_event.c | 163 | 
1 files changed, 141 insertions, 22 deletions
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index cb25628c058..d5aa97ee6ff 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -56,7 +56,9 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)  	if (status)  		return; -	clear_bit(HCI_INQUIRY, &hdev->flags); +	if (test_bit(HCI_MGMT, &hdev->flags) && +				test_and_clear_bit(HCI_INQUIRY, &hdev->flags)) +		mgmt_discovering(hdev->id, 0);  	hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status); @@ -72,7 +74,9 @@ static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)  	if (status)  		return; -	clear_bit(HCI_INQUIRY, &hdev->flags); +	if (test_bit(HCI_MGMT, &hdev->flags) && +				test_and_clear_bit(HCI_INQUIRY, &hdev->flags)) +		mgmt_discovering(hdev->id, 0);  	hci_conn_check_pending(hdev);  } @@ -841,10 +845,14 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)  	if (status) {  		hci_req_complete(hdev, HCI_OP_INQUIRY, status); -  		hci_conn_check_pending(hdev); -	} else -		set_bit(HCI_INQUIRY, &hdev->flags); +		return; +	} + +	if (test_bit(HCI_MGMT, &hdev->flags) && +					!test_and_set_bit(HCI_INQUIRY, +							&hdev->flags)) +		mgmt_discovering(hdev->id, 1);  }  static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) @@ -1013,12 +1021,19 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status)  	hci_dev_lock(hdev);  	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); -	if (conn && hci_outgoing_auth_needed(hdev, conn)) { +	if (!conn) +		goto unlock; + +	if (!hci_outgoing_auth_needed(hdev, conn)) +		goto unlock; + +	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {  		struct hci_cp_auth_requested cp;  		cp.handle = __cpu_to_le16(conn->handle);  		hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);  	} +unlock:  	hci_dev_unlock(hdev);  } @@ -1208,7 +1223,9 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff  	BT_DBG("%s status %d", hdev->name, status); -	clear_bit(HCI_INQUIRY, &hdev->flags); +	if (test_bit(HCI_MGMT, &hdev->flags) && +				test_and_clear_bit(HCI_INQUIRY, &hdev->flags)) +		mgmt_discovering(hdev->id, 0);  	hci_req_complete(hdev, HCI_OP_INQUIRY, status); @@ -1228,6 +1245,12 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *  	hci_dev_lock(hdev); +	if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) { + +		if (test_bit(HCI_MGMT, &hdev->flags)) +			mgmt_discovering(hdev->id, 1); +	} +  	for (; num_rsp; num_rsp--, info++) {  		bacpy(&data.bdaddr, &info->bdaddr);  		data.pscan_rep_mode	= info->pscan_rep_mode; @@ -1443,7 +1466,6 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s  			conn->sec_level = conn->pending_sec_level;  		} else {  			mgmt_auth_failed(hdev->id, &conn->dst, ev->status); -			conn->sec_level = BT_SECURITY_LOW;  		}  		clear_bit(HCI_CONN_AUTH_PEND, &conn->pend); @@ -1501,12 +1523,19 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb  		mgmt_remote_name(hdev->id, &ev->bdaddr, ev->name);  	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); -	if (conn && hci_outgoing_auth_needed(hdev, conn)) { +	if (!conn) +		goto unlock; + +	if (!hci_outgoing_auth_needed(hdev, conn)) +		goto unlock; + +	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {  		struct hci_cp_auth_requested cp;  		cp.handle = __cpu_to_le16(conn->handle);  		hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);  	} +unlock:  	hci_dev_unlock(hdev);  } @@ -2006,9 +2035,16 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff  	if (!test_bit(HCI_PAIRABLE, &hdev->flags))  		hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,  					sizeof(ev->bdaddr), &ev->bdaddr); +	else if (test_bit(HCI_MGMT, &hdev->flags)) { +		u8 secure; -	if (test_bit(HCI_MGMT, &hdev->flags)) -		mgmt_pin_code_request(hdev->id, &ev->bdaddr); +		if (conn->pending_sec_level == BT_SECURITY_HIGH) +			secure = 1; +		else +			secure = 0; + +		mgmt_pin_code_request(hdev->id, &ev->bdaddr, secure); +	}  	hci_dev_unlock(hdev);  } @@ -2037,17 +2073,30 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff  	BT_DBG("%s found key type %u for %s", hdev->name, key->type,  							batostr(&ev->bdaddr)); -	if (!test_bit(HCI_DEBUG_KEYS, &hdev->flags) && key->type == 0x03) { +	if (!test_bit(HCI_DEBUG_KEYS, &hdev->flags) && +				key->type == HCI_LK_DEBUG_COMBINATION) {  		BT_DBG("%s ignoring debug key", hdev->name);  		goto not_found;  	}  	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); +	if (conn) { +		if (key->type == HCI_LK_UNAUTH_COMBINATION && +				conn->auth_type != 0xff && +				(conn->auth_type & 0x01)) { +			BT_DBG("%s ignoring unauthenticated key", hdev->name); +			goto not_found; +		} -	if (key->type == 0x04 && conn && conn->auth_type != 0xff && -						(conn->auth_type & 0x01)) { -		BT_DBG("%s ignoring unauthenticated key", hdev->name); -		goto not_found; +		if (key->type == HCI_LK_COMBINATION && key->pin_len < 16 && +				conn->pending_sec_level == BT_SECURITY_HIGH) { +			BT_DBG("%s ignoring key unauthenticated for high \ +							security", hdev->name); +			goto not_found; +		} + +		conn->key_type = key->type; +		conn->pin_length = key->pin_len;  	}  	bacpy(&cp.bdaddr, &ev->bdaddr); @@ -2079,11 +2128,15 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff  		hci_conn_hold(conn);  		conn->disc_timeout = HCI_DISCONN_TIMEOUT;  		pin_len = conn->pin_length; + +		if (ev->key_type != HCI_LK_CHANGED_COMBINATION) +			conn->key_type = ev->key_type; +  		hci_conn_put(conn);  	}  	if (test_bit(HCI_LINK_KEYS, &hdev->flags)) -		hci_add_link_key(hdev, 1, &ev->bdaddr, ev->link_key, +		hci_add_link_key(hdev, conn, 1, &ev->bdaddr, ev->link_key,  							ev->key_type, pin_len);  	hci_dev_unlock(hdev); @@ -2158,6 +2211,12 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct  	hci_dev_lock(hdev); +	if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) { + +		if (test_bit(HCI_MGMT, &hdev->flags)) +			mgmt_discovering(hdev->id, 1); +	} +  	if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {  		struct inquiry_info_with_rssi_and_pscan_mode *info;  		info = (void *) (skb->data + 1); @@ -2320,6 +2379,12 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct  	if (!num_rsp)  		return; +	if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) { + +		if (test_bit(HCI_MGMT, &hdev->flags)) +			mgmt_discovering(hdev->id, 1); +	} +  	hci_dev_lock(hdev);  	for (; num_rsp; num_rsp--, info++) { @@ -2353,7 +2418,7 @@ static inline u8 hci_get_auth_req(struct hci_conn *conn)  	/* If remote requests no-bonding follow that lead */  	if (conn->remote_auth == 0x00 || conn->remote_auth == 0x01) -		return 0x00; +		return conn->remote_auth | (conn->auth_type & 0x01);  	return conn->auth_type;  } @@ -2382,7 +2447,8 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff  		bacpy(&cp.bdaddr, &ev->bdaddr);  		cp.capability = conn->io_capability; -		cp.authentication = hci_get_auth_req(conn); +		conn->auth_type = hci_get_auth_req(conn); +		cp.authentication = conn->auth_type;  		if ((conn->out == 0x01 || conn->remote_oob == 0x01) &&  				hci_find_remote_oob_data(hdev, &conn->dst)) @@ -2396,7 +2462,7 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff  		struct hci_cp_io_capability_neg_reply cp;  		bacpy(&cp.bdaddr, &ev->bdaddr); -		cp.reason = 0x16; /* Pairing not allowed */ +		cp.reason = 0x18; /* Pairing not allowed */  		hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_NEG_REPLY,  							sizeof(cp), &cp); @@ -2431,14 +2497,67 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,  							struct sk_buff *skb)  {  	struct hci_ev_user_confirm_req *ev = (void *) skb->data; +	int loc_mitm, rem_mitm, confirm_hint = 0; +	struct hci_conn *conn;  	BT_DBG("%s", hdev->name);  	hci_dev_lock(hdev); -	if (test_bit(HCI_MGMT, &hdev->flags)) -		mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey); +	if (!test_bit(HCI_MGMT, &hdev->flags)) +		goto unlock; + +	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); +	if (!conn) +		goto unlock; + +	loc_mitm = (conn->auth_type & 0x01); +	rem_mitm = (conn->remote_auth & 0x01); + +	/* If we require MITM but the remote device can't provide that +	 * (it has NoInputNoOutput) then reject the confirmation +	 * request. The only exception is when we're dedicated bonding +	 * initiators (connect_cfm_cb set) since then we always have the MITM +	 * bit set. */ +	if (!conn->connect_cfm_cb && loc_mitm && conn->remote_cap == 0x03) { +		BT_DBG("Rejecting request: remote device can't provide MITM"); +		hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY, +					sizeof(ev->bdaddr), &ev->bdaddr); +		goto unlock; +	} + +	/* If no side requires MITM protection; auto-accept */ +	if ((!loc_mitm || conn->remote_cap == 0x03) && +				(!rem_mitm || conn->io_capability == 0x03)) { +		/* If we're not the initiators request authorization to +		 * proceed from user space (mgmt_user_confirm with +		 * confirm_hint set to 1). */ +		if (!test_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { +			BT_DBG("Confirming auto-accept as acceptor"); +			confirm_hint = 1; +			goto confirm; +		} + +		BT_DBG("Auto-accept of user confirmation with %ums delay", +						hdev->auto_accept_delay); + +		if (hdev->auto_accept_delay > 0) { +			int delay = msecs_to_jiffies(hdev->auto_accept_delay); +			mod_timer(&conn->auto_accept_timer, jiffies + delay); +			goto unlock; +		} + +		hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY, +						sizeof(ev->bdaddr), &ev->bdaddr); +		goto unlock; +	} + +confirm: +	mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey, +								confirm_hint); + +unlock:  	hci_dev_unlock(hdev);  }  |