forked from mirrors/linux
		
	Bluetooth: Update device_connected and device_found events to latest API
This patch updates mgmt_ev_device_connected and mgmt_ev_device found to include an EIR-encoded remote name and class whenever possible. With this addition the mgmt_ev_remote_name event becomes unnecessary and can be removed. Since the connected event doesn't map to hci_conn_complete anymore a HCI_CONN_MGMT_CONNECTED flag is added to track when mgmt has been notified about a connection. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Acked-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
		
							parent
							
								
									a0c808b373
								
							
						
					
					
						commit
						b644ba3369
					
				
					 4 changed files with 112 additions and 50 deletions
				
			
		|  | @ -409,6 +409,7 @@ enum { | |||
| 	HCI_CONN_MODE_CHANGE_PEND, | ||||
| 	HCI_CONN_SCO_SETUP_PEND, | ||||
| 	HCI_CONN_LE_SMP_PEND, | ||||
| 	HCI_CONN_MGMT_CONNECTED, | ||||
| }; | ||||
| 
 | ||||
| static inline void hci_conn_hash_init(struct hci_dev *hdev) | ||||
|  | @ -933,7 +934,8 @@ int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status); | |||
| int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, | ||||
| 								u8 persistent); | ||||
| int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, | ||||
| 								u8 addr_type); | ||||
| 					u8 addr_type, u8 *name, u8 name_len, | ||||
| 					u8 *dev_class); | ||||
| int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, | ||||
| 						u8 link_type, u8 addr_type); | ||||
| int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status); | ||||
|  | @ -962,7 +964,8 @@ int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, | |||
| int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, | ||||
| 					u8 addr_type, u8 *dev_class, s8 rssi, | ||||
| 					u8 cfm_name, u8 *eir, u16 eir_len); | ||||
| int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name); | ||||
| int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, | ||||
| 			u8 addr_type, s8 rssi, u8 *name, u8 name_len); | ||||
| int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status); | ||||
| int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status); | ||||
| int mgmt_discovering(struct hci_dev *hdev, u8 discovering); | ||||
|  |  | |||
|  | @ -329,6 +329,11 @@ struct mgmt_ev_new_link_key { | |||
| } __packed; | ||||
| 
 | ||||
| #define MGMT_EV_DEVICE_CONNECTED	0x000A | ||||
| struct mgmt_ev_device_connected { | ||||
| 	struct mgmt_addr_info addr; | ||||
| 	__le16 eir_len; | ||||
| 	__u8 eir[0]; | ||||
| } __packed; | ||||
| 
 | ||||
| #define MGMT_EV_DEVICE_DISCONNECTED	0x000B | ||||
| 
 | ||||
|  | @ -371,20 +376,14 @@ struct mgmt_ev_device_found { | |||
| 	__u8 eir[0]; | ||||
| } __packed; | ||||
| 
 | ||||
| #define MGMT_EV_REMOTE_NAME		0x0012 | ||||
| struct mgmt_ev_remote_name { | ||||
| 	bdaddr_t bdaddr; | ||||
| 	__u8 name[MGMT_MAX_NAME_LENGTH]; | ||||
| } __packed; | ||||
| #define MGMT_EV_DISCOVERING		0x0012 | ||||
| 
 | ||||
| #define MGMT_EV_DISCOVERING		0x0013 | ||||
| 
 | ||||
| #define MGMT_EV_DEVICE_BLOCKED		0x0014 | ||||
| #define MGMT_EV_DEVICE_BLOCKED		0x0013 | ||||
| struct mgmt_ev_device_blocked { | ||||
| 	bdaddr_t bdaddr; | ||||
| } __packed; | ||||
| 
 | ||||
| #define MGMT_EV_DEVICE_UNBLOCKED	0x0015 | ||||
| #define MGMT_EV_DEVICE_UNBLOCKED	0x0014 | ||||
| struct mgmt_ev_device_unblocked { | ||||
| 	bdaddr_t bdaddr; | ||||
| } __packed; | ||||
|  |  | |||
|  | @ -1286,11 +1286,36 @@ static inline int hci_resolve_name(struct hci_dev *hdev, struct inquiry_entry *e | |||
| 	return hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp); | ||||
| } | ||||
| 
 | ||||
| static void hci_resolve_next_name(struct hci_dev *hdev, bdaddr_t *bdaddr) | ||||
| static bool hci_resolve_next_name(struct hci_dev *hdev) | ||||
| { | ||||
| 	struct discovery_state *discov = &hdev->discovery; | ||||
| 	struct inquiry_entry *e; | ||||
| 
 | ||||
| 	if (list_empty(&discov->resolve)) | ||||
| 		return false; | ||||
| 
 | ||||
| 	e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_NEEDED); | ||||
| 	if (hci_resolve_name(hdev, e) == 0) { | ||||
| 		e->name_state = NAME_PENDING; | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| static void hci_check_pending_name(struct hci_dev *hdev, struct hci_conn *conn, | ||||
| 					bdaddr_t *bdaddr, u8 *name, u8 name_len) | ||||
| { | ||||
| 	struct discovery_state *discov = &hdev->discovery; | ||||
| 	struct inquiry_entry *e; | ||||
| 
 | ||||
| 	if (conn && !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) | ||||
| 		mgmt_device_connected(hdev, bdaddr, ACL_LINK, 0x00, | ||||
| 					name, name_len, conn->dev_class); | ||||
| 
 | ||||
| 	if (discov->state == DISCOVERY_STOPPED) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (discov->state == DISCOVERY_STOPPING) | ||||
| 		goto discov_complete; | ||||
| 
 | ||||
|  | @ -1301,16 +1326,13 @@ static void hci_resolve_next_name(struct hci_dev *hdev, bdaddr_t *bdaddr) | |||
| 	if (e) { | ||||
| 		e->name_state = NAME_KNOWN; | ||||
| 		list_del(&e->list); | ||||
| 		if (name) | ||||
| 			mgmt_remote_name(hdev, bdaddr, ACL_LINK, 0x00, | ||||
| 					e->data.rssi, name, name_len); | ||||
| 	} | ||||
| 
 | ||||
| 	if (list_empty(&discov->resolve)) | ||||
| 		goto discov_complete; | ||||
| 
 | ||||
| 	e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_NEEDED); | ||||
| 	if (hci_resolve_name(hdev, e) == 0) { | ||||
| 		e->name_state = NAME_PENDING; | ||||
| 	if (hci_resolve_next_name(hdev)) | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| discov_complete: | ||||
| 	hci_discovery_set_state(hdev, DISCOVERY_STOPPED); | ||||
|  | @ -1334,10 +1356,11 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status) | |||
| 
 | ||||
| 	hci_dev_lock(hdev); | ||||
| 
 | ||||
| 	if (test_bit(HCI_MGMT, &hdev->dev_flags)) | ||||
| 		hci_resolve_next_name(hdev, &cp->bdaddr); | ||||
| 
 | ||||
| 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); | ||||
| 
 | ||||
| 	if (test_bit(HCI_MGMT, &hdev->dev_flags)) | ||||
| 		hci_check_pending_name(hdev, conn, &cp->bdaddr, NULL, 0); | ||||
| 
 | ||||
| 	if (!conn) | ||||
| 		goto unlock; | ||||
| 
 | ||||
|  | @ -1643,8 +1666,6 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s | |||
| 			conn->state = BT_CONFIG; | ||||
| 			hci_conn_hold(conn); | ||||
| 			conn->disc_timeout = HCI_DISCONN_TIMEOUT; | ||||
| 			mgmt_device_connected(hdev, &ev->bdaddr, conn->type, | ||||
| 							conn->dst_type); | ||||
| 		} else | ||||
| 			conn->state = BT_CONNECTED; | ||||
| 
 | ||||
|  | @ -1785,7 +1806,8 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff | |||
| 	if (ev->status == 0) | ||||
| 		conn->state = BT_CLOSED; | ||||
| 
 | ||||
| 	if (conn->type == ACL_LINK || conn->type == LE_LINK) { | ||||
| 	if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) && | ||||
| 			(conn->type == ACL_LINK || conn->type == LE_LINK)) { | ||||
| 		if (ev->status != 0) | ||||
| 			mgmt_disconnect_failed(hdev, &conn->dst, ev->status); | ||||
| 		else | ||||
|  | @ -1878,14 +1900,18 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb | |||
| 
 | ||||
| 	hci_dev_lock(hdev); | ||||
| 
 | ||||
| 	if (test_bit(HCI_MGMT, &hdev->dev_flags)) { | ||||
| 		if (ev->status == 0) | ||||
| 			mgmt_remote_name(hdev, &ev->bdaddr, ev->name); | ||||
| 
 | ||||
| 		hci_resolve_next_name(hdev, &ev->bdaddr); | ||||
| 	} | ||||
| 
 | ||||
| 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); | ||||
| 
 | ||||
| 	if (!test_bit(HCI_MGMT, &hdev->dev_flags)) | ||||
| 		goto check_auth; | ||||
| 
 | ||||
| 	if (ev->status == 0) | ||||
| 		hci_check_pending_name(hdev, conn, &ev->bdaddr, ev->name, | ||||
| 					strnlen(ev->name, HCI_MAX_NAME_LENGTH)); | ||||
| 	else | ||||
| 		hci_check_pending_name(hdev, conn, &ev->bdaddr, NULL, 0); | ||||
| 
 | ||||
| check_auth: | ||||
| 	if (!conn) | ||||
| 		goto unlock; | ||||
| 
 | ||||
|  | @ -1994,7 +2020,10 @@ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff | |||
| 		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)) | ||||
| 		mgmt_device_connected(hdev, &conn->dst, conn->type, | ||||
| 						conn->dst_type, NULL, 0, | ||||
| 						conn->dev_class); | ||||
| 
 | ||||
| 	if (!hci_outgoing_auth_needed(hdev, conn)) { | ||||
| 		conn->state = BT_CONNECTED; | ||||
|  | @ -2763,7 +2792,10 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b | |||
| 		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)) | ||||
| 		mgmt_device_connected(hdev, &conn->dst, conn->type, | ||||
| 						conn->dst_type, NULL, 0, | ||||
| 						conn->dev_class); | ||||
| 
 | ||||
| 	if (!hci_outgoing_auth_needed(hdev, conn)) { | ||||
| 		conn->state = BT_CONNECTED; | ||||
|  | @ -3164,7 +3196,9 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff | |||
| 		goto unlock; | ||||
| 	} | ||||
| 
 | ||||
| 	mgmt_device_connected(hdev, &ev->bdaddr, conn->type, conn->dst_type); | ||||
| 	if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) | ||||
| 		mgmt_device_connected(hdev, &ev->bdaddr, conn->type, | ||||
| 						conn->dst_type, NULL, 0, 0); | ||||
| 
 | ||||
| 	conn->sec_level = BT_SECURITY_LOW; | ||||
| 	conn->handle = __le16_to_cpu(ev->handle); | ||||
|  |  | |||
|  | @ -1244,7 +1244,6 @@ static int get_connections(struct sock *sk, u16 index) | |||
| 	struct mgmt_rp_get_connections *rp; | ||||
| 	struct hci_dev *hdev; | ||||
| 	struct hci_conn *c; | ||||
| 	struct list_head *p; | ||||
| 	size_t rp_len; | ||||
| 	u16 count; | ||||
| 	int i, err; | ||||
|  | @ -1259,8 +1258,9 @@ static int get_connections(struct sock *sk, u16 index) | |||
| 	hci_dev_lock(hdev); | ||||
| 
 | ||||
| 	count = 0; | ||||
| 	list_for_each(p, &hdev->conn_hash.list) { | ||||
| 		count++; | ||||
| 	list_for_each_entry(c, &hdev->conn_hash.list, list) { | ||||
| 		if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags)) | ||||
| 			count++; | ||||
| 	} | ||||
| 
 | ||||
| 	rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info)); | ||||
|  | @ -1274,6 +1274,8 @@ static int get_connections(struct sock *sk, u16 index) | |||
| 
 | ||||
| 	i = 0; | ||||
| 	list_for_each_entry(c, &hdev->conn_hash.list, list) { | ||||
| 		if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags)) | ||||
| 			continue; | ||||
| 		bacpy(&rp->addr[i].bdaddr, &c->dst); | ||||
| 		rp->addr[i].type = link_to_mgmt(c->type, c->dst_type); | ||||
| 		if (rp->addr[i].type == MGMT_ADDR_INVALID) | ||||
|  | @ -2465,15 +2467,28 @@ int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, | |||
| } | ||||
| 
 | ||||
| int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, | ||||
| 								u8 addr_type) | ||||
| 					u8 addr_type, u8 *name, u8 name_len, | ||||
| 					u8 *dev_class) | ||||
| { | ||||
| 	struct mgmt_addr_info ev; | ||||
| 	char buf[512]; | ||||
| 	struct mgmt_ev_device_connected *ev = (void *) buf; | ||||
| 	u16 eir_len = 0; | ||||
| 
 | ||||
| 	bacpy(&ev.bdaddr, bdaddr); | ||||
| 	ev.type = link_to_mgmt(link_type, addr_type); | ||||
| 	bacpy(&ev->addr.bdaddr, bdaddr); | ||||
| 	ev->addr.type = link_to_mgmt(link_type, addr_type); | ||||
| 
 | ||||
| 	return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, &ev, sizeof(ev), | ||||
| 									NULL); | ||||
| 	if (name_len > 0) | ||||
| 		eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, | ||||
| 								name, name_len); | ||||
| 
 | ||||
| 	if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0) | ||||
| 		eir_len = eir_append_data(&ev->eir[eir_len], eir_len, | ||||
| 					EIR_CLASS_OF_DEV, dev_class, 3); | ||||
| 
 | ||||
| 	put_unaligned_le16(eir_len, &ev->eir_len); | ||||
| 
 | ||||
| 	return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf, | ||||
| 						sizeof(*ev) + eir_len, NULL); | ||||
| } | ||||
| 
 | ||||
| static void disconnect_rsp(struct pending_cmd *cmd, void *data) | ||||
|  | @ -2813,16 +2828,27 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, | |||
| 	return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL); | ||||
| } | ||||
| 
 | ||||
| int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name) | ||||
| int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, | ||||
| 				u8 addr_type, s8 rssi, u8 *name, u8 name_len) | ||||
| { | ||||
| 	struct mgmt_ev_remote_name ev; | ||||
| 	struct mgmt_ev_device_found *ev; | ||||
| 	char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2]; | ||||
| 	u16 eir_len; | ||||
| 
 | ||||
| 	memset(&ev, 0, sizeof(ev)); | ||||
| 	ev = (struct mgmt_ev_device_found *) buf; | ||||
| 
 | ||||
| 	bacpy(&ev.bdaddr, bdaddr); | ||||
| 	memcpy(ev.name, name, HCI_MAX_NAME_LENGTH); | ||||
| 	memset(buf, 0, sizeof(buf)); | ||||
| 
 | ||||
| 	return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL); | ||||
| 	bacpy(&ev->addr.bdaddr, bdaddr); | ||||
| 	ev->addr.type = link_to_mgmt(link_type, addr_type); | ||||
| 	ev->rssi = rssi; | ||||
| 
 | ||||
| 	eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name, | ||||
| 								name_len); | ||||
| 
 | ||||
| 	put_unaligned_le16(eir_len, &ev->eir_len); | ||||
| 
 | ||||
| 	return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL); | ||||
| } | ||||
| 
 | ||||
| int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status) | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Johan Hedberg
						Johan Hedberg