summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSudha Bheemanna <b.sudha@samsung.com>2016-08-24 12:17:16 +0530
committerAmit Purwar <amit.purwar@samsung.com>2019-06-27 15:54:53 +0530
commitac160e08af6995e83e67918607110da992cc0b73 (patch)
treef0b058b627b78e3d15eef9357e1a7fe97118ec37
parent8e404467166ed065dfcc28b69a3ea769ba3149ec (diff)
downloadlinux-rpi3-ac160e08af6995e83e67918607110da992cc0b73.tar.gz
linux-rpi3-ac160e08af6995e83e67918607110da992cc0b73.tar.bz2
linux-rpi3-ac160e08af6995e83e67918607110da992cc0b73.zip
Bluetooth: Add Advertising Packet Configuration
This patch provides new MGMT commands to configure the advertising data and scan response data packets for LE peripheral devices. Change-Id: I914d13795f4fb58e5f2e1cadb55086f4bcbc82df Signed-off-by: Sudha Bheemanna <b.sudha@samsung.com> Signed-off-by: DoHyun Pyun <dh79.pyun@samsung.com> Signed-off-by: Amit Purwar <amit.purwar@samsung.com>
-rw-r--r--include/net/bluetooth/hci.h2
-rw-r--r--include/net/bluetooth/hci_core.h5
-rw-r--r--include/net/bluetooth/mgmt_tizen.h23
-rw-r--r--net/bluetooth/hci_core.c4
-rw-r--r--net/bluetooth/hci_request.c41
-rw-r--r--net/bluetooth/mgmt.c224
6 files changed, 297 insertions, 2 deletions
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 845d947dbae8..47a8194e018c 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -519,6 +519,8 @@ enum {
#define EIR_SSP_HASH_C192 0x0E /* Simple Pairing Hash C-192 */
#define EIR_SSP_RAND_R192 0x0F /* Simple Pairing Randomizer R-192 */
#define EIR_DEVICE_ID 0x10 /* device ID */
+#define EIR_SOLICIT_UUID16 0x14 /* 16-bit Solicitation UUID */
+#define EIR_MANUFACTURER_DATA 0XFF /* Manufacturer Specific Data*/
#define EIR_APPEARANCE 0x19 /* Device appearance */
#define EIR_LE_BDADDR 0x1B /* LE Bluetooth device address */
#define EIR_LE_ROLE 0x1C /* LE role */
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 3bdcf30a25cc..29522e667940 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -421,6 +421,11 @@ struct hci_dev {
struct led_trigger *power_led;
#endif
+#ifdef TIZEN_BT
+ __u8 adv_filter_policy;
+ __u8 adv_type;
+#endif
+
int (*open)(struct hci_dev *hdev);
int (*close)(struct hci_dev *hdev);
int (*flush)(struct hci_dev *hdev);
diff --git a/include/net/bluetooth/mgmt_tizen.h b/include/net/bluetooth/mgmt_tizen.h
index 6bad3c9e7f51..04bd25573e64 100644
--- a/include/net/bluetooth/mgmt_tizen.h
+++ b/include/net/bluetooth/mgmt_tizen.h
@@ -23,4 +23,27 @@
#define TIZEN_OP_CODE_BASE 0xff00
#define TIZEN_EV_BASE 0xff00
+#define MGMT_OP_SET_ADVERTISING_PARAMS (TIZEN_OP_CODE_BASE + 0x01)
+struct mgmt_cp_set_advertising_params {
+ __le16 interval_min;
+ __le16 interval_max;
+ __u8 filter_policy;
+ __u8 type;
+} __packed;
+#define MGMT_SET_ADVERTISING_PARAMS_SIZE 6
+
+#define MGMT_OP_SET_ADVERTISING_DATA (TIZEN_OP_CODE_BASE + 0x02)
+struct mgmt_cp_set_advertising_data {
+ __u8 data[HCI_MAX_AD_LENGTH];
+} __packed;
+#define MGMT_SET_ADVERTISING_DATA_SIZE HCI_MAX_AD_LENGTH
+#define MGMT_SET_ADV_MIN_APP_DATA_SIZE 1
+
+#define MGMT_OP_SET_SCAN_RSP_DATA (TIZEN_OP_CODE_BASE + 0x03)
+struct mgmt_cp_set_scan_rsp_data {
+ __u8 data[HCI_MAX_AD_LENGTH];
+} __packed;
+#define MGMT_SET_SCAN_RSP_DATA_SIZE HCI_MAX_AD_LENGTH
+#define MGMT_SET_SCAN_RSP_MIN_APP_DATA_SIZE 1
+
#endif /* __MGMT_TIZEN_H */
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 5afd67ef797a..dc4083da3dfe 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3072,6 +3072,10 @@ struct hci_dev *hci_alloc_dev(void)
hdev->le_adv_channel_map = 0x07;
hdev->le_adv_min_interval = 0x0800;
hdev->le_adv_max_interval = 0x0800;
+#ifdef TIZEN_BT
+ hdev->adv_filter_policy = 0x00;
+ hdev->adv_type = 0x00;
+#endif
hdev->le_scan_interval = 0x0060;
hdev->le_scan_window = 0x0030;
hdev->le_conn_min_interval = 0x0018;
diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c
index 9448ebd3780a..845d2fbc70c7 100644
--- a/net/bluetooth/hci_request.c
+++ b/net/bluetooth/hci_request.c
@@ -918,6 +918,7 @@ static u8 get_adv_instance_scan_rsp_len(struct hci_dev *hdev, u8 instance)
return adv_instance->scan_rsp_len;
}
+#ifndef TIZEN_BT
static u8 get_cur_adv_instance_scan_rsp_len(struct hci_dev *hdev)
{
u8 instance = hdev->cur_adv_instance;
@@ -936,6 +937,7 @@ static u8 get_cur_adv_instance_scan_rsp_len(struct hci_dev *hdev)
*/
return adv_instance->scan_rsp_len;
}
+#endif
void __hci_req_disable_advertising(struct hci_request *req)
{
@@ -1090,13 +1092,17 @@ void __hci_req_enable_advertising(struct hci_request *req)
cp.min_interval = cpu_to_le16(hdev->le_adv_min_interval);
cp.max_interval = cpu_to_le16(hdev->le_adv_max_interval);
+#ifdef TIZEN_BT
+ cp.filter_policy = hdev->adv_filter_policy;
+ cp.type = hdev->adv_type;
+#else
if (connectable)
cp.type = LE_ADV_IND;
else if (get_cur_adv_instance_scan_rsp_len(hdev))
cp.type = LE_ADV_SCAN_IND;
else
cp.type = LE_ADV_NONCONN_IND;
-
+#endif
cp.own_address_type = own_addr_type;
cp.channel_map = hdev->le_adv_channel_map;
@@ -1204,6 +1210,13 @@ void __hci_req_update_scan_rsp_data(struct hci_request *req, u8 instance)
cp.data);
else
len = create_default_scan_rsp_data(hdev, cp.data);
+#ifdef TIZEN_BT
+ /* Advertising scan response data is handled in bluez.
+ * This value will be updated only when application request the update
+ * using adapter_set_scan_rsp_data()
+ */
+ return;
+#else
if (hdev->scan_rsp_data_len == len &&
!memcmp(cp.data, hdev->scan_rsp_data, len))
@@ -1219,6 +1232,7 @@ void __hci_req_update_scan_rsp_data(struct hci_request *req, u8 instance)
hci_req_add(req, HCI_OP_LE_SET_EXT_SCAN_RSP_DATA, sizeof(cp),
&cp);
+#endif
} else {
struct hci_cp_le_set_scan_rsp_data cp;
@@ -1229,7 +1243,13 @@ void __hci_req_update_scan_rsp_data(struct hci_request *req, u8 instance)
cp.data);
else
len = create_default_scan_rsp_data(hdev, cp.data);
-
+#ifdef TIZEN_BT
+ /* Advertising scan response data is handled in bluez.
+ * This value will be updated only when application request the update
+ * using adapter_set_scan_rsp_data()
+ */
+ return;
+#else
if (hdev->scan_rsp_data_len == len &&
!memcmp(cp.data, hdev->scan_rsp_data, len))
return;
@@ -1240,6 +1260,7 @@ void __hci_req_update_scan_rsp_data(struct hci_request *req, u8 instance)
cp.length = len;
hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
+#endif
}
}
@@ -1338,6 +1359,13 @@ void __hci_req_update_adv_data(struct hci_request *req, u8 instance)
len = create_instance_adv_data(hdev, instance, cp.data);
+#ifdef TIZEN_BT
+ /* Bluez will handle the advertising data including the flag and tx
+ * power. This value will be updated only when application request the
+ * update using adapter_set_advertising_data().
+ */
+ return;
+#else
/* There's nothing to do if the data hasn't changed */
if (hdev->adv_data_len == len &&
memcmp(cp.data, hdev->adv_data, len) == 0)
@@ -1352,6 +1380,7 @@ void __hci_req_update_adv_data(struct hci_request *req, u8 instance)
cp.frag_pref = LE_SET_ADV_DATA_NO_FRAG;
hci_req_add(req, HCI_OP_LE_SET_EXT_ADV_DATA, sizeof(cp), &cp);
+#endif
} else {
struct hci_cp_le_set_adv_data cp;
@@ -1359,6 +1388,13 @@ void __hci_req_update_adv_data(struct hci_request *req, u8 instance)
len = create_instance_adv_data(hdev, instance, cp.data);
+#ifdef TIZEN_BT
+ /* Bluez will handle the advertising data including the flag and tx
+ * power. This value will be updated only when application request the
+ * update using adapter_set_advertising_data().
+ */
+ return;
+#else
/* There's nothing to do if the data hasn't changed */
if (hdev->adv_data_len == len &&
memcmp(cp.data, hdev->adv_data, len) == 0)
@@ -1370,6 +1406,7 @@ void __hci_req_update_adv_data(struct hci_request *req, u8 instance)
cp.length = len;
hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
+#endif
}
}
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 703c5618d2ff..74807788a46f 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -5073,6 +5073,225 @@ static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
return err;
}
+#ifdef TIZEN_BT
+static int set_advertising_params(struct sock *sk, struct hci_dev *hdev,
+ void *data, u16 len)
+{
+ struct mgmt_cp_set_advertising_params *cp = data;
+ __u16 min_interval;
+ __u16 max_interval;
+ int err;
+
+ BT_DBG("%s", hdev->name);
+
+ if (!lmp_le_capable(hdev))
+ return mgmt_cmd_status(sk, hdev->id,
+ MGMT_OP_SET_ADVERTISING_PARAMS,
+ MGMT_STATUS_NOT_SUPPORTED);
+
+ if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
+ return mgmt_cmd_status(sk, hdev->id,
+ MGMT_OP_SET_ADVERTISING_PARAMS,
+ MGMT_STATUS_BUSY);
+
+ min_interval = __le16_to_cpu(cp->interval_min);
+ max_interval = __le16_to_cpu(cp->interval_max);
+
+ if (min_interval > max_interval ||
+ min_interval < 0x0020 || max_interval > 0x4000)
+ return mgmt_cmd_status(sk, hdev->id,
+ MGMT_OP_SET_ADVERTISING_PARAMS,
+ MGMT_STATUS_INVALID_PARAMS);
+
+ hci_dev_lock(hdev);
+
+ hdev->le_adv_min_interval = min_interval;
+ hdev->le_adv_max_interval = max_interval;
+ hdev->adv_filter_policy = cp->filter_policy;
+ hdev->adv_type = cp->type;
+
+ err = mgmt_cmd_complete(sk, hdev->id,
+ MGMT_OP_SET_ADVERTISING_PARAMS, 0, NULL, 0);
+
+ hci_dev_unlock(hdev);
+
+ return err;
+}
+
+static void set_advertising_data_complete(struct hci_dev *hdev,
+ u8 status, u16 opcode)
+{
+ struct mgmt_cp_set_advertising_data *cp;
+ struct mgmt_pending_cmd *cmd;
+
+ BT_DBG("status 0x%02x", status);
+
+ hci_dev_lock(hdev);
+
+ cmd = pending_find(MGMT_OP_SET_ADVERTISING_DATA, hdev);
+ if (!cmd)
+ goto unlock;
+
+ cp = cmd->param;
+
+ if (status)
+ mgmt_cmd_status(cmd->sk, hdev->id,
+ MGMT_OP_SET_ADVERTISING_DATA,
+ mgmt_status(status));
+ else
+ mgmt_cmd_complete(cmd->sk, hdev->id,
+ MGMT_OP_SET_ADVERTISING_DATA, 0,
+ cp, sizeof(*cp));
+
+ mgmt_pending_remove(cmd);
+
+unlock:
+ hci_dev_unlock(hdev);
+}
+
+static int set_advertising_data(struct sock *sk, struct hci_dev *hdev,
+ void *data, u16 len)
+{
+ struct mgmt_pending_cmd *cmd;
+ struct hci_request req;
+ struct mgmt_cp_set_advertising_data *cp = data;
+ struct hci_cp_le_set_adv_data adv;
+ int err;
+
+ BT_DBG("%s", hdev->name);
+
+ if (!lmp_le_capable(hdev)) {
+ return mgmt_cmd_status(sk, hdev->id,
+ MGMT_OP_SET_ADVERTISING_DATA,
+ MGMT_STATUS_NOT_SUPPORTED);
+ }
+
+ hci_dev_lock(hdev);
+
+ if (pending_find(MGMT_OP_SET_ADVERTISING_DATA, hdev)) {
+ err = mgmt_cmd_status(sk, hdev->id,
+ MGMT_OP_SET_ADVERTISING_DATA,
+ MGMT_STATUS_BUSY);
+ goto unlocked;
+ }
+
+ if (len > HCI_MAX_AD_LENGTH) {
+ err = mgmt_cmd_status(sk, hdev->id,
+ MGMT_OP_SET_ADVERTISING_DATA,
+ MGMT_STATUS_INVALID_PARAMS);
+ goto unlocked;
+ }
+
+ cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING_DATA,
+ hdev, data, len);
+ if (!cmd) {
+ err = -ENOMEM;
+ goto unlocked;
+ }
+
+ hci_req_init(&req, hdev);
+
+ memset(&adv, 0, sizeof(adv));
+ memcpy(adv.data, cp->data, len);
+ adv.length = len;
+
+ hci_req_add(&req, HCI_OP_LE_SET_ADV_DATA, sizeof(adv), &adv);
+
+ err = hci_req_run(&req, set_advertising_data_complete);
+ if (err < 0)
+ mgmt_pending_remove(cmd);
+
+unlocked:
+ hci_dev_unlock(hdev);
+
+ return err;
+}
+
+static void set_scan_rsp_data_complete(struct hci_dev *hdev, u8 status,
+ u16 opcode)
+{
+ struct mgmt_cp_set_scan_rsp_data *cp;
+ struct mgmt_pending_cmd *cmd;
+
+ BT_DBG("status 0x%02x", status);
+
+ hci_dev_lock(hdev);
+
+ cmd = pending_find(MGMT_OP_SET_SCAN_RSP_DATA, hdev);
+ if (!cmd)
+ goto unlock;
+
+ cp = cmd->param;
+
+ if (status)
+ mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_SCAN_RSP_DATA,
+ mgmt_status(status));
+ else
+ mgmt_cmd_complete(cmd->sk, hdev->id,
+ MGMT_OP_SET_SCAN_RSP_DATA, 0,
+ cp, sizeof(*cp));
+
+ mgmt_pending_remove(cmd);
+
+unlock:
+ hci_dev_unlock(hdev);
+}
+
+static int set_scan_rsp_data(struct sock *sk, struct hci_dev *hdev, void *data,
+ u16 len)
+{
+ struct mgmt_pending_cmd *cmd;
+ struct hci_request req;
+ struct mgmt_cp_set_scan_rsp_data *cp = data;
+ struct hci_cp_le_set_scan_rsp_data rsp;
+ int err;
+
+ BT_DBG("%s", hdev->name);
+
+ if (!lmp_le_capable(hdev))
+ return mgmt_cmd_status(sk, hdev->id,
+ MGMT_OP_SET_SCAN_RSP_DATA,
+ MGMT_STATUS_NOT_SUPPORTED);
+
+ hci_dev_lock(hdev);
+
+ if (pending_find(MGMT_OP_SET_SCAN_RSP_DATA, hdev)) {
+ err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_RSP_DATA,
+ MGMT_STATUS_BUSY);
+ goto unlocked;
+ }
+
+ if (len > HCI_MAX_AD_LENGTH) {
+ err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_RSP_DATA,
+ MGMT_STATUS_INVALID_PARAMS);
+ goto unlocked;
+ }
+
+ cmd = mgmt_pending_add(sk, MGMT_OP_SET_SCAN_RSP_DATA, hdev, data, len);
+ if (!cmd) {
+ err = -ENOMEM;
+ goto unlocked;
+ }
+
+ hci_req_init(&req, hdev);
+
+ memset(&rsp, 0, sizeof(rsp));
+ memcpy(rsp.data, cp->data, len);
+ rsp.length = len;
+
+ hci_req_add(&req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(rsp), &rsp);
+
+ err = hci_req_run(&req, set_scan_rsp_data_complete);
+ if (err < 0)
+ mgmt_pending_remove(cmd);
+
+unlocked:
+ hci_dev_unlock(hdev);
+
+ return err;
+}
+#endif /* TIZEN_BT */
+
static bool ltk_is_valid(struct mgmt_ltk_info *key)
{
if (key->master != 0x00 && key->master != 0x01)
@@ -6929,6 +7148,11 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
#ifdef TIZEN_BT
static const struct hci_mgmt_handler tizen_mgmt_handlers[] = {
{ NULL }, /* 0x0000 (no command) */
+ { set_advertising_params, MGMT_SET_ADVERTISING_PARAMS_SIZE },
+ { set_advertising_data, MGMT_SET_ADV_MIN_APP_DATA_SIZE,
+ HCI_MGMT_VAR_LEN },
+ { set_scan_rsp_data, MGMT_SET_SCAN_RSP_MIN_APP_DATA_SIZE,
+ HCI_MGMT_VAR_LEN },
};
#endif