diff options
-rw-r--r-- | net/bluetooth/mgmt.c | 154 |
1 files changed, 152 insertions, 2 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 845dfcc43a20..7fd87e7135b5 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -6466,6 +6466,145 @@ static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data, | |||
6466 | return eir_len; | 6466 | return eir_len; |
6467 | } | 6467 | } |
6468 | 6468 | ||
6469 | static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status, | ||
6470 | u16 opcode, struct sk_buff *skb) | ||
6471 | { | ||
6472 | const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp; | ||
6473 | struct mgmt_rp_read_local_oob_ext_data *mgmt_rp; | ||
6474 | u8 *h192, *r192, *h256, *r256; | ||
6475 | struct mgmt_pending_cmd *cmd; | ||
6476 | u16 eir_len; | ||
6477 | int err; | ||
6478 | |||
6479 | BT_DBG("%s status %u", hdev->name, status); | ||
6480 | |||
6481 | cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev); | ||
6482 | if (!cmd) | ||
6483 | return; | ||
6484 | |||
6485 | mgmt_cp = cmd->param; | ||
6486 | |||
6487 | if (status) { | ||
6488 | status = mgmt_status(status); | ||
6489 | eir_len = 0; | ||
6490 | |||
6491 | h192 = NULL; | ||
6492 | r192 = NULL; | ||
6493 | h256 = NULL; | ||
6494 | r256 = NULL; | ||
6495 | } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) { | ||
6496 | struct hci_rp_read_local_oob_data *rp; | ||
6497 | |||
6498 | if (skb->len != sizeof(*rp)) { | ||
6499 | status = MGMT_STATUS_FAILED; | ||
6500 | eir_len = 0; | ||
6501 | } else { | ||
6502 | status = MGMT_STATUS_SUCCESS; | ||
6503 | rp = (void *)skb->data; | ||
6504 | |||
6505 | eir_len = 5 + 18 + 18; | ||
6506 | h192 = rp->hash; | ||
6507 | r192 = rp->rand; | ||
6508 | h256 = NULL; | ||
6509 | r256 = NULL; | ||
6510 | } | ||
6511 | } else { | ||
6512 | struct hci_rp_read_local_oob_ext_data *rp; | ||
6513 | |||
6514 | if (skb->len != sizeof(*rp)) { | ||
6515 | status = MGMT_STATUS_FAILED; | ||
6516 | eir_len = 0; | ||
6517 | } else { | ||
6518 | status = MGMT_STATUS_SUCCESS; | ||
6519 | rp = (void *)skb->data; | ||
6520 | |||
6521 | if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) { | ||
6522 | eir_len = 5 + 18 + 18; | ||
6523 | h192 = NULL; | ||
6524 | r192 = NULL; | ||
6525 | } else { | ||
6526 | eir_len = 5 + 18 + 18 + 18 + 18; | ||
6527 | h192 = rp->hash192; | ||
6528 | r192 = rp->rand192; | ||
6529 | } | ||
6530 | |||
6531 | h256 = rp->hash256; | ||
6532 | r256 = rp->rand256; | ||
6533 | } | ||
6534 | } | ||
6535 | |||
6536 | mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL); | ||
6537 | if (!mgmt_rp) | ||
6538 | goto done; | ||
6539 | |||
6540 | if (status) | ||
6541 | goto send_rsp; | ||
6542 | |||
6543 | eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV, | ||
6544 | hdev->dev_class, 3); | ||
6545 | |||
6546 | if (h192 && r192) { | ||
6547 | eir_len = eir_append_data(mgmt_rp->eir, eir_len, | ||
6548 | EIR_SSP_HASH_C192, h192, 16); | ||
6549 | eir_len = eir_append_data(mgmt_rp->eir, eir_len, | ||
6550 | EIR_SSP_RAND_R192, r192, 16); | ||
6551 | } | ||
6552 | |||
6553 | if (h256 && r256) { | ||
6554 | eir_len = eir_append_data(mgmt_rp->eir, eir_len, | ||
6555 | EIR_SSP_HASH_C256, h256, 16); | ||
6556 | eir_len = eir_append_data(mgmt_rp->eir, eir_len, | ||
6557 | EIR_SSP_RAND_R256, r256, 16); | ||
6558 | } | ||
6559 | |||
6560 | send_rsp: | ||
6561 | mgmt_rp->type = mgmt_cp->type; | ||
6562 | mgmt_rp->eir_len = cpu_to_le16(eir_len); | ||
6563 | |||
6564 | err = mgmt_cmd_complete(cmd->sk, hdev->id, | ||
6565 | MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status, | ||
6566 | mgmt_rp, sizeof(*mgmt_rp) + eir_len); | ||
6567 | if (err < 0 || status) | ||
6568 | goto done; | ||
6569 | |||
6570 | hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS); | ||
6571 | |||
6572 | err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev, | ||
6573 | mgmt_rp, sizeof(*mgmt_rp) + eir_len, | ||
6574 | HCI_MGMT_OOB_DATA_EVENTS, cmd->sk); | ||
6575 | done: | ||
6576 | kfree(mgmt_rp); | ||
6577 | mgmt_pending_remove(cmd); | ||
6578 | } | ||
6579 | |||
6580 | static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk, | ||
6581 | struct mgmt_cp_read_local_oob_ext_data *cp) | ||
6582 | { | ||
6583 | struct mgmt_pending_cmd *cmd; | ||
6584 | struct hci_request req; | ||
6585 | int err; | ||
6586 | |||
6587 | cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev, | ||
6588 | cp, sizeof(*cp)); | ||
6589 | if (!cmd) | ||
6590 | return -ENOMEM; | ||
6591 | |||
6592 | hci_req_init(&req, hdev); | ||
6593 | |||
6594 | if (bredr_sc_enabled(hdev)) | ||
6595 | hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL); | ||
6596 | else | ||
6597 | hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL); | ||
6598 | |||
6599 | err = hci_req_run_skb(&req, read_local_oob_ext_data_complete); | ||
6600 | if (err < 0) { | ||
6601 | mgmt_pending_remove(cmd); | ||
6602 | return err; | ||
6603 | } | ||
6604 | |||
6605 | return 0; | ||
6606 | } | ||
6607 | |||
6469 | static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev, | 6608 | static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev, |
6470 | void *data, u16 data_len) | 6609 | void *data, u16 data_len) |
6471 | { | 6610 | { |
@@ -6517,8 +6656,19 @@ static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev, | |||
6517 | eir_len = 0; | 6656 | eir_len = 0; |
6518 | switch (cp->type) { | 6657 | switch (cp->type) { |
6519 | case BIT(BDADDR_BREDR): | 6658 | case BIT(BDADDR_BREDR): |
6520 | eir_len = eir_append_data(rp->eir, eir_len, EIR_CLASS_OF_DEV, | 6659 | if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) { |
6521 | hdev->dev_class, 3); | 6660 | err = read_local_ssp_oob_req(hdev, sk, cp); |
6661 | hci_dev_unlock(hdev); | ||
6662 | if (!err) | ||
6663 | goto done; | ||
6664 | |||
6665 | status = MGMT_STATUS_FAILED; | ||
6666 | goto complete; | ||
6667 | } else { | ||
6668 | eir_len = eir_append_data(rp->eir, eir_len, | ||
6669 | EIR_CLASS_OF_DEV, | ||
6670 | hdev->dev_class, 3); | ||
6671 | } | ||
6522 | break; | 6672 | break; |
6523 | case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)): | 6673 | case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)): |
6524 | if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) && | 6674 | if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) && |