diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2014-07-02 16:10:52 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2014-07-03 11:42:58 -0400 |
commit | 73d1df2a7a1036a1f000e5f0ece6ade3e082b854 (patch) | |
tree | 6f810f637d3ea3d97b2ee20fcedf66e2d6570fbb /net/bluetooth/mgmt.c | |
parent | edd3896bc41059fc064c4ec76da004a57203d88e (diff) |
Bluetooth: Add support for Read Unconfigured Index List command
This command allows to get the list of currently known controller that
are in unconfigured state.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Diffstat (limited to 'net/bluetooth/mgmt.c')
-rw-r--r-- | net/bluetooth/mgmt.c | 91 |
1 files changed, 81 insertions, 10 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 1a78d26b0049..325bb8136d2c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -89,6 +89,7 @@ static const u16 mgmt_commands[] = { | |||
89 | MGMT_OP_ADD_DEVICE, | 89 | MGMT_OP_ADD_DEVICE, |
90 | MGMT_OP_REMOVE_DEVICE, | 90 | MGMT_OP_REMOVE_DEVICE, |
91 | MGMT_OP_LOAD_CONN_PARAM, | 91 | MGMT_OP_LOAD_CONN_PARAM, |
92 | MGMT_OP_READ_UNCONF_INDEX_LIST, | ||
92 | }; | 93 | }; |
93 | 94 | ||
94 | static const u16 mgmt_events[] = { | 95 | static const u16 mgmt_events[] = { |
@@ -336,7 +337,8 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data, | |||
336 | 337 | ||
337 | count = 0; | 338 | count = 0; |
338 | list_for_each_entry(d, &hci_dev_list, list) { | 339 | list_for_each_entry(d, &hci_dev_list, list) { |
339 | if (d->dev_type == HCI_BREDR) | 340 | if (d->dev_type == HCI_BREDR && |
341 | !test_bit(HCI_UNCONFIGURED, &d->dev_flags)) | ||
340 | count++; | 342 | count++; |
341 | } | 343 | } |
342 | 344 | ||
@@ -349,16 +351,18 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data, | |||
349 | 351 | ||
350 | count = 0; | 352 | count = 0; |
351 | list_for_each_entry(d, &hci_dev_list, list) { | 353 | list_for_each_entry(d, &hci_dev_list, list) { |
352 | if (test_bit(HCI_SETUP, &d->dev_flags)) | 354 | if (test_bit(HCI_SETUP, &d->dev_flags) || |
355 | test_bit(HCI_USER_CHANNEL, &d->dev_flags)) | ||
353 | continue; | 356 | continue; |
354 | 357 | ||
355 | if (test_bit(HCI_USER_CHANNEL, &d->dev_flags)) | 358 | /* Devices marked as raw-only are neither configured |
356 | continue; | 359 | * nor unconfigured controllers. |
357 | 360 | */ | |
358 | if (test_bit(HCI_UNCONFIGURED, &d->dev_flags)) | 361 | if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks)) |
359 | continue; | 362 | continue; |
360 | 363 | ||
361 | if (d->dev_type == HCI_BREDR) { | 364 | if (d->dev_type == HCI_BREDR && |
365 | !test_bit(HCI_UNCONFIGURED, &d->dev_flags)) { | ||
362 | rp->index[count++] = cpu_to_le16(d->id); | 366 | rp->index[count++] = cpu_to_le16(d->id); |
363 | BT_DBG("Added hci%u", d->id); | 367 | BT_DBG("Added hci%u", d->id); |
364 | } | 368 | } |
@@ -377,6 +381,65 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data, | |||
377 | return err; | 381 | return err; |
378 | } | 382 | } |
379 | 383 | ||
384 | static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev, | ||
385 | void *data, u16 data_len) | ||
386 | { | ||
387 | struct mgmt_rp_read_unconf_index_list *rp; | ||
388 | struct hci_dev *d; | ||
389 | size_t rp_len; | ||
390 | u16 count; | ||
391 | int err; | ||
392 | |||
393 | BT_DBG("sock %p", sk); | ||
394 | |||
395 | read_lock(&hci_dev_list_lock); | ||
396 | |||
397 | count = 0; | ||
398 | list_for_each_entry(d, &hci_dev_list, list) { | ||
399 | if (d->dev_type == HCI_BREDR && | ||
400 | test_bit(HCI_UNCONFIGURED, &d->dev_flags)) | ||
401 | count++; | ||
402 | } | ||
403 | |||
404 | rp_len = sizeof(*rp) + (2 * count); | ||
405 | rp = kmalloc(rp_len, GFP_ATOMIC); | ||
406 | if (!rp) { | ||
407 | read_unlock(&hci_dev_list_lock); | ||
408 | return -ENOMEM; | ||
409 | } | ||
410 | |||
411 | count = 0; | ||
412 | list_for_each_entry(d, &hci_dev_list, list) { | ||
413 | if (test_bit(HCI_SETUP, &d->dev_flags) || | ||
414 | test_bit(HCI_USER_CHANNEL, &d->dev_flags)) | ||
415 | continue; | ||
416 | |||
417 | /* Devices marked as raw-only are neither configured | ||
418 | * nor unconfigured controllers. | ||
419 | */ | ||
420 | if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks)) | ||
421 | continue; | ||
422 | |||
423 | if (d->dev_type == HCI_BREDR && | ||
424 | test_bit(HCI_UNCONFIGURED, &d->dev_flags)) { | ||
425 | rp->index[count++] = cpu_to_le16(d->id); | ||
426 | BT_DBG("Added hci%u", d->id); | ||
427 | } | ||
428 | } | ||
429 | |||
430 | rp->num_controllers = cpu_to_le16(count); | ||
431 | rp_len = sizeof(*rp) + (2 * count); | ||
432 | |||
433 | read_unlock(&hci_dev_list_lock); | ||
434 | |||
435 | err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_UNCONF_INDEX_LIST, | ||
436 | 0, rp, rp_len); | ||
437 | |||
438 | kfree(rp); | ||
439 | |||
440 | return err; | ||
441 | } | ||
442 | |||
380 | static u32 get_supported_settings(struct hci_dev *hdev) | 443 | static u32 get_supported_settings(struct hci_dev *hdev) |
381 | { | 444 | { |
382 | u32 settings = 0; | 445 | u32 settings = 0; |
@@ -5273,7 +5336,8 @@ static const struct mgmt_handler { | |||
5273 | { get_clock_info, false, MGMT_GET_CLOCK_INFO_SIZE }, | 5336 | { get_clock_info, false, MGMT_GET_CLOCK_INFO_SIZE }, |
5274 | { add_device, false, MGMT_ADD_DEVICE_SIZE }, | 5337 | { add_device, false, MGMT_ADD_DEVICE_SIZE }, |
5275 | { remove_device, false, MGMT_REMOVE_DEVICE_SIZE }, | 5338 | { remove_device, false, MGMT_REMOVE_DEVICE_SIZE }, |
5276 | { load_conn_param, true, MGMT_LOAD_CONN_PARAM_SIZE }, | 5339 | { load_conn_param, true, MGMT_LOAD_CONN_PARAM_SIZE }, |
5340 | { read_unconf_index_list, false, MGMT_READ_UNCONF_INDEX_LIST_SIZE }, | ||
5277 | }; | 5341 | }; |
5278 | 5342 | ||
5279 | int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | 5343 | int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) |
@@ -5335,8 +5399,15 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | |||
5335 | goto done; | 5399 | goto done; |
5336 | } | 5400 | } |
5337 | 5401 | ||
5338 | if ((hdev && opcode < MGMT_OP_READ_INFO) || | 5402 | if (hdev && (opcode <= MGMT_OP_READ_INDEX_LIST || |
5339 | (!hdev && opcode >= MGMT_OP_READ_INFO)) { | 5403 | opcode == MGMT_OP_READ_UNCONF_INDEX_LIST)) { |
5404 | err = cmd_status(sk, index, opcode, | ||
5405 | MGMT_STATUS_INVALID_INDEX); | ||
5406 | goto done; | ||
5407 | } | ||
5408 | |||
5409 | if (!hdev && (opcode > MGMT_OP_READ_INDEX_LIST && | ||
5410 | opcode != MGMT_OP_READ_UNCONF_INDEX_LIST)) { | ||
5340 | err = cmd_status(sk, index, opcode, | 5411 | err = cmd_status(sk, index, opcode, |
5341 | MGMT_STATUS_INVALID_INDEX); | 5412 | MGMT_STATUS_INVALID_INDEX); |
5342 | goto done; | 5413 | goto done; |