summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaganath Kanakkassery <jaganath.k.os@gmail.com>2018-07-19 07:39:42 -0400
committerMarcel Holtmann <marcel@holtmann.org>2018-07-30 07:44:52 -0400
commita0fb3726ba55138ef6fdd5dc67da6d9a70360696 (patch)
tree85a4b590c2ef41b8eac7fcc48b88739cf1c285f8
parentde181e887ac27dadda127c7d4c3e89c6da8fb6d2 (diff)
Bluetooth: Use Set ext adv/scan rsp data if controller supports
This patch implements Set Ext Adv data and Set Ext Scan rsp data if controller support extended advertising. Currently the operation is set as Complete data and fragment preference is set as no fragment < HCI Command: LE Set Extended Advertising Data (0x08|0x0037) plen 35 Handle: 0x00 Operation: Complete extended advertising data (0x03) Fragment preference: Minimize fragmentation (0x01) Data length: 0x15 16-bit Service UUIDs (complete): 2 entries Heart Rate (0x180d) Battery Service (0x180f) Name (complete): Test LE Company: Google (224) Data: 0102 > HCI Event: Command Complete (0x0e) plen 4 LE Set Extended Advertising Data (0x08|0x0037) ncmd 1 Status: Success (0x00) Signed-off-by: Jaganath Kanakkassery <jaganathx.kanakkassery@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r--include/net/bluetooth/hci.h22
-rw-r--r--net/bluetooth/hci_event.c2
-rw-r--r--net/bluetooth/hci_request.c126
-rw-r--r--net/bluetooth/hci_request.h1
-rw-r--r--net/bluetooth/mgmt.c13
5 files changed, 130 insertions, 34 deletions
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index b447b127879e..aace97099ead 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -1625,6 +1625,28 @@ struct hci_cp_ext_adv_set {
1625 __u8 max_events; 1625 __u8 max_events;
1626} __packed; 1626} __packed;
1627 1627
1628#define HCI_OP_LE_SET_EXT_ADV_DATA 0x2037
1629struct hci_cp_le_set_ext_adv_data {
1630 __u8 handle;
1631 __u8 operation;
1632 __u8 frag_pref;
1633 __u8 length;
1634 __u8 data[HCI_MAX_AD_LENGTH];
1635} __packed;
1636
1637#define HCI_OP_LE_SET_EXT_SCAN_RSP_DATA 0x2038
1638struct hci_cp_le_set_ext_scan_rsp_data {
1639 __u8 handle;
1640 __u8 operation;
1641 __u8 frag_pref;
1642 __u8 length;
1643 __u8 data[HCI_MAX_AD_LENGTH];
1644} __packed;
1645
1646#define LE_SET_ADV_DATA_OP_COMPLETE 0x03
1647
1648#define LE_SET_ADV_DATA_NO_FRAG 0x01
1649
1628/* ---- HCI Events ---- */ 1650/* ---- HCI Events ---- */
1629#define HCI_EV_INQUIRY_COMPLETE 0x01 1651#define HCI_EV_INQUIRY_COMPLETE 0x01
1630 1652
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 0418a5514819..0a92bf7e3d80 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1547,6 +1547,8 @@ static void hci_cc_set_ext_adv_param(struct hci_dev *hdev, struct sk_buff *skb)
1547 if (adv_instance) 1547 if (adv_instance)
1548 adv_instance->tx_power = rp->tx_power; 1548 adv_instance->tx_power = rp->tx_power;
1549 } 1549 }
1550 /* Update adv data as tx power is known now */
1551 hci_req_update_adv_data(hdev, hdev->cur_adv_instance);
1550 hci_dev_unlock(hdev); 1552 hci_dev_unlock(hdev);
1551} 1553}
1552 1554
diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c
index 2ac9fd67440a..c41e9bb7818b 100644
--- a/net/bluetooth/hci_request.c
+++ b/net/bluetooth/hci_request.c
@@ -1174,29 +1174,58 @@ static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 instance,
1174void __hci_req_update_scan_rsp_data(struct hci_request *req, u8 instance) 1174void __hci_req_update_scan_rsp_data(struct hci_request *req, u8 instance)
1175{ 1175{
1176 struct hci_dev *hdev = req->hdev; 1176 struct hci_dev *hdev = req->hdev;
1177 struct hci_cp_le_set_scan_rsp_data cp;
1178 u8 len; 1177 u8 len;
1179 1178
1180 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED)) 1179 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
1181 return; 1180 return;
1182 1181
1183 memset(&cp, 0, sizeof(cp)); 1182 if (ext_adv_capable(hdev)) {
1183 struct hci_cp_le_set_ext_scan_rsp_data cp;
1184 1184
1185 if (instance) 1185 memset(&cp, 0, sizeof(cp));
1186 len = create_instance_scan_rsp_data(hdev, instance, cp.data);
1187 else
1188 len = create_default_scan_rsp_data(hdev, cp.data);
1189 1186
1190 if (hdev->scan_rsp_data_len == len && 1187 if (instance)
1191 !memcmp(cp.data, hdev->scan_rsp_data, len)) 1188 len = create_instance_scan_rsp_data(hdev, instance,
1192 return; 1189 cp.data);
1190 else
1191 len = create_default_scan_rsp_data(hdev, cp.data);
1192
1193 if (hdev->scan_rsp_data_len == len &&
1194 !memcmp(cp.data, hdev->scan_rsp_data, len))
1195 return;
1196
1197 memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data));
1198 hdev->scan_rsp_data_len = len;
1199
1200 cp.handle = 0;
1201 cp.length = len;
1202 cp.operation = LE_SET_ADV_DATA_OP_COMPLETE;
1203 cp.frag_pref = LE_SET_ADV_DATA_NO_FRAG;
1204
1205 hci_req_add(req, HCI_OP_LE_SET_EXT_SCAN_RSP_DATA, sizeof(cp),
1206 &cp);
1207 } else {
1208 struct hci_cp_le_set_scan_rsp_data cp;
1209
1210 memset(&cp, 0, sizeof(cp));
1211
1212 if (instance)
1213 len = create_instance_scan_rsp_data(hdev, instance,
1214 cp.data);
1215 else
1216 len = create_default_scan_rsp_data(hdev, cp.data);
1217
1218 if (hdev->scan_rsp_data_len == len &&
1219 !memcmp(cp.data, hdev->scan_rsp_data, len))
1220 return;
1193 1221
1194 memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data)); 1222 memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data));
1195 hdev->scan_rsp_data_len = len; 1223 hdev->scan_rsp_data_len = len;
1196 1224
1197 cp.length = len; 1225 cp.length = len;
1198 1226
1199 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp); 1227 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
1228 }
1200} 1229}
1201 1230
1202static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr) 1231static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
@@ -1282,27 +1311,51 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
1282void __hci_req_update_adv_data(struct hci_request *req, u8 instance) 1311void __hci_req_update_adv_data(struct hci_request *req, u8 instance)
1283{ 1312{
1284 struct hci_dev *hdev = req->hdev; 1313 struct hci_dev *hdev = req->hdev;
1285 struct hci_cp_le_set_adv_data cp;
1286 u8 len; 1314 u8 len;
1287 1315
1288 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED)) 1316 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
1289 return; 1317 return;
1290 1318
1291 memset(&cp, 0, sizeof(cp)); 1319 if (ext_adv_capable(hdev)) {
1320 struct hci_cp_le_set_ext_adv_data cp;
1292 1321
1293 len = create_instance_adv_data(hdev, instance, cp.data); 1322 memset(&cp, 0, sizeof(cp));
1294 1323
1295 /* There's nothing to do if the data hasn't changed */ 1324 len = create_instance_adv_data(hdev, instance, cp.data);
1296 if (hdev->adv_data_len == len && 1325
1297 memcmp(cp.data, hdev->adv_data, len) == 0) 1326 /* There's nothing to do if the data hasn't changed */
1298 return; 1327 if (hdev->adv_data_len == len &&
1328 memcmp(cp.data, hdev->adv_data, len) == 0)
1329 return;
1330
1331 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
1332 hdev->adv_data_len = len;
1333
1334 cp.length = len;
1335 cp.handle = 0;
1336 cp.operation = LE_SET_ADV_DATA_OP_COMPLETE;
1337 cp.frag_pref = LE_SET_ADV_DATA_NO_FRAG;
1299 1338
1300 memcpy(hdev->adv_data, cp.data, sizeof(cp.data)); 1339 hci_req_add(req, HCI_OP_LE_SET_EXT_ADV_DATA, sizeof(cp), &cp);
1301 hdev->adv_data_len = len; 1340 } else {
1341 struct hci_cp_le_set_adv_data cp;
1342
1343 memset(&cp, 0, sizeof(cp));
1302 1344
1303 cp.length = len; 1345 len = create_instance_adv_data(hdev, instance, cp.data);
1346
1347 /* There's nothing to do if the data hasn't changed */
1348 if (hdev->adv_data_len == len &&
1349 memcmp(cp.data, hdev->adv_data, len) == 0)
1350 return;
1304 1351
1305 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp); 1352 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
1353 hdev->adv_data_len = len;
1354
1355 cp.length = len;
1356
1357 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
1358 }
1306} 1359}
1307 1360
1308int hci_req_update_adv_data(struct hci_dev *hdev, u8 instance) 1361int hci_req_update_adv_data(struct hci_dev *hdev, u8 instance)
@@ -1377,8 +1430,7 @@ unlock:
1377 hci_dev_unlock(hdev); 1430 hci_dev_unlock(hdev);
1378} 1431}
1379 1432
1380static int __hci_req_setup_ext_adv_instance(struct hci_request *req, 1433int __hci_req_setup_ext_adv_instance(struct hci_request *req, u8 instance)
1381 u8 instance)
1382{ 1434{
1383 struct hci_cp_le_set_ext_adv_params cp; 1435 struct hci_cp_le_set_ext_adv_params cp;
1384 struct hci_dev *hdev = req->hdev; 1436 struct hci_dev *hdev = req->hdev;
@@ -1453,6 +1505,7 @@ int __hci_req_start_ext_adv(struct hci_request *req, u8 instance)
1453 if (err < 0) 1505 if (err < 0)
1454 return err; 1506 return err;
1455 1507
1508 __hci_req_update_scan_rsp_data(req, instance);
1456 __hci_req_enable_ext_advertising(req); 1509 __hci_req_enable_ext_advertising(req);
1457 1510
1458 return 0; 1511 return 0;
@@ -2500,14 +2553,25 @@ static int powered_update_hci(struct hci_request *req, unsigned long opt)
2500 */ 2553 */
2501 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) || 2554 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
2502 list_empty(&hdev->adv_instances)) { 2555 list_empty(&hdev->adv_instances)) {
2503 __hci_req_update_adv_data(req, 0x00); 2556 int err;
2504 __hci_req_update_scan_rsp_data(req, 0x00); 2557
2558 if (ext_adv_capable(hdev)) {
2559 err = __hci_req_setup_ext_adv_instance(req,
2560 0x00);
2561 if (!err)
2562 __hci_req_update_scan_rsp_data(req,
2563 0x00);
2564 } else {
2565 err = 0;
2566 __hci_req_update_adv_data(req, 0x00);
2567 __hci_req_update_scan_rsp_data(req, 0x00);
2568 }
2505 2569
2506 if (hci_dev_test_flag(hdev, HCI_ADVERTISING)) { 2570 if (hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
2507 if (ext_adv_capable(hdev)) 2571 if (!ext_adv_capable(hdev))
2508 __hci_req_start_ext_adv(req, 0x00);
2509 else
2510 __hci_req_enable_advertising(req); 2572 __hci_req_enable_advertising(req);
2573 else if (!err)
2574 __hci_req_enable_ext_advertising(req);
2511 } 2575 }
2512 } else if (!list_empty(&hdev->adv_instances)) { 2576 } else if (!list_empty(&hdev->adv_instances)) {
2513 struct adv_info *adv_instance; 2577 struct adv_info *adv_instance;
diff --git a/net/bluetooth/hci_request.h b/net/bluetooth/hci_request.h
index 9b8c74df6b2b..6afc624605af 100644
--- a/net/bluetooth/hci_request.h
+++ b/net/bluetooth/hci_request.h
@@ -80,6 +80,7 @@ void hci_req_clear_adv_instance(struct hci_dev *hdev, struct sock *sk,
80 struct hci_request *req, u8 instance, 80 struct hci_request *req, u8 instance,
81 bool force); 81 bool force);
82 82
83int __hci_req_setup_ext_adv_instance(struct hci_request *req, u8 instance);
83int __hci_req_start_ext_adv(struct hci_request *req, u8 instance); 84int __hci_req_start_ext_adv(struct hci_request *req, u8 instance);
84void __hci_req_enable_ext_advertising(struct hci_request *req); 85void __hci_req_enable_ext_advertising(struct hci_request *req);
85 86
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 761a9aeaa824..142f7e72a9a2 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1847,10 +1847,17 @@ static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
1847 */ 1847 */
1848 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) { 1848 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
1849 struct hci_request req; 1849 struct hci_request req;
1850
1851 hci_req_init(&req, hdev); 1850 hci_req_init(&req, hdev);
1852 __hci_req_update_adv_data(&req, 0x00); 1851 if (ext_adv_capable(hdev)) {
1853 __hci_req_update_scan_rsp_data(&req, 0x00); 1852 int err;
1853
1854 err = __hci_req_setup_ext_adv_instance(&req, 0x00);
1855 if (!err)
1856 __hci_req_update_scan_rsp_data(&req, 0x00);
1857 } else {
1858 __hci_req_update_adv_data(&req, 0x00);
1859 __hci_req_update_scan_rsp_data(&req, 0x00);
1860 }
1854 hci_req_run(&req, NULL); 1861 hci_req_run(&req, NULL);
1855 hci_update_background_scan(hdev); 1862 hci_update_background_scan(hdev);
1856 } 1863 }