Bluetooth: mgmt: Track pending class changes

This patch adds a flag to track pending changes to the class of device.
This is needed since we cannot cleanly handle multiple simultaneous
commands and need to return a "busy" error status in the mgmt commands
that might trigger a class change.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Acked-by: Marcel Holtmann <marcel@holtmann.org>
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 79fe575..9f912dc 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -570,6 +570,7 @@
 static int update_class(struct hci_dev *hdev)
 {
 	u8 cod[3];
+	int err;
 
 	BT_DBG("%s", hdev->name);
 
@@ -586,7 +587,11 @@
 	if (memcmp(cod, hdev->dev_class, 3) == 0)
 		return 0;
 
-	return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
+	err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
+	if (err == 0)
+		set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
+
+	return err;
 }
 
 static void service_cache_off(struct work_struct *work)
@@ -1344,6 +1349,12 @@
 
 	hci_dev_lock(hdev);
 
+	if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
+		err = cmd_status(sk, index, MGMT_OP_ADD_UUID,
+							MGMT_STATUS_BUSY);
+		goto failed;
+	}
+
 	uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
 	if (!uuid) {
 		err = -ENOMEM;
@@ -1393,6 +1404,12 @@
 
 	hci_dev_lock(hdev);
 
+	if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
+		err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
+							MGMT_STATUS_BUSY);
+		goto unlock;
+	}
+
 	if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
 		err = hci_uuids_clear(hdev);
 
@@ -1460,6 +1477,12 @@
 
 	hci_dev_lock(hdev);
 
+	if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
+		err = cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
+							MGMT_STATUS_BUSY);
+		goto unlock;
+	}
+
 	hdev->major_class = cp->major;
 	hdev->minor_class = cp->minor;
 
@@ -3259,7 +3282,7 @@
 	bacpy(&ev->addr.bdaddr, bdaddr);
 	ev->addr.type = link_to_mgmt(link_type, addr_type);
 
-	put_unaligned_le32(flags, &ev->flags);
+	ev->flags = __cpu_to_le32(flags);
 
 	if (name_len > 0)
 		eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
@@ -3614,6 +3637,8 @@
 {
 	int err;
 
+	clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
+
 	err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3, NULL);
 
 	return err;