Bluetooth: Add discovery state tracking
This patch adds proper state tracking to the device discovery process. This makes it possible to return appropriate errors when trying to stop a non-active discovery or start discovery when it is already ongoing. Once name resolving is implemented this also makes it possible to know what the right action to do is when a remote name lookup is cancelled. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Acked-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
		
							parent
							
								
									30883512be
								
							
						
					
					
						commit
						ff9ef57870
					
				| @ -57,6 +57,12 @@ struct inquiry_entry { | ||||
| }; | ||||
| 
 | ||||
| struct discovery_state { | ||||
| 	enum { | ||||
| 		DISCOVERY_STOPPED, | ||||
| 		DISCOVERY_STARTING, | ||||
| 		DISCOVERY_ACTIVE, | ||||
| 		DISCOVERY_STOPPING, | ||||
| 	} state; | ||||
| 	struct list_head all;		/* All devices found during inquiry */ | ||||
| 	struct list_head unknown;	/* Name state not known */ | ||||
| 	struct list_head resolve;	/* Name needs to be resolved */ | ||||
| @ -359,11 +365,14 @@ extern int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb); | ||||
| 
 | ||||
| static inline void discovery_init(struct hci_dev *hdev) | ||||
| { | ||||
| 	hdev->discovery.state = DISCOVERY_STOPPED; | ||||
| 	INIT_LIST_HEAD(&hdev->discovery.all); | ||||
| 	INIT_LIST_HEAD(&hdev->discovery.unknown); | ||||
| 	INIT_LIST_HEAD(&hdev->discovery.resolve); | ||||
| } | ||||
| 
 | ||||
| void hci_discovery_set_state(struct hci_dev *hdev, int state); | ||||
| 
 | ||||
| static inline int inquiry_cache_empty(struct hci_dev *hdev) | ||||
| { | ||||
| 	return list_empty(&hdev->discovery.all); | ||||
|  | ||||
| @ -355,6 +355,30 @@ struct hci_dev *hci_dev_get(int index) | ||||
| } | ||||
| 
 | ||||
| /* ---- Inquiry support ---- */ | ||||
| 
 | ||||
| void hci_discovery_set_state(struct hci_dev *hdev, int state) | ||||
| { | ||||
| 	BT_DBG("%s state %u -> %u", hdev->name, hdev->discovery.state, state); | ||||
| 
 | ||||
| 	if (hdev->discovery.state == state) | ||||
| 		return; | ||||
| 
 | ||||
| 	switch (state) { | ||||
| 	case DISCOVERY_STOPPED: | ||||
| 		mgmt_discovering(hdev, 0); | ||||
| 		break; | ||||
| 	case DISCOVERY_STARTING: | ||||
| 		break; | ||||
| 	case DISCOVERY_ACTIVE: | ||||
| 		mgmt_discovering(hdev, 1); | ||||
| 		break; | ||||
| 	case DISCOVERY_STOPPING: | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	hdev->discovery.state = state; | ||||
| } | ||||
| 
 | ||||
| static void inquiry_cache_flush(struct hci_dev *hdev) | ||||
| { | ||||
| 	struct discovery_state *cache = &hdev->discovery; | ||||
| @ -367,6 +391,7 @@ static void inquiry_cache_flush(struct hci_dev *hdev) | ||||
| 
 | ||||
| 	INIT_LIST_HEAD(&cache->unknown); | ||||
| 	INIT_LIST_HEAD(&cache->resolve); | ||||
| 	cache->state = DISCOVERY_STOPPED; | ||||
| } | ||||
| 
 | ||||
| struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr) | ||||
|  | ||||
| @ -65,7 +65,7 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb) | ||||
| 	clear_bit(HCI_INQUIRY, &hdev->flags); | ||||
| 
 | ||||
| 	hci_dev_lock(hdev); | ||||
| 	mgmt_discovering(hdev, 0); | ||||
| 	hci_discovery_set_state(hdev, DISCOVERY_STOPPED); | ||||
| 	hci_dev_unlock(hdev); | ||||
| 
 | ||||
| 	hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status); | ||||
| @ -1119,7 +1119,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) | ||||
| 	set_bit(HCI_INQUIRY, &hdev->flags); | ||||
| 
 | ||||
| 	hci_dev_lock(hdev); | ||||
| 	mgmt_discovering(hdev, 1); | ||||
| 	hci_discovery_set_state(hdev, DISCOVERY_ACTIVE); | ||||
| 	hci_dev_unlock(hdev); | ||||
| } | ||||
| 
 | ||||
| @ -1507,7 +1507,7 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff | ||||
| 		return; | ||||
| 
 | ||||
| 	hci_dev_lock(hdev); | ||||
| 	mgmt_discovering(hdev, 0); | ||||
| 	hci_discovery_set_state(hdev, DISCOVERY_STOPPED); | ||||
| 	hci_dev_unlock(hdev); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1918,6 +1918,12 @@ static int start_discovery(struct sock *sk, u16 index, | ||||
| 		goto failed; | ||||
| 	} | ||||
| 
 | ||||
| 	if (hdev->discovery.state != DISCOVERY_STOPPED) { | ||||
| 		err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, | ||||
| 						MGMT_STATUS_BUSY); | ||||
| 		goto failed; | ||||
| 	} | ||||
| 
 | ||||
| 	cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0); | ||||
| 	if (!cmd) { | ||||
| 		err = -ENOMEM; | ||||
| @ -1927,6 +1933,8 @@ static int start_discovery(struct sock *sk, u16 index, | ||||
| 	err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); | ||||
| 	if (err < 0) | ||||
| 		mgmt_pending_remove(cmd); | ||||
| 	else | ||||
| 		hci_discovery_set_state(hdev, DISCOVERY_STARTING); | ||||
| 
 | ||||
| failed: | ||||
| 	hci_dev_unlock(hdev); | ||||
| @ -1950,6 +1958,12 @@ static int stop_discovery(struct sock *sk, u16 index) | ||||
| 
 | ||||
| 	hci_dev_lock(hdev); | ||||
| 
 | ||||
| 	if (hdev->discovery.state != DISCOVERY_ACTIVE) { | ||||
| 		err = cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, | ||||
| 						MGMT_STATUS_REJECTED); | ||||
| 		goto failed; | ||||
| 	} | ||||
| 
 | ||||
| 	cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0); | ||||
| 	if (!cmd) { | ||||
| 		err = -ENOMEM; | ||||
| @ -1959,6 +1973,8 @@ static int stop_discovery(struct sock *sk, u16 index) | ||||
| 	err = hci_cancel_inquiry(hdev); | ||||
| 	if (err < 0) | ||||
| 		mgmt_pending_remove(cmd); | ||||
| 	else | ||||
| 		hci_discovery_set_state(hdev, DISCOVERY_STOPPING); | ||||
| 
 | ||||
| failed: | ||||
| 	hci_dev_unlock(hdev); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user