diff options
author | Johan Hedberg <johan.hedberg@intel.com> | 2015-03-06 14:08:52 -0500 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2015-03-06 14:15:21 -0500 |
commit | b9a245fb12315f8c6528b29a991a004859c982d5 (patch) | |
tree | 8b4f636e8a1f9b9dd88b7b09b3e9c5dffec3f1ba /net/bluetooth | |
parent | 6d785aa345f525e1fdf098b7c590168f0b00f3f1 (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.c | 170 |
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 | ||
6133 | static const struct hci_mgmt_handler mgmt_handlers[] = { | 6133 | static 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 | ||
6195 | int mgmt_control(struct hci_mgmt_chan *chan, struct sock *sk, | 6208 | int 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; |