diff options
Diffstat (limited to 'net/bluetooth/mgmt.c')
| -rw-r--r-- | net/bluetooth/mgmt.c | 2400 | 
1 files changed, 1200 insertions, 1200 deletions
| diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 3e5283607b97..37087cf7dc5a 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -39,6 +39,7 @@  #include "mgmt_config.h"  #include "msft.h"  #include "eir.h" +#include "aosp.h"  #define MGMT_VERSION	1  #define MGMT_REVISION	21 @@ -276,10 +277,39 @@ static const u8 mgmt_status_table[] = {  	MGMT_STATUS_CONNECT_FAILED,	/* MAC Connection Failed */  }; -static u8 mgmt_status(u8 hci_status) +static u8 mgmt_errno_status(int err)  { -	if (hci_status < ARRAY_SIZE(mgmt_status_table)) -		return mgmt_status_table[hci_status]; +	switch (err) { +	case 0: +		return MGMT_STATUS_SUCCESS; +	case -EPERM: +		return MGMT_STATUS_REJECTED; +	case -EINVAL: +		return MGMT_STATUS_INVALID_PARAMS; +	case -EOPNOTSUPP: +		return MGMT_STATUS_NOT_SUPPORTED; +	case -EBUSY: +		return MGMT_STATUS_BUSY; +	case -ETIMEDOUT: +		return MGMT_STATUS_AUTH_FAILED; +	case -ENOMEM: +		return MGMT_STATUS_NO_RESOURCES; +	case -EISCONN: +		return MGMT_STATUS_ALREADY_CONNECTED; +	case -ENOTCONN: +		return MGMT_STATUS_DISCONNECTED; +	} + +	return MGMT_STATUS_FAILED; +} + +static u8 mgmt_status(int err) +{ +	if (err < 0) +		return mgmt_errno_status(err); + +	if (err < ARRAY_SIZE(mgmt_status_table)) +		return mgmt_status_table[err];  	return MGMT_STATUS_FAILED;  } @@ -305,6 +335,12 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,  			       HCI_SOCK_TRUSTED, skip_sk);  } +static int mgmt_event_skb(struct sk_buff *skb, struct sock *skip_sk) +{ +	return mgmt_send_event_skb(HCI_CHANNEL_CONTROL, skb, HCI_SOCK_TRUSTED, +				   skip_sk); +} +  static u8 le_addr_type(u8 mgmt_addr_type)  {  	if (mgmt_addr_type == BDADDR_LE_PUBLIC) @@ -810,12 +846,7 @@ static u32 get_supported_settings(struct hci_dev *hdev)  		settings |= MGMT_SETTING_SECURE_CONN;  		settings |= MGMT_SETTING_PRIVACY;  		settings |= MGMT_SETTING_STATIC_ADDRESS; - -		/* When the experimental feature for LL Privacy support is -		 * enabled, then advertising is no longer supported. -		 */ -		if (!hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY)) -			settings |= MGMT_SETTING_ADVERTISING; +		settings |= MGMT_SETTING_ADVERTISING;  	}  	if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) || @@ -903,13 +934,6 @@ static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)  	return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);  } -static struct mgmt_pending_cmd *pending_find_data(u16 opcode, -						  struct hci_dev *hdev, -						  const void *data) -{ -	return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data); -} -  u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev)  {  	struct mgmt_pending_cmd *cmd; @@ -951,32 +975,41 @@ bool mgmt_get_connectable(struct hci_dev *hdev)  	return hci_dev_test_flag(hdev, HCI_CONNECTABLE);  } +static int service_cache_sync(struct hci_dev *hdev, void *data) +{ +	hci_update_eir_sync(hdev); +	hci_update_class_sync(hdev); + +	return 0; +} +  static void service_cache_off(struct work_struct *work)  {  	struct hci_dev *hdev = container_of(work, struct hci_dev,  					    service_cache.work); -	struct hci_request req;  	if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))  		return; -	hci_req_init(&req, hdev); - -	hci_dev_lock(hdev); - -	__hci_req_update_eir(&req); -	__hci_req_update_class(&req); - -	hci_dev_unlock(hdev); +	hci_cmd_sync_queue(hdev, service_cache_sync, NULL, NULL); +} -	hci_req_run(&req, NULL); +static int rpa_expired_sync(struct hci_dev *hdev, void *data) +{ +	/* The generation of a new RPA and programming it into the +	 * controller happens in the hci_req_enable_advertising() +	 * function. +	 */ +	if (ext_adv_capable(hdev)) +		return hci_start_ext_adv_sync(hdev, hdev->cur_adv_instance); +	else +		return hci_enable_advertising_sync(hdev);  }  static void rpa_expired(struct work_struct *work)  {  	struct hci_dev *hdev = container_of(work, struct hci_dev,  					    rpa_expired.work); -	struct hci_request req;  	bt_dev_dbg(hdev, ""); @@ -985,16 +1018,7 @@ static void rpa_expired(struct work_struct *work)  	if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))  		return; -	/* The generation of a new RPA and programming it into the -	 * controller happens in the hci_req_enable_advertising() -	 * function. -	 */ -	hci_req_init(&req, hdev); -	if (ext_adv_capable(hdev)) -		__hci_req_start_ext_adv(&req, hdev->cur_adv_instance); -	else -		__hci_req_enable_advertising(&req); -	hci_req_run(&req, NULL); +	hci_cmd_sync_queue(hdev, rpa_expired_sync, NULL, NULL);  }  static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev) @@ -1131,16 +1155,6 @@ static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)  				 sizeof(settings));  } -static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode) -{ -	bt_dev_dbg(hdev, "status 0x%02x", status); - -	if (hci_conn_count(hdev) == 0) { -		cancel_delayed_work(&hdev->power_off); -		queue_work(hdev->req_workqueue, &hdev->power_off.work); -	} -} -  void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)  {  	struct mgmt_ev_advertising_added ev; @@ -1168,38 +1182,77 @@ static void cancel_adv_timeout(struct hci_dev *hdev)  	}  } -static int clean_up_hci_state(struct hci_dev *hdev) +/* This function requires the caller holds hdev->lock */ +static void restart_le_actions(struct hci_dev *hdev)  { -	struct hci_request req; -	struct hci_conn *conn; -	bool discov_stopped; -	int err; +	struct hci_conn_params *p; -	hci_req_init(&req, hdev); +	list_for_each_entry(p, &hdev->le_conn_params, list) { +		/* Needed for AUTO_OFF case where might not "really" +		 * have been powered off. +		 */ +		list_del_init(&p->action); -	if (test_bit(HCI_ISCAN, &hdev->flags) || -	    test_bit(HCI_PSCAN, &hdev->flags)) { -		u8 scan = 0x00; -		hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); +		switch (p->auto_connect) { +		case HCI_AUTO_CONN_DIRECT: +		case HCI_AUTO_CONN_ALWAYS: +			list_add(&p->action, &hdev->pend_le_conns); +			break; +		case HCI_AUTO_CONN_REPORT: +			list_add(&p->action, &hdev->pend_le_reports); +			break; +		default: +			break; +		}  	} +} -	hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, false); +static int new_settings(struct hci_dev *hdev, struct sock *skip) +{ +	__le32 ev = cpu_to_le32(get_current_settings(hdev)); -	if (hci_dev_test_flag(hdev, HCI_LE_ADV)) -		__hci_req_disable_advertising(&req); +	return mgmt_limited_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, +				  sizeof(ev), HCI_MGMT_SETTING_EVENTS, skip); +} -	discov_stopped = hci_req_stop_discovery(&req); +static void mgmt_set_powered_complete(struct hci_dev *hdev, void *data, int err) +{ +	struct mgmt_pending_cmd *cmd = data; +	struct mgmt_mode *cp = cmd->param; + +	bt_dev_dbg(hdev, "err %d", err); + +	if (!err) { +		if (cp->val) { +			hci_dev_lock(hdev); +			restart_le_actions(hdev); +			hci_update_passive_scan(hdev); +			hci_dev_unlock(hdev); +		} -	list_for_each_entry(conn, &hdev->conn_hash.list, list) { -		/* 0x15 == Terminated due to Power Off */ -		__hci_abort_conn(&req, conn, 0x15); +		send_settings_rsp(cmd->sk, cmd->opcode, hdev); + +		/* Only call new_setting for power on as power off is deferred +		 * to hdev->power_off work which does call hci_dev_do_close. +		 */ +		if (cp->val) +			new_settings(hdev, cmd->sk); +	} else { +		mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, +				mgmt_status(err));  	} -	err = hci_req_run(&req, clean_up_hci_complete); -	if (!err && discov_stopped) -		hci_discovery_set_state(hdev, DISCOVERY_STOPPING); +	mgmt_pending_free(cmd); +} -	return err; +static int set_powered_sync(struct hci_dev *hdev, void *data) +{ +	struct mgmt_pending_cmd *cmd = data; +	struct mgmt_mode *cp = cmd->param; + +	BT_DBG("%s", hdev->name); + +	return hci_set_powered_sync(hdev, cp->val);  }  static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, @@ -1228,43 +1281,20 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,  		goto failed;  	} -	cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len); +	cmd = mgmt_pending_new(sk, MGMT_OP_SET_POWERED, hdev, data, len);  	if (!cmd) {  		err = -ENOMEM;  		goto failed;  	} -	if (cp->val) { -		queue_work(hdev->req_workqueue, &hdev->power_on); -		err = 0; -	} else { -		/* Disconnect connections, stop scans, etc */ -		err = clean_up_hci_state(hdev); -		if (!err) -			queue_delayed_work(hdev->req_workqueue, &hdev->power_off, -					   HCI_POWER_OFF_TIMEOUT); - -		/* ENODATA means there were no HCI commands queued */ -		if (err == -ENODATA) { -			cancel_delayed_work(&hdev->power_off); -			queue_work(hdev->req_workqueue, &hdev->power_off.work); -			err = 0; -		} -	} +	err = hci_cmd_sync_queue(hdev, set_powered_sync, cmd, +				 mgmt_set_powered_complete);  failed:  	hci_dev_unlock(hdev);  	return err;  } -static int new_settings(struct hci_dev *hdev, struct sock *skip) -{ -	__le32 ev = cpu_to_le32(get_current_settings(hdev)); - -	return mgmt_limited_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, -				  sizeof(ev), HCI_MGMT_SETTING_EVENTS, skip); -} -  int mgmt_new_settings(struct hci_dev *hdev)  {  	return new_settings(hdev, NULL); @@ -1346,23 +1376,20 @@ static u8 mgmt_le_support(struct hci_dev *hdev)  		return MGMT_STATUS_SUCCESS;  } -void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status) +static void mgmt_set_discoverable_complete(struct hci_dev *hdev, void *data, +					   int err)  { -	struct mgmt_pending_cmd *cmd; +	struct mgmt_pending_cmd *cmd = data; -	bt_dev_dbg(hdev, "status 0x%02x", status); +	bt_dev_dbg(hdev, "err %d", err);  	hci_dev_lock(hdev); -	cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev); -	if (!cmd) -		goto unlock; - -	if (status) { -		u8 mgmt_err = mgmt_status(status); +	if (err) { +		u8 mgmt_err = mgmt_status(err);  		mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);  		hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE); -		goto remove_cmd; +		goto done;  	}  	if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) && @@ -1374,13 +1401,18 @@ void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status)  	send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);  	new_settings(hdev, cmd->sk); -remove_cmd: -	mgmt_pending_remove(cmd); - -unlock: +done: +	mgmt_pending_free(cmd);  	hci_dev_unlock(hdev);  } +static int set_discoverable_sync(struct hci_dev *hdev, void *data) +{ +	BT_DBG("%s", hdev->name); + +	return hci_update_discoverable_sync(hdev); +} +  static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,  			    u16 len)  { @@ -1479,7 +1511,7 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,  		goto failed;  	} -	cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len); +	cmd = mgmt_pending_new(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);  	if (!cmd) {  		err = -ENOMEM;  		goto failed; @@ -1503,39 +1535,34 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,  	else  		hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE); -	queue_work(hdev->req_workqueue, &hdev->discoverable_update); -	err = 0; +	err = hci_cmd_sync_queue(hdev, set_discoverable_sync, cmd, +				 mgmt_set_discoverable_complete);  failed:  	hci_dev_unlock(hdev);  	return err;  } -void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status) +static void mgmt_set_connectable_complete(struct hci_dev *hdev, void *data, +					  int err)  { -	struct mgmt_pending_cmd *cmd; +	struct mgmt_pending_cmd *cmd = data; -	bt_dev_dbg(hdev, "status 0x%02x", status); +	bt_dev_dbg(hdev, "err %d", err);  	hci_dev_lock(hdev); -	cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev); -	if (!cmd) -		goto unlock; - -	if (status) { -		u8 mgmt_err = mgmt_status(status); +	if (err) { +		u8 mgmt_err = mgmt_status(err);  		mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err); -		goto remove_cmd; +		goto done;  	}  	send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);  	new_settings(hdev, cmd->sk); -remove_cmd: -	mgmt_pending_remove(cmd); - -unlock: +done: +	mgmt_pending_free(cmd);  	hci_dev_unlock(hdev);  } @@ -1561,13 +1588,20 @@ static int set_connectable_update_settings(struct hci_dev *hdev,  	if (changed) {  		hci_req_update_scan(hdev); -		hci_update_background_scan(hdev); +		hci_update_passive_scan(hdev);  		return new_settings(hdev, sk);  	}  	return 0;  } +static int set_connectable_sync(struct hci_dev *hdev, void *data) +{ +	BT_DBG("%s", hdev->name); + +	return hci_update_connectable_sync(hdev); +} +  static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,  			   u16 len)  { @@ -1600,7 +1634,7 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,  		goto failed;  	} -	cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len); +	cmd = mgmt_pending_new(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);  	if (!cmd) {  		err = -ENOMEM;  		goto failed; @@ -1617,8 +1651,8 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,  		hci_dev_clear_flag(hdev, HCI_CONNECTABLE);  	} -	queue_work(hdev->req_workqueue, &hdev->connectable_update); -	err = 0; +	err = hci_cmd_sync_queue(hdev, set_connectable_sync, cmd, +				 mgmt_set_connectable_complete);  failed:  	hci_dev_unlock(hdev); @@ -1653,12 +1687,7 @@ static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,  		/* In limited privacy mode the change of bondable mode  		 * may affect the local advertising address.  		 */ -		if (hdev_is_powered(hdev) && -		    hci_dev_test_flag(hdev, HCI_ADVERTISING) && -		    hci_dev_test_flag(hdev, HCI_DISCOVERABLE) && -		    hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY)) -			queue_work(hdev->req_workqueue, -				   &hdev->discoverable_update); +		hci_update_discoverable(hdev);  		err = new_settings(hdev, sk);  	} @@ -1737,6 +1766,69 @@ failed:  	return err;  } +static void set_ssp_complete(struct hci_dev *hdev, void *data, int err) +{ +	struct cmd_lookup match = { NULL, hdev }; +	struct mgmt_pending_cmd *cmd = data; +	struct mgmt_mode *cp = cmd->param; +	u8 enable = cp->val; +	bool changed; + +	if (err) { +		u8 mgmt_err = mgmt_status(err); + +		if (enable && hci_dev_test_and_clear_flag(hdev, +							  HCI_SSP_ENABLED)) { +			hci_dev_clear_flag(hdev, HCI_HS_ENABLED); +			new_settings(hdev, NULL); +		} + +		mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp, +				     &mgmt_err); +		return; +	} + +	if (enable) { +		changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED); +	} else { +		changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED); + +		if (!changed) +			changed = hci_dev_test_and_clear_flag(hdev, +							      HCI_HS_ENABLED); +		else +			hci_dev_clear_flag(hdev, HCI_HS_ENABLED); +	} + +	mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match); + +	if (changed) +		new_settings(hdev, match.sk); + +	if (match.sk) +		sock_put(match.sk); + +	hci_update_eir_sync(hdev); +} + +static int set_ssp_sync(struct hci_dev *hdev, void *data) +{ +	struct mgmt_pending_cmd *cmd = data; +	struct mgmt_mode *cp = cmd->param; +	bool changed = false; +	int err; + +	if (cp->val) +		changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED); + +	err = hci_write_ssp_mode_sync(hdev, cp->val); + +	if (!err && changed) +		hci_dev_clear_flag(hdev, HCI_SSP_ENABLED); + +	return err; +} +  static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)  {  	struct mgmt_mode *cp = data; @@ -1798,19 +1890,18 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)  	}  	cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len); -	if (!cmd) { +	if (!cmd)  		err = -ENOMEM; -		goto failed; -	} - -	if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS)) -		hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE, -			     sizeof(cp->val), &cp->val); +	else +		err = hci_cmd_sync_queue(hdev, set_ssp_sync, cmd, +					 set_ssp_complete); -	err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);  	if (err < 0) { -		mgmt_pending_remove(cmd); -		goto failed; +		err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, +				      MGMT_STATUS_FAILED); + +		if (cmd) +			mgmt_pending_remove(cmd);  	}  failed: @@ -1879,18 +1970,17 @@ unlock:  	return err;  } -static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode) +static void set_le_complete(struct hci_dev *hdev, void *data, int err)  {  	struct cmd_lookup match = { NULL, hdev }; +	u8 status = mgmt_status(err); -	hci_dev_lock(hdev); +	bt_dev_dbg(hdev, "err %d", err);  	if (status) { -		u8 mgmt_err = mgmt_status(status); -  		mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp, -				     &mgmt_err); -		goto unlock; +							&status); +		return;  	}  	mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match); @@ -1899,39 +1989,54 @@ static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)  	if (match.sk)  		sock_put(match.sk); +} + +static int set_le_sync(struct hci_dev *hdev, void *data) +{ +	struct mgmt_pending_cmd *cmd = data; +	struct mgmt_mode *cp = cmd->param; +	u8 val = !!cp->val; +	int err; + +	if (!val) { +		if (hci_dev_test_flag(hdev, HCI_LE_ADV)) +			hci_disable_advertising_sync(hdev); + +		if (ext_adv_capable(hdev)) +			hci_remove_ext_adv_instance_sync(hdev, 0, cmd->sk); +	} else { +		hci_dev_set_flag(hdev, HCI_LE_ENABLED); +	} + +	err = hci_write_le_host_supported_sync(hdev, val, 0);  	/* Make sure the controller has a good default for  	 * advertising data. Restrict the update to when LE  	 * has actually been enabled. During power on, the  	 * update in powered_update_hci will take care of it.  	 */ -	if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) { -		struct hci_request req; -		hci_req_init(&req, hdev); +	if (!err && hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {  		if (ext_adv_capable(hdev)) { -			int err; +			int status; -			err = __hci_req_setup_ext_adv_instance(&req, 0x00); -			if (!err) -				__hci_req_update_scan_rsp_data(&req, 0x00); +			status = hci_setup_ext_adv_instance_sync(hdev, 0x00); +			if (!status) +				hci_update_scan_rsp_data_sync(hdev, 0x00);  		} else { -			__hci_req_update_adv_data(&req, 0x00); -			__hci_req_update_scan_rsp_data(&req, 0x00); +			hci_update_adv_data_sync(hdev, 0x00); +			hci_update_scan_rsp_data_sync(hdev, 0x00);  		} -		hci_req_run(&req, NULL); -		hci_update_background_scan(hdev); + +		hci_update_passive_scan(hdev);  	} -unlock: -	hci_dev_unlock(hdev); +	return err;  }  static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)  {  	struct mgmt_mode *cp = data; -	struct hci_cp_write_le_host_supported hci_cp;  	struct mgmt_pending_cmd *cmd; -	struct hci_request req;  	int err;  	u8 val, enabled; @@ -2001,33 +2106,20 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)  	}  	cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len); -	if (!cmd) { +	if (!cmd)  		err = -ENOMEM; -		goto unlock; -	} - -	hci_req_init(&req, hdev); - -	memset(&hci_cp, 0, sizeof(hci_cp)); +	else +		err = hci_cmd_sync_queue(hdev, set_le_sync, cmd, +					 set_le_complete); -	if (val) { -		hci_cp.le = val; -		hci_cp.simul = 0x00; -	} else { -		if (hci_dev_test_flag(hdev, HCI_LE_ADV)) -			__hci_req_disable_advertising(&req); +	if (err < 0) { +		err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE, +				      MGMT_STATUS_FAILED); -		if (ext_adv_capable(hdev)) -			__hci_req_clear_ext_adv_sets(&req); +		if (cmd) +			mgmt_pending_remove(cmd);  	} -	hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp), -		    &hci_cp); - -	err = hci_req_run(&req, le_enable_complete); -	if (err < 0) -		mgmt_pending_remove(cmd); -  unlock:  	hci_dev_unlock(hdev);  	return err; @@ -2075,37 +2167,33 @@ static u8 get_uuid_size(const u8 *uuid)  	return 16;  } -static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status) +static void mgmt_class_complete(struct hci_dev *hdev, void *data, int err)  { -	struct mgmt_pending_cmd *cmd; +	struct mgmt_pending_cmd *cmd = data; -	hci_dev_lock(hdev); - -	cmd = pending_find(mgmt_op, hdev); -	if (!cmd) -		goto unlock; +	bt_dev_dbg(hdev, "err %d", err);  	mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, -			  mgmt_status(status), hdev->dev_class, 3); +			  mgmt_status(err), hdev->dev_class, 3); -	mgmt_pending_remove(cmd); - -unlock: -	hci_dev_unlock(hdev); +	mgmt_pending_free(cmd);  } -static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode) +static int add_uuid_sync(struct hci_dev *hdev, void *data)  { -	bt_dev_dbg(hdev, "status 0x%02x", status); +	int err; -	mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status); +	err = hci_update_class_sync(hdev); +	if (err) +		return err; + +	return hci_update_eir_sync(hdev);  }  static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)  {  	struct mgmt_cp_add_uuid *cp = data;  	struct mgmt_pending_cmd *cmd; -	struct hci_request req;  	struct bt_uuid *uuid;  	int err; @@ -2131,28 +2219,17 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)  	list_add_tail(&uuid->list, &hdev->uuids); -	hci_req_init(&req, hdev); - -	__hci_req_update_class(&req); -	__hci_req_update_eir(&req); - -	err = hci_req_run(&req, add_uuid_complete); -	if (err < 0) { -		if (err != -ENODATA) -			goto failed; - -		err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0, -					hdev->dev_class, 3); -		goto failed; -	} - -	cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len); +	cmd = mgmt_pending_new(sk, MGMT_OP_ADD_UUID, hdev, data, len);  	if (!cmd) {  		err = -ENOMEM;  		goto failed;  	} -	err = 0; +	err = hci_cmd_sync_queue(hdev, add_uuid_sync, cmd, mgmt_class_complete); +	if (err < 0) { +		mgmt_pending_free(cmd); +		goto failed; +	}  failed:  	hci_dev_unlock(hdev); @@ -2173,11 +2250,15 @@ static bool enable_service_cache(struct hci_dev *hdev)  	return false;  } -static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode) +static int remove_uuid_sync(struct hci_dev *hdev, void *data)  { -	bt_dev_dbg(hdev, "status 0x%02x", status); +	int err; + +	err = hci_update_class_sync(hdev); +	if (err) +		return err; -	mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status); +	return hci_update_eir_sync(hdev);  }  static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, @@ -2187,7 +2268,6 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,  	struct mgmt_pending_cmd *cmd;  	struct bt_uuid *match, *tmp;  	u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -	struct hci_request req;  	int err, found;  	bt_dev_dbg(hdev, "sock %p", sk); @@ -2231,39 +2311,35 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,  	}  update_class: -	hci_req_init(&req, hdev); - -	__hci_req_update_class(&req); -	__hci_req_update_eir(&req); - -	err = hci_req_run(&req, remove_uuid_complete); -	if (err < 0) { -		if (err != -ENODATA) -			goto unlock; - -		err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0, -					hdev->dev_class, 3); -		goto unlock; -	} - -	cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len); +	cmd = mgmt_pending_new(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);  	if (!cmd) {  		err = -ENOMEM;  		goto unlock;  	} -	err = 0; +	err = hci_cmd_sync_queue(hdev, remove_uuid_sync, cmd, +				 mgmt_class_complete); +	if (err < 0) +		mgmt_pending_free(cmd);  unlock:  	hci_dev_unlock(hdev);  	return err;  } -static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode) +static int set_class_sync(struct hci_dev *hdev, void *data)  { -	bt_dev_dbg(hdev, "status 0x%02x", status); +	int err = 0; -	mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status); +	if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) { +		cancel_delayed_work_sync(&hdev->service_cache); +		err = hci_update_eir_sync(hdev); +	} + +	if (err) +		return err; + +	return hci_update_class_sync(hdev);  }  static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data, @@ -2271,7 +2347,6 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,  {  	struct mgmt_cp_set_dev_class *cp = data;  	struct mgmt_pending_cmd *cmd; -	struct hci_request req;  	int err;  	bt_dev_dbg(hdev, "sock %p", sk); @@ -2303,34 +2378,16 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,  		goto unlock;  	} -	hci_req_init(&req, hdev); - -	if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) { -		hci_dev_unlock(hdev); -		cancel_delayed_work_sync(&hdev->service_cache); -		hci_dev_lock(hdev); -		__hci_req_update_eir(&req); -	} - -	__hci_req_update_class(&req); - -	err = hci_req_run(&req, set_class_complete); -	if (err < 0) { -		if (err != -ENODATA) -			goto unlock; - -		err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0, -					hdev->dev_class, 3); -		goto unlock; -	} - -	cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len); +	cmd = mgmt_pending_new(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);  	if (!cmd) {  		err = -ENOMEM;  		goto unlock;  	} -	err = 0; +	err = hci_cmd_sync_queue(hdev, set_class_sync, cmd, +				 mgmt_class_complete); +	if (err < 0) +		mgmt_pending_free(cmd);  unlock:  	hci_dev_unlock(hdev); @@ -3228,65 +3285,70 @@ static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,  				 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);  } -static void adv_expire(struct hci_dev *hdev, u32 flags) +static int adv_expire_sync(struct hci_dev *hdev, u32 flags)  {  	struct adv_info *adv_instance; -	struct hci_request req; -	int err;  	adv_instance = hci_find_adv_instance(hdev, hdev->cur_adv_instance);  	if (!adv_instance) -		return; +		return 0;  	/* stop if current instance doesn't need to be changed */  	if (!(adv_instance->flags & flags)) -		return; +		return 0;  	cancel_adv_timeout(hdev);  	adv_instance = hci_get_next_instance(hdev, adv_instance->instance);  	if (!adv_instance) -		return; +		return 0; -	hci_req_init(&req, hdev); -	err = __hci_req_schedule_adv_instance(&req, adv_instance->instance, -					      true); -	if (err) -		return; +	hci_schedule_adv_instance_sync(hdev, adv_instance->instance, true); -	hci_req_run(&req, NULL); +	return 0;  } -static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode) +static int name_changed_sync(struct hci_dev *hdev, void *data)  { -	struct mgmt_cp_set_local_name *cp; -	struct mgmt_pending_cmd *cmd; - -	bt_dev_dbg(hdev, "status 0x%02x", status); - -	hci_dev_lock(hdev); +	return adv_expire_sync(hdev, MGMT_ADV_FLAG_LOCAL_NAME); +} -	cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev); -	if (!cmd) -		goto unlock; +static void set_name_complete(struct hci_dev *hdev, void *data, int err) +{ +	struct mgmt_pending_cmd *cmd = data; +	struct mgmt_cp_set_local_name *cp = cmd->param; +	u8 status = mgmt_status(err); -	cp = cmd->param; +	bt_dev_dbg(hdev, "err %d", err);  	if (status) {  		mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, -			        mgmt_status(status)); +				status);  	} else {  		mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,  				  cp, sizeof(*cp));  		if (hci_dev_test_flag(hdev, HCI_LE_ADV)) -			adv_expire(hdev, MGMT_ADV_FLAG_LOCAL_NAME); +			hci_cmd_sync_queue(hdev, name_changed_sync, NULL, NULL);  	}  	mgmt_pending_remove(cmd); +} -unlock: -	hci_dev_unlock(hdev); +static int set_name_sync(struct hci_dev *hdev, void *data) +{ +	if (lmp_bredr_capable(hdev)) { +		hci_update_name_sync(hdev); +		hci_update_eir_sync(hdev); +	} + +	/* The name is stored in the scan response data and so +	 * no need to update the advertising data here. +	 */ +	if (lmp_le_capable(hdev) && hci_dev_test_flag(hdev, HCI_ADVERTISING)) +		hci_update_scan_rsp_data_sync(hdev, hdev->cur_adv_instance); + +	return 0;  }  static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data, @@ -3294,7 +3356,6 @@ static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,  {  	struct mgmt_cp_set_local_name *cp = data;  	struct mgmt_pending_cmd *cmd; -	struct hci_request req;  	int err;  	bt_dev_dbg(hdev, "sock %p", sk); @@ -3330,35 +3391,34 @@ static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,  	}  	cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len); -	if (!cmd) { +	if (!cmd)  		err = -ENOMEM; -		goto failed; -	} +	else +		err = hci_cmd_sync_queue(hdev, set_name_sync, cmd, +					 set_name_complete); -	memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name)); +	if (err < 0) { +		err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, +				      MGMT_STATUS_FAILED); -	hci_req_init(&req, hdev); +		if (cmd) +			mgmt_pending_remove(cmd); -	if (lmp_bredr_capable(hdev)) { -		__hci_req_update_name(&req); -		__hci_req_update_eir(&req); +		goto failed;  	} -	/* The name is stored in the scan response data and so -	 * no need to update the advertising data here. -	 */ -	if (lmp_le_capable(hdev) && hci_dev_test_flag(hdev, HCI_ADVERTISING)) -		__hci_req_update_scan_rsp_data(&req, hdev->cur_adv_instance); - -	err = hci_req_run(&req, set_name_complete); -	if (err < 0) -		mgmt_pending_remove(cmd); +	memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));  failed:  	hci_dev_unlock(hdev);  	return err;  } +static int appearance_changed_sync(struct hci_dev *hdev, void *data) +{ +	return adv_expire_sync(hdev, MGMT_ADV_FLAG_APPEARANCE); +} +  static int set_appearance(struct sock *sk, struct hci_dev *hdev, void *data,  			  u16 len)  { @@ -3380,7 +3440,8 @@ static int set_appearance(struct sock *sk, struct hci_dev *hdev, void *data,  		hdev->appearance = appearance;  		if (hci_dev_test_flag(hdev, HCI_LE_ADV)) -			adv_expire(hdev, MGMT_ADV_FLAG_APPEARANCE); +			hci_cmd_sync_queue(hdev, appearance_changed_sync, NULL, +					   NULL);  		ext_info_changed(hdev, sk);  	} @@ -3426,23 +3487,26 @@ int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip)  			  sizeof(ev), skip);  } -static void set_default_phy_complete(struct hci_dev *hdev, u8 status, -				     u16 opcode, struct sk_buff *skb) +static void set_default_phy_complete(struct hci_dev *hdev, void *data, int err)  { -	struct mgmt_pending_cmd *cmd; +	struct mgmt_pending_cmd *cmd = data; +	struct sk_buff *skb = cmd->skb; +	u8 status = mgmt_status(err); -	bt_dev_dbg(hdev, "status 0x%02x", status); - -	hci_dev_lock(hdev); +	if (!status) { +		if (!skb) +			status = MGMT_STATUS_FAILED; +		else if (IS_ERR(skb)) +			status = mgmt_status(PTR_ERR(skb)); +		else +			status = mgmt_status(skb->data[0]); +	} -	cmd = pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev); -	if (!cmd) -		goto unlock; +	bt_dev_dbg(hdev, "status %d", status);  	if (status) {  		mgmt_cmd_status(cmd->sk, hdev->id, -				MGMT_OP_SET_PHY_CONFIGURATION, -				mgmt_status(status)); +				MGMT_OP_SET_PHY_CONFIGURATION, status);  	} else {  		mgmt_cmd_complete(cmd->sk, hdev->id,  				  MGMT_OP_SET_PHY_CONFIGURATION, 0, @@ -3451,19 +3515,56 @@ static void set_default_phy_complete(struct hci_dev *hdev, u8 status,  		mgmt_phy_configuration_changed(hdev, cmd->sk);  	} +	if (skb && !IS_ERR(skb)) +		kfree_skb(skb); +  	mgmt_pending_remove(cmd); +} -unlock: -	hci_dev_unlock(hdev); +static int set_default_phy_sync(struct hci_dev *hdev, void *data) +{ +	struct mgmt_pending_cmd *cmd = data; +	struct mgmt_cp_set_phy_configuration *cp = cmd->param; +	struct hci_cp_le_set_default_phy cp_phy; +	u32 selected_phys = __le32_to_cpu(cp->selected_phys); + +	memset(&cp_phy, 0, sizeof(cp_phy)); + +	if (!(selected_phys & MGMT_PHY_LE_TX_MASK)) +		cp_phy.all_phys |= 0x01; + +	if (!(selected_phys & MGMT_PHY_LE_RX_MASK)) +		cp_phy.all_phys |= 0x02; + +	if (selected_phys & MGMT_PHY_LE_1M_TX) +		cp_phy.tx_phys |= HCI_LE_SET_PHY_1M; + +	if (selected_phys & MGMT_PHY_LE_2M_TX) +		cp_phy.tx_phys |= HCI_LE_SET_PHY_2M; + +	if (selected_phys & MGMT_PHY_LE_CODED_TX) +		cp_phy.tx_phys |= HCI_LE_SET_PHY_CODED; + +	if (selected_phys & MGMT_PHY_LE_1M_RX) +		cp_phy.rx_phys |= HCI_LE_SET_PHY_1M; + +	if (selected_phys & MGMT_PHY_LE_2M_RX) +		cp_phy.rx_phys |= HCI_LE_SET_PHY_2M; + +	if (selected_phys & MGMT_PHY_LE_CODED_RX) +		cp_phy.rx_phys |= HCI_LE_SET_PHY_CODED; + +	cmd->skb =  __hci_cmd_sync(hdev, HCI_OP_LE_SET_DEFAULT_PHY, +				   sizeof(cp_phy), &cp_phy, HCI_CMD_TIMEOUT); + +	return 0;  }  static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,  				 void *data, u16 len)  {  	struct mgmt_cp_set_phy_configuration *cp = data; -	struct hci_cp_le_set_default_phy cp_phy;  	struct mgmt_pending_cmd *cmd; -	struct hci_request req;  	u32 selected_phys, configurable_phys, supported_phys, unconfigure_phys;  	u16 pkt_type = (HCI_DH1 | HCI_DM1);  	bool changed = false; @@ -3567,44 +3668,20 @@ static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,  	cmd = mgmt_pending_add(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data,  			       len); -	if (!cmd) { +	if (!cmd)  		err = -ENOMEM; -		goto unlock; -	} - -	hci_req_init(&req, hdev); - -	memset(&cp_phy, 0, sizeof(cp_phy)); - -	if (!(selected_phys & MGMT_PHY_LE_TX_MASK)) -		cp_phy.all_phys |= 0x01; - -	if (!(selected_phys & MGMT_PHY_LE_RX_MASK)) -		cp_phy.all_phys |= 0x02; - -	if (selected_phys & MGMT_PHY_LE_1M_TX) -		cp_phy.tx_phys |= HCI_LE_SET_PHY_1M; - -	if (selected_phys & MGMT_PHY_LE_2M_TX) -		cp_phy.tx_phys |= HCI_LE_SET_PHY_2M; - -	if (selected_phys & MGMT_PHY_LE_CODED_TX) -		cp_phy.tx_phys |= HCI_LE_SET_PHY_CODED; - -	if (selected_phys & MGMT_PHY_LE_1M_RX) -		cp_phy.rx_phys |= HCI_LE_SET_PHY_1M; - -	if (selected_phys & MGMT_PHY_LE_2M_RX) -		cp_phy.rx_phys |= HCI_LE_SET_PHY_2M; - -	if (selected_phys & MGMT_PHY_LE_CODED_RX) -		cp_phy.rx_phys |= HCI_LE_SET_PHY_CODED; +	else +		err = hci_cmd_sync_queue(hdev, set_default_phy_sync, cmd, +					 set_default_phy_complete); -	hci_req_add(&req, HCI_OP_LE_SET_DEFAULT_PHY, sizeof(cp_phy), &cp_phy); +	if (err < 0) { +		err = mgmt_cmd_status(sk, hdev->id, +				      MGMT_OP_SET_PHY_CONFIGURATION, +				      MGMT_STATUS_FAILED); -	err = hci_req_run_skb(&req, set_default_phy_complete); -	if (err < 0) -		mgmt_pending_remove(cmd); +		if (cmd) +			mgmt_pending_remove(cmd); +	}  unlock:  	hci_dev_unlock(hdev); @@ -3805,7 +3882,7 @@ static const u8 offload_codecs_uuid[16] = {  };  /* 671b10b5-42c0-4696-9227-eb28d1b049d6 */ -static const u8 simult_central_periph_uuid[16] = { +static const u8 le_simultaneous_roles_uuid[16] = {  	0xd6, 0x49, 0xb0, 0xd1, 0x28, 0xeb, 0x27, 0x92,  	0x96, 0x46, 0xc0, 0x42, 0xb5, 0x10, 0x1b, 0x67,  }; @@ -3838,21 +3915,18 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,  	}  #endif -	if (hdev) { -		if (test_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks) && -		    (hdev->le_states[4] & 0x08) &&	/* Central */ -		    (hdev->le_states[4] & 0x40) &&	/* Peripheral */ -		    (hdev->le_states[3] & 0x10))	/* Simultaneous */ +	if (hdev && hci_dev_le_state_simultaneous(hdev)) { +		if (hci_dev_test_flag(hdev, HCI_LE_SIMULTANEOUS_ROLES))  			flags = BIT(0);  		else  			flags = 0; -		memcpy(rp->features[idx].uuid, simult_central_periph_uuid, 16); +		memcpy(rp->features[idx].uuid, le_simultaneous_roles_uuid, 16);  		rp->features[idx].flags = cpu_to_le32(flags);  		idx++;  	} -	if (hdev && use_ll_privacy(hdev)) { +	if (hdev && ll_privacy_capable(hdev)) {  		if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))  			flags = BIT(0) | BIT(1);  		else @@ -3863,7 +3937,8 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,  		idx++;  	} -	if (hdev && hdev->set_quality_report) { +	if (hdev && (aosp_has_quality_report(hdev) || +		     hdev->set_quality_report)) {  		if (hci_dev_test_flag(hdev, HCI_QUALITY_REPORT))  			flags = BIT(0);  		else @@ -3906,36 +3981,27 @@ static int exp_ll_privacy_feature_changed(bool enabled, struct hci_dev *hdev,  	memcpy(ev.uuid, rpa_resolution_uuid, 16);  	ev.flags = cpu_to_le32((enabled ? BIT(0) : 0) | BIT(1)); +	if (enabled && privacy_mode_capable(hdev)) +		set_bit(HCI_CONN_FLAG_DEVICE_PRIVACY, hdev->conn_flags); +	else +		clear_bit(HCI_CONN_FLAG_DEVICE_PRIVACY, hdev->conn_flags); +  	return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, hdev,  				  &ev, sizeof(ev),  				  HCI_MGMT_EXP_FEATURE_EVENTS, skip);  } -#ifdef CONFIG_BT_FEATURE_DEBUG -static int exp_debug_feature_changed(bool enabled, struct sock *skip) -{ -	struct mgmt_ev_exp_feature_changed ev; - -	memset(&ev, 0, sizeof(ev)); -	memcpy(ev.uuid, debug_uuid, 16); -	ev.flags = cpu_to_le32(enabled ? BIT(0) : 0); - -	return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, NULL, -				  &ev, sizeof(ev), -				  HCI_MGMT_EXP_FEATURE_EVENTS, skip); -} -#endif - -static int exp_quality_report_feature_changed(bool enabled, struct sock *skip) +static int exp_feature_changed(struct hci_dev *hdev, const u8 *uuid, +			       bool enabled, struct sock *skip)  {  	struct mgmt_ev_exp_feature_changed ev;  	memset(&ev, 0, sizeof(ev)); -	memcpy(ev.uuid, quality_report_uuid, 16); +	memcpy(ev.uuid, uuid, 16);  	ev.flags = cpu_to_le32(enabled ? BIT(0) : 0); -	return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, NULL, +	return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, hdev,  				  &ev, sizeof(ev),  				  HCI_MGMT_EXP_FEATURE_EVENTS, skip);  } @@ -3962,17 +4028,18 @@ static int set_zero_key_func(struct sock *sk, struct hci_dev *hdev,  		bt_dbg_set(false);  		if (changed) -			exp_debug_feature_changed(false, sk); +			exp_feature_changed(NULL, ZERO_KEY, false, sk);  	}  #endif  	if (hdev && use_ll_privacy(hdev) && !hdev_is_powered(hdev)) { -		bool changed = hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY); - -		hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY); +		bool changed; +		changed = hci_dev_test_and_clear_flag(hdev, +						      HCI_ENABLE_LL_PRIVACY);  		if (changed) -			exp_ll_privacy_feature_changed(false, hdev, sk); +			exp_feature_changed(hdev, rpa_resolution_uuid, false, +					    sk);  	}  	hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS); @@ -4023,7 +4090,7 @@ static int set_debug_func(struct sock *sk, struct hci_dev *hdev,  				&rp, sizeof(rp));  	if (changed) -		exp_debug_feature_changed(val, sk); +		exp_feature_changed(hdev, debug_uuid, val, sk);  	return err;  } @@ -4065,15 +4132,15 @@ static int set_rpa_resolution_func(struct sock *sk, struct hci_dev *hdev,  	val = !!cp->param[0];  	if (val) { -		changed = !hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY); -		hci_dev_set_flag(hdev, HCI_ENABLE_LL_PRIVACY); +		changed = !hci_dev_test_and_set_flag(hdev, +						     HCI_ENABLE_LL_PRIVACY);  		hci_dev_clear_flag(hdev, HCI_ADVERTISING);  		/* Enable LL privacy + supported settings changed */  		flags = BIT(0) | BIT(1);  	} else { -		changed = hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY); -		hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY); +		changed = hci_dev_test_and_clear_flag(hdev, +						      HCI_ENABLE_LL_PRIVACY);  		/* Disable LL privacy + supported settings changed */  		flags = BIT(1); @@ -4125,7 +4192,7 @@ static int set_quality_report_func(struct sock *sk, struct hci_dev *hdev,  	val = !!cp->param[0];  	changed = (val != hci_dev_test_flag(hdev, HCI_QUALITY_REPORT)); -	if (!hdev->set_quality_report) { +	if (!aosp_has_quality_report(hdev) && !hdev->set_quality_report) {  		err = mgmt_cmd_status(sk, hdev->id,  				      MGMT_OP_SET_EXP_FEATURE,  				      MGMT_STATUS_NOT_SUPPORTED); @@ -4133,13 +4200,18 @@ static int set_quality_report_func(struct sock *sk, struct hci_dev *hdev,  	}  	if (changed) { -		err = hdev->set_quality_report(hdev, val); +		if (hdev->set_quality_report) +			err = hdev->set_quality_report(hdev, val); +		else +			err = aosp_set_quality_report(hdev, val); +  		if (err) {  			err = mgmt_cmd_status(sk, hdev->id,  					      MGMT_OP_SET_EXP_FEATURE,  					      MGMT_STATUS_FAILED);  			goto unlock_quality_report;  		} +  		if (val)  			hci_dev_set_flag(hdev, HCI_QUALITY_REPORT);  		else @@ -4151,31 +4223,18 @@ static int set_quality_report_func(struct sock *sk, struct hci_dev *hdev,  	memcpy(rp.uuid, quality_report_uuid, 16);  	rp.flags = cpu_to_le32(val ? BIT(0) : 0);  	hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS); -	err = mgmt_cmd_complete(sk, hdev->id, -				MGMT_OP_SET_EXP_FEATURE, 0, + +	err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_EXP_FEATURE, 0,  				&rp, sizeof(rp));  	if (changed) -		exp_quality_report_feature_changed(val, sk); +		exp_feature_changed(hdev, quality_report_uuid, val, sk);  unlock_quality_report:  	hci_req_sync_unlock(hdev);  	return err;  } -static int exp_offload_codec_feature_changed(bool enabled, struct sock *skip) -{ -	struct mgmt_ev_exp_feature_changed ev; - -	memset(&ev, 0, sizeof(ev)); -	memcpy(ev.uuid, offload_codecs_uuid, 16); -	ev.flags = cpu_to_le32(enabled ? BIT(0) : 0); - -	return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, NULL, -				  &ev, sizeof(ev), -				  HCI_MGMT_EXP_FEATURE_EVENTS, skip); -} -  static int set_offload_codec_func(struct sock *sk, struct hci_dev *hdev,  				  struct mgmt_cp_set_exp_feature *cp,  				  u16 data_len) @@ -4229,7 +4288,65 @@ static int set_offload_codec_func(struct sock *sk, struct hci_dev *hdev,  				&rp, sizeof(rp));  	if (changed) -		exp_offload_codec_feature_changed(val, sk); +		exp_feature_changed(hdev, offload_codecs_uuid, val, sk); + +	return err; +} + +static int set_le_simultaneous_roles_func(struct sock *sk, struct hci_dev *hdev, +					  struct mgmt_cp_set_exp_feature *cp, +					  u16 data_len) +{ +	bool val, changed; +	int err; +	struct mgmt_rp_set_exp_feature rp; + +	/* Command requires to use a valid controller index */ +	if (!hdev) +		return mgmt_cmd_status(sk, MGMT_INDEX_NONE, +				       MGMT_OP_SET_EXP_FEATURE, +				       MGMT_STATUS_INVALID_INDEX); + +	/* Parameters are limited to a single octet */ +	if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1) +		return mgmt_cmd_status(sk, hdev->id, +				       MGMT_OP_SET_EXP_FEATURE, +				       MGMT_STATUS_INVALID_PARAMS); + +	/* Only boolean on/off is supported */ +	if (cp->param[0] != 0x00 && cp->param[0] != 0x01) +		return mgmt_cmd_status(sk, hdev->id, +				       MGMT_OP_SET_EXP_FEATURE, +				       MGMT_STATUS_INVALID_PARAMS); + +	val = !!cp->param[0]; +	changed = (val != hci_dev_test_flag(hdev, HCI_LE_SIMULTANEOUS_ROLES)); + +	if (!hci_dev_le_state_simultaneous(hdev)) { +		return mgmt_cmd_status(sk, hdev->id, +				       MGMT_OP_SET_EXP_FEATURE, +				       MGMT_STATUS_NOT_SUPPORTED); +	} + +	if (changed) { +		if (val) +			hci_dev_set_flag(hdev, HCI_LE_SIMULTANEOUS_ROLES); +		else +			hci_dev_clear_flag(hdev, HCI_LE_SIMULTANEOUS_ROLES); +	} + +	bt_dev_info(hdev, "LE simultaneous roles enable %d changed %d", +		    val, changed); + +	memcpy(rp.uuid, le_simultaneous_roles_uuid, 16); +	rp.flags = cpu_to_le32(val ? BIT(0) : 0); +	hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS); +	err = mgmt_cmd_complete(sk, hdev->id, +				MGMT_OP_SET_EXP_FEATURE, 0, +				&rp, sizeof(rp)); + +	if (changed) +		exp_feature_changed(hdev, le_simultaneous_roles_uuid, val, sk);  	return err;  } @@ -4246,6 +4363,7 @@ static const struct mgmt_exp_feature {  	EXP_FEAT(rpa_resolution_uuid, set_rpa_resolution_func),  	EXP_FEAT(quality_report_uuid, set_quality_report_func),  	EXP_FEAT(offload_codecs_uuid, set_offload_codec_func), +	EXP_FEAT(le_simultaneous_roles_uuid, set_le_simultaneous_roles_func),  	/* end with a null feature */  	EXP_FEAT(NULL, NULL) @@ -4269,8 +4387,6 @@ static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,  			       MGMT_STATUS_NOT_SUPPORTED);  } -#define SUPPORTED_DEVICE_FLAGS() ((1U << HCI_CONN_FLAG_MAX) - 1) -  static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,  			    u16 data_len)  { @@ -4278,7 +4394,7 @@ static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,  	struct mgmt_rp_get_device_flags rp;  	struct bdaddr_list_with_flags *br_params;  	struct hci_conn_params *params; -	u32 supported_flags = SUPPORTED_DEVICE_FLAGS(); +	u32 supported_flags;  	u32 current_flags = 0;  	u8 status = MGMT_STATUS_INVALID_PARAMS; @@ -4287,6 +4403,9 @@ static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,  	hci_dev_lock(hdev); +	bitmap_to_arr32(&supported_flags, hdev->conn_flags, +			__HCI_CONN_NUM_FLAGS); +  	memset(&rp, 0, sizeof(rp));  	if (cp->addr.type == BDADDR_BREDR) { @@ -4296,7 +4415,8 @@ static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,  		if (!br_params)  			goto done; -		current_flags = br_params->current_flags; +		bitmap_to_arr32(¤t_flags, br_params->flags, +				__HCI_CONN_NUM_FLAGS);  	} else {  		params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,  						le_addr_type(cp->addr.type)); @@ -4304,7 +4424,8 @@ static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,  		if (!params)  			goto done; -		current_flags = params->current_flags; +		bitmap_to_arr32(¤t_flags, params->flags, +				__HCI_CONN_NUM_FLAGS);  	}  	bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); @@ -4342,13 +4463,16 @@ static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,  	struct bdaddr_list_with_flags *br_params;  	struct hci_conn_params *params;  	u8 status = MGMT_STATUS_INVALID_PARAMS; -	u32 supported_flags = SUPPORTED_DEVICE_FLAGS(); +	u32 supported_flags;  	u32 current_flags = __le32_to_cpu(cp->current_flags);  	bt_dev_dbg(hdev, "Set device flags %pMR (type 0x%x) = 0x%x",  		   &cp->addr.bdaddr, cp->addr.type,  		   __le32_to_cpu(current_flags)); +	bitmap_to_arr32(&supported_flags, hdev->conn_flags, +			__HCI_CONN_NUM_FLAGS); +  	if ((supported_flags | current_flags) != supported_flags) {  		bt_dev_warn(hdev, "Bad flag given (0x%x) vs supported (0x%0x)",  			    current_flags, supported_flags); @@ -4363,7 +4487,7 @@ static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,  							      cp->addr.type);  		if (br_params) { -			br_params->current_flags = current_flags; +			bitmap_from_u64(br_params->flags, current_flags);  			status = MGMT_STATUS_SUCCESS;  		} else {  			bt_dev_warn(hdev, "No such BR/EDR device %pMR (0x%x)", @@ -4373,8 +4497,15 @@ static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,  		params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,  						le_addr_type(cp->addr.type));  		if (params) { -			params->current_flags = current_flags; +			bitmap_from_u64(params->flags, current_flags);  			status = MGMT_STATUS_SUCCESS; + +			/* Update passive scan if HCI_CONN_FLAG_DEVICE_PRIVACY +			 * has been set. +			 */ +			if (test_bit(HCI_CONN_FLAG_DEVICE_PRIVACY, +				     params->flags)) +				hci_update_passive_scan(hdev);  		} else {  			bt_dev_warn(hdev, "No such LE device %pMR (0x%x)",  				    &cp->addr.bdaddr, @@ -4496,7 +4627,7 @@ int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status)  		hdev->adv_monitors_cnt++;  		if (monitor->state == ADV_MONITOR_STATE_NOT_REGISTERED)  			monitor->state = ADV_MONITOR_STATE_REGISTERED; -		hci_update_background_scan(hdev); +		hci_update_passive_scan(hdev);  	}  	err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, @@ -4722,7 +4853,7 @@ int mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status)  	rp.monitor_handle = cp->monitor_handle;  	if (!status) -		hci_update_background_scan(hdev); +		hci_update_passive_scan(hdev);  	err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,  				mgmt_status(status), &rp, sizeof(rp)); @@ -4801,28 +4932,33 @@ unlock:  			       status);  } -static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status, -				         u16 opcode, struct sk_buff *skb) +static void read_local_oob_data_complete(struct hci_dev *hdev, void *data, int err)  {  	struct mgmt_rp_read_local_oob_data mgmt_rp;  	size_t rp_size = sizeof(mgmt_rp); -	struct mgmt_pending_cmd *cmd; +	struct mgmt_pending_cmd *cmd = data; +	struct sk_buff *skb = cmd->skb; +	u8 status = mgmt_status(err); -	bt_dev_dbg(hdev, "status %u", status); +	if (!status) { +		if (!skb) +			status = MGMT_STATUS_FAILED; +		else if (IS_ERR(skb)) +			status = mgmt_status(PTR_ERR(skb)); +		else +			status = mgmt_status(skb->data[0]); +	} -	cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev); -	if (!cmd) -		return; +	bt_dev_dbg(hdev, "status %d", status); -	if (status || !skb) { -		mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, -				status ? mgmt_status(status) : MGMT_STATUS_FAILED); +	if (status) { +		mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, status);  		goto remove;  	}  	memset(&mgmt_rp, 0, sizeof(mgmt_rp)); -	if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) { +	if (!bredr_sc_enabled(hdev)) {  		struct hci_rp_read_local_oob_data *rp = (void *) skb->data;  		if (skb->len < sizeof(*rp)) { @@ -4857,14 +4993,31 @@ static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,  			  MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);  remove: -	mgmt_pending_remove(cmd); +	if (skb && !IS_ERR(skb)) +		kfree_skb(skb); + +	mgmt_pending_free(cmd); +} + +static int read_local_oob_data_sync(struct hci_dev *hdev, void *data) +{ +	struct mgmt_pending_cmd *cmd = data; + +	if (bredr_sc_enabled(hdev)) +		cmd->skb = hci_read_local_oob_data_sync(hdev, true, cmd->sk); +	else +		cmd->skb = hci_read_local_oob_data_sync(hdev, false, cmd->sk); + +	if (IS_ERR(cmd->skb)) +		return PTR_ERR(cmd->skb); +	else +		return 0;  }  static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,  			       void *data, u16 data_len)  {  	struct mgmt_pending_cmd *cmd; -	struct hci_request req;  	int err;  	bt_dev_dbg(hdev, "sock %p", sk); @@ -4889,22 +5042,20 @@ static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,  		goto unlock;  	} -	cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0); -	if (!cmd) { +	cmd = mgmt_pending_new(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0); +	if (!cmd)  		err = -ENOMEM; -		goto unlock; -	} - -	hci_req_init(&req, hdev); - -	if (bredr_sc_enabled(hdev)) -		hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);  	else -		hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL); +		err = hci_cmd_sync_queue(hdev, read_local_oob_data_sync, cmd, +					 read_local_oob_data_complete); -	err = hci_req_run_skb(&req, read_local_oob_data_complete); -	if (err < 0) -		mgmt_pending_remove(cmd); +	if (err < 0) { +		err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, +				      MGMT_STATUS_FAILED); + +		if (cmd) +			mgmt_pending_free(cmd); +	}  unlock:  	hci_dev_unlock(hdev); @@ -5077,13 +5228,6 @@ void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)  	}  	hci_dev_unlock(hdev); - -	/* Handle suspend notifier */ -	if (test_and_clear_bit(SUSPEND_UNPAUSE_DISCOVERY, -			       hdev->suspend_tasks)) { -		bt_dev_dbg(hdev, "Unpaused discovery"); -		wake_up(&hdev->suspend_wait_q); -	}  }  static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type, @@ -5113,6 +5257,25 @@ static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,  	return true;  } +static void start_discovery_complete(struct hci_dev *hdev, void *data, int err) +{ +	struct mgmt_pending_cmd *cmd = data; + +	bt_dev_dbg(hdev, "err %d", err); + +	mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err), +			  cmd->param, 1); +	mgmt_pending_free(cmd); + +	hci_discovery_set_state(hdev, err ? DISCOVERY_STOPPED: +				DISCOVERY_FINDING); +} + +static int start_discovery_sync(struct hci_dev *hdev, void *data) +{ +	return hci_start_discovery_sync(hdev); +} +  static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,  				    u16 op, void *data, u16 len)  { @@ -5164,17 +5327,20 @@ static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,  	else  		hdev->discovery.limited = false; -	cmd = mgmt_pending_add(sk, op, hdev, data, len); +	cmd = mgmt_pending_new(sk, op, hdev, data, len);  	if (!cmd) {  		err = -ENOMEM;  		goto failed;  	} -	cmd->cmd_complete = generic_cmd_complete; +	err = hci_cmd_sync_queue(hdev, start_discovery_sync, cmd, +				 start_discovery_complete); +	if (err < 0) { +		mgmt_pending_free(cmd); +		goto failed; +	}  	hci_discovery_set_state(hdev, DISCOVERY_STARTING); -	queue_work(hdev->req_workqueue, &hdev->discov_update); -	err = 0;  failed:  	hci_dev_unlock(hdev); @@ -5196,13 +5362,6 @@ static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,  					data, len);  } -static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd, -					  u8 status) -{ -	return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, -				 cmd->param, 1); -} -  static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,  				   void *data, u16 len)  { @@ -5271,15 +5430,13 @@ static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,  		goto failed;  	} -	cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY, +	cmd = mgmt_pending_new(sk, MGMT_OP_START_SERVICE_DISCOVERY,  			       hdev, data, len);  	if (!cmd) {  		err = -ENOMEM;  		goto failed;  	} -	cmd->cmd_complete = service_discovery_cmd_complete; -  	/* Clear the discovery filter first to free any previously  	 * allocated memory for the UUID list.  	 */ @@ -5303,9 +5460,14 @@ static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,  		}  	} +	err = hci_cmd_sync_queue(hdev, start_discovery_sync, cmd, +				 start_discovery_complete); +	if (err < 0) { +		mgmt_pending_free(cmd); +		goto failed; +	} +  	hci_discovery_set_state(hdev, DISCOVERY_STARTING); -	queue_work(hdev->req_workqueue, &hdev->discov_update); -	err = 0;  failed:  	hci_dev_unlock(hdev); @@ -5327,12 +5489,25 @@ void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)  	}  	hci_dev_unlock(hdev); +} -	/* Handle suspend notifier */ -	if (test_and_clear_bit(SUSPEND_PAUSE_DISCOVERY, hdev->suspend_tasks)) { -		bt_dev_dbg(hdev, "Paused discovery"); -		wake_up(&hdev->suspend_wait_q); -	} +static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err) +{ +	struct mgmt_pending_cmd *cmd = data; + +	bt_dev_dbg(hdev, "err %d", err); + +	mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err), +			  cmd->param, 1); +	mgmt_pending_free(cmd); + +	if (!err) +		hci_discovery_set_state(hdev, DISCOVERY_STOPPED); +} + +static int stop_discovery_sync(struct hci_dev *hdev, void *data) +{ +	return hci_stop_discovery_sync(hdev);  }  static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data, @@ -5360,17 +5535,20 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,  		goto unlock;  	} -	cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len); +	cmd = mgmt_pending_new(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);  	if (!cmd) {  		err = -ENOMEM;  		goto unlock;  	} -	cmd->cmd_complete = generic_cmd_complete; +	err = hci_cmd_sync_queue(hdev, stop_discovery_sync, cmd, +				 stop_discovery_complete); +	if (err < 0) { +		mgmt_pending_free(cmd); +		goto unlock; +	}  	hci_discovery_set_state(hdev, DISCOVERY_STOPPING); -	queue_work(hdev->req_workqueue, &hdev->discov_update); -	err = 0;  unlock:  	hci_dev_unlock(hdev); @@ -5491,11 +5669,15 @@ done:  	return err;  } +static int set_device_id_sync(struct hci_dev *hdev, void *data) +{ +	return hci_update_eir_sync(hdev); +} +  static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,  			 u16 len)  {  	struct mgmt_cp_set_device_id *cp = data; -	struct hci_request req;  	int err;  	__u16 source; @@ -5517,38 +5699,32 @@ static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,  	err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,  				NULL, 0); -	hci_req_init(&req, hdev); -	__hci_req_update_eir(&req); -	hci_req_run(&req, NULL); +	hci_cmd_sync_queue(hdev, set_device_id_sync, NULL, NULL);  	hci_dev_unlock(hdev);  	return err;  } -static void enable_advertising_instance(struct hci_dev *hdev, u8 status, -					u16 opcode) +static void enable_advertising_instance(struct hci_dev *hdev, int err)  { -	bt_dev_dbg(hdev, "status %u", status); +	if (err) +		bt_dev_err(hdev, "failed to re-configure advertising %d", err); +	else +		bt_dev_dbg(hdev, "status %d", err);  } -static void set_advertising_complete(struct hci_dev *hdev, u8 status, -				     u16 opcode) +static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)  {  	struct cmd_lookup match = { NULL, hdev }; -	struct hci_request req;  	u8 instance;  	struct adv_info *adv_instance; -	int err; - -	hci_dev_lock(hdev); +	u8 status = mgmt_status(err);  	if (status) { -		u8 mgmt_err = mgmt_status(status); -  		mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, -				     cmd_status_rsp, &mgmt_err); -		goto unlock; +				     cmd_status_rsp, &status); +		return;  	}  	if (hci_dev_test_flag(hdev, HCI_LE_ADV)) @@ -5564,46 +5740,60 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,  	if (match.sk)  		sock_put(match.sk); -	/* Handle suspend notifier */ -	if (test_and_clear_bit(SUSPEND_PAUSE_ADVERTISING, -			       hdev->suspend_tasks)) { -		bt_dev_dbg(hdev, "Paused advertising"); -		wake_up(&hdev->suspend_wait_q); -	} else if (test_and_clear_bit(SUSPEND_UNPAUSE_ADVERTISING, -				      hdev->suspend_tasks)) { -		bt_dev_dbg(hdev, "Unpaused advertising"); -		wake_up(&hdev->suspend_wait_q); -	} -  	/* If "Set Advertising" was just disabled and instance advertising was  	 * set up earlier, then re-enable multi-instance advertising.  	 */  	if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||  	    list_empty(&hdev->adv_instances)) -		goto unlock; +		return;  	instance = hdev->cur_adv_instance;  	if (!instance) {  		adv_instance = list_first_entry_or_null(&hdev->adv_instances,  							struct adv_info, list);  		if (!adv_instance) -			goto unlock; +			return;  		instance = adv_instance->instance;  	} -	hci_req_init(&req, hdev); +	err = hci_schedule_adv_instance_sync(hdev, instance, true); -	err = __hci_req_schedule_adv_instance(&req, instance, true); +	enable_advertising_instance(hdev, err); +} -	if (!err) -		err = hci_req_run(&req, enable_advertising_instance); +static int set_adv_sync(struct hci_dev *hdev, void *data) +{ +	struct mgmt_pending_cmd *cmd = data; +	struct mgmt_mode *cp = cmd->param; +	u8 val = !!cp->val; -	if (err) -		bt_dev_err(hdev, "failed to re-configure advertising"); +	if (cp->val == 0x02) +		hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE); +	else +		hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE); -unlock: -	hci_dev_unlock(hdev); +	cancel_adv_timeout(hdev); + +	if (val) { +		/* Switch to instance "0" for the Set Advertising setting. +		 * We cannot use update_[adv|scan_rsp]_data() here as the +		 * HCI_ADVERTISING flag is not yet set. +		 */ +		hdev->cur_adv_instance = 0x00; + +		if (ext_adv_capable(hdev)) { +			hci_start_ext_adv_sync(hdev, 0x00); +		} else { +			hci_update_adv_data_sync(hdev, 0x00); +			hci_update_scan_rsp_data_sync(hdev, 0x00); +			hci_enable_advertising_sync(hdev); +		} +	} else { +		hci_disable_advertising_sync(hdev); +	} + +	return 0;  }  static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data, @@ -5611,7 +5801,6 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,  {  	struct mgmt_mode *cp = data;  	struct mgmt_pending_cmd *cmd; -	struct hci_request req;  	u8 val, status;  	int err; @@ -5622,13 +5811,6 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,  		return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,  				       status); -	/* Enabling the experimental LL Privay support disables support for -	 * advertising. -	 */ -	if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY)) -		return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING, -				       MGMT_STATUS_NOT_SUPPORTED); -  	if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)  		return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,  				       MGMT_STATUS_INVALID_PARAMS); @@ -5684,40 +5866,13 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,  	}  	cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len); -	if (!cmd) { +	if (!cmd)  		err = -ENOMEM; -		goto unlock; -	} - -	hci_req_init(&req, hdev); - -	if (cp->val == 0x02) -		hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);  	else -		hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE); - -	cancel_adv_timeout(hdev); - -	if (val) { -		/* Switch to instance "0" for the Set Advertising setting. -		 * We cannot use update_[adv|scan_rsp]_data() here as the -		 * HCI_ADVERTISING flag is not yet set. -		 */ -		hdev->cur_adv_instance = 0x00; +		err = hci_cmd_sync_queue(hdev, set_adv_sync, cmd, +					 set_advertising_complete); -		if (ext_adv_capable(hdev)) { -			__hci_req_start_ext_adv(&req, 0x00); -		} else { -			__hci_req_update_adv_data(&req, 0x00); -			__hci_req_update_scan_rsp_data(&req, 0x00); -			__hci_req_enable_advertising(&req); -		} -	} else { -		__hci_req_disable_advertising(&req); -	} - -	err = hci_req_run(&req, set_advertising_complete); -	if (err < 0) +	if (err < 0 && cmd)  		mgmt_pending_remove(cmd);  unlock: @@ -5810,38 +5965,23 @@ static int set_scan_params(struct sock *sk, struct hci_dev *hdev,  	 * loaded.  	 */  	if (hci_dev_test_flag(hdev, HCI_LE_SCAN) && -	    hdev->discovery.state == DISCOVERY_STOPPED) { -		struct hci_request req; - -		hci_req_init(&req, hdev); - -		hci_req_add_le_scan_disable(&req, false); -		hci_req_add_le_passive_scan(&req); - -		hci_req_run(&req, NULL); -	} +	    hdev->discovery.state == DISCOVERY_STOPPED) +		hci_update_passive_scan(hdev);  	hci_dev_unlock(hdev);  	return err;  } -static void fast_connectable_complete(struct hci_dev *hdev, u8 status, -				      u16 opcode) +static void fast_connectable_complete(struct hci_dev *hdev, void *data, int err)  { -	struct mgmt_pending_cmd *cmd; - -	bt_dev_dbg(hdev, "status 0x%02x", status); - -	hci_dev_lock(hdev); +	struct mgmt_pending_cmd *cmd = data; -	cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev); -	if (!cmd) -		goto unlock; +	bt_dev_dbg(hdev, "err %d", err); -	if (status) { +	if (err) {  		mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, -			        mgmt_status(status)); +				mgmt_status(err));  	} else {  		struct mgmt_mode *cp = cmd->param; @@ -5854,10 +5994,15 @@ static void fast_connectable_complete(struct hci_dev *hdev, u8 status,  		new_settings(hdev, cmd->sk);  	} -	mgmt_pending_remove(cmd); +	mgmt_pending_free(cmd); +} -unlock: -	hci_dev_unlock(hdev); +static int write_fast_connectable_sync(struct hci_dev *hdev, void *data) +{ +	struct mgmt_pending_cmd *cmd = data; +	struct mgmt_mode *cp = cmd->param; + +	return hci_write_fast_connectable_sync(hdev, cp->val);  }  static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, @@ -5865,58 +6010,49 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,  {  	struct mgmt_mode *cp = data;  	struct mgmt_pending_cmd *cmd; -	struct hci_request req;  	int err;  	bt_dev_dbg(hdev, "sock %p", sk);  	if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||  	    hdev->hci_ver < BLUETOOTH_VER_1_2) -		return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, +		return mgmt_cmd_status(sk, hdev->id, +				       MGMT_OP_SET_FAST_CONNECTABLE,  				       MGMT_STATUS_NOT_SUPPORTED);  	if (cp->val != 0x00 && cp->val != 0x01) -		return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, +		return mgmt_cmd_status(sk, hdev->id, +				       MGMT_OP_SET_FAST_CONNECTABLE,  				       MGMT_STATUS_INVALID_PARAMS);  	hci_dev_lock(hdev); -	if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) { -		err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, -				      MGMT_STATUS_BUSY); -		goto unlock; -	} -  	if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) { -		err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE, -					hdev); +		err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);  		goto unlock;  	}  	if (!hdev_is_powered(hdev)) {  		hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE); -		err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE, -					hdev); +		err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);  		new_settings(hdev, sk);  		goto unlock;  	} -	cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev, -			       data, len); -	if (!cmd) { +	cmd = mgmt_pending_new(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev, data, +			       len); +	if (!cmd)  		err = -ENOMEM; -		goto unlock; -	} - -	hci_req_init(&req, hdev); - -	__hci_req_write_fast_connectable(&req, cp->val); +	else +		err = hci_cmd_sync_queue(hdev, write_fast_connectable_sync, cmd, +					 fast_connectable_complete); -	err = hci_req_run(&req, fast_connectable_complete);  	if (err < 0) { -		err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, -				      MGMT_STATUS_FAILED); -		mgmt_pending_remove(cmd); +		mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, +				MGMT_STATUS_FAILED); + +		if (cmd) +			mgmt_pending_free(cmd);  	}  unlock: @@ -5925,20 +6061,14 @@ unlock:  	return err;  } -static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode) +static void set_bredr_complete(struct hci_dev *hdev, void *data, int err)  { -	struct mgmt_pending_cmd *cmd; +	struct mgmt_pending_cmd *cmd = data; -	bt_dev_dbg(hdev, "status 0x%02x", status); - -	hci_dev_lock(hdev); - -	cmd = pending_find(MGMT_OP_SET_BREDR, hdev); -	if (!cmd) -		goto unlock; +	bt_dev_dbg(hdev, "err %d", err); -	if (status) { -		u8 mgmt_err = mgmt_status(status); +	if (err) { +		u8 mgmt_err = mgmt_status(err);  		/* We need to restore the flag if related HCI commands  		 * failed. @@ -5951,17 +6081,31 @@ static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)  		new_settings(hdev, cmd->sk);  	} -	mgmt_pending_remove(cmd); +	mgmt_pending_free(cmd); +} -unlock: -	hci_dev_unlock(hdev); +static int set_bredr_sync(struct hci_dev *hdev, void *data) +{ +	int status; + +	status = hci_write_fast_connectable_sync(hdev, false); + +	if (!status) +		status = hci_update_scan_sync(hdev); + +	/* Since only the advertising data flags will change, there +	 * is no need to update the scan response data. +	 */ +	if (!status) +		status = hci_update_adv_data_sync(hdev, hdev->cur_adv_instance); + +	return status;  }  static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)  {  	struct mgmt_mode *cp = data;  	struct mgmt_pending_cmd *cmd; -	struct hci_request req;  	int err;  	bt_dev_dbg(hdev, "sock %p", sk); @@ -6033,15 +6177,19 @@ static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)  		}  	} -	if (pending_find(MGMT_OP_SET_BREDR, hdev)) { -		err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR, -				      MGMT_STATUS_BUSY); -		goto unlock; -	} - -	cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len); -	if (!cmd) { +	cmd = mgmt_pending_new(sk, MGMT_OP_SET_BREDR, hdev, data, len); +	if (!cmd)  		err = -ENOMEM; +	else +		err = hci_cmd_sync_queue(hdev, set_bredr_sync, cmd, +					 set_bredr_complete); + +	if (err < 0) { +		mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR, +				MGMT_STATUS_FAILED); +		if (cmd) +			mgmt_pending_free(cmd); +  		goto unlock;  	} @@ -6050,42 +6198,23 @@ static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)  	 */  	hci_dev_set_flag(hdev, HCI_BREDR_ENABLED); -	hci_req_init(&req, hdev); - -	__hci_req_write_fast_connectable(&req, false); -	__hci_req_update_scan(&req); - -	/* Since only the advertising data flags will change, there -	 * is no need to update the scan response data. -	 */ -	__hci_req_update_adv_data(&req, hdev->cur_adv_instance); - -	err = hci_req_run(&req, set_bredr_complete); -	if (err < 0) -		mgmt_pending_remove(cmd); -  unlock:  	hci_dev_unlock(hdev);  	return err;  } -static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode) +static void set_secure_conn_complete(struct hci_dev *hdev, void *data, int err)  { -	struct mgmt_pending_cmd *cmd; +	struct mgmt_pending_cmd *cmd = data;  	struct mgmt_mode *cp; -	bt_dev_dbg(hdev, "status %u", status); - -	hci_dev_lock(hdev); +	bt_dev_dbg(hdev, "err %d", err); -	cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev); -	if (!cmd) -		goto unlock; +	if (err) { +		u8 mgmt_err = mgmt_status(err); -	if (status) { -		mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, -			        mgmt_status(status)); -		goto remove; +		mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err); +		goto done;  	}  	cp = cmd->param; @@ -6105,13 +6234,23 @@ static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)  		break;  	} -	send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev); +	send_settings_rsp(cmd->sk, cmd->opcode, hdev);  	new_settings(hdev, cmd->sk); -remove: -	mgmt_pending_remove(cmd); -unlock: -	hci_dev_unlock(hdev); +done: +	mgmt_pending_free(cmd); +} + +static int set_secure_conn_sync(struct hci_dev *hdev, void *data) +{ +	struct mgmt_pending_cmd *cmd = data; +	struct mgmt_mode *cp = cmd->param; +	u8 val = !!cp->val; + +	/* Force write of val */ +	hci_dev_set_flag(hdev, HCI_SC_ENABLED); + +	return hci_write_sc_support_sync(hdev, val);  }  static int set_secure_conn(struct sock *sk, struct hci_dev *hdev, @@ -6119,7 +6258,6 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,  {  	struct mgmt_mode *cp = data;  	struct mgmt_pending_cmd *cmd; -	struct hci_request req;  	u8 val;  	int err; @@ -6138,7 +6276,7 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,  	if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)  		return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN, -				  MGMT_STATUS_INVALID_PARAMS); +				       MGMT_STATUS_INVALID_PARAMS);  	hci_dev_lock(hdev); @@ -6169,12 +6307,6 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,  		goto failed;  	} -	if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) { -		err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN, -				      MGMT_STATUS_BUSY); -		goto failed; -	} -  	val = !!cp->val;  	if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) && @@ -6183,18 +6315,18 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,  		goto failed;  	} -	cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len); -	if (!cmd) { +	cmd = mgmt_pending_new(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len); +	if (!cmd)  		err = -ENOMEM; -		goto failed; -	} +	else +		err = hci_cmd_sync_queue(hdev, set_secure_conn_sync, cmd, +					 set_secure_conn_complete); -	hci_req_init(&req, hdev); -	hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val); -	err = hci_req_run(&req, sc_enable_complete);  	if (err < 0) { -		mgmt_pending_remove(cmd); -		goto failed; +		mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN, +				MGMT_STATUS_FAILED); +		if (cmd) +			mgmt_pending_free(cmd);  	}  failed: @@ -6508,14 +6640,19 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,  	return err;  } -static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status) +static void get_conn_info_complete(struct hci_dev *hdev, void *data, int err)  { +	struct mgmt_pending_cmd *cmd = data;  	struct hci_conn *conn = cmd->user_data; +	struct mgmt_cp_get_conn_info *cp = cmd->param;  	struct mgmt_rp_get_conn_info rp; -	int err; +	u8 status; + +	bt_dev_dbg(hdev, "err %d", err); -	memcpy(&rp.addr, cmd->param, sizeof(rp.addr)); +	memcpy(&rp.addr, &cp->addr.bdaddr, sizeof(rp.addr)); +	status = mgmt_status(err);  	if (status == MGMT_STATUS_SUCCESS) {  		rp.rssi = conn->rssi;  		rp.tx_power = conn->tx_power; @@ -6526,67 +6663,58 @@ static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)  		rp.max_tx_power = HCI_TX_POWER_INVALID;  	} -	err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO, -				status, &rp, sizeof(rp)); +	mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO, status, +			  &rp, sizeof(rp)); -	hci_conn_drop(conn); -	hci_conn_put(conn); +	if (conn) { +		hci_conn_drop(conn); +		hci_conn_put(conn); +	} -	return err; +	mgmt_pending_free(cmd);  } -static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status, -				       u16 opcode) +static int get_conn_info_sync(struct hci_dev *hdev, void *data)  { -	struct hci_cp_read_rssi *cp; -	struct mgmt_pending_cmd *cmd; +	struct mgmt_pending_cmd *cmd = data; +	struct mgmt_cp_get_conn_info *cp = cmd->param;  	struct hci_conn *conn; -	u16 handle; -	u8 status; - -	bt_dev_dbg(hdev, "status 0x%02x", hci_status); +	int err; +	__le16   handle; -	hci_dev_lock(hdev); +	/* Make sure we are still connected */ +	if (cp->addr.type == BDADDR_BREDR) +		conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, +					       &cp->addr.bdaddr); +	else +		conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr); -	/* Commands sent in request are either Read RSSI or Read Transmit Power -	 * Level so we check which one was last sent to retrieve connection -	 * handle.  Both commands have handle as first parameter so it's safe to -	 * cast data on the same command struct. -	 * -	 * First command sent is always Read RSSI and we fail only if it fails. -	 * In other case we simply override error to indicate success as we -	 * already remembered if TX power value is actually valid. -	 */ -	cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI); -	if (!cp) { -		cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER); -		status = MGMT_STATUS_SUCCESS; -	} else { -		status = mgmt_status(hci_status); +	if (!conn || conn != cmd->user_data || conn->state != BT_CONNECTED) { +		if (cmd->user_data) { +			hci_conn_drop(cmd->user_data); +			hci_conn_put(cmd->user_data); +			cmd->user_data = NULL; +		} +		return MGMT_STATUS_NOT_CONNECTED;  	} -	if (!cp) { -		bt_dev_err(hdev, "invalid sent_cmd in conn_info response"); -		goto unlock; -	} +	handle = cpu_to_le16(conn->handle); -	handle = __le16_to_cpu(cp->handle); -	conn = hci_conn_hash_lookup_handle(hdev, handle); -	if (!conn) { -		bt_dev_err(hdev, "unknown handle (%u) in conn_info response", -			   handle); -		goto unlock; -	} +	/* Refresh RSSI each time */ +	err = hci_read_rssi_sync(hdev, handle); -	cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn); -	if (!cmd) -		goto unlock; +	/* For LE links TX power does not change thus we don't need to +	 * query for it once value is known. +	 */ +	if (!err && (!bdaddr_type_is_le(cp->addr.type) || +		     conn->tx_power == HCI_TX_POWER_INVALID)) +		err = hci_read_tx_power_sync(hdev, handle, 0x00); -	cmd->cmd_complete(cmd, status); -	mgmt_pending_remove(cmd); +	/* Max TX power needs to be read only once per connection */ +	if (!err && conn->max_tx_power == HCI_TX_POWER_INVALID) +		err = hci_read_tx_power_sync(hdev, handle, 0x01); -unlock: -	hci_dev_unlock(hdev); +	return err;  }  static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data, @@ -6631,12 +6759,6 @@ static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,  		goto unlock;  	} -	if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) { -		err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO, -					MGMT_STATUS_BUSY, &rp, sizeof(rp)); -		goto unlock; -	} -  	/* To avoid client trying to guess when to poll again for information we  	 * calculate conn info age as random value between min/max set in hdev.  	 */ @@ -6650,49 +6772,28 @@ static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,  	if (time_after(jiffies, conn->conn_info_timestamp +  		       msecs_to_jiffies(conn_info_age)) ||  	    !conn->conn_info_timestamp) { -		struct hci_request req; -		struct hci_cp_read_tx_power req_txp_cp; -		struct hci_cp_read_rssi req_rssi_cp;  		struct mgmt_pending_cmd *cmd; -		hci_req_init(&req, hdev); -		req_rssi_cp.handle = cpu_to_le16(conn->handle); -		hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp), -			    &req_rssi_cp); - -		/* For LE links TX power does not change thus we don't need to -		 * query for it once value is known. -		 */ -		if (!bdaddr_type_is_le(cp->addr.type) || -		    conn->tx_power == HCI_TX_POWER_INVALID) { -			req_txp_cp.handle = cpu_to_le16(conn->handle); -			req_txp_cp.type = 0x00; -			hci_req_add(&req, HCI_OP_READ_TX_POWER, -				    sizeof(req_txp_cp), &req_txp_cp); -		} +		cmd = mgmt_pending_new(sk, MGMT_OP_GET_CONN_INFO, hdev, data, +				       len); +		if (!cmd) +			err = -ENOMEM; +		else +			err = hci_cmd_sync_queue(hdev, get_conn_info_sync, +						 cmd, get_conn_info_complete); -		/* Max TX power needs to be read only once per connection */ -		if (conn->max_tx_power == HCI_TX_POWER_INVALID) { -			req_txp_cp.handle = cpu_to_le16(conn->handle); -			req_txp_cp.type = 0x01; -			hci_req_add(&req, HCI_OP_READ_TX_POWER, -				    sizeof(req_txp_cp), &req_txp_cp); -		} +		if (err < 0) { +			mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO, +					  MGMT_STATUS_FAILED, &rp, sizeof(rp)); -		err = hci_req_run(&req, conn_info_refresh_complete); -		if (err < 0) -			goto unlock; +			if (cmd) +				mgmt_pending_free(cmd); -		cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev, -				       data, len); -		if (!cmd) { -			err = -ENOMEM;  			goto unlock;  		}  		hci_conn_hold(conn);  		cmd->user_data = hci_conn_get(conn); -		cmd->cmd_complete = conn_info_cmd_complete;  		conn->conn_info_timestamp = jiffies;  	} else { @@ -6710,82 +6811,76 @@ unlock:  	return err;  } -static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status) +static void get_clock_info_complete(struct hci_dev *hdev, void *data, int err)  { -	struct hci_conn *conn = cmd->user_data; +	struct mgmt_pending_cmd *cmd = data; +	struct mgmt_cp_get_clock_info *cp = cmd->param;  	struct mgmt_rp_get_clock_info rp; -	struct hci_dev *hdev; -	int err; +	struct hci_conn *conn = cmd->user_data; +	u8 status = mgmt_status(err); + +	bt_dev_dbg(hdev, "err %d", err);  	memset(&rp, 0, sizeof(rp)); -	memcpy(&rp.addr, cmd->param, sizeof(rp.addr)); +	bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); +	rp.addr.type = cp->addr.type; -	if (status) +	if (err)  		goto complete; -	hdev = hci_dev_get(cmd->index); -	if (hdev) { -		rp.local_clock = cpu_to_le32(hdev->clock); -		hci_dev_put(hdev); -	} +	rp.local_clock = cpu_to_le32(hdev->clock);  	if (conn) {  		rp.piconet_clock = cpu_to_le32(conn->clock);  		rp.accuracy = cpu_to_le16(conn->clock_accuracy); -	} - -complete: -	err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp, -				sizeof(rp)); - -	if (conn) {  		hci_conn_drop(conn);  		hci_conn_put(conn);  	} -	return err; +complete: +	mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp, +			  sizeof(rp)); + +	mgmt_pending_free(cmd);  } -static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode) +static int get_clock_info_sync(struct hci_dev *hdev, void *data)  { -	struct hci_cp_read_clock *hci_cp; -	struct mgmt_pending_cmd *cmd; -	struct hci_conn *conn; - -	bt_dev_dbg(hdev, "status %u", status); +	struct mgmt_pending_cmd *cmd = data; +	struct mgmt_cp_get_clock_info *cp = cmd->param; +	struct hci_cp_read_clock hci_cp; +	struct hci_conn *conn = cmd->user_data; +	int err; -	hci_dev_lock(hdev); +	memset(&hci_cp, 0, sizeof(hci_cp)); +	err = hci_read_clock_sync(hdev, &hci_cp); -	hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK); -	if (!hci_cp) -		goto unlock; +	if (conn) { +		/* Make sure connection still exists */ +		conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, +					       &cp->addr.bdaddr); -	if (hci_cp->which) { -		u16 handle = __le16_to_cpu(hci_cp->handle); -		conn = hci_conn_hash_lookup_handle(hdev, handle); -	} else { -		conn = NULL; +		if (conn && conn == cmd->user_data && +		    conn->state == BT_CONNECTED) { +			hci_cp.handle = cpu_to_le16(conn->handle); +			hci_cp.which = 0x01; /* Piconet clock */ +			err = hci_read_clock_sync(hdev, &hci_cp); +		} else if (cmd->user_data) { +			hci_conn_drop(cmd->user_data); +			hci_conn_put(cmd->user_data); +			cmd->user_data = NULL; +		}  	} -	cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn); -	if (!cmd) -		goto unlock; - -	cmd->cmd_complete(cmd, mgmt_status(status)); -	mgmt_pending_remove(cmd); - -unlock: -	hci_dev_unlock(hdev); +	return err;  }  static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data, -			 u16 len) +								u16 len)  {  	struct mgmt_cp_get_clock_info *cp = data;  	struct mgmt_rp_get_clock_info rp; -	struct hci_cp_read_clock hci_cp;  	struct mgmt_pending_cmd *cmd; -	struct hci_request req;  	struct hci_conn *conn;  	int err; @@ -6823,31 +6918,25 @@ static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,  		conn = NULL;  	} -	cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len); -	if (!cmd) { +	cmd = mgmt_pending_new(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len); +	if (!cmd)  		err = -ENOMEM; -		goto unlock; -	} - -	cmd->cmd_complete = clock_info_cmd_complete; +	else +		err = hci_cmd_sync_queue(hdev, get_clock_info_sync, cmd, +					 get_clock_info_complete); -	hci_req_init(&req, hdev); +	if (err < 0) { +		err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO, +					MGMT_STATUS_FAILED, &rp, sizeof(rp)); -	memset(&hci_cp, 0, sizeof(hci_cp)); -	hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp); +		if (cmd) +			mgmt_pending_free(cmd); -	if (conn) { +	} else if (conn) {  		hci_conn_hold(conn);  		cmd->user_data = hci_conn_get(conn); - -		hci_cp.handle = cpu_to_le16(conn->handle); -		hci_cp.which = 0x01; /* Piconet clock */ -		hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);  	} -	err = hci_req_run(&req, get_clock_info_complete); -	if (err < 0) -		mgmt_pending_remove(cmd);  unlock:  	hci_dev_unlock(hdev); @@ -6928,6 +7017,11 @@ static void device_added(struct sock *sk, struct hci_dev *hdev,  	mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);  } +static int add_device_sync(struct hci_dev *hdev, void *data) +{ +	return hci_update_passive_scan_sync(hdev); +} +  static int add_device(struct sock *sk, struct hci_dev *hdev,  		      void *data, u16 len)  { @@ -6936,6 +7030,7 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,  	struct hci_conn_params *params;  	int err;  	u32 current_flags = 0; +	u32 supported_flags;  	bt_dev_dbg(hdev, "sock %p", sk); @@ -7007,15 +7102,20 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,  		params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,  						addr_type);  		if (params) -			current_flags = params->current_flags; +			bitmap_to_arr32(¤t_flags, params->flags, +					__HCI_CONN_NUM_FLAGS);  	} -	hci_update_background_scan(hdev); +	err = hci_cmd_sync_queue(hdev, add_device_sync, NULL, NULL); +	if (err < 0) +		goto unlock;  added:  	device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action); +	bitmap_to_arr32(&supported_flags, hdev->conn_flags, +			__HCI_CONN_NUM_FLAGS);  	device_flags_changed(NULL, hdev, &cp->addr.bdaddr, cp->addr.type, -			     SUPPORTED_DEVICE_FLAGS(), current_flags); +			     supported_flags, current_flags);  	err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,  				MGMT_STATUS_SUCCESS, &cp->addr, @@ -7037,6 +7137,11 @@ static void device_removed(struct sock *sk, struct hci_dev *hdev,  	mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);  } +static int remove_device_sync(struct hci_dev *hdev, void *data) +{ +	return hci_update_passive_scan_sync(hdev); +} +  static int remove_device(struct sock *sk, struct hci_dev *hdev,  			 void *data, u16 len)  { @@ -7116,7 +7221,6 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,  		list_del(¶ms->action);  		list_del(¶ms->list);  		kfree(params); -		hci_update_background_scan(hdev);  		device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);  	} else { @@ -7153,10 +7257,10 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,  		}  		bt_dev_dbg(hdev, "All LE connection parameters were removed"); - -		hci_update_background_scan(hdev);  	} +	hci_cmd_sync_queue(hdev, remove_device_sync, NULL, NULL); +  complete:  	err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,  				MGMT_STATUS_SUCCESS, &cp->addr, @@ -7359,21 +7463,27 @@ unlock:  	return err;  } -static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status, -					     u16 opcode, struct sk_buff *skb) +static void read_local_oob_ext_data_complete(struct hci_dev *hdev, void *data, +					     int err)  {  	const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;  	struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;  	u8 *h192, *r192, *h256, *r256; -	struct mgmt_pending_cmd *cmd; +	struct mgmt_pending_cmd *cmd = data; +	struct sk_buff *skb = cmd->skb; +	u8 status = mgmt_status(err);  	u16 eir_len; -	int err; -	bt_dev_dbg(hdev, "status %u", status); +	if (!status) { +		if (!skb) +			status = MGMT_STATUS_FAILED; +		else if (IS_ERR(skb)) +			status = mgmt_status(PTR_ERR(skb)); +		else +			status = mgmt_status(skb->data[0]); +	} -	cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev); -	if (!cmd) -		return; +	bt_dev_dbg(hdev, "status %u", status);  	mgmt_cp = cmd->param; @@ -7385,7 +7495,7 @@ static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,  		r192 = NULL;  		h256 = NULL;  		r256 = NULL; -	} else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) { +	} else if (!bredr_sc_enabled(hdev)) {  		struct hci_rp_read_local_oob_data *rp;  		if (skb->len != sizeof(*rp)) { @@ -7466,6 +7576,9 @@ send_rsp:  				 mgmt_rp, sizeof(*mgmt_rp) + eir_len,  				 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);  done: +	if (skb && !IS_ERR(skb)) +		kfree_skb(skb); +  	kfree(mgmt_rp);  	mgmt_pending_remove(cmd);  } @@ -7474,7 +7587,6 @@ static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,  				  struct mgmt_cp_read_local_oob_ext_data *cp)  {  	struct mgmt_pending_cmd *cmd; -	struct hci_request req;  	int err;  	cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev, @@ -7482,14 +7594,9 @@ static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,  	if (!cmd)  		return -ENOMEM; -	hci_req_init(&req, hdev); - -	if (bredr_sc_enabled(hdev)) -		hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL); -	else -		hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL); +	err = hci_cmd_sync_queue(hdev, read_local_oob_data_sync, cmd, +				 read_local_oob_ext_data_complete); -	err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);  	if (err < 0) {  		mgmt_pending_remove(cmd);  		return err; @@ -7713,13 +7820,6 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,  		return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,  				       MGMT_STATUS_REJECTED); -	/* Enabling the experimental LL Privay support disables support for -	 * advertising. -	 */ -	if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY)) -		return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES, -				       MGMT_STATUS_NOT_SUPPORTED); -  	hci_dev_lock(hdev);  	rp_len = sizeof(*rp) + hdev->adv_instance_cnt; @@ -7876,58 +7976,66 @@ static bool adv_busy(struct hci_dev *hdev)  		pending_find(MGMT_OP_ADD_EXT_ADV_DATA, hdev));  } -static void add_advertising_complete(struct hci_dev *hdev, u8 status, -				     u16 opcode) +static void add_adv_complete(struct hci_dev *hdev, struct sock *sk, u8 instance, +			     int err)  { -	struct mgmt_pending_cmd *cmd; -	struct mgmt_cp_add_advertising *cp; -	struct mgmt_rp_add_advertising rp; -	struct adv_info *adv_instance, *n; -	u8 instance; +	struct adv_info *adv, *n; -	bt_dev_dbg(hdev, "status %u", status); +	bt_dev_dbg(hdev, "err %d", err);  	hci_dev_lock(hdev); -	cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev); -	if (!cmd) -		cmd = pending_find(MGMT_OP_ADD_EXT_ADV_DATA, hdev); +	list_for_each_entry_safe(adv, n, &hdev->adv_instances, list) { +		u8 instance; -	list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) { -		if (!adv_instance->pending) +		if (!adv->pending)  			continue; -		if (!status) { -			adv_instance->pending = false; +		if (!err) { +			adv->pending = false;  			continue;  		} -		instance = adv_instance->instance; +		instance = adv->instance;  		if (hdev->cur_adv_instance == instance)  			cancel_adv_timeout(hdev);  		hci_remove_adv_instance(hdev, instance); -		mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance); +		mgmt_advertising_removed(sk, hdev, instance);  	} -	if (!cmd) -		goto unlock; +	hci_dev_unlock(hdev); +} + +static void add_advertising_complete(struct hci_dev *hdev, void *data, int err) +{ +	struct mgmt_pending_cmd *cmd = data; +	struct mgmt_cp_add_advertising *cp = cmd->param; +	struct mgmt_rp_add_advertising rp; + +	memset(&rp, 0, sizeof(rp)); -	cp = cmd->param;  	rp.instance = cp->instance; -	if (status) +	if (err)  		mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, -				mgmt_status(status)); +				mgmt_status(err));  	else  		mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, -				  mgmt_status(status), &rp, sizeof(rp)); +				  mgmt_status(err), &rp, sizeof(rp)); -	mgmt_pending_remove(cmd); +	add_adv_complete(hdev, cmd->sk, cp->instance, err); -unlock: -	hci_dev_unlock(hdev); +	mgmt_pending_free(cmd); +} + +static int add_advertising_sync(struct hci_dev *hdev, void *data) +{ +	struct mgmt_pending_cmd *cmd = data; +	struct mgmt_cp_add_advertising *cp = cmd->param; + +	return hci_schedule_adv_instance_sync(hdev, cp->instance, true);  }  static int add_advertising(struct sock *sk, struct hci_dev *hdev, @@ -7943,7 +8051,6 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,  	struct adv_info *next_instance;  	int err;  	struct mgmt_pending_cmd *cmd; -	struct hci_request req;  	bt_dev_dbg(hdev, "sock %p", sk); @@ -7952,13 +8059,6 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,  		return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,  				       status); -	/* Enabling the experimental LL Privay support disables support for -	 * advertising. -	 */ -	if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY)) -		return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING, -				       MGMT_STATUS_NOT_SUPPORTED); -  	if (cp->instance < 1 || cp->instance > hdev->le_num_of_adv_sets)  		return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,  				       MGMT_STATUS_INVALID_PARAMS); @@ -8051,25 +8151,19 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,  	/* We're good to go, update advertising data, parameters, and start  	 * advertising.  	 */ -	cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data, +	cmd = mgmt_pending_new(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,  			       data_len);  	if (!cmd) {  		err = -ENOMEM;  		goto unlock;  	} -	hci_req_init(&req, hdev); - -	err = __hci_req_schedule_adv_instance(&req, schedule_instance, true); +	cp->instance = schedule_instance; -	if (!err) -		err = hci_req_run(&req, add_advertising_complete); - -	if (err < 0) { -		err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING, -				      MGMT_STATUS_FAILED); -		mgmt_pending_remove(cmd); -	} +	err = hci_cmd_sync_queue(hdev, add_advertising_sync, cmd, +				 add_advertising_complete); +	if (err < 0) +		mgmt_pending_free(cmd);  unlock:  	hci_dev_unlock(hdev); @@ -8077,30 +8171,25 @@ unlock:  	return err;  } -static void add_ext_adv_params_complete(struct hci_dev *hdev, u8 status, -					u16 opcode) +static void add_ext_adv_params_complete(struct hci_dev *hdev, void *data, +					int err)  { -	struct mgmt_pending_cmd *cmd; -	struct mgmt_cp_add_ext_adv_params *cp; +	struct mgmt_pending_cmd *cmd = data; +	struct mgmt_cp_add_ext_adv_params *cp = cmd->param;  	struct mgmt_rp_add_ext_adv_params rp; -	struct adv_info *adv_instance; +	struct adv_info *adv;  	u32 flags;  	BT_DBG("%s", hdev->name);  	hci_dev_lock(hdev); -	cmd = pending_find(MGMT_OP_ADD_EXT_ADV_PARAMS, hdev); -	if (!cmd) -		goto unlock; - -	cp = cmd->param; -	adv_instance = hci_find_adv_instance(hdev, cp->instance); -	if (!adv_instance) +	adv = hci_find_adv_instance(hdev, cp->instance); +	if (!adv)  		goto unlock;  	rp.instance = cp->instance; -	rp.tx_power = adv_instance->tx_power; +	rp.tx_power = adv->tx_power;  	/* While we're at it, inform userspace of the available space for this  	 * advertisement, given the flags that will be used. @@ -8109,39 +8198,44 @@ static void add_ext_adv_params_complete(struct hci_dev *hdev, u8 status,  	rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);  	rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false); -	if (status) { +	if (err) {  		/* If this advertisement was previously advertising and we  		 * failed to update it, we signal that it has been removed and  		 * delete its structure  		 */ -		if (!adv_instance->pending) +		if (!adv->pending)  			mgmt_advertising_removed(cmd->sk, hdev, cp->instance);  		hci_remove_adv_instance(hdev, cp->instance);  		mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, -				mgmt_status(status)); - +				mgmt_status(err));  	} else {  		mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, -				  mgmt_status(status), &rp, sizeof(rp)); +				  mgmt_status(err), &rp, sizeof(rp));  	}  unlock:  	if (cmd) -		mgmt_pending_remove(cmd); +		mgmt_pending_free(cmd);  	hci_dev_unlock(hdev);  } +static int add_ext_adv_params_sync(struct hci_dev *hdev, void *data) +{ +	struct mgmt_pending_cmd *cmd = data; +	struct mgmt_cp_add_ext_adv_params *cp = cmd->param; + +	return hci_setup_ext_adv_instance_sync(hdev, cp->instance); +} +  static int add_ext_adv_params(struct sock *sk, struct hci_dev *hdev,  			      void *data, u16 data_len)  {  	struct mgmt_cp_add_ext_adv_params *cp = data;  	struct mgmt_rp_add_ext_adv_params rp;  	struct mgmt_pending_cmd *cmd = NULL; -	struct adv_info *adv_instance; -	struct hci_request req;  	u32 flags, min_interval, max_interval;  	u16 timeout, duration;  	u8 status; @@ -8223,29 +8317,18 @@ static int add_ext_adv_params(struct sock *sk, struct hci_dev *hdev,  	/* Submit request for advertising params if ext adv available */  	if (ext_adv_capable(hdev)) { -		hci_req_init(&req, hdev); -		adv_instance = hci_find_adv_instance(hdev, cp->instance); - -		/* Updating parameters of an active instance will return a -		 * Command Disallowed error, so we must first disable the -		 * instance if it is active. -		 */ -		if (!adv_instance->pending) -			__hci_req_disable_ext_adv_instance(&req, cp->instance); - -		__hci_req_setup_ext_adv_instance(&req, cp->instance); - -		err = hci_req_run(&req, add_ext_adv_params_complete); - -		if (!err) -			cmd = mgmt_pending_add(sk, MGMT_OP_ADD_EXT_ADV_PARAMS, -					       hdev, data, data_len); +		cmd = mgmt_pending_new(sk, MGMT_OP_ADD_EXT_ADV_PARAMS, hdev, +				       data, data_len);  		if (!cmd) {  			err = -ENOMEM;  			hci_remove_adv_instance(hdev, cp->instance);  			goto unlock;  		} +		err = hci_cmd_sync_queue(hdev, add_ext_adv_params_sync, cmd, +					 add_ext_adv_params_complete); +		if (err < 0) +			mgmt_pending_free(cmd);  	} else {  		rp.instance = cp->instance;  		rp.tx_power = HCI_ADV_TX_POWER_NO_PREFERENCE; @@ -8262,6 +8345,49 @@ unlock:  	return err;  } +static void add_ext_adv_data_complete(struct hci_dev *hdev, void *data, int err) +{ +	struct mgmt_pending_cmd *cmd = data; +	struct mgmt_cp_add_ext_adv_data *cp = cmd->param; +	struct mgmt_rp_add_advertising rp; + +	add_adv_complete(hdev, cmd->sk, cp->instance, err); + +	memset(&rp, 0, sizeof(rp)); + +	rp.instance = cp->instance; + +	if (err) +		mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, +				mgmt_status(err)); +	else +		mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, +				  mgmt_status(err), &rp, sizeof(rp)); + +	mgmt_pending_free(cmd); +} + +static int add_ext_adv_data_sync(struct hci_dev *hdev, void *data) +{ +	struct mgmt_pending_cmd *cmd = data; +	struct mgmt_cp_add_ext_adv_data *cp = cmd->param; +	int err; + +	if (ext_adv_capable(hdev)) { +		err = hci_update_adv_data_sync(hdev, cp->instance); +		if (err) +			return err; + +		err = hci_update_scan_rsp_data_sync(hdev, cp->instance); +		if (err) +			return err; + +		return hci_enable_ext_advertising_sync(hdev, cp->instance); +	} + +	return hci_schedule_adv_instance_sync(hdev, cp->instance, true); +} +  static int add_ext_adv_data(struct sock *sk, struct hci_dev *hdev, void *data,  			    u16 data_len)  { @@ -8272,7 +8398,6 @@ static int add_ext_adv_data(struct sock *sk, struct hci_dev *hdev, void *data,  	struct adv_info *adv_instance;  	int err = 0;  	struct mgmt_pending_cmd *cmd; -	struct hci_request req;  	BT_DBG("%s", hdev->name); @@ -8314,78 +8439,52 @@ static int add_ext_adv_data(struct sock *sk, struct hci_dev *hdev, void *data,  				  cp->data, cp->scan_rsp_len,  				  cp->data + cp->adv_data_len); -	/* We're good to go, update advertising data, parameters, and start -	 * advertising. -	 */ - -	hci_req_init(&req, hdev); - -	hci_req_add(&req, HCI_OP_READ_LOCAL_NAME, 0, NULL); - -	if (ext_adv_capable(hdev)) { -		__hci_req_update_adv_data(&req, cp->instance); -		__hci_req_update_scan_rsp_data(&req, cp->instance); -		__hci_req_enable_ext_advertising(&req, cp->instance); - -	} else { -		/* If using software rotation, determine next instance to use */ - -		if (hdev->cur_adv_instance == cp->instance) { -			/* If the currently advertised instance is being changed -			 * then cancel the current advertising and schedule the -			 * next instance. If there is only one instance then the -			 * overridden advertising data will be visible right -			 * away -			 */ -			cancel_adv_timeout(hdev); - -			next_instance = hci_get_next_instance(hdev, -							      cp->instance); -			if (next_instance) -				schedule_instance = next_instance->instance; -		} else if (!hdev->adv_instance_timeout) { -			/* Immediately advertise the new instance if no other -			 * instance is currently being advertised. -			 */ -			schedule_instance = cp->instance; -		} +	/* If using software rotation, determine next instance to use */ +	if (hdev->cur_adv_instance == cp->instance) { +		/* If the currently advertised instance is being changed +		 * then cancel the current advertising and schedule the +		 * next instance. If there is only one instance then the +		 * overridden advertising data will be visible right +		 * away +		 */ +		cancel_adv_timeout(hdev); -		/* If the HCI_ADVERTISING flag is set or there is no instance to -		 * be advertised then we have no HCI communication to make. -		 * Simply return. +		next_instance = hci_get_next_instance(hdev, cp->instance); +		if (next_instance) +			schedule_instance = next_instance->instance; +	} else if (!hdev->adv_instance_timeout) { +		/* Immediately advertise the new instance if no other +		 * instance is currently being advertised.  		 */ -		if (hci_dev_test_flag(hdev, HCI_ADVERTISING) || -		    !schedule_instance) { -			if (adv_instance->pending) { -				mgmt_advertising_added(sk, hdev, cp->instance); -				adv_instance->pending = false; -			} -			rp.instance = cp->instance; -			err = mgmt_cmd_complete(sk, hdev->id, -						MGMT_OP_ADD_EXT_ADV_DATA, -						MGMT_STATUS_SUCCESS, &rp, -						sizeof(rp)); -			goto unlock; -		} +		schedule_instance = cp->instance; +	} -		err = __hci_req_schedule_adv_instance(&req, schedule_instance, -						      true); +	/* If the HCI_ADVERTISING flag is set or there is no instance to +	 * be advertised then we have no HCI communication to make. +	 * Simply return. +	 */ +	if (hci_dev_test_flag(hdev, HCI_ADVERTISING) || !schedule_instance) { +		if (adv_instance->pending) { +			mgmt_advertising_added(sk, hdev, cp->instance); +			adv_instance->pending = false; +		} +		rp.instance = cp->instance; +		err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA, +					MGMT_STATUS_SUCCESS, &rp, sizeof(rp)); +		goto unlock;  	} -	cmd = mgmt_pending_add(sk, MGMT_OP_ADD_EXT_ADV_DATA, hdev, data, +	cmd = mgmt_pending_new(sk, MGMT_OP_ADD_EXT_ADV_DATA, hdev, data,  			       data_len);  	if (!cmd) {  		err = -ENOMEM;  		goto clear_new_instance;  	} -	if (!err) -		err = hci_req_run(&req, add_advertising_complete); - +	err = hci_cmd_sync_queue(hdev, add_ext_adv_data_sync, cmd, +				 add_ext_adv_data_complete);  	if (err < 0) { -		err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA, -				      MGMT_STATUS_FAILED); -		mgmt_pending_remove(cmd); +		mgmt_pending_free(cmd);  		goto clear_new_instance;  	} @@ -8408,54 +8507,53 @@ unlock:  	return err;  } -static void remove_advertising_complete(struct hci_dev *hdev, u8 status, -					u16 opcode) +static void remove_advertising_complete(struct hci_dev *hdev, void *data, +					int err)  { -	struct mgmt_pending_cmd *cmd; -	struct mgmt_cp_remove_advertising *cp; +	struct mgmt_pending_cmd *cmd = data; +	struct mgmt_cp_remove_advertising *cp = cmd->param;  	struct mgmt_rp_remove_advertising rp; -	bt_dev_dbg(hdev, "status %u", status); +	bt_dev_dbg(hdev, "err %d", err); -	hci_dev_lock(hdev); +	memset(&rp, 0, sizeof(rp)); +	rp.instance = cp->instance; -	/* A failure status here only means that we failed to disable -	 * advertising. Otherwise, the advertising instance has been removed, -	 * so report success. -	 */ -	cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev); -	if (!cmd) -		goto unlock; +	if (err) +		mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, +				mgmt_status(err)); +	else +		mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, +				  MGMT_STATUS_SUCCESS, &rp, sizeof(rp)); -	cp = cmd->param; -	rp.instance = cp->instance; +	mgmt_pending_free(cmd); +} -	mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS, -			  &rp, sizeof(rp)); -	mgmt_pending_remove(cmd); +static int remove_advertising_sync(struct hci_dev *hdev, void *data) +{ +	struct mgmt_pending_cmd *cmd = data; +	struct mgmt_cp_remove_advertising *cp = cmd->param; +	int err; -unlock: -	hci_dev_unlock(hdev); +	err = hci_remove_advertising_sync(hdev, cmd->sk, cp->instance, true); +	if (err) +		return err; + +	if (list_empty(&hdev->adv_instances)) +		err = hci_disable_advertising_sync(hdev); + +	return err;  }  static int remove_advertising(struct sock *sk, struct hci_dev *hdev,  			      void *data, u16 data_len)  {  	struct mgmt_cp_remove_advertising *cp = data; -	struct mgmt_rp_remove_advertising rp;  	struct mgmt_pending_cmd *cmd; -	struct hci_request req;  	int err;  	bt_dev_dbg(hdev, "sock %p", sk); -	/* Enabling the experimental LL Privay support disables support for -	 * advertising. -	 */ -	if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY)) -		return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING, -				       MGMT_STATUS_NOT_SUPPORTED); -  	hci_dev_lock(hdev);  	if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) { @@ -8479,44 +8577,17 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,  		goto unlock;  	} -	hci_req_init(&req, hdev); - -	/* If we use extended advertising, instance is disabled and removed */ -	if (ext_adv_capable(hdev)) { -		__hci_req_disable_ext_adv_instance(&req, cp->instance); -		__hci_req_remove_ext_adv_instance(&req, cp->instance); -	} - -	hci_req_clear_adv_instance(hdev, sk, &req, cp->instance, true); - -	if (list_empty(&hdev->adv_instances)) -		__hci_req_disable_advertising(&req); - -	/* If no HCI commands have been collected so far or the HCI_ADVERTISING -	 * flag is set or the device isn't powered then we have no HCI -	 * communication to make. Simply return. -	 */ -	if (skb_queue_empty(&req.cmd_q) || -	    !hdev_is_powered(hdev) || -	    hci_dev_test_flag(hdev, HCI_ADVERTISING)) { -		hci_req_purge(&req); -		rp.instance = cp->instance; -		err = mgmt_cmd_complete(sk, hdev->id, -					MGMT_OP_REMOVE_ADVERTISING, -					MGMT_STATUS_SUCCESS, &rp, sizeof(rp)); -		goto unlock; -	} - -	cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data, +	cmd = mgmt_pending_new(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,  			       data_len);  	if (!cmd) {  		err = -ENOMEM;  		goto unlock;  	} -	err = hci_req_run(&req, remove_advertising_complete); +	err = hci_cmd_sync_queue(hdev, remove_advertising_sync, cmd, +				 remove_advertising_complete);  	if (err < 0) -		mgmt_pending_remove(cmd); +		mgmt_pending_free(cmd);  unlock:  	hci_dev_unlock(hdev); @@ -8758,31 +8829,6 @@ void mgmt_index_removed(struct hci_dev *hdev)  			 HCI_MGMT_EXT_INDEX_EVENTS);  } -/* This function requires the caller holds hdev->lock */ -static void restart_le_actions(struct hci_dev *hdev) -{ -	struct hci_conn_params *p; - -	list_for_each_entry(p, &hdev->le_conn_params, list) { -		/* Needed for AUTO_OFF case where might not "really" -		 * have been powered off. -		 */ -		list_del_init(&p->action); - -		switch (p->auto_connect) { -		case HCI_AUTO_CONN_DIRECT: -		case HCI_AUTO_CONN_ALWAYS: -			list_add(&p->action, &hdev->pend_le_conns); -			break; -		case HCI_AUTO_CONN_REPORT: -			list_add(&p->action, &hdev->pend_le_reports); -			break; -		default: -			break; -		} -	} -} -  void mgmt_power_on(struct hci_dev *hdev, int err)  {  	struct cmd_lookup match = { NULL, hdev }; @@ -8793,7 +8839,7 @@ void mgmt_power_on(struct hci_dev *hdev, int err)  	if (!err) {  		restart_le_actions(hdev); -		hci_update_background_scan(hdev); +		hci_update_passive_scan(hdev);  	}  	mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); @@ -9008,11 +9054,19 @@ void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,  void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,  			   u8 *name, u8 name_len)  { -	char buf[512]; -	struct mgmt_ev_device_connected *ev = (void *) buf; +	struct sk_buff *skb; +	struct mgmt_ev_device_connected *ev;  	u16 eir_len = 0;  	u32 flags = 0; +	if (conn->le_adv_data_len > 0) +		skb = mgmt_alloc_skb(hdev, MGMT_EV_DEVICE_CONNECTED, +				     conn->le_adv_data_len); +	else +		skb = mgmt_alloc_skb(hdev, MGMT_EV_DEVICE_CONNECTED, +				     2 + name_len + 5); + +	ev = skb_put(skb, sizeof(*ev));  	bacpy(&ev->addr.bdaddr, &conn->dst);  	ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type); @@ -9026,24 +9080,26 @@ void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,  	 * adding any BR/EDR data to the LE adv.  	 */  	if (conn->le_adv_data_len > 0) { -		memcpy(&ev->eir[eir_len], -		       conn->le_adv_data, conn->le_adv_data_len); +		skb_put_data(skb, conn->le_adv_data, conn->le_adv_data_len);  		eir_len = conn->le_adv_data_len;  	} else { -		if (name_len > 0) +		if (name_len > 0) {  			eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,  						  name, name_len); +			skb_put(skb, eir_len); +		} -		if (memcmp(conn->dev_class, "\0\0\0", 3) != 0) +		if (memcmp(conn->dev_class, "\0\0\0", 3) != 0) {  			eir_len = eir_append_data(ev->eir, eir_len,  						  EIR_CLASS_OF_DEV,  						  conn->dev_class, 3); +			skb_put(skb, 5); +		}  	}  	ev->eir_len = cpu_to_le16(eir_len); -	mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf, -		    sizeof(*ev) + eir_len, NULL); +	mgmt_event_skb(skb, NULL);  }  static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data) @@ -9349,74 +9405,6 @@ void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)  		sock_put(match.sk);  } -static void clear_eir(struct hci_request *req) -{ -	struct hci_dev *hdev = req->hdev; -	struct hci_cp_write_eir cp; - -	if (!lmp_ext_inq_capable(hdev)) -		return; - -	memset(hdev->eir, 0, sizeof(hdev->eir)); - -	memset(&cp, 0, sizeof(cp)); - -	hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp); -} - -void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) -{ -	struct cmd_lookup match = { NULL, hdev }; -	struct hci_request req; -	bool changed = false; - -	if (status) { -		u8 mgmt_err = mgmt_status(status); - -		if (enable && hci_dev_test_and_clear_flag(hdev, -							  HCI_SSP_ENABLED)) { -			hci_dev_clear_flag(hdev, HCI_HS_ENABLED); -			new_settings(hdev, NULL); -		} - -		mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp, -				     &mgmt_err); -		return; -	} - -	if (enable) { -		changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED); -	} else { -		changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED); -		if (!changed) -			changed = hci_dev_test_and_clear_flag(hdev, -							      HCI_HS_ENABLED); -		else -			hci_dev_clear_flag(hdev, HCI_HS_ENABLED); -	} - -	mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match); - -	if (changed) -		new_settings(hdev, match.sk); - -	if (match.sk) -		sock_put(match.sk); - -	hci_req_init(&req, hdev); - -	if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) { -		if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS)) -			hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE, -				    sizeof(enable), &enable); -		__hci_req_update_eir(&req); -	} else { -		clear_eir(&req); -	} - -	hci_req_run(&req, NULL); -} -  static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)  {  	struct cmd_lookup *match = data; @@ -9605,9 +9593,8 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,  		       u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,  		       u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)  { -	char buf[512]; -	struct mgmt_ev_device_found *ev = (void *)buf; -	size_t ev_size; +	struct sk_buff *skb; +	struct mgmt_ev_device_found *ev;  	/* Don't send events for a non-kernel initiated discovery. With  	 * LE one exception is if we have pend_le_reports > 0 in which @@ -9642,13 +9629,13 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,  		}  	} -	/* Make sure that the buffer is big enough. The 5 extra bytes -	 * are for the potential CoD field. -	 */ -	if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf)) +	/* Allocate skb. The 5 extra bytes are for the potential CoD field */ +	skb = mgmt_alloc_skb(hdev, MGMT_EV_DEVICE_FOUND, +			     sizeof(*ev) + eir_len + scan_rsp_len + 5); +	if (!skb)  		return; -	memset(buf, 0, sizeof(buf)); +	ev = skb_put(skb, sizeof(*ev));  	/* In case of device discovery with BR/EDR devices (pre 1.2), the  	 * RSSI value was reported as 0 when not available. This behavior @@ -9669,44 +9656,57 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,  	if (eir_len > 0)  		/* Copy EIR or advertising data into event */ -		memcpy(ev->eir, eir, eir_len); +		skb_put_data(skb, eir, eir_len); -	if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV, -				       NULL)) -		eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV, -					  dev_class, 3); +	if (dev_class && !eir_get_data(eir, eir_len, EIR_CLASS_OF_DEV, NULL)) { +		u8 eir_cod[5]; + +		eir_len += eir_append_data(eir_cod, 0, EIR_CLASS_OF_DEV, +					   dev_class, 3); +		skb_put_data(skb, eir_cod, sizeof(eir_cod)); +	}  	if (scan_rsp_len > 0)  		/* Append scan response data to event */ -		memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len); +		skb_put_data(skb, scan_rsp, scan_rsp_len);  	ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len); -	ev_size = sizeof(*ev) + eir_len + scan_rsp_len; -	mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL); +	mgmt_event_skb(skb, NULL);  }  void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,  		      u8 addr_type, s8 rssi, u8 *name, u8 name_len)  { +	struct sk_buff *skb;  	struct mgmt_ev_device_found *ev; -	char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];  	u16 eir_len; +	u32 flags; -	ev = (struct mgmt_ev_device_found *) buf; - -	memset(buf, 0, sizeof(buf)); +	if (name_len) +		skb = mgmt_alloc_skb(hdev, MGMT_EV_DEVICE_FOUND, 2 + name_len); +	else +		skb = mgmt_alloc_skb(hdev, MGMT_EV_DEVICE_FOUND, 0); +	ev = skb_put(skb, sizeof(*ev));  	bacpy(&ev->addr.bdaddr, bdaddr);  	ev->addr.type = link_to_bdaddr(link_type, addr_type);  	ev->rssi = rssi; -	eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name, -				  name_len); +	if (name) { +		eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name, +					  name_len); +		flags = 0; +		skb_put(skb, eir_len); +	} else { +		eir_len = 0; +		flags = MGMT_DEV_FOUND_NAME_REQUEST_FAILED; +	}  	ev->eir_len = cpu_to_le16(eir_len); +	ev->flags = cpu_to_le32(flags); -	mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL); +	mgmt_event_skb(skb, NULL);  }  void mgmt_discovering(struct hci_dev *hdev, u8 discovering) |