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 | |
| 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>
| -rw-r--r-- | include/net/bluetooth/hci_core.h | 6 | ||||
| -rw-r--r-- | net/bluetooth/mgmt.c | 170 |
2 files changed, 93 insertions, 83 deletions
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index b2a183d201b7..afc641c5e55c 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h | |||
| @@ -1273,11 +1273,15 @@ void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb); | |||
| 1273 | 1273 | ||
| 1274 | void hci_sock_dev_event(struct hci_dev *hdev, int event); | 1274 | void hci_sock_dev_event(struct hci_dev *hdev, int event); |
| 1275 | 1275 | ||
| 1276 | #define HCI_MGMT_VAR_LEN (1 << 0) | ||
| 1277 | #define HCI_MGMT_NO_HDEV (1 << 1) | ||
| 1278 | #define HCI_MGMT_UNCONFIGURED (1 << 2) | ||
| 1279 | |||
| 1276 | struct hci_mgmt_handler { | 1280 | struct hci_mgmt_handler { |
| 1277 | int (*func) (struct sock *sk, struct hci_dev *hdev, void *data, | 1281 | int (*func) (struct sock *sk, struct hci_dev *hdev, void *data, |
| 1278 | u16 data_len); | 1282 | u16 data_len); |
| 1279 | bool var_len; | ||
| 1280 | size_t data_len; | 1283 | size_t data_len; |
| 1284 | unsigned long flags; | ||
| 1281 | }; | 1285 | }; |
| 1282 | 1286 | ||
| 1283 | struct hci_mgmt_chan { | 1287 | struct hci_mgmt_chan { |
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 | |||
