aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/mgmt.c
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2014-07-04 12:11:55 -0400
committerJohan Hedberg <johan.hedberg@intel.com>2014-07-04 14:10:30 -0400
commitdbece37a3233933ec89f77f04049e13ad9b29634 (patch)
tree911e51a4adacd04e71ad34d881efed01f3e3c9aa /net/bluetooth/mgmt.c
parent0ad184ef5828542e3e73cce8a875fb4e029725b7 (diff)
Bluetooth: Add support for Set External Configuration management command
The Set External Configuration management command allows for switching between configured and unconfigured start if HCI_QURIK_EXTERNAL_CONFIG is set by the transport driver. 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.c77
1 files changed, 75 insertions, 2 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index d2d0e051e4f2..91bccef63f30 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -91,6 +91,7 @@ static const u16 mgmt_commands[] = {
91 MGMT_OP_LOAD_CONN_PARAM, 91 MGMT_OP_LOAD_CONN_PARAM,
92 MGMT_OP_READ_UNCONF_INDEX_LIST, 92 MGMT_OP_READ_UNCONF_INDEX_LIST,
93 MGMT_OP_READ_CONFIG_INFO, 93 MGMT_OP_READ_CONFIG_INFO,
94 MGMT_OP_SET_EXTERNAL_CONFIG,
94}; 95};
95 96
96static const u16 mgmt_events[] = { 97static const u16 mgmt_events[] = {
@@ -441,11 +442,25 @@ static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
441 return err; 442 return err;
442} 443}
443 444
445static bool is_configured(struct hci_dev *hdev)
446{
447 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
448 !test_bit(HCI_EXT_CONFIGURED, &hdev->dev_flags))
449 return false;
450
451 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
452 !bacmp(&hdev->public_addr, BDADDR_ANY))
453 return false;
454
455 return true;
456}
457
444static __le32 get_missing_options(struct hci_dev *hdev) 458static __le32 get_missing_options(struct hci_dev *hdev)
445{ 459{
446 u32 options = 0; 460 u32 options = 0;
447 461
448 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks)) 462 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
463 !test_bit(HCI_EXT_CONFIGURED, &hdev->dev_flags))
449 options |= MGMT_OPTION_EXTERNAL_CONFIG; 464 options |= MGMT_OPTION_EXTERNAL_CONFIG;
450 465
451 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) && 466 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
@@ -455,6 +470,14 @@ static __le32 get_missing_options(struct hci_dev *hdev)
455 return cpu_to_le32(options); 470 return cpu_to_le32(options);
456} 471}
457 472
473static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
474{
475 __le32 options = get_missing_options(hdev);
476
477 return cmd_complete(sk, hdev->id, opcode, 0, &options,
478 sizeof(options));
479}
480
458static int read_config_info(struct sock *sk, struct hci_dev *hdev, 481static int read_config_info(struct sock *sk, struct hci_dev *hdev,
459 void *data, u16 data_len) 482 void *data, u16 data_len)
460{ 483{
@@ -5355,6 +5378,54 @@ static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
5355 return cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0, NULL, 0); 5378 return cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0, NULL, 0);
5356} 5379}
5357 5380
5381static int set_external_config(struct sock *sk, struct hci_dev *hdev,
5382 void *data, u16 len)
5383{
5384 struct mgmt_cp_set_external_config *cp = data;
5385 bool changed;
5386 int err;
5387
5388 BT_DBG("%s", hdev->name);
5389
5390 if (hdev_is_powered(hdev))
5391 return cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5392 MGMT_STATUS_REJECTED);
5393
5394 if (cp->config != 0x00 && cp->config != 0x01)
5395 return cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5396 MGMT_STATUS_INVALID_PARAMS);
5397
5398 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
5399 return cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
5400 MGMT_STATUS_NOT_SUPPORTED);
5401
5402 hci_dev_lock(hdev);
5403
5404 if (cp->config)
5405 changed = !test_and_set_bit(HCI_EXT_CONFIGURED,
5406 &hdev->dev_flags);
5407 else
5408 changed = test_and_clear_bit(HCI_EXT_CONFIGURED,
5409 &hdev->dev_flags);
5410
5411 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
5412 if (err < 0)
5413 goto unlock;
5414
5415 if (!changed)
5416 goto unlock;
5417
5418 if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) == is_configured(hdev)) {
5419 mgmt_index_removed(hdev);
5420 change_bit(HCI_UNCONFIGURED, &hdev->dev_flags);
5421 mgmt_index_added(hdev);
5422 }
5423
5424unlock:
5425 hci_dev_unlock(hdev);
5426 return err;
5427}
5428
5358static const struct mgmt_handler { 5429static const struct mgmt_handler {
5359 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data, 5430 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
5360 u16 data_len); 5431 u16 data_len);
@@ -5417,6 +5488,7 @@ static const struct mgmt_handler {
5417 { load_conn_param, true, MGMT_LOAD_CONN_PARAM_SIZE }, 5488 { load_conn_param, true, MGMT_LOAD_CONN_PARAM_SIZE },
5418 { read_unconf_index_list, false, MGMT_READ_UNCONF_INDEX_LIST_SIZE }, 5489 { read_unconf_index_list, false, MGMT_READ_UNCONF_INDEX_LIST_SIZE },
5419 { read_config_info, false, MGMT_READ_CONFIG_INFO_SIZE }, 5490 { read_config_info, false, MGMT_READ_CONFIG_INFO_SIZE },
5491 { set_external_config, false, MGMT_SET_EXTERNAL_CONFIG_SIZE },
5420}; 5492};
5421 5493
5422int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) 5494int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
@@ -5469,7 +5541,8 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
5469 } 5541 }
5470 5542
5471 if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) && 5543 if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) &&
5472 opcode != MGMT_OP_READ_CONFIG_INFO) { 5544 opcode != MGMT_OP_READ_CONFIG_INFO &&
5545 opcode != MGMT_OP_SET_EXTERNAL_CONFIG) {
5473 err = cmd_status(sk, index, opcode, 5546 err = cmd_status(sk, index, opcode,
5474 MGMT_STATUS_INVALID_INDEX); 5547 MGMT_STATUS_INVALID_INDEX);
5475 goto done; 5548 goto done;