BT_DBG("request for %s", hdev->name);
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);
if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
BT_DBG("request for %s", hdev->name);
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
- MGMT_STATUS_INVALID_PARAMS);
-
timeout = get_unaligned_le16(&cp->timeout);
if (!cp->val && timeout > 0)
return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
BT_DBG("request for %s", hdev->name);
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);
if (!hdev_is_powered(hdev)) {
BT_DBG("request for %s", hdev->name);
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);
if (cp->val)
BT_DBG("request for %s", hdev->name);
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);
if (!hdev_is_powered(hdev)) {
BT_DBG("request for %s", hdev->name);
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);
if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
BT_DBG("request for %s", hdev->name);
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
- MGMT_STATUS_INVALID_PARAMS);
-
if (!enable_hs)
return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
MGMT_STATUS_NOT_SUPPORTED);
BT_DBG("request for %s", hdev->name);
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);
if (!enable_le || !(hdev->features[4] & LMP_LE)) {
BT_DBG("request for %s", hdev->name);
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);
if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
BT_DBG("request for %s", hdev->name);
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);
if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
BT_DBG("request for %s", hdev->name);
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);
if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
u16 key_count, expected_len;
int i;
- if (len < sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
- MGMT_STATUS_INVALID_PARAMS);
-
key_count = get_unaligned_le16(&cp->key_count);
expected_len = sizeof(*cp) + key_count *
struct hci_conn *conn;
int err;
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);
memset(&rp, 0, sizeof(rp));
BT_DBG("");
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);
if (!test_bit(HCI_UP, &hdev->flags)) {
BT_DBG("");
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);
if (!hdev_is_powered(hdev)) {
BT_DBG("");
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);
if (!hdev_is_powered(hdev)) {
BT_DBG("");
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);
hdev->io_capability = cp->io_capability;
BT_DBG("");
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);
if (!hdev_is_powered(hdev)) {
BT_DBG("");
- if (len != sizeof(*addr))
- return cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);
if (!hdev_is_powered(hdev)) {
BT_DBG("");
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_NEG_REPLY,
- MGMT_STATUS_INVALID_PARAMS);
-
return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
MGMT_OP_USER_CONFIRM_NEG_REPLY,
HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
BT_DBG("");
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_USER_PASSKEY_REPLY,
- EINVAL);
-
return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
MGMT_OP_USER_PASSKEY_REPLY,
HCI_OP_USER_PASSKEY_REPLY,
BT_DBG("");
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_USER_PASSKEY_NEG_REPLY,
- EINVAL);
-
return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
MGMT_OP_USER_PASSKEY_NEG_REPLY,
HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
BT_DBG("");
- if (len != sizeof(*mgmt_cp))
- return cmd_status(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);
memcpy(hdev->short_name, mgmt_cp->short_name,
BT_DBG("%s ", hdev->name);
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);
if (!hdev_is_powered(hdev)) {
BT_DBG("%s", hdev->name);
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);
if (!hdev_is_powered(hdev)) {
BT_DBG("%s", hdev->name);
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);
if (!hdev_is_powered(hdev)) {
BT_DBG("%s", hdev->name);
- if (len != sizeof(*mgmt_cp))
- return cmd_status(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);
if (!hci_discovery_active(hdev)) {
BT_DBG("%s", hdev->name);
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);
if (!hci_discovery_active(hdev)) {
BT_DBG("%s", hdev->name);
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);
err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
BT_DBG("%s", hdev->name);
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);
err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
BT_DBG("%s", hdev->name);
- if (len != sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
- MGMT_STATUS_INVALID_PARAMS);
-
if (!hdev_is_powered(hdev))
return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
MGMT_STATUS_NOT_POWERED);
u16 key_count, expected_len;
int i;
- if (len < sizeof(*cp))
- return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
- EINVAL);
-
key_count = get_unaligned_le16(&cp->key_count);
expected_len = sizeof(*cp) + key_count *
struct mgmt_handler {
int (*func) (struct sock *sk, struct hci_dev *hdev,
void *data, u16 data_len);
+ bool var_len;
+ size_t data_len;
} mgmt_handlers[] = {
{ NULL }, /* 0x0000 (no command) */
- { read_version, },
- { read_commands, },
- { read_index_list, },
- { read_controller_info, },
- { set_powered, },
- { set_discoverable, },
- { set_connectable, },
- { set_fast_connectable, },
- { set_pairable, },
- { set_link_security, },
- { set_ssp, },
- { set_hs, },
- { set_le, },
- { set_dev_class, },
- { set_local_name, },
- { add_uuid, },
- { remove_uuid, },
- { load_link_keys, },
- { load_long_term_keys, },
- { disconnect, },
- { get_connections, },
- { pin_code_reply, },
- { pin_code_neg_reply, },
- { set_io_capability, },
- { pair_device, },
- { cancel_pair_device, },
- { unpair_device, },
- { user_confirm_reply, },
- { user_confirm_neg_reply, },
- { user_passkey_reply, },
- { user_passkey_neg_reply, },
- { read_local_oob_data, },
- { add_remote_oob_data, },
- { remove_remote_oob_data, },
- { start_discovery, },
- { stop_discovery, },
- { confirm_name, },
- { block_device, },
- { unblock_device, },
+ { read_version, false, MGMT_READ_VERSION_SIZE },
+ { read_commands, false, MGMT_READ_COMMANDS_SIZE },
+ { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
+ { read_controller_info, false, MGMT_READ_INFO_SIZE },
+ { set_powered, false, MGMT_SETTING_SIZE },
+ { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
+ { set_connectable, false, MGMT_SETTING_SIZE },
+ { set_fast_connectable, false, MGMT_SETTING_SIZE },
+ { set_pairable, false, MGMT_SETTING_SIZE },
+ { set_link_security, false, MGMT_SETTING_SIZE },
+ { set_ssp, false, MGMT_SETTING_SIZE },
+ { set_hs, false, MGMT_SETTING_SIZE },
+ { set_le, false, MGMT_SETTING_SIZE },
+ { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
+ { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
+ { add_uuid, false, MGMT_ADD_UUID_SIZE },
+ { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
+ { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
+ { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
+ { disconnect, false, MGMT_DISCONNECT_SIZE },
+ { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
+ { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
+ { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
+ { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
+ { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
+ { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
+ { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
+ { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
+ { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
+ { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
+ { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
+ { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
+ { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
+ { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
+ { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
+ { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
+ { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
+ { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
+ { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
};
struct mgmt_hdr *hdr;
u16 opcode, index, len;
struct hci_dev *hdev = NULL;
+ struct mgmt_handler *handler;
int err;
BT_DBG("got %zu bytes", msglen);
goto done;
}
+ handler = &mgmt_handlers[opcode];
+
+ if ((handler->var_len && len < handler->data_len) ||
+ (!handler->var_len && len != handler->data_len)) {
+ err = cmd_status(sk, index, opcode,
+ MGMT_STATUS_INVALID_PARAMS);
+ goto done;
+ }
+
if (hdev)
mgmt_init_hdev(sk, hdev);
cp = buf + sizeof(*hdr);
- err = mgmt_handlers[opcode].func(sk, hdev, cp, len);
+ err = handler->func(sk, hdev, cp, len);
if (err < 0)
goto done;