diff options
-rw-r--r-- | net/bluetooth/mgmt.c | 45 |
1 files changed, 36 insertions, 9 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index bf17a62a1bef..367837d0da2d 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -1336,6 +1336,29 @@ unlock: | |||
1336 | return err; | 1336 | return err; |
1337 | } | 1337 | } |
1338 | 1338 | ||
1339 | /* This is a helper function to test for pending mgmt commands that can | ||
1340 | * cause CoD or EIR HCI commands. We can only allow one such pending | ||
1341 | * mgmt command at a time since otherwise we cannot easily track what | ||
1342 | * the current values are, will be, and based on that calculate if a new | ||
1343 | * HCI command needs to be sent and if yes with what value. | ||
1344 | */ | ||
1345 | static bool pending_eir_or_class(struct hci_dev *hdev) | ||
1346 | { | ||
1347 | struct pending_cmd *cmd; | ||
1348 | |||
1349 | list_for_each_entry(cmd, &hdev->mgmt_pending, list) { | ||
1350 | switch (cmd->opcode) { | ||
1351 | case MGMT_OP_ADD_UUID: | ||
1352 | case MGMT_OP_REMOVE_UUID: | ||
1353 | case MGMT_OP_SET_DEV_CLASS: | ||
1354 | case MGMT_OP_SET_POWERED: | ||
1355 | return true; | ||
1356 | } | ||
1357 | } | ||
1358 | |||
1359 | return false; | ||
1360 | } | ||
1361 | |||
1339 | static const u8 bluetooth_base_uuid[] = { | 1362 | static const u8 bluetooth_base_uuid[] = { |
1340 | 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, | 1363 | 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, |
1341 | 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1364 | 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
@@ -1367,7 +1390,7 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) | |||
1367 | 1390 | ||
1368 | hci_dev_lock(hdev); | 1391 | hci_dev_lock(hdev); |
1369 | 1392 | ||
1370 | if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { | 1393 | if (pending_eir_or_class(hdev)) { |
1371 | err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID, | 1394 | err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID, |
1372 | MGMT_STATUS_BUSY); | 1395 | MGMT_STATUS_BUSY); |
1373 | goto failed; | 1396 | goto failed; |
@@ -1439,7 +1462,7 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, | |||
1439 | 1462 | ||
1440 | hci_dev_lock(hdev); | 1463 | hci_dev_lock(hdev); |
1441 | 1464 | ||
1442 | if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { | 1465 | if (pending_eir_or_class(hdev)) { |
1443 | err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID, | 1466 | err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID, |
1444 | MGMT_STATUS_BUSY); | 1467 | MGMT_STATUS_BUSY); |
1445 | goto unlock; | 1468 | goto unlock; |
@@ -1515,15 +1538,19 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data, | |||
1515 | return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, | 1538 | return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, |
1516 | MGMT_STATUS_NOT_SUPPORTED); | 1539 | MGMT_STATUS_NOT_SUPPORTED); |
1517 | 1540 | ||
1518 | if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) | 1541 | hci_dev_lock(hdev); |
1519 | return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, | ||
1520 | MGMT_STATUS_BUSY); | ||
1521 | 1542 | ||
1522 | if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) | 1543 | if (pending_eir_or_class(hdev)) { |
1523 | return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, | 1544 | err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, |
1524 | MGMT_STATUS_INVALID_PARAMS); | 1545 | MGMT_STATUS_BUSY); |
1546 | goto unlock; | ||
1547 | } | ||
1525 | 1548 | ||
1526 | hci_dev_lock(hdev); | 1549 | if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) { |
1550 | err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, | ||
1551 | MGMT_STATUS_INVALID_PARAMS); | ||
1552 | goto unlock; | ||
1553 | } | ||
1527 | 1554 | ||
1528 | hdev->major_class = cp->major; | 1555 | hdev->major_class = cp->major; |
1529 | hdev->minor_class = cp->minor; | 1556 | hdev->minor_class = cp->minor; |