From 0a5b5a2551a2c54533aae24da411967bda15f043 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Tue, 23 Aug 2016 17:07:10 +0530 Subject: [PATCH 01/16] Bluetooth: Add "TIZEN_BT" flag Added the tizen specific flag for use in adding tizen patches. Change-Id: Ia391644fddbe600c8d845e0bf0808f587aa73e0c Signed-off-by: Sudha Bheemanna Signed-off-by: DoHyun Pyun Signed-off-by: Amit Purwar --- include/net/bluetooth/bluetooth.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index fabee6d..d5f01e8 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -37,6 +37,9 @@ #define PF_BLUETOOTH AF_BLUETOOTH #endif +/*To enable Tizen specific fixes */ +#define TIZEN_BT + /* Bluetooth versions */ #define BLUETOOTH_VER_1_1 1 #define BLUETOOTH_VER_1_2 2 -- 2.7.4 From 8e404467166ed065dfcc28b69a3ea769ba3149ec Mon Sep 17 00:00:00 2001 From: "h.sandeep" Date: Thu, 1 Sep 2016 12:00:57 +0530 Subject: [PATCH 02/16] Bluetooth: Add MGMT tizen_handlers and TIZEN_OP_BASE_CODE. Added the basic skeleton code for tizen_mgmt_handlers and mgmt_tizen.h header file. Change-Id: I8f3100aa79e6673840ba561f0a9c50238ca0880b Signed-off-by: h.sandeep Signed-off-by: Amit Purwar --- include/net/bluetooth/hci_core.h | 4 ++++ include/net/bluetooth/mgmt_tizen.h | 26 ++++++++++++++++++++++++++ net/bluetooth/hci_sock.c | 21 +++++++++++++++++++++ net/bluetooth/mgmt.c | 13 +++++++++++++ 4 files changed, 64 insertions(+) create mode 100644 include/net/bluetooth/mgmt_tizen.h diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index cc2d0c3..3bdcf30 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1472,6 +1472,10 @@ struct hci_mgmt_chan { unsigned short channel; size_t handler_count; const struct hci_mgmt_handler *handlers; +#ifdef TIZEN_BT + size_t tizen_handler_count; + const struct hci_mgmt_handler *tizen_handlers; +#endif void (*hdev_init) (struct sock *sk, struct hci_dev *hdev); }; diff --git a/include/net/bluetooth/mgmt_tizen.h b/include/net/bluetooth/mgmt_tizen.h new file mode 100644 index 0000000..6bad3c9 --- /dev/null +++ b/include/net/bluetooth/mgmt_tizen.h @@ -0,0 +1,26 @@ +/* + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (c) 2015-2016 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __MGMT_TIZEN_H +#define __MGMT_TIZEN_H + +#define TIZEN_OP_CODE_BASE 0xff00 +#define TIZEN_EV_BASE 0xff00 + +#endif /* __MGMT_TIZEN_H */ diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index d4e2a16..5698525 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -33,6 +33,9 @@ #include #include #include +#ifdef TIZEN_BT +#include +#endif #include "mgmt_util.h" @@ -1498,6 +1501,21 @@ static int hci_mgmt_cmd(struct hci_mgmt_chan *chan, struct sock *sk, goto done; } +#ifdef TIZEN_BT + if (opcode >= TIZEN_OP_CODE_BASE) { + u16 tizen_opcode_index = opcode - TIZEN_OP_CODE_BASE; + if (tizen_opcode_index >= chan->tizen_handler_count || + chan->tizen_handlers[tizen_opcode_index].func == NULL) { + BT_DBG("Unknown op %u", opcode); + err = mgmt_cmd_status(sk, index, opcode, + MGMT_STATUS_UNKNOWN_COMMAND); + goto done; + } + + handler = &chan->tizen_handlers[tizen_opcode_index]; + + } else { +#endif if (chan->channel == HCI_CHANNEL_CONTROL) { struct sk_buff *skb; @@ -1520,6 +1538,9 @@ static int hci_mgmt_cmd(struct hci_mgmt_chan *chan, struct sock *sk, } handler = &chan->handlers[opcode]; +#ifdef TIZEN_BT + } +#endif if (!hci_sock_test_flag(sk, HCI_SOCK_TRUSTED) && !(handler->flags & HCI_MGMT_UNTRUSTED)) { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ccce954..703c561 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -32,6 +32,9 @@ #include #include #include +#ifdef TIZEN_BT +#include +#endif #include "hci_request.h" #include "smp.h" @@ -6923,6 +6926,12 @@ static const struct hci_mgmt_handler mgmt_handlers[] = { { set_phy_configuration, MGMT_SET_PHY_CONFIGURATION_SIZE }, }; +#ifdef TIZEN_BT +static const struct hci_mgmt_handler tizen_mgmt_handlers[] = { + { NULL }, /* 0x0000 (no command) */ +}; +#endif + void mgmt_index_added(struct hci_dev *hdev) { struct mgmt_ev_ext_index ev; @@ -7947,6 +7956,10 @@ static struct hci_mgmt_chan chan = { .channel = HCI_CHANNEL_CONTROL, .handler_count = ARRAY_SIZE(mgmt_handlers), .handlers = mgmt_handlers, +#ifdef TIZEN_BT + .tizen_handler_count = ARRAY_SIZE(tizen_mgmt_handlers), + .tizen_handlers = tizen_mgmt_handlers, +#endif .hdev_init = mgmt_init_hdev, }; -- 2.7.4 From ac160e08af6995e83e67918607110da992cc0b73 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Wed, 24 Aug 2016 12:17:16 +0530 Subject: [PATCH 03/16] 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 Signed-off-by: DoHyun Pyun Signed-off-by: Amit Purwar --- include/net/bluetooth/hci.h | 2 + include/net/bluetooth/hci_core.h | 5 + include/net/bluetooth/mgmt_tizen.h | 23 ++++ net/bluetooth/hci_core.c | 4 + net/bluetooth/hci_request.c | 41 ++++++- net/bluetooth/mgmt.c | 224 +++++++++++++++++++++++++++++++++++++ 6 files changed, 297 insertions(+), 2 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 845d947..47a8194 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 3bdcf30..29522e6 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 6bad3c9..04bd255 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 5afd67e..dc4083d 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 9448ebd..845d2fb 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 703c561..7480778 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 -- 2.7.4 From 3e0794db72dd33912d00c7bf1123583bb658152f Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Wed, 24 Aug 2016 15:02:56 +0530 Subject: [PATCH 04/16] Bluetooth: Functions to modify WhiteList This patch provides MGMT commands to manage the white list which includes, adding, removing and clearing the devices from white list. Change-Id: If71107129d3a090ae81448a8122b76accd4f5522 Signed-off-by: Sudha Bheemanna Signed-off-by: DoHyun Pyun Signed-off-by: Amit Purwar --- include/net/bluetooth/mgmt_tizen.h | 17 +++ net/bluetooth/mgmt.c | 241 +++++++++++++++++++++++++++++++++++++ 2 files changed, 258 insertions(+) diff --git a/include/net/bluetooth/mgmt_tizen.h b/include/net/bluetooth/mgmt_tizen.h index 04bd255..6dc8e36 100644 --- a/include/net/bluetooth/mgmt_tizen.h +++ b/include/net/bluetooth/mgmt_tizen.h @@ -46,4 +46,21 @@ struct mgmt_cp_set_scan_rsp_data { #define MGMT_SET_SCAN_RSP_DATA_SIZE HCI_MAX_AD_LENGTH #define MGMT_SET_SCAN_RSP_MIN_APP_DATA_SIZE 1 +#define MGMT_OP_ADD_DEV_WHITE_LIST (TIZEN_OP_CODE_BASE + 0x04) +struct mgmt_cp_add_dev_white_list { + __u8 bdaddr_type; + bdaddr_t bdaddr; +} __packed; +#define MGMT_ADD_DEV_WHITE_LIST_SIZE 7 + +#define MGMT_OP_REMOVE_DEV_FROM_WHITE_LIST (TIZEN_OP_CODE_BASE + 0x05) +struct mgmt_cp_remove_dev_from_white_list { + __u8 bdaddr_type; + bdaddr_t bdaddr; +} __packed; +#define MGMT_REMOVE_DEV_FROM_WHITE_LIST_SIZE 7 + +#define MGMT_OP_CLEAR_DEV_WHITE_LIST (TIZEN_OP_CODE_BASE + 0x06) +#define MGMT_OP_CLEAR_DEV_WHITE_LIST_SIZE 0 + #endif /* __MGMT_TIZEN_H */ diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 7480778..c8081c1 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5290,6 +5290,244 @@ unlocked: return err; } + +/* Adv White List feature */ +static void add_white_list_complete(struct hci_dev *hdev, u8 status, u16 opcode) +{ + struct mgmt_cp_add_dev_white_list *cp; + struct mgmt_pending_cmd *cmd; + + BT_DBG("status 0x%02x", status); + + hci_dev_lock(hdev); + + cmd = pending_find(MGMT_OP_ADD_DEV_WHITE_LIST, hdev); + if (!cmd) + goto unlock; + + cp = cmd->param; + + if (status) + mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_ADD_DEV_WHITE_LIST, + mgmt_status(status)); + else + mgmt_cmd_complete(cmd->sk, hdev->id, + MGMT_OP_ADD_DEV_WHITE_LIST, 0, cp, sizeof(*cp)); + + mgmt_pending_remove(cmd); + +unlock: + hci_dev_unlock(hdev); +} + +static int add_white_list(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + struct mgmt_pending_cmd *cmd; + struct mgmt_cp_add_dev_white_list *cp = data; + struct hci_request req; + int err; + + BT_DBG("%s", hdev->name); + + if (!lmp_le_capable(hdev)) + return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_DEV_WHITE_LIST, + MGMT_STATUS_NOT_SUPPORTED); + + if (!hdev_is_powered(hdev)) + return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_DEV_WHITE_LIST, + MGMT_STATUS_REJECTED); + + hci_dev_lock(hdev); + + if (pending_find(MGMT_OP_ADD_DEV_WHITE_LIST, hdev)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_DEV_WHITE_LIST, + MGMT_STATUS_BUSY); + goto unlocked; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_ADD_DEV_WHITE_LIST, hdev, data, len); + if (!cmd) { + err = -ENOMEM; + goto unlocked; + } + + hci_req_init(&req, hdev); + + hci_req_add(&req, HCI_OP_LE_ADD_TO_WHITE_LIST, sizeof(*cp), cp); + + err = hci_req_run(&req, add_white_list_complete); + if (err < 0) { + mgmt_pending_remove(cmd); + goto unlocked; + } + +unlocked: + hci_dev_unlock(hdev); + + return err; +} + +static void remove_from_white_list_complete(struct hci_dev *hdev, + u8 status, u16 opcode) +{ + struct mgmt_cp_remove_dev_from_white_list *cp; + struct mgmt_pending_cmd *cmd; + + BT_DBG("status 0x%02x", status); + + hci_dev_lock(hdev); + + cmd = pending_find(MGMT_OP_REMOVE_DEV_FROM_WHITE_LIST, hdev); + if (!cmd) + goto unlock; + + cp = cmd->param; + + if (status) + mgmt_cmd_status(cmd->sk, hdev->id, + MGMT_OP_REMOVE_DEV_FROM_WHITE_LIST, + mgmt_status(status)); + else + mgmt_cmd_complete(cmd->sk, hdev->id, + MGMT_OP_REMOVE_DEV_FROM_WHITE_LIST, 0, + cp, sizeof(*cp)); + + mgmt_pending_remove(cmd); + +unlock: + hci_dev_unlock(hdev); +} + +static int remove_from_white_list(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + struct mgmt_pending_cmd *cmd; + struct mgmt_cp_remove_dev_from_white_list *cp = data; + struct hci_request req; + int err; + + BT_DBG("%s", hdev->name); + + if (!lmp_le_capable(hdev)) + return mgmt_cmd_status(sk, hdev->id, + MGMT_OP_REMOVE_DEV_FROM_WHITE_LIST, + MGMT_STATUS_NOT_SUPPORTED); + + if (!hdev_is_powered(hdev)) + return mgmt_cmd_status(sk, hdev->id, + MGMT_OP_REMOVE_DEV_FROM_WHITE_LIST, + MGMT_STATUS_REJECTED); + + hci_dev_lock(hdev); + + if (pending_find(MGMT_OP_REMOVE_DEV_FROM_WHITE_LIST, hdev)) { + err = mgmt_cmd_status(sk, hdev->id, + MGMT_OP_REMOVE_DEV_FROM_WHITE_LIST, + MGMT_STATUS_BUSY); + goto unlocked; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_DEV_FROM_WHITE_LIST, + hdev, data, len); + if (!cmd) { + err = -ENOMEM; + goto unlocked; + } + + hci_req_init(&req, hdev); + + hci_req_add(&req, HCI_OP_LE_DEL_FROM_WHITE_LIST, sizeof(*cp), cp); + + err = hci_req_run(&req, remove_from_white_list_complete); + if (err < 0) { + mgmt_pending_remove(cmd); + goto unlocked; + } + +unlocked: + hci_dev_unlock(hdev); + + return err; +} + +static void clear_white_list_complete(struct hci_dev *hdev, u8 status, + u16 opcode) +{ + struct mgmt_pending_cmd *cmd; + + BT_DBG("status 0x%02x", status); + + hci_dev_lock(hdev); + + cmd = pending_find(MGMT_OP_CLEAR_DEV_WHITE_LIST, hdev); + if (!cmd) + goto unlock; + + if (status) + mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_CLEAR_DEV_WHITE_LIST, + mgmt_status(status)); + else + mgmt_cmd_complete(cmd->sk, hdev->id, + MGMT_OP_CLEAR_DEV_WHITE_LIST, + 0, NULL, 0); + + mgmt_pending_remove(cmd); + +unlock: + hci_dev_unlock(hdev); +} + +static int clear_white_list(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + struct mgmt_pending_cmd *cmd; + struct hci_request req; + int err; + + BT_DBG("%s", hdev->name); + + if (!lmp_le_capable(hdev)) + return mgmt_cmd_status(sk, hdev->id, + MGMT_OP_CLEAR_DEV_WHITE_LIST, + MGMT_STATUS_NOT_SUPPORTED); + + if (!hdev_is_powered(hdev)) + return mgmt_cmd_status(sk, hdev->id, + MGMT_OP_CLEAR_DEV_WHITE_LIST, + MGMT_STATUS_REJECTED); + + hci_dev_lock(hdev); + + if (pending_find(MGMT_OP_CLEAR_DEV_WHITE_LIST, hdev)) { + err = mgmt_cmd_status(sk, hdev->id, + MGMT_OP_CLEAR_DEV_WHITE_LIST, + MGMT_STATUS_BUSY); + goto unlocked; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_CLEAR_DEV_WHITE_LIST, + hdev, NULL, 0); + if (!cmd) { + err = -ENOMEM; + goto unlocked; + } + + hci_req_init(&req, hdev); + + hci_req_add(&req, HCI_OP_LE_CLEAR_WHITE_LIST, 0, NULL); + + err = hci_req_run(&req, clear_white_list_complete); + if (err < 0) { + mgmt_pending_remove(cmd); + goto unlocked; + } + +unlocked: + hci_dev_unlock(hdev); + + return err; +} #endif /* TIZEN_BT */ static bool ltk_is_valid(struct mgmt_ltk_info *key) @@ -7153,6 +7391,9 @@ static const struct hci_mgmt_handler tizen_mgmt_handlers[] = { HCI_MGMT_VAR_LEN }, { set_scan_rsp_data, MGMT_SET_SCAN_RSP_MIN_APP_DATA_SIZE, HCI_MGMT_VAR_LEN }, + { add_white_list, MGMT_ADD_DEV_WHITE_LIST_SIZE }, + { remove_from_white_list, MGMT_REMOVE_DEV_FROM_WHITE_LIST_SIZE }, + { clear_white_list, MGMT_OP_CLEAR_DEV_WHITE_LIST_SIZE }, }; #endif -- 2.7.4 From 1219474c5e8e1a84a8f3061b767c44eb255ee048 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Wed, 24 Aug 2016 17:21:15 +0530 Subject: [PATCH 05/16] Bluetooth: Add RSSI Monitor feature Added feature support for monitoring the RSSI value. Commands and events for enabling, disabling and setting rssi threshold values are added. Change-Id: I850643a9228afc017e54217a11826b9c6a68a96b Signed-off-by: Sudha Bheemanna Signed-off-by: Seung-Woo Kim Signed-off-by: Amit Purwar --- include/net/bluetooth/hci.h | 54 +++ include/net/bluetooth/hci_core.h | 80 +++++ include/net/bluetooth/mgmt_tizen.h | 63 ++++ net/bluetooth/hci_event.c | 32 ++ net/bluetooth/mgmt.c | 686 +++++++++++++++++++++++++++++++++++++ 5 files changed, 915 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 47a8194..a5c140e 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1674,6 +1674,60 @@ struct hci_cp_le_set_adv_set_rand_addr { bdaddr_t bdaddr; } __packed; +#ifdef TIZEN_BT +/* + * Vendor Specific HCI Command + * Vendor: Broadcom + * Purpose: This HCI is used to enable RSSI monitoring and setting + * Threshold Values for LE Link + */ +#define HCI_OP_ENABLE_RSSI 0xfce9 + +struct hci_cp_set_enable_rssi { + __u8 hci_le_ext_opcode; + __u8 le_enable_cs_Features; + __u8 data[3]; +} __packed; + +struct hci_cp_set_rssi_threshold { + __u8 hci_le_ext_opcode; + __u8 mode; + __le16 conn_handle; + __u8 alert_mask; + __u8 low_th; + __u8 in_range_th; + __u8 high_th; +} __packed; + +struct hci_cc_rsp_enable_rssi { + __u8 status; + __u8 le_ext_opcode; +} __packed; + +struct hci_ev_vendor_specific_rssi_alert { + __le16 conn_handle; + __s8 alert_type; + __s8 rssi_dbm; +} __packed; + +/* + * Vendor Specific HCI Command + * Vendor: Broadcom + * Purpose: This HCI is used to get Raw RSSI value for a Link + */ +#define HCI_OP_GET_RAW_RSSI 0xfc48 + +struct hci_cp_get_raw_rssi { + __le16 conn_handle; +} __packed; + +struct hci_cc_rp_get_raw_rssi { + __u8 status; + __le16 conn_handle; + __s8 rssi_dbm; +} __packed; +#endif + /* ---- HCI Events ---- */ #define HCI_EV_INQUIRY_COMPLETE 0x01 diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 29522e6..33a567d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -517,6 +517,9 @@ struct hci_conn { void *sco_data; struct amp_mgr *amp_mgr; +#ifdef TIZEN_BT + bool rssi_monitored; +#endif struct hci_conn *link; void (*connect_cfm_cb) (struct hci_conn *conn, u8 status); @@ -895,6 +898,70 @@ static inline struct hci_conn *hci_lookup_le_connect(struct hci_dev *hdev) return NULL; } +#ifdef TIZEN_BT +static inline bool hci_conn_rssi_state_set(struct hci_dev *hdev, + __u8 type, bdaddr_t *ba, bool value) +{ + struct hci_conn_hash *h = &hdev->conn_hash; + struct hci_conn *c; + __u8 conn_type; + + if (type == 0x01) + conn_type = LE_LINK; + else + conn_type = ACL_LINK; + + rcu_read_lock(); + + list_for_each_entry_rcu(c, &h->list, list) { + if (c->type == conn_type && !bacmp(&c->dst, ba)) { + c->rssi_monitored = value; + rcu_read_unlock(); + return true; + } + } + + rcu_read_unlock(); + return false; +} + +static inline void hci_conn_rssi_unset_all(struct hci_dev *hdev, + __u8 type) +{ + struct hci_conn_hash *h = &hdev->conn_hash; + struct hci_conn *c; + __u8 conn_type; + + if (type == 0x01) + conn_type = LE_LINK; + else + conn_type = ACL_LINK; + + rcu_read_lock(); + list_for_each_entry_rcu(c, &h->list, list) { + if (c->type == conn_type) + c->rssi_monitored = false; + } + rcu_read_unlock(); +} + +static inline int hci_conn_hash_lookup_rssi_count(struct hci_dev *hdev) +{ + struct hci_conn_hash *h = &hdev->conn_hash; + struct hci_conn *c; + int count = 0; + + rcu_read_lock(); + list_for_each_entry_rcu(c, &h->list, list) { + if (c->rssi_monitored == true) + ++count; + } + rcu_read_unlock(); + + return count; +} +#endif + int hci_disconnect(struct hci_conn *conn, __u8 reason); bool hci_setup_sync(struct hci_conn *conn, __u16 handle); void hci_sco_setup(struct hci_conn *conn, __u8 status); @@ -1578,6 +1645,19 @@ void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev, u8 instance); int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip); +#ifdef TIZEN_BT +void mgmt_rssi_enable_success(struct sock *sk, struct hci_dev *hdev, + void *data, struct hci_cc_rsp_enable_rssi *rp, int success); +void mgmt_rssi_disable_success(struct sock *sk, struct hci_dev *hdev, + void *data, struct hci_cc_rsp_enable_rssi *rp, int success); +int mgmt_set_rssi_threshold(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len); +void mgmt_rssi_alert_evt(struct hci_dev *hdev, struct sk_buff *skb); +void mgmt_raw_rssi_response(struct hci_dev *hdev, + struct hci_cc_rp_get_raw_rssi *rp, int success); +void mgmt_enable_rssi_cc(struct hci_dev *hdev, void *response, u8 status); +#endif + u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, u16 to_multiplier); void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand, diff --git a/include/net/bluetooth/mgmt_tizen.h b/include/net/bluetooth/mgmt_tizen.h index 6dc8e36..46f652b 100644 --- a/include/net/bluetooth/mgmt_tizen.h +++ b/include/net/bluetooth/mgmt_tizen.h @@ -63,4 +63,67 @@ struct mgmt_cp_remove_dev_from_white_list { #define MGMT_OP_CLEAR_DEV_WHITE_LIST (TIZEN_OP_CODE_BASE + 0x06) #define MGMT_OP_CLEAR_DEV_WHITE_LIST_SIZE 0 +/* For RSSI monitoring */ +#define MGMT_OP_SET_RSSI_ENABLE (TIZEN_OP_CODE_BASE + 0x07) +#define MGMT_SET_RSSI_ENABLE_SIZE 10 + +struct mgmt_cp_set_enable_rssi { + __s8 low_th; + __s8 in_range_th; + __s8 high_th; + bdaddr_t bdaddr; + __s8 link_type; +} __packed; + +struct mgmt_cc_rsp_enable_rssi { + __u8 status; + __u8 le_ext_opcode; + bdaddr_t bt_address; + __s8 link_type; +} __packed; + +#define MGMT_OP_GET_RAW_RSSI (TIZEN_OP_CODE_BASE + 0x08) +#define MGMT_GET_RAW_RSSI_SIZE 7 + +struct mgmt_cp_get_raw_rssi { + bdaddr_t bt_address; + __u8 link_type; +} __packed; + +#define MGMT_OP_SET_RSSI_DISABLE (TIZEN_OP_CODE_BASE + 0x09) +#define MGMT_SET_RSSI_DISABLE_SIZE 7 +struct mgmt_cp_disable_rssi { + bdaddr_t bdaddr; + __u8 link_type; +} __packed; +struct mgmt_cc_rp_disable_rssi { + __u8 status; + __u8 le_ext_opcode; + bdaddr_t bt_address; + __s8 link_type; +} __packed; +/* RSSI monitoring */ + +/* For handling of RSSI Events */ +#define MGMT_EV_RSSI_ALERT (TIZEN_EV_BASE + 0x04) +struct mgmt_ev_vendor_specific_rssi_alert { + bdaddr_t bdaddr; + __s8 link_type; + __s8 alert_type; + __s8 rssi_dbm; +} __packed; + +#define MGMT_EV_RAW_RSSI (TIZEN_EV_BASE + 0x05) +struct mgmt_cc_rp_get_raw_rssi { + __u8 status; + __s8 rssi_dbm; + __u8 link_type; + bdaddr_t bt_address; +} __packed; + +#define MGMT_EV_RSSI_ENABLED (TIZEN_EV_BASE + 0x06) + +#define MGMT_EV_RSSI_DISABLED (TIZEN_EV_BASE + 0x07) +/* Handling of RSSI Events */ + #endif /* __MGMT_TIZEN_H */ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 3e7badb..f7616f7 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1604,6 +1604,30 @@ static void hci_cc_set_ext_adv_param(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_unlock(hdev); } +#ifdef TIZEN_BT +static void hci_cc_enable_rssi(struct hci_dev *hdev, + struct sk_buff *skb) +{ + struct hci_cc_rsp_enable_rssi *rp = (void *)skb->data; + + BT_DBG("hci_cc_enable_rssi - %s status 0x%2.2x Event_LE_ext_Opcode 0x%2.2x", + hdev->name, rp->status, rp->le_ext_opcode); + + mgmt_enable_rssi_cc(hdev, rp, rp->status); +} + +static void hci_cc_get_raw_rssi(struct hci_dev *hdev, + struct sk_buff *skb) +{ + struct hci_cc_rp_get_raw_rssi *rp = (void *)skb->data; + + BT_DBG("hci_cc_get_raw_rssi- %s Get Raw Rssi Response[%2.2x %4.4x %2.2X]", + hdev->name, rp->status, rp->conn_handle, rp->rssi_dbm); + + mgmt_raw_rssi_response(hdev, rp, rp->status); +} +#endif + static void hci_cc_read_rssi(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_rp_read_rssi *rp = (void *) skb->data; @@ -3342,7 +3366,15 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb, case HCI_OP_LE_SET_ADV_SET_RAND_ADDR: hci_cc_le_set_adv_set_random_addr(hdev, skb); break; +#ifdef TIZEN_BT + case HCI_OP_ENABLE_RSSI: + hci_cc_enable_rssi(hdev, skb); + break; + case HCI_OP_GET_RAW_RSSI: + hci_cc_get_raw_rssi(hdev, skb); + break; +#endif default: BT_DBG("%s opcode 0x%4.4x", hdev->name, *opcode); break; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c8081c1..f63f7c0 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5528,6 +5528,689 @@ unlocked: return err; } + +static void set_rssi_threshold_complete(struct hci_dev *hdev, + u8 status, u16 opcode) +{ + struct mgmt_pending_cmd *cmd; + + BT_DBG("status 0x%02x", status); + + hci_dev_lock(hdev); + + cmd = pending_find(MGMT_OP_SET_RSSI_ENABLE, hdev); + if (!cmd) + goto unlock; + + if (status) + mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_RSSI_ENABLE, + mgmt_status(status)); + else + mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_RSSI_ENABLE, 0, + NULL, 0); + + mgmt_pending_remove(cmd); + +unlock: + hci_dev_unlock(hdev); +} + +static void set_rssi_disable_complete(struct hci_dev *hdev, + u8 status, u16 opcode) +{ + struct mgmt_pending_cmd *cmd; + + BT_DBG("status 0x%02x", status); + + hci_dev_lock(hdev); + + cmd = pending_find(MGMT_OP_SET_RSSI_DISABLE, hdev); + if (!cmd) + goto unlock; + + if (status) + mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_RSSI_DISABLE, + mgmt_status(status)); + else + mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_RSSI_DISABLE, + 0, NULL, 0); + + mgmt_pending_remove(cmd); + +unlock: + hci_dev_unlock(hdev); +} + +int mgmt_set_rssi_threshold(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + int err = 0; + struct hci_cp_set_rssi_threshold th = { 0, }; + struct mgmt_cp_set_enable_rssi *cp = data; + struct hci_conn *conn; + struct mgmt_pending_cmd *cmd; + struct hci_request req; + __u8 dest_type; + + hci_dev_lock(hdev); + + cmd = pending_find(MGMT_OP_SET_RSSI_ENABLE, hdev); + if (!cmd) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_RSSI_ENABLE, + MGMT_STATUS_FAILED); + goto unlocked; + } + + if (!lmp_le_capable(hdev)) { + mgmt_pending_remove(cmd); + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_RSSI_ENABLE, + MGMT_STATUS_NOT_SUPPORTED); + goto unlocked; + } + + if (!hdev_is_powered(hdev)) { + BT_DBG("%s", hdev->name); + mgmt_pending_remove(cmd); + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_RSSI_ENABLE, + MGMT_STATUS_NOT_POWERED); + goto unlocked; + } + + if (cp->link_type == 0x01) + dest_type = LE_LINK; + else + dest_type = ACL_LINK; + + /* Get LE/ACL link handle info */ + conn = hci_conn_hash_lookup_ba(hdev, + dest_type, &cp->bdaddr); + + if (!conn) { + err = mgmt_cmd_complete(sk, hdev->id, + MGMT_OP_SET_RSSI_ENABLE, 1, NULL, 0); + mgmt_pending_remove(cmd); + goto unlocked; + } + + hci_req_init(&req, hdev); + + th.hci_le_ext_opcode = 0x0B; + th.mode = 0x01; + th.conn_handle = conn->handle; + th.alert_mask = 0x07; + th.low_th = cp->low_th; + th.in_range_th = cp->in_range_th; + th.high_th = cp->high_th; + + hci_req_add(&req, HCI_OP_ENABLE_RSSI, sizeof(th), &th); + err = hci_req_run(&req, set_rssi_threshold_complete); + + if (err < 0) { + mgmt_pending_remove(cmd); + BT_ERR("Error in requesting hci_req_run"); + goto unlocked; + } + +unlocked: + hci_dev_unlock(hdev); + return err; +} + +void mgmt_rssi_enable_success(struct sock *sk, struct hci_dev *hdev, + void *data, struct hci_cc_rsp_enable_rssi *rp, int success) +{ + struct mgmt_cc_rsp_enable_rssi mgmt_rp = { 0, }; + struct mgmt_cp_set_enable_rssi *cp = data; + struct mgmt_pending_cmd *cmd; + + if (!cp || !rp) + goto remove_cmd; + + mgmt_rp.status = rp->status; + mgmt_rp.le_ext_opcode = rp->le_ext_opcode; + mgmt_rp.bt_address = cp->bdaddr; + mgmt_rp.link_type = cp->link_type; + + mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_RSSI_ENABLE, + MGMT_STATUS_SUCCESS, &mgmt_rp, + sizeof(struct mgmt_cc_rsp_enable_rssi)); + + mgmt_event(MGMT_EV_RSSI_ENABLED, hdev, &mgmt_rp, + sizeof(struct mgmt_cc_rsp_enable_rssi), NULL); + + hci_conn_rssi_unset_all(hdev, mgmt_rp.link_type); + hci_conn_rssi_state_set(hdev, mgmt_rp.link_type, + &mgmt_rp.bt_address, true); + +remove_cmd: + hci_dev_lock(hdev); + cmd = pending_find(MGMT_OP_SET_RSSI_ENABLE, hdev); + if (cmd) + mgmt_pending_remove(cmd); + + hci_dev_unlock(hdev); +} + +void mgmt_rssi_disable_success(struct sock *sk, struct hci_dev *hdev, + void *data, struct hci_cc_rsp_enable_rssi *rp, int success) +{ + struct mgmt_cc_rp_disable_rssi mgmt_rp = { 0, }; + struct mgmt_cp_disable_rssi *cp = data; + struct mgmt_pending_cmd *cmd; + + if (!cp || !rp) + goto remove_cmd; + + mgmt_rp.status = rp->status; + mgmt_rp.le_ext_opcode = rp->le_ext_opcode; + mgmt_rp.bt_address = cp->bdaddr; + mgmt_rp.link_type = cp->link_type; + + mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_RSSI_DISABLE, + MGMT_STATUS_SUCCESS, &mgmt_rp, + sizeof(struct mgmt_cc_rsp_enable_rssi)); + + mgmt_event(MGMT_EV_RSSI_DISABLED, hdev, &mgmt_rp, + sizeof(struct mgmt_cc_rsp_enable_rssi), NULL); + + hci_conn_rssi_state_set(hdev, mgmt_rp.link_type, + &mgmt_rp.bt_address, false); + +remove_cmd: + hci_dev_lock(hdev); + cmd = pending_find(MGMT_OP_SET_RSSI_DISABLE, hdev); + if (cmd) + mgmt_pending_remove(cmd); + + hci_dev_unlock(hdev); +} + +static int mgmt_set_disable_rssi(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + struct mgmt_pending_cmd *cmd; + struct hci_request req; + struct hci_cp_set_enable_rssi cp_en = { 0, }; + int err; + + BT_DBG("Set Disable RSSI."); + + cp_en.hci_le_ext_opcode = 0x01; + cp_en.le_enable_cs_Features = 0x00; + cp_en.data[0] = 0x00; + cp_en.data[1] = 0x00; + cp_en.data[2] = 0x00; + + hci_dev_lock(hdev); + + cmd = pending_find(MGMT_OP_SET_RSSI_DISABLE, hdev); + if (!cmd) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_RSSI_DISABLE, + MGMT_STATUS_FAILED); + goto unlocked; + } + + if (!lmp_le_capable(hdev)) { + mgmt_pending_remove(cmd); + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_RSSI_DISABLE, + MGMT_STATUS_NOT_SUPPORTED); + goto unlocked; + } + + if (!hdev_is_powered(hdev)) { + BT_DBG("%s", hdev->name); + mgmt_pending_remove(cmd); + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_RSSI_DISABLE, + MGMT_STATUS_NOT_POWERED); + goto unlocked; + } + + hci_req_init(&req, hdev); + + BT_DBG("Enable Len: %zu [%2.2X %2.2X %2.2X %2.2X %2.2X]", + sizeof(struct hci_cp_set_enable_rssi), + cp_en.hci_le_ext_opcode, cp_en.le_enable_cs_Features, + cp_en.data[0], cp_en.data[1], cp_en.data[2]); + + hci_req_add(&req, HCI_OP_ENABLE_RSSI, sizeof(cp_en), &cp_en); + err = hci_req_run(&req, set_rssi_disable_complete); + + if (err < 0) { + mgmt_pending_remove(cmd); + BT_ERR("Error in requesting hci_req_run"); + goto unlocked; + } + +unlocked: + hci_dev_unlock(hdev); + return err; +} + +void mgmt_enable_rssi_cc(struct hci_dev *hdev, void *response, u8 status) +{ + struct hci_cc_rsp_enable_rssi *rp = response; + struct mgmt_pending_cmd *cmd_enable = NULL; + struct mgmt_pending_cmd *cmd_disable = NULL; + struct mgmt_cp_set_enable_rssi *cp_en; + struct mgmt_cp_disable_rssi *cp_dis; + + hci_dev_lock(hdev); + cmd_enable = pending_find(MGMT_OP_SET_RSSI_ENABLE, hdev); + cmd_disable = pending_find(MGMT_OP_SET_RSSI_DISABLE, hdev); + hci_dev_unlock(hdev); + + if (cmd_enable) + BT_DBG("Enable Request"); + + if (cmd_disable) + BT_DBG("Disable Request"); + + if (cmd_enable) { + cp_en = cmd_enable->param; + + if (status != 0x00) + return; + + switch (rp->le_ext_opcode) { + case 0x01: + BT_DBG("RSSI enabled.. Setting Threshold..."); + mgmt_set_rssi_threshold(cmd_enable->sk, hdev, + cp_en, sizeof(*cp_en)); + break; + + case 0x0B: + BT_DBG("Sending RSSI enable success"); + mgmt_rssi_enable_success(cmd_enable->sk, hdev, + cp_en, rp, rp->status); + break; + } + + } else if (cmd_disable) { + cp_dis = cmd_disable->param; + + if (status != 0x00) + return; + + switch (rp->le_ext_opcode) { + case 0x01: + BT_DBG("Sending RSSI disable success"); + mgmt_rssi_disable_success(cmd_disable->sk, hdev, + cp_dis, rp, rp->status); + break; + + case 0x0B: + /* + * Only unset RSSI Threshold values for the Link if + * RSSI is monitored for other BREDR or LE Links + */ + if (hci_conn_hash_lookup_rssi_count(hdev) > 1) { + BT_DBG("Unset Threshold. Other links being monitored"); + mgmt_rssi_disable_success(cmd_disable->sk, hdev, + cp_dis, rp, rp->status); + } else { + BT_DBG("Unset Threshold. Disabling..."); + mgmt_set_disable_rssi(cmd_disable->sk, hdev, + cp_dis, sizeof(*cp_dis)); + } + break; + } + } +} + +static void set_rssi_enable_complete(struct hci_dev *hdev, u8 status, + u16 opcode) +{ + struct mgmt_pending_cmd *cmd; + + BT_DBG("status 0x%02x", status); + + hci_dev_lock(hdev); + + cmd = pending_find(MGMT_OP_SET_RSSI_ENABLE, hdev); + if (!cmd) + goto unlock; + + if (status) + mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_RSSI_ENABLE, + mgmt_status(status)); + else + mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_RSSI_ENABLE, 0, + NULL, 0); + + mgmt_pending_remove(cmd); + +unlock: + hci_dev_unlock(hdev); +} + +static int set_enable_rssi(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + struct mgmt_pending_cmd *cmd; + struct hci_request req; + struct mgmt_cp_set_enable_rssi *cp = data; + struct hci_cp_set_enable_rssi cp_en = { 0, }; + int err; + + BT_DBG("Set Enable RSSI."); + + cp_en.hci_le_ext_opcode = 0x01; + cp_en.le_enable_cs_Features = 0x04; + cp_en.data[0] = 0x00; + cp_en.data[1] = 0x00; + cp_en.data[2] = 0x00; + + hci_dev_lock(hdev); + + if (!lmp_le_capable(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_RSSI_ENABLE, + MGMT_STATUS_NOT_SUPPORTED); + goto unlocked; + } + + if (!hdev_is_powered(hdev)) { + BT_DBG("%s", hdev->name); + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_RSSI_ENABLE, + MGMT_STATUS_NOT_POWERED); + goto unlocked; + } + + if (pending_find(MGMT_OP_SET_RSSI_ENABLE, hdev)) { + BT_DBG("%s", hdev->name); + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_RSSI_ENABLE, + MGMT_STATUS_BUSY); + goto unlocked; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_SET_RSSI_ENABLE, hdev, cp, + sizeof(*cp)); + if (!cmd) { + BT_DBG("%s", hdev->name); + err = -ENOMEM; + goto unlocked; + } + + /* If RSSI is already enabled directly set Threshold values */ + if (hci_conn_hash_lookup_rssi_count(hdev) > 0) { + hci_dev_unlock(hdev); + BT_DBG("RSSI Enabled. Directly set Threshold"); + err = mgmt_set_rssi_threshold(sk, hdev, cp, sizeof(*cp)); + return err; + } + + hci_req_init(&req, hdev); + + BT_DBG("Enable Len: %zu [%2.2X %2.2X %2.2X %2.2X %2.2X]", + sizeof(struct hci_cp_set_enable_rssi), + cp_en.hci_le_ext_opcode, cp_en.le_enable_cs_Features, + cp_en.data[0], cp_en.data[1], cp_en.data[2]); + + hci_req_add(&req, HCI_OP_ENABLE_RSSI, sizeof(cp_en), &cp_en); + err = hci_req_run(&req, set_rssi_enable_complete); + + if (err < 0) { + mgmt_pending_remove(cmd); + BT_ERR("Error in requesting hci_req_run"); + goto unlocked; + } + +unlocked: + hci_dev_unlock(hdev); + + return err; +} + +static void get_raw_rssi_complete(struct hci_dev *hdev, u8 status, u16 opcode) +{ + struct mgmt_pending_cmd *cmd; + + BT_DBG("status 0x%02x", status); + + hci_dev_lock(hdev); + + cmd = pending_find(MGMT_OP_GET_RAW_RSSI, hdev); + if (!cmd) + goto unlock; + + mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_GET_RAW_RSSI, + MGMT_STATUS_SUCCESS, &status, 1); + + mgmt_pending_remove(cmd); + +unlock: + hci_dev_unlock(hdev); +} + +static int get_raw_rssi(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) +{ + struct mgmt_pending_cmd *cmd; + struct hci_request req; + struct mgmt_cp_get_raw_rssi *cp = data; + struct hci_cp_get_raw_rssi hci_cp; + + struct hci_conn *conn; + int err; + __u8 dest_type; + + BT_DBG("Get Raw RSSI."); + + hci_dev_lock(hdev); + + if (!lmp_le_capable(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_RAW_RSSI, + MGMT_STATUS_NOT_SUPPORTED); + goto unlocked; + } + + if (cp->link_type == 0x01) + dest_type = LE_LINK; + else + dest_type = ACL_LINK; + + /* Get LE/BREDR link handle info */ + conn = hci_conn_hash_lookup_ba(hdev, + dest_type, &cp->bt_address); + if (!conn) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_RAW_RSSI, + MGMT_STATUS_NOT_CONNECTED); + goto unlocked; + } + hci_cp.conn_handle = conn->handle; + + if (!hdev_is_powered(hdev)) { + BT_DBG("%s", hdev->name); + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_RAW_RSSI, + MGMT_STATUS_NOT_POWERED); + goto unlocked; + } + + if (pending_find(MGMT_OP_GET_RAW_RSSI, hdev)) { + BT_DBG("%s", hdev->name); + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_RAW_RSSI, + MGMT_STATUS_BUSY); + goto unlocked; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_GET_RAW_RSSI, hdev, data, len); + if (!cmd) { + BT_DBG("%s", hdev->name); + err = -ENOMEM; + goto unlocked; + } + + hci_req_init(&req, hdev); + + BT_DBG("Connection Handle [%d]", hci_cp.conn_handle); + hci_req_add(&req, HCI_OP_GET_RAW_RSSI, sizeof(hci_cp), &hci_cp); + err = hci_req_run(&req, get_raw_rssi_complete); + + if (err < 0) { + mgmt_pending_remove(cmd); + BT_ERR("Error in requesting hci_req_run"); + } + +unlocked: + hci_dev_unlock(hdev); + + return err; +} + +void mgmt_raw_rssi_response(struct hci_dev *hdev, + struct hci_cc_rp_get_raw_rssi *rp, int success) +{ + struct mgmt_cc_rp_get_raw_rssi mgmt_rp = { 0, }; + struct hci_conn *conn; + + mgmt_rp.status = rp->status; + mgmt_rp.rssi_dbm = rp->rssi_dbm; + + conn = hci_conn_hash_lookup_handle(hdev, rp->conn_handle); + if (!conn) + return; + + bacpy(&mgmt_rp.bt_address, &conn->dst); + if (conn->type == LE_LINK) + mgmt_rp.link_type = 0x01; + else + mgmt_rp.link_type = 0x00; + + mgmt_event(MGMT_EV_RAW_RSSI, hdev, &mgmt_rp, + sizeof(struct mgmt_cc_rp_get_raw_rssi), NULL); +} + +static void set_disable_threshold_complete(struct hci_dev *hdev, + u8 status, u16 opcode) +{ + struct mgmt_pending_cmd *cmd; + + BT_DBG("status 0x%02x", status); + + hci_dev_lock(hdev); + + cmd = pending_find(MGMT_OP_SET_RSSI_DISABLE, hdev); + if (!cmd) + goto unlock; + + mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_RSSI_DISABLE, + MGMT_STATUS_SUCCESS, &status, 1); + + mgmt_pending_remove(cmd); + +unlock: + hci_dev_unlock(hdev); +} + +/** Removes monitoring for a link*/ +static int set_disable_threshold(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + int err = 0; + struct hci_cp_set_rssi_threshold th = { 0, }; + struct mgmt_cp_disable_rssi *cp = data; + struct hci_conn *conn; + struct mgmt_pending_cmd *cmd; + struct hci_request req; + __u8 dest_type; + + BT_DBG("Set Disable RSSI."); + + hci_dev_lock(hdev); + + if (!lmp_le_capable(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_RSSI_DISABLE, + MGMT_STATUS_NOT_SUPPORTED); + goto unlocked; + } + + /* Get LE/ACL link handle info*/ + if (cp->link_type == 0x01) + dest_type = LE_LINK; + else + dest_type = ACL_LINK; + + conn = hci_conn_hash_lookup_ba(hdev, dest_type, &cp->bdaddr); + if (!conn) { + err = mgmt_cmd_complete(sk, hdev->id, + MGMT_OP_SET_RSSI_DISABLE, 1, NULL, 0); + goto unlocked; + } + + th.hci_le_ext_opcode = 0x0B; + th.mode = 0x01; + th.conn_handle = conn->handle; + th.alert_mask = 0x00; + th.low_th = 0x00; + th.in_range_th = 0x00; + th.high_th = 0x00; + + if (!hdev_is_powered(hdev)) { + BT_DBG("%s", hdev->name); + err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_RSSI_DISABLE, + 0, data, len); + goto unlocked; + } + + if (pending_find(MGMT_OP_SET_RSSI_DISABLE, hdev)) { + BT_DBG("%s", hdev->name); + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_RSSI_DISABLE, + MGMT_STATUS_BUSY); + goto unlocked; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_SET_RSSI_DISABLE, hdev, cp, + sizeof(*cp)); + if (!cmd) { + BT_DBG("%s", hdev->name); + err = -ENOMEM; + goto unlocked; + } + + hci_req_init(&req, hdev); + + hci_req_add(&req, HCI_OP_ENABLE_RSSI, sizeof(th), &th); + err = hci_req_run(&req, set_disable_threshold_complete); + if (err < 0) { + mgmt_pending_remove(cmd); + BT_ERR("Error in requesting hci_req_run"); + goto unlocked; + } + +unlocked: + hci_dev_unlock(hdev); + + return err; +} + +void mgmt_rssi_alert_evt(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_ev_vendor_specific_rssi_alert *ev = (void *)skb->data; + struct mgmt_ev_vendor_specific_rssi_alert mgmt_ev; + struct hci_conn *conn; + + BT_DBG("RSSI alert [%2.2X %2.2X %2.2X]", + ev->conn_handle, ev->alert_type, ev->rssi_dbm); + + conn = hci_conn_hash_lookup_handle(hdev, ev->conn_handle); + + if (!conn) { + BT_ERR("RSSI alert Error: Device not found for handle"); + return; + } + bacpy(&mgmt_ev.bdaddr, &conn->dst); + + if (conn->type == LE_LINK) + mgmt_ev.link_type = 0x01; + else + mgmt_ev.link_type = 0x00; + + mgmt_ev.alert_type = ev->alert_type; + mgmt_ev.rssi_dbm = ev->rssi_dbm; + + mgmt_event(MGMT_EV_RSSI_ALERT, hdev, &mgmt_ev, + sizeof(struct mgmt_ev_vendor_specific_rssi_alert), + NULL); +} #endif /* TIZEN_BT */ static bool ltk_is_valid(struct mgmt_ltk_info *key) @@ -7394,6 +8077,9 @@ static const struct hci_mgmt_handler tizen_mgmt_handlers[] = { { add_white_list, MGMT_ADD_DEV_WHITE_LIST_SIZE }, { remove_from_white_list, MGMT_REMOVE_DEV_FROM_WHITE_LIST_SIZE }, { clear_white_list, MGMT_OP_CLEAR_DEV_WHITE_LIST_SIZE }, + { set_enable_rssi, MGMT_SET_RSSI_ENABLE_SIZE }, + { get_raw_rssi, MGMT_GET_RAW_RSSI_SIZE }, + { set_disable_threshold, MGMT_SET_RSSI_DISABLE_SIZE }, }; #endif -- 2.7.4 From e34861ba152f3b103b80f6b786d54d0f9f2f32a3 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 25 Aug 2016 10:17:19 +0530 Subject: [PATCH 06/16] Bluetooth: Update device name on remote_name_event This patch updates the device name on receiving the HCI event remote_name_event during connection establishment. Change-Id: I9a217e6760b1803a70af201a3f6903e722079749 Signed-off-by: Sudha Bheemanna Signed-off-by: Seung-Woo Kim Signed-off-by: Amit Purwar --- include/net/bluetooth/hci_core.h | 2 ++ include/net/bluetooth/mgmt_tizen.h | 11 +++++++++++ net/bluetooth/hci_event.c | 10 ++++++++++ net/bluetooth/mgmt.c | 24 ++++++++++++++++++++++++ 4 files changed, 47 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 33a567d..7448efa 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1656,6 +1656,8 @@ void mgmt_rssi_alert_evt(struct hci_dev *hdev, struct sk_buff *skb); void mgmt_raw_rssi_response(struct hci_dev *hdev, struct hci_cc_rp_get_raw_rssi *rp, int success); void mgmt_enable_rssi_cc(struct hci_dev *hdev, void *response, u8 status); +int mgmt_device_name_update(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name, + u8 name_len); #endif u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, diff --git a/include/net/bluetooth/mgmt_tizen.h b/include/net/bluetooth/mgmt_tizen.h index 46f652b..102faf0 100644 --- a/include/net/bluetooth/mgmt_tizen.h +++ b/include/net/bluetooth/mgmt_tizen.h @@ -104,6 +104,17 @@ struct mgmt_cc_rp_disable_rssi { } __packed; /* RSSI monitoring */ +/* EVENTS */ + +/* For device name update changes */ +#define MGMT_EV_DEVICE_NAME_UPDATE (TIZEN_EV_BASE + 0x01) +struct mgmt_ev_device_name_update { + struct mgmt_addr_info addr; + __le16 eir_len; + __u8 eir[0]; +} __packed; +/* Device name update changes */ + /* For handling of RSSI Events */ #define MGMT_EV_RSSI_ALERT (TIZEN_EV_BASE + 0x04) struct mgmt_ev_vendor_specific_rssi_alert { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index f7616f7..919271d 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1898,15 +1898,25 @@ static void hci_check_pending_name(struct hci_dev *hdev, struct hci_conn *conn, struct discovery_state *discov = &hdev->discovery; struct inquiry_entry *e; +#ifdef TIZEN_BT /* Update the mgmt connected state if necessary. Be careful with * conn objects that exist but are not (yet) connected however. * Only those in BT_CONFIG or BT_CONNECTED states can be * considered connected. */ if (conn && + (conn->state == BT_CONFIG || conn->state == BT_CONNECTED)) { + if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) + mgmt_device_connected(hdev, conn, 0, name, name_len); + else + mgmt_device_name_update(hdev, bdaddr, name, name_len); + } +#else + if (conn && (conn->state == BT_CONFIG || conn->state == BT_CONNECTED) && !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) mgmt_device_connected(hdev, conn, 0, name, name_len); +#endif if (discov->state == DISCOVERY_STOPPED) return; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f63f7c0..4172a2b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -7163,6 +7163,30 @@ unlock: return err; } +#ifdef TIZEN_BT +int mgmt_device_name_update(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name, + u8 name_len) +{ + char buf[512]; + struct mgmt_ev_device_name_update *ev = (void *)buf; + u16 eir_len = 0; + + if (name_len <= 0) + return -EINVAL; + + bacpy(&ev->addr.bdaddr, bdaddr); + ev->addr.type = BDADDR_BREDR; + + eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name, + name_len); + + ev->eir_len = cpu_to_le16(eir_len); + + return mgmt_event(MGMT_EV_DEVICE_NAME_UPDATE, hdev, buf, + sizeof(*ev) + eir_len, NULL); +} +#endif + static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status, u16 opcode, struct sk_buff *skb) { -- 2.7.4 From ad533092ee5944eba4e419f39213fadbac69ba21 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 25 Aug 2016 11:23:02 +0530 Subject: [PATCH 07/16] Bluetooth: Add BT LE discovery feature This patch adds new MGMT commands to start LE discovery separately and handles LE discovery state. Change-Id: I85958b8c2b5c7e28f57c69e86037ab1e61a75db0 Signed-off-by: Sudha Bheemanna Signed-off-by: Seung-Woo Kim Signed-off-by: Amit Purwar --- include/net/bluetooth/hci_core.h | 7 + include/net/bluetooth/mgmt_tizen.h | 14 ++ net/bluetooth/hci_core.c | 45 +++++++ net/bluetooth/hci_event.c | 4 + net/bluetooth/mgmt.c | 269 +++++++++++++++++++++++++++++++++++++ 5 files changed, 339 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 7448efa..116df10 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -370,6 +370,9 @@ struct hci_dev { void *smp_bredr_data; struct discovery_state discovery; +#ifdef TIZEN_BT + struct discovery_state le_discovery; +#endif struct hci_conn_hash conn_hash; struct list_head mgmt_pending; @@ -960,6 +963,9 @@ static inline int hci_conn_hash_lookup_rssi_count(struct hci_dev *hdev) return count; } + +bool hci_le_discovery_active(struct hci_dev *hdev); +void hci_le_discovery_set_state(struct hci_dev *hdev, int state); #endif int hci_disconnect(struct hci_conn *conn, __u8 reason); @@ -1658,6 +1664,7 @@ void mgmt_raw_rssi_response(struct hci_dev *hdev, void mgmt_enable_rssi_cc(struct hci_dev *hdev, void *response, u8 status); int mgmt_device_name_update(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name, u8 name_len); +void mgmt_le_discovering(struct hci_dev *hdev, u8 discovering); #endif u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, diff --git a/include/net/bluetooth/mgmt_tizen.h b/include/net/bluetooth/mgmt_tizen.h index 102faf0..844af75 100644 --- a/include/net/bluetooth/mgmt_tizen.h +++ b/include/net/bluetooth/mgmt_tizen.h @@ -104,6 +104,20 @@ struct mgmt_cc_rp_disable_rssi { } __packed; /* RSSI monitoring */ +/* For le discovery */ +#define MGMT_OP_START_LE_DISCOVERY (TIZEN_OP_CODE_BASE + 0x0a) +struct mgmt_cp_start_le_discovery { + __u8 type; +} __packed; +#define MGMT_START_LE_DISCOVERY_SIZE 1 + +#define MGMT_OP_STOP_LE_DISCOVERY (TIZEN_OP_CODE_BASE + 0x0b) +struct mgmt_cp_stop_le_discovery { + __u8 type; +} __packed; +#define MGMT_STOP_LE_DISCOVERY_SIZE 1 +/* le discovery */ + /* EVENTS */ /* For device name update changes */ diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index dc4083d..32c29db 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1066,6 +1066,51 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state) } } +#ifdef TIZEN_BT +bool hci_le_discovery_active(struct hci_dev *hdev) +{ + struct discovery_state *discov = &hdev->le_discovery; + + switch (discov->state) { + case DISCOVERY_FINDING: + case DISCOVERY_RESOLVING: + return true; + + default: + return false; + } +} + +void hci_le_discovery_set_state(struct hci_dev *hdev, int state) +{ + BT_DBG("%s state %u -> %u", hdev->name, + hdev->le_discovery.state, state); + + if (hdev->le_discovery.state == state) + return; + + switch (state) { + case DISCOVERY_STOPPED: + hci_update_background_scan(hdev); + + if (hdev->le_discovery.state != DISCOVERY_STARTING) + mgmt_le_discovering(hdev, 0); + break; + case DISCOVERY_STARTING: + break; + case DISCOVERY_FINDING: + mgmt_le_discovering(hdev, 1); + break; + case DISCOVERY_RESOLVING: + break; + case DISCOVERY_STOPPING: + break; + } + + hdev->le_discovery.state = state; +} +#endif + void hci_inquiry_cache_flush(struct hci_dev *hdev) { struct discovery_state *cache = &hdev->discovery; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 919271d..452d699 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1278,7 +1278,11 @@ static void le_set_scan_enable_complete(struct hci_dev *hdev, u8 enable) * re-enable it again if necessary. */ if (hci_dev_test_and_clear_flag(hdev, HCI_LE_SCAN_INTERRUPTED)) +#ifndef TIZEN_BT /* The below line is kernel bug. */ hci_discovery_set_state(hdev, DISCOVERY_STOPPED); +#else + hci_le_discovery_set_state(hdev, DISCOVERY_STOPPED); +#endif else if (!hci_dev_test_flag(hdev, HCI_LE_ADV) && hdev->discovery.state == DISCOVERY_FINDING) hci_req_reenable_advertising(hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 4172a2b..e0692bd 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6211,6 +6211,273 @@ void mgmt_rssi_alert_evt(struct hci_dev *hdev, struct sk_buff *skb) sizeof(struct mgmt_ev_vendor_specific_rssi_alert), NULL); } + +static int mgmt_start_le_discovery_failed(struct hci_dev *hdev, u8 status) +{ + struct mgmt_pending_cmd *cmd; + u8 type; + int err; + + hci_le_discovery_set_state(hdev, DISCOVERY_STOPPED); + + cmd = pending_find(MGMT_OP_START_LE_DISCOVERY, hdev); + if (!cmd) + return -ENOENT; + + type = hdev->le_discovery.type; + + err = mgmt_cmd_complete(cmd->sk, hdev->id, cmd->opcode, + mgmt_status(status), &type, sizeof(type)); + mgmt_pending_remove(cmd); + + return err; +} + +static void start_le_discovery_complete(struct hci_dev *hdev, u8 status, + u16 opcode) +{ + unsigned long timeout = 0; + + BT_DBG("status %d", status); + + if (status) { + hci_dev_lock(hdev); + mgmt_start_le_discovery_failed(hdev, status); + hci_dev_unlock(hdev); + return; + } + + hci_dev_lock(hdev); + hci_le_discovery_set_state(hdev, DISCOVERY_FINDING); + hci_dev_unlock(hdev); + + if (hdev->le_discovery.type != DISCOV_TYPE_LE) + BT_ERR("Invalid discovery type %d", hdev->le_discovery.type); + + if (!timeout) + return; + + queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable, timeout); +} + +static int start_le_discovery(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + struct mgmt_cp_start_le_discovery *cp = data; + struct mgmt_pending_cmd *cmd; + struct hci_cp_le_set_scan_param param_cp; + struct hci_cp_le_set_scan_enable enable_cp; + struct hci_request req; + u8 status, own_addr_type; + int err; + + BT_DBG("%s", hdev->name); + + hci_dev_lock(hdev); + + if (!hdev_is_powered(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_START_LE_DISCOVERY, + MGMT_STATUS_NOT_POWERED); + goto unlock; + } + + if (hdev->le_discovery.state != DISCOVERY_STOPPED) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_START_LE_DISCOVERY, + MGMT_STATUS_BUSY); + goto unlock; + } + + if (cp->type != DISCOV_TYPE_LE) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_START_LE_DISCOVERY, + MGMT_STATUS_INVALID_PARAMS); + goto unlock; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_START_LE_DISCOVERY, hdev, NULL, 0); + if (!cmd) { + err = -ENOMEM; + goto unlock; + } + + hdev->le_discovery.type = cp->type; + + hci_req_init(&req, hdev); + + status = mgmt_le_support(hdev); + if (status) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_START_LE_DISCOVERY, + status); + mgmt_pending_remove(cmd); + goto unlock; + } + + /* If controller is scanning, it means the background scanning + * is running. Thus, we should temporarily stop it in order to + * set the discovery scanning parameters. + */ + if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) + hci_req_add_le_scan_disable(&req); + + memset(¶m_cp, 0, sizeof(param_cp)); + + /* All active scans will be done with either a resolvable + * private address (when privacy feature has been enabled) + * or unresolvable private address. + */ + err = hci_update_random_address(&req, true, hci_dev_test_flag(hdev, HCI_PRIVACY), &own_addr_type); + if (err < 0) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_START_LE_DISCOVERY, + MGMT_STATUS_FAILED); + mgmt_pending_remove(cmd); + goto unlock; + } + + param_cp.type = hdev->le_scan_type; + param_cp.interval = cpu_to_le16(hdev->le_scan_interval); + param_cp.window = cpu_to_le16(hdev->le_scan_window); + param_cp.own_address_type = own_addr_type; + hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp), + ¶m_cp); + + memset(&enable_cp, 0, sizeof(enable_cp)); + enable_cp.enable = LE_SCAN_ENABLE; + enable_cp.filter_dup = LE_SCAN_FILTER_DUP_DISABLE; + + hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp), + &enable_cp); + + err = hci_req_run(&req, start_le_discovery_complete); + if (err < 0) + mgmt_pending_remove(cmd); + else + hci_le_discovery_set_state(hdev, DISCOVERY_STARTING); + +unlock: + hci_dev_unlock(hdev); + return err; +} + +static int mgmt_stop_le_discovery_failed(struct hci_dev *hdev, u8 status) +{ + struct mgmt_pending_cmd *cmd; + int err; + + cmd = pending_find(MGMT_OP_STOP_LE_DISCOVERY, hdev); + if (!cmd) + return -ENOENT; + + err = mgmt_cmd_complete(cmd->sk, hdev->id, cmd->opcode, + mgmt_status(status), &hdev->le_discovery.type, + sizeof(hdev->le_discovery.type)); + mgmt_pending_remove(cmd); + + return err; +} + +static void stop_le_discovery_complete(struct hci_dev *hdev, u8 status, + u16 opcode) +{ + BT_DBG("status %d", status); + + hci_dev_lock(hdev); + + if (status) { + mgmt_stop_le_discovery_failed(hdev, status); + goto unlock; + } + + hci_le_discovery_set_state(hdev, DISCOVERY_STOPPED); + +unlock: + hci_dev_unlock(hdev); +} + +static int stop_le_discovery(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + struct mgmt_cp_stop_le_discovery *mgmt_cp = data; + struct mgmt_pending_cmd *cmd; + struct hci_request req; + int err; + + BT_DBG("%s", hdev->name); + + hci_dev_lock(hdev); + + if (!hci_le_discovery_active(hdev)) { + err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_LE_DISCOVERY, + MGMT_STATUS_REJECTED, &mgmt_cp->type, + sizeof(mgmt_cp->type)); + goto unlock; + } + + if (hdev->le_discovery.type != mgmt_cp->type) { + err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_LE_DISCOVERY, + MGMT_STATUS_INVALID_PARAMS, + &mgmt_cp->type, sizeof(mgmt_cp->type)); + goto unlock; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_STOP_LE_DISCOVERY, hdev, NULL, 0); + if (!cmd) { + err = -ENOMEM; + goto unlock; + } + + hci_req_init(&req, hdev); + + if (hdev->le_discovery.state != DISCOVERY_FINDING) { + BT_DBG("unknown le discovery state %u", + hdev->le_discovery.state); + + mgmt_pending_remove(cmd); + err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_LE_DISCOVERY, + MGMT_STATUS_FAILED, &mgmt_cp->type, + sizeof(mgmt_cp->type)); + goto unlock; + } + + cancel_delayed_work(&hdev->le_scan_disable); + hci_req_add_le_scan_disable(&req); + + err = hci_req_run(&req, stop_le_discovery_complete); + if (err < 0) + mgmt_pending_remove(cmd); + else + hci_le_discovery_set_state(hdev, DISCOVERY_STOPPING); + +unlock: + hci_dev_unlock(hdev); + return err; +} + +/* Separate LE discovery */ +void mgmt_le_discovering(struct hci_dev *hdev, u8 discovering) +{ + struct mgmt_ev_discovering ev; + struct mgmt_pending_cmd *cmd; + + BT_DBG("%s le discovering %u", hdev->name, discovering); + + if (discovering) + cmd = pending_find(MGMT_OP_START_LE_DISCOVERY, hdev); + else + cmd = pending_find(MGMT_OP_STOP_LE_DISCOVERY, hdev); + + if (cmd) { + u8 type = hdev->le_discovery.type; + + mgmt_cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type, + sizeof(type)); + mgmt_pending_remove(cmd); + } + + memset(&ev, 0, sizeof(ev)); + ev.type = hdev->le_discovery.type; + ev.discovering = discovering; + + mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL); +} #endif /* TIZEN_BT */ static bool ltk_is_valid(struct mgmt_ltk_info *key) @@ -8104,6 +8371,8 @@ static const struct hci_mgmt_handler tizen_mgmt_handlers[] = { { set_enable_rssi, MGMT_SET_RSSI_ENABLE_SIZE }, { get_raw_rssi, MGMT_GET_RAW_RSSI_SIZE }, { set_disable_threshold, MGMT_SET_RSSI_DISABLE_SIZE }, + { start_le_discovery, MGMT_START_LE_DISCOVERY_SIZE }, + { stop_le_discovery, MGMT_STOP_LE_DISCOVERY_SIZE }, }; #endif -- 2.7.4 From 342bc20801793c731c402a2154e1e89a59e7f181 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 25 Aug 2016 11:41:34 +0530 Subject: [PATCH 08/16] Bluetooth: Add stop LE auto connection feature Added new MGMT command to disable LE auto connection. Change-Id: I1f5f61b83227501ad54019008b405fd47fd722a3 Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar --- include/net/bluetooth/mgmt_tizen.h | 5 +++++ net/bluetooth/mgmt.c | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/include/net/bluetooth/mgmt_tizen.h b/include/net/bluetooth/mgmt_tizen.h index 844af75..fab5beb 100644 --- a/include/net/bluetooth/mgmt_tizen.h +++ b/include/net/bluetooth/mgmt_tizen.h @@ -118,6 +118,11 @@ struct mgmt_cp_stop_le_discovery { #define MGMT_STOP_LE_DISCOVERY_SIZE 1 /* le discovery */ +/* For LE auto connection */ +#define MGMT_OP_DISABLE_LE_AUTO_CONNECT (TIZEN_OP_CODE_BASE + 0x0c) +#define MGMT_DISABLE_LE_AUTO_CONNECT_SIZE 0 +/* LE auto connection */ + /* EVENTS */ /* For device name update changes */ diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index e0692bd..ca4cc79 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6478,6 +6478,24 @@ void mgmt_le_discovering(struct hci_dev *hdev, u8 discovering) mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL); } + +static int disable_le_auto_connect(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + int err; + + BT_DBG("%s", hdev->name); + + hci_dev_lock(hdev); + + err = hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN_CANCEL, 0, NULL); + if (err < 0) + BT_ERR("HCI_OP_LE_CREATE_CONN_CANCEL is failed"); + + hci_dev_unlock(hdev); + + return err; +} #endif /* TIZEN_BT */ static bool ltk_is_valid(struct mgmt_ltk_info *key) @@ -8373,6 +8391,7 @@ static const struct hci_mgmt_handler tizen_mgmt_handlers[] = { { set_disable_threshold, MGMT_SET_RSSI_DISABLE_SIZE }, { start_le_discovery, MGMT_START_LE_DISCOVERY_SIZE }, { stop_le_discovery, MGMT_STOP_LE_DISCOVERY_SIZE }, + { disable_le_auto_connect, MGMT_DISABLE_LE_AUTO_CONNECT_SIZE }, }; #endif -- 2.7.4 From d86aac7fe2c67f07d25e3f1f04c37406eda62808 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 25 Aug 2016 11:58:22 +0530 Subject: [PATCH 09/16] Bluetooth: Add LE connection parameter update procedure Added new MGMT command to update LE connection parameters Change-Id: I6ae16513437cd42d40e75958aa8415baa1cbedbb Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar --- include/net/bluetooth/hci_core.h | 5 ++ include/net/bluetooth/mgmt_tizen.h | 28 +++++++++++ net/bluetooth/hci_event.c | 14 ++++++ net/bluetooth/mgmt.c | 98 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 145 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 116df10..54bdbd7 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1665,6 +1665,11 @@ void mgmt_enable_rssi_cc(struct hci_dev *hdev, void *response, u8 status); int mgmt_device_name_update(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name, u8 name_len); void mgmt_le_discovering(struct hci_dev *hdev, u8 discovering); +int mgmt_le_conn_updated(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type, + u8 dst_type, u16 conn_interval, u16 conn_latency, + u16 supervision_timeout); +int mgmt_le_conn_update_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 link_type, u8 addr_type, u8 status); #endif u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, diff --git a/include/net/bluetooth/mgmt_tizen.h b/include/net/bluetooth/mgmt_tizen.h index fab5beb..c912a69 100644 --- a/include/net/bluetooth/mgmt_tizen.h +++ b/include/net/bluetooth/mgmt_tizen.h @@ -123,6 +123,18 @@ struct mgmt_cp_stop_le_discovery { #define MGMT_DISABLE_LE_AUTO_CONNECT_SIZE 0 /* LE auto connection */ +/* For Add LE connection parameter update procedure */ +#define MGMT_LE_CONN_UPDATE_SIZE 14 +#define MGMT_OP_LE_CONN_UPDATE (TIZEN_OP_CODE_BASE + 0x0d) +struct mgmt_cp_le_conn_update { + __le16 conn_interval_min; + __le16 conn_interval_max; + __le16 conn_latency; + __le16 supervision_timeout; + bdaddr_t bdaddr; +} __packed; +/* Add LE connection parameter update procedure */ + /* EVENTS */ /* For device name update changes */ @@ -156,4 +168,20 @@ struct mgmt_cc_rp_get_raw_rssi { #define MGMT_EV_RSSI_DISABLED (TIZEN_EV_BASE + 0x07) /* Handling of RSSI Events */ +/* For Add LE connection update Events */ +#define MGMT_EV_CONN_UPDATED (TIZEN_EV_BASE + 0x08) +struct mgmt_ev_conn_updated { + struct mgmt_addr_info addr; + __le16 conn_interval; + __le16 conn_latency; + __le16 supervision_timeout; +} __packed; + +#define MGMT_EV_CONN_UPDATE_FAILED (TIZEN_EV_BASE + 0x09) +struct mgmt_ev_conn_update_failed { + struct mgmt_addr_info addr; + __u8 status; +} __packed; +/* Add LE connection update Events */ + #endif /* __MGMT_TIZEN_H */ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 452d699..c4cf906 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -5062,12 +5062,26 @@ static void hci_le_conn_update_complete_evt(struct hci_dev *hdev, conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); if (conn) { +#ifdef TIZEN_BT + if (ev->status) { + hci_dev_unlock(hdev); + mgmt_le_conn_update_failed(hdev, &conn->dst, + conn->type, conn->dst_type, ev->status); + return; + } +#endif conn->le_conn_interval = le16_to_cpu(ev->interval); conn->le_conn_latency = le16_to_cpu(ev->latency); conn->le_supv_timeout = le16_to_cpu(ev->supervision_timeout); } hci_dev_unlock(hdev); + +#ifdef TIZEN_BT + mgmt_le_conn_updated(hdev, &conn->dst, conn->type, + conn->dst_type, conn->le_conn_interval, + conn->le_conn_latency, conn->le_supv_timeout); +#endif } /* This function requires the caller holds hdev->lock */ diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ca4cc79..6c085f1 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6496,6 +6496,74 @@ static int disable_le_auto_connect(struct sock *sk, struct hci_dev *hdev, return err; } + +static inline int check_le_conn_update_param(u16 min, u16 max, u16 latency, + u16 to_multiplier) +{ + u16 max_latency; + + if (min > max || min < 6 || max > 3200) + return -EINVAL; + + if (to_multiplier < 10 || to_multiplier > 3200) + return -EINVAL; + + if (max >= to_multiplier * 8) + return -EINVAL; + + max_latency = (to_multiplier * 8 / max) - 1; + + if (latency > 499 || latency > max_latency) + return -EINVAL; + + return 0; +} + +static int le_conn_update(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) +{ + struct mgmt_cp_le_conn_update *cp = data; + + struct hci_conn *conn; + u16 min, max, latency, supervision_timeout; + int err = -1; + + if (!hdev_is_powered(hdev)) + return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LE_CONN_UPDATE, + MGMT_STATUS_NOT_POWERED); + + min = __le16_to_cpu(cp->conn_interval_min); + max = __le16_to_cpu(cp->conn_interval_max); + latency = __le16_to_cpu(cp->conn_latency); + supervision_timeout = __le16_to_cpu(cp->supervision_timeout); + + BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x supervision_timeout: 0x%4.4x", + min, max, latency, supervision_timeout); + + err = check_le_conn_update_param(min, max, latency, + supervision_timeout); + + if (err < 0) + return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LE_CONN_UPDATE, + MGMT_STATUS_INVALID_PARAMS); + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr); + if (!conn) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_LE_CONN_UPDATE, + MGMT_STATUS_NOT_CONNECTED); + hci_dev_unlock(hdev); + return err; + } + + hci_dev_unlock(hdev); + + hci_le_conn_update(conn, min, max, latency, supervision_timeout); + + return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LE_CONN_UPDATE, 0, + NULL, 0); +} #endif /* TIZEN_BT */ static bool ltk_is_valid(struct mgmt_ltk_info *key) @@ -7470,6 +7538,35 @@ int mgmt_device_name_update(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name, return mgmt_event(MGMT_EV_DEVICE_NAME_UPDATE, hdev, buf, sizeof(*ev) + eir_len, NULL); } + +int mgmt_le_conn_update_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 link_type, u8 addr_type, u8 status) +{ + struct mgmt_ev_conn_update_failed ev; + + bacpy(&ev.addr.bdaddr, bdaddr); + ev.addr.type = link_to_bdaddr(link_type, addr_type); + ev.status = status; + + return mgmt_event(MGMT_EV_CONN_UPDATE_FAILED, hdev, + &ev, sizeof(ev), NULL); +} + +int mgmt_le_conn_updated(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 link_type, u8 addr_type, u16 conn_interval, + u16 conn_latency, u16 supervision_timeout) +{ + struct mgmt_ev_conn_updated ev; + + bacpy(&ev.addr.bdaddr, bdaddr); + ev.addr.type = link_to_bdaddr(link_type, addr_type); + ev.conn_interval = cpu_to_le16(conn_interval); + ev.conn_latency = cpu_to_le16(conn_latency); + ev.supervision_timeout = cpu_to_le16(supervision_timeout); + + return mgmt_event(MGMT_EV_CONN_UPDATED, hdev, + &ev, sizeof(ev), NULL); +} #endif static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status, @@ -8392,6 +8489,7 @@ static const struct hci_mgmt_handler tizen_mgmt_handlers[] = { { start_le_discovery, MGMT_START_LE_DISCOVERY_SIZE }, { stop_le_discovery, MGMT_STOP_LE_DISCOVERY_SIZE }, { disable_le_auto_connect, MGMT_DISABLE_LE_AUTO_CONNECT_SIZE }, + { le_conn_update, MGMT_LE_CONN_UPDATE_SIZE }, }; #endif -- 2.7.4 From 46a63f6344d02b4f654288c315e801d296c338d2 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 25 Aug 2016 12:13:09 +0530 Subject: [PATCH 10/16] Bluetooth: Set Manufacturer data feature Added new MGMT command to set the manufacturer data in the BR/EDR packet. Change-Id: Ie08062f4cad0c676deab94fd95fdc1a8c5602135 Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar --- include/net/bluetooth/hci_core.h | 6 ++ include/net/bluetooth/mgmt_tizen.h | 8 +++ net/bluetooth/mgmt.c | 122 +++++++++++++++++++++++++++++++++++++ 3 files changed, 136 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 54bdbd7..cfbf41d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -202,6 +202,10 @@ struct amp_assoc { #define HCI_MAX_PAGES 3 +#ifdef TIZEN_BT +#define HCI_MAX_EIR_MANUFACTURER_DATA_LENGTH 100 +#endif + struct hci_dev { struct list_head list; struct mutex lock; @@ -427,6 +431,8 @@ struct hci_dev { #ifdef TIZEN_BT __u8 adv_filter_policy; __u8 adv_type; + __u8 manufacturer_len; + __u8 manufacturer_data[HCI_MAX_EIR_MANUFACTURER_DATA_LENGTH]; #endif int (*open)(struct hci_dev *hdev); diff --git a/include/net/bluetooth/mgmt_tizen.h b/include/net/bluetooth/mgmt_tizen.h index c912a69..4f24c42 100644 --- a/include/net/bluetooth/mgmt_tizen.h +++ b/include/net/bluetooth/mgmt_tizen.h @@ -135,6 +135,14 @@ struct mgmt_cp_le_conn_update { } __packed; /* Add LE connection parameter update procedure */ +/* For Set Manufacturer Data */ +#define MGMT_OP_SET_MANUFACTURER_DATA (TIZEN_OP_CODE_BASE + 0x0e) +struct mgmt_cp_set_manufacturer_data { + __u8 data[100]; +} __packed; +#define MGMT_SET_MANUFACTURER_DATA_SIZE 100 +/* Set Manufacturer Data */ + /* EVENTS */ /* For device name update changes */ diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 6c085f1..9146a37 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6564,6 +6564,127 @@ static int le_conn_update(struct sock *sk, struct hci_dev *hdev, void *data, return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LE_CONN_UPDATE, 0, NULL, 0); } + +static void set_manufacturer_data_complete(struct hci_dev *hdev, u8 status, + u16 opcode) +{ + struct mgmt_cp_set_manufacturer_data *cp; + struct mgmt_pending_cmd *cmd; + + BT_DBG("status 0x%02x", status); + + hci_dev_lock(hdev); + + cmd = pending_find(MGMT_OP_SET_MANUFACTURER_DATA, hdev); + if (!cmd) + goto unlock; + + cp = cmd->param; + + if (status) + mgmt_cmd_status(cmd->sk, hdev->id, + MGMT_OP_SET_MANUFACTURER_DATA, + mgmt_status(status)); + else + mgmt_cmd_complete(cmd->sk, hdev->id, + MGMT_OP_SET_MANUFACTURER_DATA, 0, + cp, sizeof(*cp)); + + mgmt_pending_remove(cmd); + +unlock: + hci_dev_unlock(hdev); +} + +static int set_manufacturer_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_manufacturer_data *cp = data; + u8 old_data[HCI_MAX_EIR_LENGTH] = {0, }; + u8 old_len; + int err; + + BT_DBG("%s", hdev->name); + + if (!lmp_bredr_capable(hdev)) + return mgmt_cmd_status(sk, hdev->id, + MGMT_OP_SET_MANUFACTURER_DATA, + MGMT_STATUS_NOT_SUPPORTED); + + if (cp->data[0] == 0 || + cp->data[0] - 1 > sizeof(hdev->manufacturer_data)) + return mgmt_cmd_status(sk, hdev->id, + MGMT_OP_SET_MANUFACTURER_DATA, + MGMT_STATUS_INVALID_PARAMS); + + if (cp->data[1] != 0xFF) + return mgmt_cmd_status(sk, hdev->id, + MGMT_OP_SET_MANUFACTURER_DATA, + MGMT_STATUS_NOT_SUPPORTED); + + hci_dev_lock(hdev); + + if (pending_find(MGMT_OP_SET_MANUFACTURER_DATA, hdev)) { + err = mgmt_cmd_status(sk, hdev->id, + MGMT_OP_SET_MANUFACTURER_DATA, + MGMT_STATUS_BUSY); + goto unlocked; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_SET_MANUFACTURER_DATA, hdev, data, + len); + if (!cmd) { + err = -ENOMEM; + goto unlocked; + } + + hci_req_init(&req, hdev); + + /* if new data is same as previous data then return command + * complete event + */ + if (hdev->manufacturer_len == cp->data[0] - 1 && + !memcmp(hdev->manufacturer_data, cp->data + 2, cp->data[0] - 1)) { + mgmt_pending_remove(cmd); + mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_MANUFACTURER_DATA, + 0, cp, sizeof(*cp)); + err = 0; + goto unlocked; + } + + old_len = hdev->manufacturer_len; + if (old_len > 0) + memcpy(old_data, hdev->manufacturer_data, old_len); + + hdev->manufacturer_len = cp->data[0] - 1; + if (hdev->manufacturer_len > 0) + memcpy(hdev->manufacturer_data, cp->data + 2, + hdev->manufacturer_len); + + __hci_req_update_eir(&req); + + err = hci_req_run(&req, set_manufacturer_data_complete); + if (err < 0) { + mgmt_pending_remove(cmd); + goto failed; + } + +unlocked: + hci_dev_unlock(hdev); + + return err; + +failed: + memset(hdev->manufacturer_data, 0x00, sizeof(hdev->manufacturer_data)); + hdev->manufacturer_len = old_len; + if (hdev->manufacturer_len > 0) + memcpy(hdev->manufacturer_data, old_data, + hdev->manufacturer_len); + hci_dev_unlock(hdev); + return err; +} #endif /* TIZEN_BT */ static bool ltk_is_valid(struct mgmt_ltk_info *key) @@ -8490,6 +8611,7 @@ static const struct hci_mgmt_handler tizen_mgmt_handlers[] = { { stop_le_discovery, MGMT_STOP_LE_DISCOVERY_SIZE }, { disable_le_auto_connect, MGMT_DISABLE_LE_AUTO_CONNECT_SIZE }, { le_conn_update, MGMT_LE_CONN_UPDATE_SIZE }, + { set_manufacturer_data, MGMT_SET_MANUFACTURER_DATA_SIZE }, }; #endif -- 2.7.4 From d538cc72892331d21dace4fe5bf27af40d60ca2e Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 25 Aug 2016 12:46:07 +0530 Subject: [PATCH 11/16] Bluetooth: Add set LE scan parameter feature Added new MGMT command to set LE scan parameters Change-Id: I5ea660f97e93dfcc72273971ad0250e7f582f718 Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar --- include/net/bluetooth/mgmt_tizen.h | 8 ++++++ net/bluetooth/mgmt.c | 59 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/include/net/bluetooth/mgmt_tizen.h b/include/net/bluetooth/mgmt_tizen.h index 4f24c42..4c2e9d0 100644 --- a/include/net/bluetooth/mgmt_tizen.h +++ b/include/net/bluetooth/mgmt_tizen.h @@ -143,6 +143,14 @@ struct mgmt_cp_set_manufacturer_data { #define MGMT_SET_MANUFACTURER_DATA_SIZE 100 /* Set Manufacturer Data */ +#define MGMT_OP_LE_SET_SCAN_PARAMS (TIZEN_OP_CODE_BASE + 0x0f) +struct mgmt_cp_le_set_scan_params { + __u8 type; /* le scan type */ + __le16 interval; + __le16 window; +} __packed; +#define MGMT_LE_SET_SCAN_PARAMS_SIZE 5 + /* EVENTS */ /* For device name update changes */ diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9146a37..afadd7c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6685,6 +6685,64 @@ failed: hci_dev_unlock(hdev); return err; } + +static int le_set_scan_params(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + struct mgmt_cp_le_set_scan_params *cp = data; + __u16 interval, window; + int err; + + BT_DBG("%s", hdev->name); + + if (!lmp_le_capable(hdev)) + return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LE_SET_SCAN_PARAMS, + MGMT_STATUS_NOT_SUPPORTED); + + interval = __le16_to_cpu(cp->interval); + + if (interval < 0x0004 || interval > 0x4000) + return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LE_SET_SCAN_PARAMS, + MGMT_STATUS_INVALID_PARAMS); + + window = __le16_to_cpu(cp->window); + + if (window < 0x0004 || window > 0x4000) + return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LE_SET_SCAN_PARAMS, + MGMT_STATUS_INVALID_PARAMS); + + if (window > interval) + return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LE_SET_SCAN_PARAMS, + MGMT_STATUS_INVALID_PARAMS); + + hci_dev_lock(hdev); + + hdev->le_scan_type = cp->type; + hdev->le_scan_interval = interval; + hdev->le_scan_window = window; + + err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LE_SET_SCAN_PARAMS, 0, + NULL, 0); + + /* If background scan is running, restart it so new parameters are + * loaded. + */ + if (hci_dev_test_flag(hdev, HCI_LE_SCAN) && + hdev->discovery.state == DISCOVERY_STOPPED) { + struct hci_request req; + + hci_req_init(&req, hdev); + + hci_req_add_le_scan_disable(&req); + hci_req_add_le_passive_scan(&req); + + hci_req_run(&req, NULL); + } + + hci_dev_unlock(hdev); + + return err; +} #endif /* TIZEN_BT */ static bool ltk_is_valid(struct mgmt_ltk_info *key) @@ -8612,6 +8670,7 @@ static const struct hci_mgmt_handler tizen_mgmt_handlers[] = { { disable_le_auto_connect, MGMT_DISABLE_LE_AUTO_CONNECT_SIZE }, { le_conn_update, MGMT_LE_CONN_UPDATE_SIZE }, { set_manufacturer_data, MGMT_SET_MANUFACTURER_DATA_SIZE }, + { le_set_scan_params, MGMT_LE_SET_SCAN_PARAMS_SIZE }, }; #endif -- 2.7.4 From 90d3f0dce7fb1ba148d0bf3bf3f34db5f7c99c4d Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 8 Sep 2016 10:56:15 +0530 Subject: [PATCH 12/16] Bluetooth: Add LE vendor specific event handler This patch adds the vendor specific LE meta event handler. It handles the vendor specific handles like, LE_MULTI_ADV_STATE_CHANGE_SUB_EVENT, LE_RSSI_LINK_ALERT. Change-Id: I1f344a31e36f9c7442fe0bd8b598e67d9f5fb9bf Signed-off-by: Sudha Bheemanna [divide hci vendor speicif group event function] Signed-off-by: Seung-Woo Kim Signed-off-by: Amit Purwar --- include/net/bluetooth/hci.h | 19 +++++++++++++++++ net/bluetooth/hci_event.c | 50 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index a5c140e..94aa9c1 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -2096,6 +2096,25 @@ struct hci_ev_sync_train_complete { #define HCI_EV_SLAVE_PAGE_RESP_TIMEOUT 0x54 +#ifdef TIZEN_BT +/* + * Vendor Specific HCI Event + * Vendor: Broadcom + * Purpose: This HCI Event gives RSSI Alerts for monitored LE Link + */ +#define HCI_EV_VENDOR_SPECIFIC 0xFF +struct hci_ev_vendor_specific { + __u8 event_sub_code; +} __packed; + +#define LE_META_VENDOR_SPECIFIC_GROUP_EVENT 0xE9 +struct hci_ev_ext_vendor_specific { + __u8 event_le_ext_sub_code; +} __packed; + +#define LE_RSSI_LINK_ALERT 0x02 +#endif + #define HCI_EV_LE_CONN_COMPLETE 0x01 struct hci_ev_le_conn_complete { __u8 status; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index c4cf906..77f1d10 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1630,6 +1630,50 @@ static void hci_cc_get_raw_rssi(struct hci_dev *hdev, mgmt_raw_rssi_response(hdev, rp, rp->status); } + +static void hci_vendor_specific_group_ext_evt(struct hci_dev *hdev, + struct sk_buff *skb) +{ + struct hci_ev_ext_vendor_specific *ev = (void *)skb->data; + __u8 event_le_ext_sub_code; + + BT_DBG("RSSI event LE_META_VENDOR_SPECIFIC_GROUP_EVENT: %X", + LE_META_VENDOR_SPECIFIC_GROUP_EVENT); + + skb_pull(skb, sizeof(*ev)); + event_le_ext_sub_code = ev->event_le_ext_sub_code; + + switch (event_le_ext_sub_code) { + case LE_RSSI_LINK_ALERT: + BT_DBG("RSSI event LE_RSSI_LINK_ALERT %X", + LE_RSSI_LINK_ALERT); + mgmt_rssi_alert_evt(hdev, skb); + break; + + default: + break; + } +} + +static void hci_vendor_specific_evt(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_ev_vendor_specific *ev = (void *)skb->data; + __u8 event_sub_code; + + BT_DBG("hci_vendor_specific_evt"); + + skb_pull(skb, sizeof(*ev)); + event_sub_code = ev->event_sub_code; + + switch (event_sub_code) { + case LE_META_VENDOR_SPECIFIC_GROUP_EVENT: + hci_vendor_specific_group_ext_evt(hdev, skb); + break; + + default: + break; + } +} #endif static void hci_cc_read_rssi(struct hci_dev *hdev, struct sk_buff *skb) @@ -5974,6 +6018,12 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) hci_num_comp_blocks_evt(hdev, skb); break; +#ifdef TIZEN_BT + case HCI_EV_VENDOR_SPECIFIC: + hci_vendor_specific_evt(hdev, skb); + break; +#endif + default: BT_DBG("%s event 0x%2.2x", hdev->name, event); break; -- 2.7.4 From 4eba792a3433ff0b39afa00fe40cd948beab6182 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Wed, 7 Sep 2016 15:42:22 +0530 Subject: [PATCH 13/16] Bluetooth: Add hardware error MGMT event Add code to handle hardware error MGMT event. Change-Id: I5875ea2aeae7aba95c1f8e15b456704dc6bcdee4 Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar --- include/net/bluetooth/hci_core.h | 1 + include/net/bluetooth/mgmt_tizen.h | 7 +++++++ net/bluetooth/hci_event.c | 5 +++++ net/bluetooth/mgmt.c | 8 ++++++++ 4 files changed, 21 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index cfbf41d..6998103 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1676,6 +1676,7 @@ int mgmt_le_conn_updated(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type, u16 supervision_timeout); int mgmt_le_conn_update_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status); +void mgmt_hardware_error(struct hci_dev *hdev, u8 err_code); #endif u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, diff --git a/include/net/bluetooth/mgmt_tizen.h b/include/net/bluetooth/mgmt_tizen.h index 4c2e9d0..680ad8b 100644 --- a/include/net/bluetooth/mgmt_tizen.h +++ b/include/net/bluetooth/mgmt_tizen.h @@ -162,6 +162,13 @@ struct mgmt_ev_device_name_update { } __packed; /* Device name update changes */ +/* For handling of hardware error event */ +#define MGMT_EV_HARDWARE_ERROR (TIZEN_EV_BASE + 0x02) +struct mgmt_ev_hardware_error { + __u8 error_code; +} __packed; +/* handling of hardware error event */ + /* For handling of RSSI Events */ #define MGMT_EV_RSSI_ALERT (TIZEN_EV_BASE + 0x04) struct mgmt_ev_vendor_specific_rssi_alert { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 77f1d10..457849a 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3574,6 +3574,11 @@ static void hci_hardware_error_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_hardware_error *ev = (void *) skb->data; +#ifdef TIZEN_BT + hci_dev_lock(hdev); + mgmt_hardware_error(hdev, ev->code); + hci_dev_unlock(hdev); +#endif hdev->hw_error_code = ev->code; queue_work(hdev->req_workqueue, &hdev->error_reset); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index afadd7c..6481015 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6743,6 +6743,14 @@ static int le_set_scan_params(struct sock *sk, struct hci_dev *hdev, return err; } + +void mgmt_hardware_error(struct hci_dev *hdev, u8 err_code) +{ + struct mgmt_ev_hardware_error ev; + + ev.error_code = err_code; + mgmt_event(MGMT_EV_HARDWARE_ERROR, hdev, &ev, sizeof(ev), NULL); +} #endif /* TIZEN_BT */ static bool ltk_is_valid(struct mgmt_ltk_info *key) -- 2.7.4 From dffc37fa57bc0338738313e55067fee8b73bc33a Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Wed, 7 Sep 2016 16:47:58 +0530 Subject: [PATCH 14/16] Bluetooth: Add H/W TX timeout error MGMT event This patch sends the H/W TX timeout error MGMT event if HCI command timeout occurs after sending HCI commands. Change-Id: I5eb593f2fe4d31c404dd94ef582790e47d03b10a Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar --- include/net/bluetooth/hci.h | 4 ++++ include/net/bluetooth/hci_core.h | 1 + include/net/bluetooth/mgmt_tizen.h | 4 ++++ net/bluetooth/hci_core.c | 11 +++++++++++ net/bluetooth/mgmt.c | 5 +++++ 5 files changed, 25 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 94aa9c1..252e0bf 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -279,7 +279,11 @@ enum { #define HCI_DISCONN_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ #define HCI_PAIRING_TIMEOUT msecs_to_jiffies(60000) /* 60 seconds */ #define HCI_INIT_TIMEOUT msecs_to_jiffies(10000) /* 10 seconds */ +#ifdef TIZEN_BT +#define HCI_CMD_TIMEOUT msecs_to_jiffies(5000) /* 5 seconds */ +#else #define HCI_CMD_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ +#endif #define HCI_ACL_TX_TIMEOUT msecs_to_jiffies(45000) /* 45 seconds */ #define HCI_AUTO_OFF_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ #define HCI_POWER_OFF_TIMEOUT msecs_to_jiffies(5000) /* 5 seconds */ diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 6998103..50b3132 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1677,6 +1677,7 @@ int mgmt_le_conn_updated(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type, int mgmt_le_conn_update_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status); void mgmt_hardware_error(struct hci_dev *hdev, u8 err_code); +void mgmt_tx_timeout_error(struct hci_dev *hdev); #endif u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, diff --git a/include/net/bluetooth/mgmt_tizen.h b/include/net/bluetooth/mgmt_tizen.h index 680ad8b..fd5a9fe 100644 --- a/include/net/bluetooth/mgmt_tizen.h +++ b/include/net/bluetooth/mgmt_tizen.h @@ -169,6 +169,10 @@ struct mgmt_ev_hardware_error { } __packed; /* handling of hardware error event */ +/* For HCI TX Timeout Error */ +#define MGMT_EV_TX_TIMEOUT_ERROR (TIZEN_EV_BASE + 0x03) +/* HCI TX Timeout Error */ + /* For handling of RSSI Events */ #define MGMT_EV_RSSI_ALERT (TIZEN_EV_BASE + 0x04) struct mgmt_ev_vendor_specific_rssi_alert { diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 32c29db..fb289c1 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1109,6 +1109,13 @@ void hci_le_discovery_set_state(struct hci_dev *hdev, int state) hdev->le_discovery.state = state; } + +static void hci_tx_timeout_error_evt(struct hci_dev *hdev) +{ + BT_ERR("%s H/W TX Timeout error", hdev->name); + + mgmt_tx_timeout_error(hdev); +} #endif void hci_inquiry_cache_flush(struct hci_dev *hdev) @@ -2623,6 +2630,10 @@ static void hci_cmd_timeout(struct work_struct *work) bt_dev_err(hdev, "command tx timeout"); } +#ifdef TIZEN_BT + hci_tx_timeout_error_evt(hdev); +#endif + atomic_set(&hdev->cmd_cnt, 1); queue_work(hdev->workqueue, &hdev->cmd_work); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 6481015..9e5b85f 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6751,6 +6751,11 @@ void mgmt_hardware_error(struct hci_dev *hdev, u8 err_code) ev.error_code = err_code; mgmt_event(MGMT_EV_HARDWARE_ERROR, hdev, &ev, sizeof(ev), NULL); } + +void mgmt_tx_timeout_error(struct hci_dev *hdev) +{ + mgmt_event(MGMT_EV_TX_TIMEOUT_ERROR, hdev, NULL, 0, NULL); +} #endif /* TIZEN_BT */ static bool ltk_is_valid(struct mgmt_ltk_info *key) -- 2.7.4 From 222edf542abbc77a957e594a88b10998bafd3ac2 Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Thu, 29 Sep 2016 01:59:05 +0900 Subject: [PATCH 15/16] Bluetooth: fix vendor ext rssi link alert event This patch fixes style for rssi link alert event from vendor specific group ext. Change-Id: I0e7003e417c5f5a590cce8264caccad515dd3c10 Signed-off-by: Seung-Woo Kim Signed-off-by: Amit Purwar --- include/net/bluetooth/hci.h | 11 +++++------ include/net/bluetooth/hci_core.h | 3 ++- net/bluetooth/hci_event.c | 15 ++++++++++++--- net/bluetooth/mgmt.c | 12 ++++++------ 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 252e0bf..7fe16b5 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1708,12 +1708,6 @@ struct hci_cc_rsp_enable_rssi { __u8 le_ext_opcode; } __packed; -struct hci_ev_vendor_specific_rssi_alert { - __le16 conn_handle; - __s8 alert_type; - __s8 rssi_dbm; -} __packed; - /* * Vendor Specific HCI Command * Vendor: Broadcom @@ -2117,6 +2111,11 @@ struct hci_ev_ext_vendor_specific { } __packed; #define LE_RSSI_LINK_ALERT 0x02 +struct hci_ev_vendor_specific_rssi_alert { + __le16 conn_handle; + __s8 alert_type; + __s8 rssi_dbm; +} __packed; #endif #define HCI_EV_LE_CONN_COMPLETE 0x01 diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 50b3132..0538dea 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1664,7 +1664,8 @@ void mgmt_rssi_disable_success(struct sock *sk, struct hci_dev *hdev, void *data, struct hci_cc_rsp_enable_rssi *rp, int success); int mgmt_set_rssi_threshold(struct sock *sk, struct hci_dev *hdev, void *data, u16 len); -void mgmt_rssi_alert_evt(struct hci_dev *hdev, struct sk_buff *skb); +void mgmt_rssi_alert_evt(struct hci_dev *hdev, u16 conn_handle, + s8 alert_type, s8 rssi_dbm); void mgmt_raw_rssi_response(struct hci_dev *hdev, struct hci_cc_rp_get_raw_rssi *rp, int success); void mgmt_enable_rssi_cc(struct hci_dev *hdev, void *response, u8 status); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 457849a..2fa62e5 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1631,6 +1631,17 @@ static void hci_cc_get_raw_rssi(struct hci_dev *hdev, mgmt_raw_rssi_response(hdev, rp, rp->status); } +static void hci_vendor_ext_rssi_link_alert_evt(struct hci_dev *hdev, + struct sk_buff *skb) +{ + struct hci_ev_vendor_specific_rssi_alert *ev = (void *)skb->data; + + BT_DBG("RSSI event LE_RSSI_LINK_ALERT %X", LE_RSSI_LINK_ALERT); + + mgmt_rssi_alert_evt(hdev, ev->conn_handle, ev->alert_type, + ev->rssi_dbm); +} + static void hci_vendor_specific_group_ext_evt(struct hci_dev *hdev, struct sk_buff *skb) { @@ -1645,9 +1656,7 @@ static void hci_vendor_specific_group_ext_evt(struct hci_dev *hdev, switch (event_le_ext_sub_code) { case LE_RSSI_LINK_ALERT: - BT_DBG("RSSI event LE_RSSI_LINK_ALERT %X", - LE_RSSI_LINK_ALERT); - mgmt_rssi_alert_evt(hdev, skb); + hci_vendor_ext_rssi_link_alert_evt(hdev, skb); break; default: diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9e5b85f..78d0b2f 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6182,16 +6182,16 @@ unlocked: return err; } -void mgmt_rssi_alert_evt(struct hci_dev *hdev, struct sk_buff *skb) +void mgmt_rssi_alert_evt(struct hci_dev *hdev, u16 conn_handle, + s8 alert_type, s8 rssi_dbm) { - struct hci_ev_vendor_specific_rssi_alert *ev = (void *)skb->data; struct mgmt_ev_vendor_specific_rssi_alert mgmt_ev; struct hci_conn *conn; BT_DBG("RSSI alert [%2.2X %2.2X %2.2X]", - ev->conn_handle, ev->alert_type, ev->rssi_dbm); + conn_handle, alert_type, rssi_dbm); - conn = hci_conn_hash_lookup_handle(hdev, ev->conn_handle); + conn = hci_conn_hash_lookup_handle(hdev, conn_handle); if (!conn) { BT_ERR("RSSI alert Error: Device not found for handle"); @@ -6204,8 +6204,8 @@ void mgmt_rssi_alert_evt(struct hci_dev *hdev, struct sk_buff *skb) else mgmt_ev.link_type = 0x00; - mgmt_ev.alert_type = ev->alert_type; - mgmt_ev.rssi_dbm = ev->rssi_dbm; + mgmt_ev.alert_type = alert_type; + mgmt_ev.rssi_dbm = rssi_dbm; mgmt_event(MGMT_EV_RSSI_ALERT, hdev, &mgmt_ev, sizeof(struct mgmt_ev_vendor_specific_rssi_alert), -- 2.7.4 From ab4abe03b59a6ac1262b739b2f148c1fde92c630 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 8 Sep 2016 10:10:03 +0530 Subject: [PATCH 16/16] Bluetooth: Add LE device found MGMT event This patch adds new MGMT event for LE device discovery and allows the handling of all advertisement packets in platform. Change-Id: I1927acb75eff0b60a5899898c6d7a000e1a108ef Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar --- include/net/bluetooth/hci.h | 7 +++++++ include/net/bluetooth/hci_core.h | 6 ++++++ include/net/bluetooth/mgmt_tizen.h | 22 ++++++++++++++++++++ net/bluetooth/hci_event.c | 20 ++++++++++++++++++ net/bluetooth/mgmt.c | 42 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 97 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 7fe16b5..87f9ffc 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -2116,6 +2116,13 @@ struct hci_ev_vendor_specific_rssi_alert { __s8 alert_type; __s8 rssi_dbm; } __packed; + +#define LE_MULTI_ADV_STATE_CHANGE_SUB_EVENT 0x55 +struct hci_ev_vendor_specific_multi_adv_state { + __u8 adv_instance; + __u8 state_change_reason; + __le16 connection_handle; +} __packed; #endif #define HCI_EV_LE_CONN_COMPLETE 0x01 diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 0538dea..2780ba9 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1679,6 +1679,12 @@ int mgmt_le_conn_update_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status); void mgmt_hardware_error(struct hci_dev *hdev, u8 err_code); void mgmt_tx_timeout_error(struct hci_dev *hdev); +/* Pass adv type in the le device found */ +void mgmt_le_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, + u8 addr_type, u8 *dev_class, s8 rssi, u32 flags, u8 *eir, + u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len, u8 adv_type); +void mgmt_multi_adv_state_change_evt(struct hci_dev *hdev, u8 adv_instance, + u8 state_change_reason, u16 connection_handle); #endif u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, diff --git a/include/net/bluetooth/mgmt_tizen.h b/include/net/bluetooth/mgmt_tizen.h index fd5a9fe..504c2d4 100644 --- a/include/net/bluetooth/mgmt_tizen.h +++ b/include/net/bluetooth/mgmt_tizen.h @@ -211,4 +211,26 @@ struct mgmt_ev_conn_update_failed { } __packed; /* Add LE connection update Events */ +/* For LE device found event */ +#define MGMT_EV_LE_DEVICE_FOUND (TIZEN_EV_BASE + 0x0a) +struct mgmt_ev_le_device_found { + struct mgmt_addr_info addr; + __s8 rssi; + __le32 flags; + __s8 adv_type; + __le16 eir_len; + __u8 eir[0]; +} __packed; +/* LE device found event */ + +/* For LE advertisement state changed event */ +#define MGMT_EV_MULTI_ADV_STATE_CHANGED (TIZEN_EV_BASE + 0x0b) +struct mgmt_ev_vendor_specific_multi_adv_state_changed { + __u8 adv_instance; + __u8 state_change_reason; + __le16 connection_handle; +} __packed; +/* LE advertisement state changed event */ + + #endif /* __MGMT_TIZEN_H */ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 2fa62e5..62e3a31 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1223,6 +1223,7 @@ static void clear_pending_adv_report(struct hci_dev *hdev) d->last_adv_data_len = 0; } +#ifndef TIZEN_BT static void store_pending_adv_report(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type, s8 rssi, u32 flags, u8 *data, u8 len) @@ -1236,6 +1237,7 @@ static void store_pending_adv_report(struct hci_dev *hdev, bdaddr_t *bdaddr, memcpy(d->last_adv_data, data, len); d->last_adv_data_len = len; } +#endif static void le_set_scan_enable_complete(struct hci_dev *hdev, u8 enable) { @@ -5235,10 +5237,14 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, u8 bdaddr_type, bdaddr_t *direct_addr, u8 direct_addr_type, s8 rssi, u8 *data, u8 len) { +#ifndef TIZEN_BT struct discovery_state *d = &hdev->discovery; +#endif struct smp_irk *irk; struct hci_conn *conn; +#ifndef TIZEN_BT bool match; +#endif u32 flags; u8 *ptr, real_len; @@ -5330,16 +5336,24 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, if (type == LE_ADV_DIRECT_IND) return; +#ifndef TIZEN_BT + /* Handle all adv packet in platform */ if (!hci_pend_le_action_lookup(&hdev->pend_le_reports, bdaddr, bdaddr_type)) return; +#endif if (type == LE_ADV_NONCONN_IND || type == LE_ADV_SCAN_IND) flags = MGMT_DEV_FOUND_NOT_CONNECTABLE; else flags = 0; +#ifdef TIZEN_BT + mgmt_le_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL, + rssi, flags, data, len, NULL, 0, type); +#else mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL, rssi, flags, data, len, NULL, 0); +#endif return; } @@ -5364,6 +5378,11 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, else flags = 0; +#ifdef TIZEN_BT + /* Disable adv ind and scan rsp merging */ + mgmt_le_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL, + rssi, flags, data, len, NULL, 0, type); +#else /* If there's nothing pending either store the data from this * event or send an immediate device found event if the data * should not be stored for later. @@ -5426,6 +5445,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, d->last_adv_addr_type, NULL, rssi, d->last_adv_flags, d->last_adv_data, d->last_adv_data_len, data, len); clear_pending_adv_report(hdev); +#endif } static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 78d0b2f..27563d2 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -7759,6 +7759,48 @@ int mgmt_le_conn_updated(struct hci_dev *hdev, bdaddr_t *bdaddr, return mgmt_event(MGMT_EV_CONN_UPDATED, hdev, &ev, sizeof(ev), NULL); } + +/* le device found event - Pass adv type */ +void mgmt_le_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, + u8 addr_type, u8 *dev_class, s8 rssi, u32 flags, u8 *eir, + u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len, u8 adv_type) +{ + char buf[512]; + struct mgmt_ev_le_device_found *ev = (void *)buf; + size_t ev_size; + + if (!hci_discovery_active(hdev) && !hci_le_discovery_active(hdev)) + return; + + /* Make sure that the buffer is big enough. The 5 extra bytes + * are for the potential CoD field. + */ + if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf)) + return; + + memset(buf, 0, sizeof(buf)); + + bacpy(&ev->addr.bdaddr, bdaddr); + ev->addr.type = link_to_bdaddr(link_type, addr_type); + ev->rssi = rssi; + ev->flags = cpu_to_le32(flags); + ev->adv_type = adv_type; + + if (eir_len > 0) + memcpy(ev->eir, eir, eir_len); + + if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV, NULL)) + eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV, + dev_class, 3); + + if (scan_rsp_len > 0) + memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len); + + ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len); + ev_size = sizeof(*ev) + eir_len + scan_rsp_len; + + mgmt_event(MGMT_EV_LE_DEVICE_FOUND, hdev, ev, ev_size, NULL); +} #endif static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status, -- 2.7.4