aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2015-03-06 14:08:52 -0500
committerMarcel Holtmann <marcel@holtmann.org>2015-03-06 14:15:21 -0500
commitb9a245fb12315f8c6528b29a991a004859c982d5 (patch)
tree8b4f636e8a1f9b9dd88b7b09b3e9c5dffec3f1ba /net/bluetooth
parent6d785aa345f525e1fdf098b7c590168f0b00f3f1 (diff)
Bluetooth: Move all mgmt command quirks to handler table
In order to completely generalize the mgmt command handling we need to move away command-specific information from mgmt_control() into the actual command table. This patch adds a new 'flags' field to the handler entries which can now contain the following command specific information: - Command takes variable length parameters - Command doesn't target any specific HCI device - Command can be sent when the HCI device is unconfigured After this the mgmt_control() function is completely generic and can potentially be reused by new HCI channels. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/mgmt.c170
1 files changed, 88 insertions, 82 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index bb02dd1b82bf..f65516420a31 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -6132,64 +6132,77 @@ unlock:
6132 6132
6133static const struct hci_mgmt_handler mgmt_handlers[] = { 6133static const struct hci_mgmt_handler mgmt_handlers[] = {
6134 { NULL }, /* 0x0000 (no command) */ 6134 { NULL }, /* 0x0000 (no command) */
6135 { read_version, false, MGMT_READ_VERSION_SIZE }, 6135 { read_version, MGMT_READ_VERSION_SIZE,
6136 { read_commands, false, MGMT_READ_COMMANDS_SIZE }, 6136 HCI_MGMT_NO_HDEV },
6137 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE }, 6137 { read_commands, MGMT_READ_COMMANDS_SIZE,
6138 { read_controller_info, false, MGMT_READ_INFO_SIZE }, 6138 HCI_MGMT_NO_HDEV },
6139 { set_powered, false, MGMT_SETTING_SIZE }, 6139 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
6140 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE }, 6140 HCI_MGMT_NO_HDEV },
6141 { set_connectable, false, MGMT_SETTING_SIZE }, 6141 { read_controller_info, MGMT_READ_INFO_SIZE, 0 },
6142 { set_fast_connectable, false, MGMT_SETTING_SIZE }, 6142 { set_powered, MGMT_SETTING_SIZE, 0 },
6143 { set_bondable, false, MGMT_SETTING_SIZE }, 6143 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE, 0 },
6144 { set_link_security, false, MGMT_SETTING_SIZE }, 6144 { set_connectable, MGMT_SETTING_SIZE, 0 },
6145 { set_ssp, false, MGMT_SETTING_SIZE }, 6145 { set_fast_connectable, MGMT_SETTING_SIZE, 0 },
6146 { set_hs, false, MGMT_SETTING_SIZE }, 6146 { set_bondable, MGMT_SETTING_SIZE, 0 },
6147 { set_le, false, MGMT_SETTING_SIZE }, 6147 { set_link_security, MGMT_SETTING_SIZE, 0 },
6148 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE }, 6148 { set_ssp, MGMT_SETTING_SIZE, 0 },
6149 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE }, 6149 { set_hs, MGMT_SETTING_SIZE, 0 },
6150 { add_uuid, false, MGMT_ADD_UUID_SIZE }, 6150 { set_le, MGMT_SETTING_SIZE, 0 },
6151 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE }, 6151 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE, 0 },
6152 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE }, 6152 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE, 0 },
6153 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE }, 6153 { add_uuid, MGMT_ADD_UUID_SIZE, 0 },
6154 { disconnect, false, MGMT_DISCONNECT_SIZE }, 6154 { remove_uuid, MGMT_REMOVE_UUID_SIZE, 0 },
6155 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE }, 6155 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
6156 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE }, 6156 HCI_MGMT_VAR_LEN },
6157 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE }, 6157 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
6158 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE }, 6158 HCI_MGMT_VAR_LEN },
6159 { pair_device, false, MGMT_PAIR_DEVICE_SIZE }, 6159 { disconnect, MGMT_DISCONNECT_SIZE, 0 },
6160 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE }, 6160 { get_connections, MGMT_GET_CONNECTIONS_SIZE, 0 },
6161 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE }, 6161 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE, 0 },
6162 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE }, 6162 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE, 0 },
6163 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE }, 6163 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE, 0 },
6164 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE }, 6164 { pair_device, MGMT_PAIR_DEVICE_SIZE, 0 },
6165 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE }, 6165 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE, 0 },
6166 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE }, 6166 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE, 0 },
6167 { add_remote_oob_data, true, MGMT_ADD_REMOTE_OOB_DATA_SIZE }, 6167 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE, 0 },
6168 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE }, 6168 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE, 0 },
6169 { start_discovery, false, MGMT_START_DISCOVERY_SIZE }, 6169 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE, 0 },
6170 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE }, 6170 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE, 0 },
6171 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE }, 6171 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
6172 { block_device, false, MGMT_BLOCK_DEVICE_SIZE }, 6172 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
6173 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE }, 6173 HCI_MGMT_VAR_LEN },
6174 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE }, 6174 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE, 0 },
6175 { set_advertising, false, MGMT_SETTING_SIZE }, 6175 { start_discovery, MGMT_START_DISCOVERY_SIZE, 0 },
6176 { set_bredr, false, MGMT_SETTING_SIZE }, 6176 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE, 0 },
6177 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE }, 6177 { confirm_name, MGMT_CONFIRM_NAME_SIZE, 0 },
6178 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE }, 6178 { block_device, MGMT_BLOCK_DEVICE_SIZE, 0 },
6179 { set_secure_conn, false, MGMT_SETTING_SIZE }, 6179 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE, 0 },
6180 { set_debug_keys, false, MGMT_SETTING_SIZE }, 6180 { set_device_id, MGMT_SET_DEVICE_ID_SIZE, 0 },
6181 { set_privacy, false, MGMT_SET_PRIVACY_SIZE }, 6181 { set_advertising, MGMT_SETTING_SIZE, 0 },
6182 { load_irks, true, MGMT_LOAD_IRKS_SIZE }, 6182 { set_bredr, MGMT_SETTING_SIZE, 0 },
6183 { get_conn_info, false, MGMT_GET_CONN_INFO_SIZE }, 6183 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE, 0 },
6184 { get_clock_info, false, MGMT_GET_CLOCK_INFO_SIZE }, 6184 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE, 0 },
6185 { add_device, false, MGMT_ADD_DEVICE_SIZE }, 6185 { set_secure_conn, MGMT_SETTING_SIZE, 0 },
6186 { remove_device, false, MGMT_REMOVE_DEVICE_SIZE }, 6186 { set_debug_keys, MGMT_SETTING_SIZE, 0 },
6187 { load_conn_param, true, MGMT_LOAD_CONN_PARAM_SIZE }, 6187 { set_privacy, MGMT_SET_PRIVACY_SIZE, 0 },
6188 { read_unconf_index_list, false, MGMT_READ_UNCONF_INDEX_LIST_SIZE }, 6188 { load_irks, MGMT_LOAD_IRKS_SIZE,
6189 { read_config_info, false, MGMT_READ_CONFIG_INFO_SIZE }, 6189 HCI_MGMT_VAR_LEN },
6190 { set_external_config, false, MGMT_SET_EXTERNAL_CONFIG_SIZE }, 6190 { get_conn_info, MGMT_GET_CONN_INFO_SIZE, 0 },
6191 { set_public_address, false, MGMT_SET_PUBLIC_ADDRESS_SIZE }, 6191 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE, 0 },
6192 { start_service_discovery,true, MGMT_START_SERVICE_DISCOVERY_SIZE }, 6192 { add_device, MGMT_ADD_DEVICE_SIZE, 0 },
6193 { remove_device, MGMT_REMOVE_DEVICE_SIZE, 0 },
6194 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
6195 HCI_MGMT_VAR_LEN },
6196 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
6197 HCI_MGMT_NO_HDEV },
6198 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
6199 HCI_MGMT_UNCONFIGURED },
6200 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
6201 HCI_MGMT_UNCONFIGURED },
6202 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
6203 HCI_MGMT_UNCONFIGURED },
6204 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
6205 HCI_MGMT_VAR_LEN },
6193}; 6206};
6194 6207
6195int mgmt_control(struct hci_mgmt_chan *chan, struct sock *sk, 6208int mgmt_control(struct hci_mgmt_chan *chan, struct sock *sk,
@@ -6201,6 +6214,7 @@ int mgmt_control(struct hci_mgmt_chan *chan, struct sock *sk,
6201 u16 opcode, index, len; 6214 u16 opcode, index, len;
6202 struct hci_dev *hdev = NULL; 6215 struct hci_dev *hdev = NULL;
6203 const struct hci_mgmt_handler *handler; 6216 const struct hci_mgmt_handler *handler;
6217 bool var_len, no_hdev;
6204 int err; 6218 int err;
6205 6219
6206 BT_DBG("got %zu bytes", msglen); 6220 BT_DBG("got %zu bytes", msglen);
@@ -6227,6 +6241,16 @@ int mgmt_control(struct hci_mgmt_chan *chan, struct sock *sk,
6227 goto done; 6241 goto done;
6228 } 6242 }
6229 6243
6244 if (opcode >= chan->handler_count ||
6245 chan->handlers[opcode].func == NULL) {
6246 BT_DBG("Unknown op %u", opcode);
6247 err = cmd_status(sk, index, opcode,
6248 MGMT_STATUS_UNKNOWN_COMMAND);
6249 goto done;
6250 }
6251
6252 handler = &chan->handlers[opcode];
6253
6230 if (index != MGMT_INDEX_NONE) { 6254 if (index != MGMT_INDEX_NONE) {
6231 hdev = hci_dev_get(index); 6255 hdev = hci_dev_get(index);
6232 if (!hdev) { 6256 if (!hdev) {
@@ -6244,41 +6268,23 @@ int mgmt_control(struct hci_mgmt_chan *chan, struct sock *sk,
6244 } 6268 }
6245 6269
6246 if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) && 6270 if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) &&
6247 opcode != MGMT_OP_READ_CONFIG_INFO && 6271 !(handler->flags & HCI_MGMT_UNCONFIGURED)) {
6248 opcode != MGMT_OP_SET_EXTERNAL_CONFIG &&
6249 opcode != MGMT_OP_SET_PUBLIC_ADDRESS) {
6250 err = cmd_status(sk, index, opcode, 6272 err = cmd_status(sk, index, opcode,
6251 MGMT_STATUS_INVALID_INDEX); 6273 MGMT_STATUS_INVALID_INDEX);
6252 goto done; 6274 goto done;
6253 } 6275 }
6254 } 6276 }
6255 6277
6256 if (opcode >= chan->handler_count || 6278 no_hdev = (handler->flags & HCI_MGMT_NO_HDEV);
6257 chan->handlers[opcode].func == NULL) { 6279 if (no_hdev != !hdev) {
6258 BT_DBG("Unknown op %u", opcode);
6259 err = cmd_status(sk, index, opcode,
6260 MGMT_STATUS_UNKNOWN_COMMAND);
6261 goto done;
6262 }
6263
6264 if (hdev && (opcode <= MGMT_OP_READ_INDEX_LIST ||
6265 opcode == MGMT_OP_READ_UNCONF_INDEX_LIST)) {
6266 err = cmd_status(sk, index, opcode,
6267 MGMT_STATUS_INVALID_INDEX);
6268 goto done;
6269 }
6270
6271 if (!hdev && (opcode > MGMT_OP_READ_INDEX_LIST &&
6272 opcode != MGMT_OP_READ_UNCONF_INDEX_LIST)) {
6273 err = cmd_status(sk, index, opcode, 6280 err = cmd_status(sk, index, opcode,
6274 MGMT_STATUS_INVALID_INDEX); 6281 MGMT_STATUS_INVALID_INDEX);
6275 goto done; 6282 goto done;
6276 } 6283 }
6277 6284
6278 handler = &chan->handlers[opcode]; 6285 var_len = (handler->flags & HCI_MGMT_VAR_LEN);
6279 6286 if ((var_len && len < handler->data_len) ||
6280 if ((handler->var_len && len < handler->data_len) || 6287 (!var_len && len != handler->data_len)) {
6281 (!handler->var_len && len != handler->data_len)) {
6282 err = cmd_status(sk, index, opcode, 6288 err = cmd_status(sk, index, opcode,
6283 MGMT_STATUS_INVALID_PARAMS); 6289 MGMT_STATUS_INVALID_PARAMS);
6284 goto done; 6290 goto done;