struct list_head list;
__u16 opcode;
int index;
- void *cmd;
+ void *param;
struct sock *sk;
void *user_data;
};
set_bit(HCI_MGMT, &hdev->flags);
+ memset(&rp, 0, sizeof(rp));
+
rp.type = hdev->dev_type;
rp.powered = test_bit(HCI_UP, &hdev->flags);
rp.hci_ver = hdev->hci_ver;
put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
+ memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
+
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
static void mgmt_pending_free(struct pending_cmd *cmd)
{
sock_put(cmd->sk);
- kfree(cmd->cmd);
+ kfree(cmd->param);
kfree(cmd);
}
cmd->opcode = opcode;
cmd->index = index;
- cmd->cmd = kmalloc(len, GFP_ATOMIC);
- if (!cmd->cmd) {
+ cmd->param = kmalloc(len, GFP_ATOMIC);
+ if (!cmd->param) {
kfree(cmd);
return NULL;
}
- memcpy(cmd->cmd, data, len);
+ if (data)
+ memcpy(cmd->param, data, len);
cmd->sk = sk;
sock_hold(sk);
return err;
}
+static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
+ u16 len)
+{
+ struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
+ struct hci_cp_write_local_name hci_cp;
+ struct hci_dev *hdev;
+ struct pending_cmd *cmd;
+ int err;
+
+ BT_DBG("");
+
+ if (len != sizeof(*mgmt_cp))
+ return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
+
+ hdev = hci_dev_get(index);
+ if (!hdev)
+ return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
+
+ hci_dev_lock_bh(hdev);
+
+ cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
+ if (!cmd) {
+ err = -ENOMEM;
+ goto failed;
+ }
+
+ memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
+ err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
+ &hci_cp);
+ if (err < 0)
+ mgmt_pending_remove(cmd);
+
+failed:
+ hci_dev_unlock_bh(hdev);
+ hci_dev_put(hdev);
+
+ 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;
+}
+
+static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
+ u16 len)
+{
+ struct hci_dev *hdev;
+ struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
+ int err;
+
+ BT_DBG("hci%u ", index);
+
+ if (len != sizeof(*cp))
+ return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
+ EINVAL);
+
+ hdev = hci_dev_get(index);
+ if (!hdev)
+ return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
+ ENODEV);
+
+ hci_dev_lock_bh(hdev);
+
+ err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
+ cp->randomizer);
+ if (err < 0)
+ err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
+ else
+ err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
+ 0);
+
+ hci_dev_unlock_bh(hdev);
+ hci_dev_put(hdev);
+
+ return err;
+}
+
+static int remove_remote_oob_data(struct sock *sk, u16 index,
+ unsigned char *data, u16 len)
+{
+ struct hci_dev *hdev;
+ struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
+ int err;
+
+ BT_DBG("hci%u ", index);
+
+ if (len != sizeof(*cp))
+ return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
+ EINVAL);
+
+ hdev = hci_dev_get(index);
+ if (!hdev)
+ return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
+ ENODEV);
+
+ hci_dev_lock_bh(hdev);
+
+ err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
+ if (err < 0)
+ err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
+ -err);
+ else
+ err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
+ NULL, 0);
+
+ 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;
case MGMT_OP_USER_CONFIRM_NEG_REPLY:
err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
break;
+ 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;
+ case MGMT_OP_ADD_REMOTE_OOB_DATA:
+ err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
+ break;
+ case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
+ err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
+ len);
+ break;
+
default:
BT_DBG("Unknown op %u", opcode);
err = cmd_status(sk, index, opcode, 0x01);
static void mode_rsp(struct pending_cmd *cmd, void *data)
{
- struct mgmt_mode *cp = cmd->cmd;
+ struct mgmt_mode *cp = cmd->param;
struct cmd_lookup *match = data;
if (cp->val != match->val)
static void disconnect_rsp(struct pending_cmd *cmd, void *data)
{
- struct mgmt_cp_disconnect *cp = cmd->cmd;
+ struct mgmt_cp_disconnect *cp = cmd->param;
struct sock **sk = data;
struct mgmt_rp_disconnect rp;
return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
}
+
+int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
+{
+ struct pending_cmd *cmd;
+ struct mgmt_cp_set_local_name ev;
+ int err;
+
+ memset(&ev, 0, sizeof(ev));
+ memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
+
+ cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
+ if (!cmd)
+ goto send_event;
+
+ if (status) {
+ err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
+ goto failed;
+ }
+
+ err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
+ sizeof(ev));
+ if (err < 0)
+ goto failed;
+
+send_event:
+ err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
+ cmd ? cmd->sk : NULL);
+
+failed:
+ if (cmd)
+ 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;
+}