aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2015-04-07 14:52:22 -0400
committerMarcel Holtmann <marcel@holtmann.org>2015-04-07 17:31:20 -0400
commit40f66c05c360777e847033ddbe076d88123719d1 (patch)
tree29235693c160fef4f626e375832314ae52031b7e
parentd619ffcfbd07983d34dc87d474af6cb5c21adf27 (diff)
Bluetooth: Add local SSP OOB data to OOB ext data mgmt command
The Read Local Out Of Band Extended Data mgmt command is specified to return the SSP values when given a BR/EDR address type as input parameter. The returned values may include either the 192-bit variants of C and R, or their 256-bit variants, or both, depending on the status of Secure Connections and Secure Connections Only modes. If SSP is not enabled the command will only return the Class of Device value (like it has done so far). Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r--net/bluetooth/mgmt.c154
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
6469static 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
6560send_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);
6575done:
6576 kfree(mgmt_rp);
6577 mgmt_pending_remove(cmd);
6578}
6579
6580static 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
6469static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev, 6608static 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) &&