aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArman Uguray <armansito@chromium.org>2015-03-23 18:57:14 -0400
committerMarcel Holtmann <marcel@holtmann.org>2015-03-23 20:53:47 -0400
commit4117ed70a55128273f1b6d00c7725e4c8a5c0031 (patch)
tree93cd4ed4655711e1a626d85b65a5949ae8638deb
parentda929335f27d955172539bf56bed1ac9ff9b8d45 (diff)
Bluetooth: Add support for instance scan response
This patch implements setting the Scan Response data provided as part of an advertising instance through the Add Advertising command. Signed-off-by: Arman Uguray <armansito@chromium.org> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r--net/bluetooth/mgmt.c66
1 files changed, 52 insertions, 14 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 5e5a738ea95c..762ca9be9806 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -793,7 +793,7 @@ static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
793 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data); 793 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
794} 794}
795 795
796static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr) 796static u8 create_default_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
797{ 797{
798 u8 ad_len = 0; 798 u8 ad_len = 0;
799 size_t name_len; 799 size_t name_len;
@@ -819,7 +819,19 @@ static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
819 return ad_len; 819 return ad_len;
820} 820}
821 821
822static void update_scan_rsp_data(struct hci_request *req) 822static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
823{
824 /* TODO: Set the appropriate entries based on advertising instance flags
825 * here once flags other than 0 are supported.
826 */
827 memcpy(ptr, hdev->adv_instance.scan_rsp_data,
828 hdev->adv_instance.scan_rsp_len);
829
830 return hdev->adv_instance.scan_rsp_len;
831}
832
833static void update_scan_rsp_data_for_instance(struct hci_request *req,
834 u8 instance)
823{ 835{
824 struct hci_dev *hdev = req->hdev; 836 struct hci_dev *hdev = req->hdev;
825 struct hci_cp_le_set_scan_rsp_data cp; 837 struct hci_cp_le_set_scan_rsp_data cp;
@@ -830,10 +842,13 @@ static void update_scan_rsp_data(struct hci_request *req)
830 842
831 memset(&cp, 0, sizeof(cp)); 843 memset(&cp, 0, sizeof(cp));
832 844
833 len = create_scan_rsp_data(hdev, cp.data); 845 if (instance)
846 len = create_instance_scan_rsp_data(hdev, cp.data);
847 else
848 len = create_default_scan_rsp_data(hdev, cp.data);
834 849
835 if (hdev->scan_rsp_data_len == len && 850 if (hdev->scan_rsp_data_len == len &&
836 memcmp(cp.data, hdev->scan_rsp_data, len) == 0) 851 !memcmp(cp.data, hdev->scan_rsp_data, len))
837 return; 852 return;
838 853
839 memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data)); 854 memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data));
@@ -844,6 +859,25 @@ static void update_scan_rsp_data(struct hci_request *req)
844 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp); 859 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
845} 860}
846 861
862static void update_scan_rsp_data(struct hci_request *req)
863{
864 struct hci_dev *hdev = req->hdev;
865 u8 instance;
866
867 /* The "Set Advertising" setting supersedes the "Add Advertising"
868 * setting. Here we set the scan response data based on which
869 * setting was set. When neither apply, default to the global settings,
870 * represented by instance "0".
871 */
872 if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
873 !hci_dev_test_flag(hdev, HCI_ADVERTISING))
874 instance = 0x01;
875 else
876 instance = 0x00;
877
878 update_scan_rsp_data_for_instance(req, instance);
879}
880
847static u8 get_adv_discov_flags(struct hci_dev *hdev) 881static u8 get_adv_discov_flags(struct hci_dev *hdev)
848{ 882{
849 struct mgmt_pending_cmd *cmd; 883 struct mgmt_pending_cmd *cmd;
@@ -4547,6 +4581,7 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
4547 if (val) { 4581 if (val) {
4548 /* Switch to instance "0" for the Set Advertising setting. */ 4582 /* Switch to instance "0" for the Set Advertising setting. */
4549 update_adv_data_for_instance(&req, 0); 4583 update_adv_data_for_instance(&req, 0);
4584 update_scan_rsp_data_for_instance(&req, 0);
4550 enable_advertising(&req); 4585 enable_advertising(&req);
4551 } else { 4586 } else {
4552 disable_advertising(&req); 4587 disable_advertising(&req);
@@ -6408,25 +6443,25 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
6408 return err; 6443 return err;
6409} 6444}
6410 6445
6411static bool adv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *adv_data, 6446static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
6412 u8 adv_data_len) 6447 u8 len)
6413{ 6448{
6414 u8 max_adv_len = HCI_MAX_AD_LENGTH; 6449 u8 max_len = HCI_MAX_AD_LENGTH;
6415 int i, cur_len; 6450 int i, cur_len;
6416 6451
6417 /* TODO: Correctly reduce adv_len based on adv_flags. */ 6452 /* TODO: Correctly reduce len based on adv_flags. */
6418 6453
6419 if (adv_data_len > max_adv_len) 6454 if (len > max_len)
6420 return false; 6455 return false;
6421 6456
6422 /* Make sure that adv_data is correctly formatted. */ 6457 /* Make sure that the data is correctly formatted. */
6423 for (i = 0, cur_len = 0; i < adv_data_len; i += (cur_len + 1)) { 6458 for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
6424 cur_len = adv_data[i]; 6459 cur_len = data[i];
6425 6460
6426 /* If the current field length would exceed the total data 6461 /* If the current field length would exceed the total data
6427 * length, then it's invalid. 6462 * length, then it's invalid.
6428 */ 6463 */
6429 if (i + cur_len >= adv_data_len) 6464 if (i + cur_len >= len)
6430 return false; 6465 return false;
6431 } 6466 }
6432 6467
@@ -6526,7 +6561,9 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
6526 goto unlock; 6561 goto unlock;
6527 } 6562 }
6528 6563
6529 if (!adv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len)) { 6564 if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len) ||
6565 !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len,
6566 cp->scan_rsp_len)) {
6530 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING, 6567 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6531 MGMT_STATUS_INVALID_PARAMS); 6568 MGMT_STATUS_INVALID_PARAMS);
6532 goto unlock; 6569 goto unlock;
@@ -6570,6 +6607,7 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
6570 hci_req_init(&req, hdev); 6607 hci_req_init(&req, hdev);
6571 6608
6572 update_adv_data(&req); 6609 update_adv_data(&req);
6610 update_scan_rsp_data(&req);
6573 enable_advertising(&req); 6611 enable_advertising(&req);
6574 6612
6575 err = hci_req_run(&req, add_advertising_complete); 6613 err = hci_req_run(&req, add_advertising_complete);