Bluetooth: Add read_local_oob_data management command
authorSzymon Janc <szymon.janc@tieto.com>
Tue, 22 Mar 2011 12:12:21 +0000 (13:12 +0100)
committerGustavo F. Padovan <padovan@profusion.mobi>
Thu, 31 Mar 2011 17:22:57 +0000 (14:22 -0300)
This patch adds a command to read local OOB data to the managment interface.
The command maps directly to the Read Local OOB Data HCI command.

Signed-off-by: Szymon Janc <szymon.janc@tieto.com>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/mgmt.h
net/bluetooth/hci_event.c
net/bluetooth/mgmt.c

index 1cd031cd1c4d1a394e8ae5b3046fe34fc8204375..ac4de1afe046921ffbd625d3a77ce745569f02c6 100644 (file)
@@ -613,6 +613,13 @@ struct hci_cp_write_ssp_mode {
        __u8     mode;
 } __packed;
 
+#define HCI_OP_READ_LOCAL_OOB_DATA             0x0c57
+struct hci_rp_read_local_oob_data {
+       __u8     status;
+       __u8     hash[16];
+       __u8     randomizer[16];
+} __packed;
+
 #define HCI_OP_READ_INQ_RSP_TX_POWER   0x0c58
 
 #define HCI_OP_READ_LOCAL_VERSION      0x1001
index 3912c7ab717c1de3d9b9f5deef25e7c06efcc164..fd9b8a31e5b0cc011cf9de7e74ec97d25f36d1be 100644 (file)
@@ -768,6 +768,8 @@ int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr,
                                                                u8 status);
 int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status);
 int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status);
+int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
+                                                               u8 status);
 
 /* HCI info for socket */
 #define hci_pi(sk) ((struct hci_pinfo *) sk)
index 89e7c82c4784763599e3f6599d9679d873d23ffe..6ebb1265c36ef9ec9086a83c897fa8055014fc16 100644 (file)
@@ -177,6 +177,12 @@ struct mgmt_cp_set_local_name {
        __u8 name[MGMT_MAX_NAME_LENGTH];
 } __packed;
 
+#define MGMT_OP_READ_LOCAL_OOB_DATA    0x0018
+struct mgmt_rp_read_local_oob_data {
+       __u8 hash[16];
+       __u8 randomizer[16];
+} __packed;
+
 #define MGMT_EV_CMD_COMPLETE           0x0001
 struct mgmt_ev_cmd_complete {
        __le16 opcode;
index 0def3e1fe5eff57efd2c77c7dcce78b8442e93bb..582ef60a8bc0d60328c4fa12aa7fbdf97ec51e42 100644 (file)
@@ -822,6 +822,17 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
                                                                rp->status);
 }
 
+static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
+                                                       struct sk_buff *skb)
+{
+       struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
+
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+       mgmt_read_local_oob_data_reply_complete(hdev->id, rp->hash,
+                                               rp->randomizer, rp->status);
+}
+
 static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
 {
        BT_DBG("%s status 0x%x", hdev->name, status);
@@ -1752,6 +1763,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
                hci_cc_pin_code_neg_reply(hdev, skb);
                break;
 
+       case HCI_OP_READ_LOCAL_OOB_DATA:
+               hci_cc_read_local_oob_data_reply(hdev, skb);
+               break;
+
        case HCI_OP_LE_READ_BUFFER_SIZE:
                hci_cc_le_read_buffer_size(hdev, skb);
                break;
index 93f0f04c8bcdce1053739f9e12c497dce8c44596..33b1f7400dab0ac2fc4d374df11de9c656a5634b 100644 (file)
@@ -1296,6 +1296,55 @@ failed:
        return err;
 }
 
+static int read_local_oob_data(struct sock *sk, u16 index)
+{
+       struct hci_dev *hdev;
+       struct pending_cmd *cmd;
+       int err;
+
+       BT_DBG("hci%u", index);
+
+       hdev = hci_dev_get(index);
+       if (!hdev)
+               return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
+                                                                       ENODEV);
+
+       hci_dev_lock_bh(hdev);
+
+       if (!test_bit(HCI_UP, &hdev->flags)) {
+               err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
+                                                               ENETDOWN);
+               goto unlock;
+       }
+
+       if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
+               err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
+                                                               EOPNOTSUPP);
+               goto unlock;
+       }
+
+       if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
+               err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
+               goto unlock;
+       }
+
+       cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
+       if (!cmd) {
+               err = -ENOMEM;
+               goto unlock;
+       }
+
+       err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
+       if (err < 0)
+               mgmt_pending_remove(cmd);
+
+unlock:
+       hci_dev_unlock_bh(hdev);
+       hci_dev_put(hdev);
+
+       return err;
+}
+
 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
 {
        unsigned char *buf;
@@ -1394,6 +1443,10 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
        case MGMT_OP_SET_LOCAL_NAME:
                err = set_local_name(sk, index, buf + sizeof(*hdr), len);
                break;
+       case MGMT_OP_READ_LOCAL_OOB_DATA:
+               err = read_local_oob_data(sk, index);
+               break;
+
        default:
                BT_DBG("Unknown op %u", opcode);
                err = cmd_status(sk, index, opcode, 0x01);
@@ -1723,3 +1776,33 @@ failed:
                mgmt_pending_remove(cmd);
        return err;
 }
+
+int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
+                                                               u8 status)
+{
+       struct pending_cmd *cmd;
+       int err;
+
+       BT_DBG("hci%u status %u", index, status);
+
+       cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
+       if (!cmd)
+               return -ENOENT;
+
+       if (status) {
+               err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
+                                                                       EIO);
+       } else {
+               struct mgmt_rp_read_local_oob_data rp;
+
+               memcpy(rp.hash, hash, sizeof(rp.hash));
+               memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
+
+               err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
+                                                       &rp, sizeof(rp));
+       }
+
+       mgmt_pending_remove(cmd);
+
+       return err;
+}