From 57318d3ffcd7eef2237ac65cd5171d3149a914c9 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 25 Aug 2016 11:23:02 +0530 Subject: [PATCH 01/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: I68218f1e666ed5850ca2b81efe956272c83d30d1 Signed-off-by: Sudha Bheemanna Signed-off-by: Seung-Woo Kim Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung --- 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 | 266 +++++++++++++++++++++++++++++++++++++ 5 files changed, 336 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index b65780d..03a6c65 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -572,6 +572,9 @@ struct hci_dev { u8 wake_reason; bdaddr_t wake_addr; u8 wake_addr_type; +#ifdef TIZEN_BT + struct discovery_state le_discovery; +#endif struct hci_conn_hash conn_hash; @@ -1517,6 +1520,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); @@ -2370,6 +2376,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 int hci_abort_conn(struct hci_conn *conn, u8 reason); 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 5943609..24d6dae 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -175,6 +175,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_passive_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 6f2f46b..19dc4f9 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1816,7 +1816,11 @@ static void le_set_scan_enable_complete(struct hci_dev *hdev, u8 enable) * therefore discovery as stopped. */ 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) queue_work(hdev->workqueue, &hdev->reenable_adv_work); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 65e6c0a..5495ab7c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -8300,6 +8300,270 @@ 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); + + 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, false); + + 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_sync(hdev, 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: + 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, false); + + 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) @@ -10556,6 +10820,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 f56aa578a504fc943dc5a077c09fa5805701a6fc Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 25 Aug 2016 11:41:34 +0530 Subject: [PATCH 02/16] Bluetooth: Add stop LE auto connection feature Added new MGMT command to disable LE auto connection. Change-Id: Ifd2dd85ea6368dad76f6753f442ffd94f53fc208 Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung --- 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 5495ab7c..ec09e63 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -8564,6 +8564,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) @@ -10822,6 +10840,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 590a9030b094c5c60469686db47722992d813d27 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 25 Aug 2016 11:58:22 +0530 Subject: [PATCH 03/16] Bluetooth: Add LE connection parameter update procedure Added new MGMT command to update LE connection parameters Change-Id: I44d366eb6f6b3aa090b34e3e314becd7b96537af Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung --- 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 03a6c65..4541b81 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -2377,6 +2377,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 int hci_abort_conn(struct hci_conn *conn, u8 reason); 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 19dc4f9..af3acd72 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -6202,12 +6202,26 @@ static void hci_le_conn_update_complete_evt(struct hci_dev *hdev, void *data, 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 ec09e63..0de45a9 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -8582,6 +8582,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) @@ -9515,6 +9583,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, void *data, @@ -10841,6 +10938,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 5ce7ba4cf0704feffd386ec1e78d7dd60c20a45e Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 25 Aug 2016 12:13:09 +0530 Subject: [PATCH 04/16] Bluetooth: Set Manufacturer data feature Added new MGMT command to set the manufacturer data in the BR/EDR packet. Change-Id: I1b97854795eec10f9f8481a96709abcd0ba26b52 Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung --- 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 4541b81..016c598 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -351,6 +351,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; @@ -665,6 +669,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 0de45a9..bbc5a4f 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -8650,6 +8650,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_update_eir_sync(hdev); + + 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) @@ -10939,6 +11060,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 5e6bd9b73b2119bc194bc6f0c5a49b5708a4f423 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 25 Aug 2016 12:46:07 +0530 Subject: [PATCH 05/16] Bluetooth: Add set LE scan parameter feature Added new MGMT command to set LE scan parameters Change-Id: I851cb2181bd626adc1f7f80297d37480a010b52d Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung --- 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 bbc5a4f..7fe034e 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -8771,6 +8771,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, false); + 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) @@ -11061,6 +11119,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 0ff33064fd15cfda2509cdcd7cf996dfc4509017 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 8 Sep 2016 10:56:15 +0530 Subject: [PATCH 06/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. Signed-off-by: Sudha Bheemanna [divide hci vendor speicif group event function] Signed-off-by: Seung-Woo Kim Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung Change-Id: I75395d8a0df5393eadc4be89aad8daefc89f507e --- include/net/bluetooth/hci.h | 19 +++++++++++++++++ net/bluetooth/hci_event.c | 51 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 03bdb16..ba13cfd 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -2670,6 +2670,25 @@ struct hci_ev_sync_train_complete { #define HCI_EV_PERIPHERAL_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 af3acd72..1cae8aa 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2264,6 +2264,51 @@ static u8 hci_cc_get_raw_rssi(struct hci_dev *hdev, void *data, return 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, void *data, + 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 u8 hci_cc_read_rssi(struct hci_dev *hdev, void *data, @@ -7713,8 +7758,14 @@ static const struct hci_ev { /* [0x48 = HCI_EV_NUM_COMP_BLOCKS] */ HCI_EV(HCI_EV_NUM_COMP_BLOCKS, hci_num_comp_blocks_evt, sizeof(struct hci_ev_num_comp_blocks)), +#ifdef TIZEN_BT + /* [0xFF = HCI_EV_VENDOR_SPECIFIC] */ + HCI_EV(HCI_EV_VENDOR_SPECIFIC, hci_vendor_specific_evt, + sizeof(struct hci_ev_vendor_specific)), +#else /* [0xff = HCI_EV_VENDOR] */ HCI_EV_VL(HCI_EV_VENDOR, msft_vendor_evt, 0, HCI_MAX_EVENT_SIZE), +#endif }; static void hci_event_func(struct hci_dev *hdev, u8 event, struct sk_buff *skb, -- 2.7.4 From d84be01f5f6466848f6093143c1e515d1440da47 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Wed, 7 Sep 2016 15:42:22 +0530 Subject: [PATCH 07/16] Bluetooth: Add hardware error MGMT event Add code to handle hardware error MGMT event. Change-Id: I7966385b6711b944baa17a7ebe671cc94b3e948e Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung --- 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 016c598..7657824 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -2388,6 +2388,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 int hci_abort_conn(struct hci_conn *conn, u8 reason); 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 1cae8aa..02fbc7c 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4495,6 +4495,11 @@ static void hci_hardware_error_evt(struct hci_dev *hdev, void *data, bt_dev_dbg(hdev, "code 0x%2.2x", ev->code); +#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 7fe034e..52bca43 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -8829,6 +8829,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 e6dd8dab0df501f927d9c950b0938bdf7da9872f Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Wed, 7 Sep 2016 16:47:58 +0530 Subject: [PATCH 08/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: If1da7ae0633d9b99c76c982810d65ee2e466fc9e Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung --- 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 ba13cfd..33446aa 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -433,7 +433,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_NCMD_TIMEOUT msecs_to_jiffies(4000) /* 4 seconds */ #define HCI_ACL_TX_TIMEOUT msecs_to_jiffies(45000) /* 45 seconds */ #define HCI_AUTO_OFF_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 7657824..5a10159 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -2389,6 +2389,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 int hci_abort_conn(struct hci_conn *conn, u8 reason); 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 24d6dae..3a87f4f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -218,6 +218,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) @@ -1547,6 +1554,10 @@ static void hci_cmd_timeout(struct work_struct *work) if (hdev->cmd_timeout) hdev->cmd_timeout(hdev); +#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 52bca43..43b23ab 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -8837,6 +8837,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 8d383c2ae001bee46dca8bd6d49cf400643283da Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Thu, 29 Sep 2016 01:59:05 +0900 Subject: [PATCH 09/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: Ib78a778cef9233bd7c63dae4ffcd49aeb167c1b0 Signed-off-by: Seung-Woo Kim Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung --- 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 33446aa..6640c46 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -2264,12 +2264,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 @@ -2691,6 +2685,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 5a10159..44bef8e 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -2376,7 +2376,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 02fbc7c..c53bdb0 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2265,6 +2265,17 @@ static u8 hci_cc_get_raw_rssi(struct hci_dev *hdev, void *data, return 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) { @@ -2279,9 +2290,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 43b23ab..52d4ecd 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -8271,16 +8271,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"); @@ -8293,8 +8293,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 3f69cf3e7df3d8f0ba51f015eff7b37bebe7380f Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 8 Sep 2016 10:10:03 +0530 Subject: [PATCH 10/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: Ifff3ccb291a3a0fc23256763e089613ee4efbec4 Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung --- 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 | 21 ++++++++++++++++++- net/bluetooth/mgmt.c | 42 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 97 insertions(+), 1 deletion(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 6640c46..de473e2 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -2690,6 +2690,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 44bef8e..02588f4 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -2391,6 +2391,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 int hci_abort_conn(struct hci_conn *conn, u8 reason); 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 c53bdb0..9f69420 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1759,6 +1759,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) @@ -1775,6 +1776,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) { @@ -6380,10 +6382,13 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, u8 direct_addr_type, s8 rssi, u8 *data, u8 len, bool ext_adv, bool ctl_time, u64 instant) { +#ifndef TIZEN_BT struct discovery_state *d = &hdev->discovery; + bool match; +#endif struct smp_irk *irk; struct hci_conn *conn; - bool match, bdaddr_resolved; + bool bdaddr_resolved; u32 flags; u8 *ptr; @@ -6496,13 +6501,21 @@ 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) && idr_is_empty(&hdev->adv_monitors_idr)) return; +#endif +#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, 0); +#endif return; } @@ -6519,6 +6532,11 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, if (type == LE_ADV_SCAN_RSP) flags = MGMT_DEV_FOUND_SCAN_RSP; +#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. @@ -6582,6 +6600,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, 0); clear_pending_adv_report(hdev); +#endif } static void hci_le_adv_report_evt(struct hci_dev *hdev, void *data, diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 52d4ecd..ccbe063 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -9804,6 +9804,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, void *data, -- 2.7.4 From 04f03369821a31e3bde6e078638a7d4b7c8cca35 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 8 Sep 2016 10:31:17 +0530 Subject: [PATCH 11/16] Bluetooth: Add multiple LE advertise state change event This patch adds code for providing multiple LE advertisement state changed event to upper layer. Signed-off-by: Sudha Bheemanna [divide hci_vendor_mutli_adv_state_change_evt and remove hci event structure from mgmt] Signed-off-by: Seung-Woo Kim Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung Change-Id: I203e677538646b8107d43a5ac7653ce717ca44ef --- net/bluetooth/hci_event.c | 16 ++++++++++++++++ net/bluetooth/mgmt.c | 17 +++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 9f69420..4eebc73 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2300,6 +2300,18 @@ static void hci_vendor_specific_group_ext_evt(struct hci_dev *hdev, } } +static void hci_vendor_multi_adv_state_change_evt(struct hci_dev *hdev, + struct sk_buff *skb) +{ + struct hci_ev_vendor_specific_multi_adv_state *ev = (void *)skb->data; + + BT_DBG("LE_MULTI_ADV_STATE_CHANGE_SUB_EVENT"); + + mgmt_multi_adv_state_change_evt(hdev, ev->adv_instance, + ev->state_change_reason, + ev->connection_handle); +} + static void hci_vendor_specific_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb) { @@ -2316,6 +2328,10 @@ static void hci_vendor_specific_evt(struct hci_dev *hdev, void *data, hci_vendor_specific_group_ext_evt(hdev, skb); break; + case LE_MULTI_ADV_STATE_CHANGE_SUB_EVENT: + hci_vendor_multi_adv_state_change_evt(hdev, skb); + break; + default: break; } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ccbe063..9333af0 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -8842,6 +8842,23 @@ void mgmt_tx_timeout_error(struct hci_dev *hdev) { mgmt_event(MGMT_EV_TX_TIMEOUT_ERROR, hdev, NULL, 0, NULL); } + +void mgmt_multi_adv_state_change_evt(struct hci_dev *hdev, u8 adv_instance, + u8 state_change_reason, u16 connection_handle) +{ + struct mgmt_ev_vendor_specific_multi_adv_state_changed mgmt_ev; + + BT_DBG("Multi adv state changed [%2.2X %2.2X %2.2X]", + adv_instance, state_change_reason, connection_handle); + + mgmt_ev.adv_instance = adv_instance; + mgmt_ev.state_change_reason = state_change_reason; + mgmt_ev.connection_handle = connection_handle; + + mgmt_event(MGMT_EV_MULTI_ADV_STATE_CHANGED, hdev, &mgmt_ev, + sizeof(struct mgmt_ev_vendor_specific_multi_adv_state_changed), + NULL); +} #endif /* TIZEN_BT */ static bool ltk_is_valid(struct mgmt_ltk_info *key) -- 2.7.4 From 82df6a4f4d7cbd7b925a21be5b91ade6557a063b Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Tue, 6 Sep 2016 16:38:36 +0530 Subject: [PATCH 12/16] Bluetooth: Add MGMT command to set SCO settings Added code to set sco settings. Signed-off-by: Sudha Bheemanna [remove sco link policy part] Signed-off-by: Seung-Woo Kim Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung Change-Id: I5d7a594e50a37b7886dd6b9b9c90ea00c0bc9dda --- include/net/bluetooth/hci.h | 23 +++++++++++++++++++++++ include/net/bluetooth/hci_core.h | 19 +++++++++++++++++++ include/net/bluetooth/mgmt_tizen.h | 10 ++++++++++ include/net/bluetooth/sco.h | 7 +++++++ 4 files changed, 59 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index de473e2..4b9df2d 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -2280,6 +2280,29 @@ struct hci_cc_rp_get_raw_rssi { __le16 conn_handle; __s8 rssi_dbm; } __packed; + +#define HCI_BCM_ENABLE_WBS_REQ 0xfc7e +struct hci_cp_bcm_wbs_req { + __u8 role; + __le16 pkt_type; +} __packed; + +#define HCI_BCM_I2C_PCM_REQ 0xfc6d +struct hci_cp_i2c_pcm_req { + __u8 i2c_enable; + __u8 is_master; + __u8 pcm_rate; + __u8 clock_rate; +} __packed; + +#define HCI_BCM_SCO_PCM_REQ 0xfc1c +struct hci_cp_sco_pcm_req { + __u8 sco_routing; + __u8 pcm_rate; + __u8 frame_type; + __u8 sync_mode; + __u8 clock_mode; +} __packed; #endif /* ---- HCI Events ---- */ diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 02588f4..8258305 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -792,6 +792,8 @@ struct hci_conn { #ifdef TIZEN_BT bool rssi_monitored; + __u8 sco_role; + __u16 voice_setting; #endif struct list_head link_list; struct hci_conn *parent; @@ -1529,6 +1531,23 @@ static inline int hci_conn_hash_lookup_rssi_count(struct hci_dev *hdev) bool hci_le_discovery_active(struct hci_dev *hdev); void hci_le_discovery_set_state(struct hci_dev *hdev, int state); + +static inline struct hci_conn *hci_conn_hash_lookup_sco(struct hci_dev *hdev) +{ + struct hci_conn_hash *h = &hdev->conn_hash; + struct hci_conn *c; + + rcu_read_lock(); + list_for_each_entry_rcu(c, &h->list, list) { + if (c->type == SCO_LINK || c->type == ESCO_LINK) { + rcu_read_unlock(); + return c; + } + } + rcu_read_unlock(); + + return NULL; +} #endif int hci_disconnect(struct hci_conn *conn, __u8 reason); diff --git a/include/net/bluetooth/mgmt_tizen.h b/include/net/bluetooth/mgmt_tizen.h index 504c2d4..4eaa867 100644 --- a/include/net/bluetooth/mgmt_tizen.h +++ b/include/net/bluetooth/mgmt_tizen.h @@ -151,6 +151,16 @@ struct mgmt_cp_le_set_scan_params { } __packed; #define MGMT_LE_SET_SCAN_PARAMS_SIZE 5 +#define MGMT_SCO_ROLE_HANDSFREE 0x00 +#define MGMT_SCO_ROLE_AUDIO_GATEWAY 0x01 +#define MGMT_OP_SET_VOICE_SETTING (TIZEN_OP_CODE_BASE + 0x10) +struct mgmt_cp_set_voice_setting { + bdaddr_t bdaddr; + uint8_t sco_role; + uint16_t voice_setting; +} __packed; +#define MGMT_SET_VOICE_SETTING_SIZE 9 + /* EVENTS */ /* For device name update changes */ diff --git a/include/net/bluetooth/sco.h b/include/net/bluetooth/sco.h index f40ddb4..bca05bf 100644 --- a/include/net/bluetooth/sco.h +++ b/include/net/bluetooth/sco.h @@ -46,4 +46,11 @@ struct sco_conninfo { __u8 dev_class[3]; }; +#ifdef TIZEN_BT +void sco_connect_set_gw_nbc(struct hci_dev *hdev); +void sco_connect_set_gw_wbc(struct hci_dev *hdev); +void sco_connect_set_nbc(struct hci_dev *hdev); +void sco_connect_set_wbc(struct hci_dev *hdev); +#endif + #endif /* __SCO_H */ -- 2.7.4 From 43cc1acefac2f4568ae4e126551659d6bc231753 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 8 Sep 2016 12:37:45 +0530 Subject: [PATCH 13/16] Bluetooth: Set the link for SCO connection This patch sets the link policy for SCO/eSCO connection. Signed-off-by: Sudha Bheemanna [add link policy setting in sco connection] Signed-off-by: Seung-Woo Kim Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung Change-Id: I285b1f15404fe612f6e3a54881207dbcb373554d --- net/bluetooth/hci_conn.c | 19 +++++ net/bluetooth/hci_event.c | 29 ++++++++ net/bluetooth/mgmt.c | 57 +++++++++++++++ net/bluetooth/sco.c | 182 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 287 insertions(+) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 1fdf4b9..66e6a128 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -50,6 +50,16 @@ struct conn_handle_t { __u16 handle; }; +#ifdef TIZEN_BT +static const struct sco_param esco_param_cvsd[] = { + { (EDR_ESCO_MASK & ~ESCO_2EV3) | SCO_ESCO_MASK | ESCO_EV3, + 0x000a, 0x01 }, /* S3 */ + { EDR_ESCO_MASK & ~ESCO_2EV3, 0x0007, 0x01 }, /* S2 */ + { EDR_ESCO_MASK | ESCO_EV3, 0x0007, 0x01 }, /* S1 */ + { EDR_ESCO_MASK | ESCO_HV3, 0xffff, 0x01 }, /* D1 */ + { EDR_ESCO_MASK | ESCO_HV1, 0xffff, 0x01 }, /* D0 */ +}; +#else static const struct sco_param esco_param_cvsd[] = { { EDR_ESCO_MASK & ~ESCO_2EV3, 0x000a, 0x01 }, /* S3 */ { EDR_ESCO_MASK & ~ESCO_2EV3, 0x0007, 0x01 }, /* S2 */ @@ -57,16 +67,25 @@ static const struct sco_param esco_param_cvsd[] = { { EDR_ESCO_MASK | ESCO_HV3, 0xffff, 0x01 }, /* D1 */ { EDR_ESCO_MASK | ESCO_HV1, 0xffff, 0x01 }, /* D0 */ }; +#endif static const struct sco_param sco_param_cvsd[] = { { EDR_ESCO_MASK | ESCO_HV3, 0xffff, 0xff }, /* D1 */ { EDR_ESCO_MASK | ESCO_HV1, 0xffff, 0xff }, /* D0 */ }; +#ifdef TIZEN_BT +static const struct sco_param esco_param_msbc[] = { + { (EDR_ESCO_MASK & ~ESCO_2EV3) | ESCO_EV3, + 0x000d, 0x02 }, /* T2 */ + { EDR_ESCO_MASK & ~ESCO_2EV3, 0x000d, 0x02 }, /* T2 */ +}; +#else static const struct sco_param esco_param_msbc[] = { { EDR_ESCO_MASK & ~ESCO_2EV3, 0x000d, 0x02 }, /* T2 */ { EDR_ESCO_MASK | ESCO_EV3, 0x0008, 0x02 }, /* T1 */ }; +#endif /* This function requires the caller holds hdev->lock */ static void hci_connect_le_scan_cleanup(struct hci_conn *conn, u8 status) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 4eebc73..ea450a1 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -217,6 +217,10 @@ static u8 hci_cc_write_link_policy(struct hci_dev *hdev, void *data, struct hci_rp_write_link_policy *rp = data; struct hci_conn *conn; void *sent; +#ifdef TIZEN_BT + struct hci_cp_write_link_policy cp; + struct hci_conn *sco_conn; +#endif bt_dev_dbg(hdev, "status 0x%2.2x", rp->status); @@ -233,6 +237,17 @@ static u8 hci_cc_write_link_policy(struct hci_dev *hdev, void *data, if (conn) conn->link_policy = get_unaligned_le16(sent + 2); +#ifdef TIZEN_BT + sco_conn = hci_conn_hash_lookup_sco(hdev); + if (sco_conn && bacmp(&sco_conn->dst, &conn->dst) == 0 && + conn->link_policy & HCI_LP_SNIFF) { + BT_ERR("SNIFF is not allowed during sco connection"); + cp.handle = __cpu_to_le16(conn->handle); + cp.policy = __cpu_to_le16(conn->link_policy & ~HCI_LP_SNIFF); + hci_send_cmd(hdev, HCI_OP_WRITE_LINK_POLICY, sizeof(cp), &cp); + } +#endif + hci_dev_unlock(hdev); return rp->status; @@ -3444,6 +3459,20 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data, if (ie) memcpy(ie->data.dev_class, ev->dev_class, 3); +#ifdef TIZEN_BT + if ((ev->link_type == SCO_LINK || ev->link_type == ESCO_LINK) && + hci_conn_hash_lookup_sco(hdev)) { + struct hci_cp_reject_conn_req cp; + + bacpy(&cp.bdaddr, &ev->bdaddr); + cp.reason = HCI_ERROR_REJ_LIMITED_RESOURCES; + hci_send_cmd(hdev, HCI_OP_REJECT_CONN_REQ, + sizeof(cp), &cp); + hci_dev_unlock(hdev); + return; + } +#endif + conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr); if (!conn) { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9333af0..74142dd 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -34,6 +34,7 @@ #include #ifdef TIZEN_BT #include +#include #endif #include "hci_request.h" @@ -8830,6 +8831,61 @@ static int le_set_scan_params(struct sock *sk, struct hci_dev *hdev, return err; } +static int set_voice_setting(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + struct mgmt_cp_set_voice_setting *cp = data; + struct hci_conn *conn; + struct hci_conn *sco_conn; + + int err; + + BT_DBG("%s", hdev->name); + + if (!lmp_bredr_capable(hdev)) { + return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_VOICE_SETTING, + MGMT_STATUS_NOT_SUPPORTED); + } + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); + if (!conn) { + err = mgmt_cmd_complete(sk, hdev->id, + MGMT_OP_SET_VOICE_SETTING, 0, NULL, 0); + goto unlock; + } + + conn->voice_setting = cp->voice_setting; + conn->sco_role = cp->sco_role; + + sco_conn = hci_conn_hash_lookup_sco(hdev); + if (sco_conn && bacmp(&sco_conn->dst, &cp->bdaddr) != 0) { + BT_ERR("There is other SCO connection."); + goto done; + } + + if (conn->sco_role == MGMT_SCO_ROLE_HANDSFREE) { + if (conn->voice_setting == 0x0063) + sco_connect_set_wbc(hdev); + else + sco_connect_set_nbc(hdev); + } else { + if (conn->voice_setting == 0x0063) + sco_connect_set_gw_wbc(hdev); + else + sco_connect_set_gw_nbc(hdev); + } + +done: + err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_VOICE_SETTING, 0, + cp, sizeof(cp)); + +unlock: + hci_dev_unlock(hdev); + return err; +} + void mgmt_hardware_error(struct hci_dev *hdev, u8 err_code) { struct mgmt_ev_hardware_error ev; @@ -11192,6 +11248,7 @@ static const struct hci_mgmt_handler tizen_mgmt_handlers[] = { { 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 }, + { set_voice_setting, MGMT_SET_VOICE_SETTING_SIZE }, }; #endif diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index c736186..6524cc9 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -33,6 +33,11 @@ #include #include +#ifdef TIZEN_BT +#include +#include +#endif + static bool disable_esco; static const struct proto_ops sco_sock_ops; @@ -869,8 +874,15 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname, } /* Explicitly check for these values */ +#ifdef TIZEN_BT + /* Codec defer accept */ + if (voice.setting != (BT_VOICE_TRANSPARENT | + BT_VOICE_CVSD_16BIT) && + voice.setting != BT_VOICE_CVSD_16BIT) { +#else if (voice.setting != BT_VOICE_TRANSPARENT && voice.setting != BT_VOICE_CVSD_16BIT) { +#endif err = -EINVAL; break; } @@ -1252,6 +1264,10 @@ static int sco_sock_release(struct socket *sock) release_sock(sk); } +#ifdef TIZEN_BT + /* SCO kernel panic fix */ + bt_sock_unlink(&sco_sk_list, sk); +#endif sock_orphan(sk); sco_sock_kill(sk); return err; @@ -1278,7 +1294,12 @@ static void sco_conn_ready(struct sco_conn *conn) return; } +#ifdef TIZEN_BT + /* Multiple SCO accept feature */ + parent = sco_get_sock_listen(&conn->hcon->dst); +#else parent = sco_get_sock_listen(&conn->hcon->src); +#endif if (!parent) { sco_conn_unlock(conn); return; @@ -1316,6 +1337,131 @@ static void sco_conn_ready(struct sco_conn *conn) } } +#ifdef TIZEN_BT +/* WBC/NBC feature */ +void sco_connect_set_gw_nbc(struct hci_dev *hdev) +{ + struct hci_cp_write_voice_setting cp1; + struct hci_cp_bcm_wbs_req cp2; + struct hci_cp_i2c_pcm_req cp3; + struct hci_cp_sco_pcm_req cp4; + + BT_DBG("Setting the NBC params, hdev = %p", hdev); + + cp1.voice_setting = cpu_to_le16(0x0060); + hci_send_cmd(hdev, HCI_OP_WRITE_VOICE_SETTING, sizeof(cp1), &cp1); + hdev->voice_setting = cpu_to_le16(0x0060); + + cp2.role = 0x00; /* WbDisable */ + cp2.pkt_type = cpu_to_le16(0x0002); + hci_send_cmd(hdev, HCI_BCM_ENABLE_WBS_REQ, sizeof(cp2), &cp2); + + cp3.i2c_enable = 0x01; + cp3.is_master = 0x00; + cp3.pcm_rate = 0x00; + cp3.clock_rate = 0x01; + hci_send_cmd(hdev, HCI_BCM_I2C_PCM_REQ, sizeof(cp3), &cp3); + + cp4.sco_routing = 0x00; + cp4.pcm_rate = 0x01; + cp4.frame_type = 0x00; + cp4.sync_mode = 0x00; + cp4.clock_mode = 0x00; + hci_send_cmd(hdev, HCI_BCM_SCO_PCM_REQ, sizeof(cp4), &cp4); +} + +void sco_connect_set_gw_wbc(struct hci_dev *hdev) +{ + struct hci_cp_write_voice_setting cp1; + struct hci_cp_bcm_wbs_req cp2; + struct hci_cp_i2c_pcm_req cp3; + struct hci_cp_sco_pcm_req cp4; + + BT_DBG("Setting the WBC params, hdev = %p", hdev); + cp1.voice_setting = cpu_to_le16(0x0003 | 0x0060); + hci_send_cmd(hdev, HCI_OP_WRITE_VOICE_SETTING, sizeof(cp1), &cp1); + hdev->voice_setting = cpu_to_le16(0x0003 | 0x0060); + + cp2.role = 0x01; /* Enable */ + cp2.pkt_type = cpu_to_le16(0x0002); + hci_send_cmd(hdev, HCI_BCM_ENABLE_WBS_REQ, sizeof(cp2), &cp2); + + cp3.i2c_enable = 0x00; + cp3.is_master = 0x00; + cp3.pcm_rate = 0x01; + cp3.clock_rate = 0x02; + hci_send_cmd(hdev, HCI_BCM_I2C_PCM_REQ, sizeof(cp3), &cp3); + + cp4.sco_routing = 0x00; + cp4.pcm_rate = 0x00; + cp4.frame_type = 0x00; + cp4.sync_mode = 0x00; + cp4.clock_mode = 0x00; + hci_send_cmd(hdev, HCI_BCM_SCO_PCM_REQ, sizeof(cp4), &cp4); +} + +void sco_connect_set_nbc(struct hci_dev *hdev) +{ + struct hci_cp_write_voice_setting cp1; + struct hci_cp_bcm_wbs_req cp2; + struct hci_cp_i2c_pcm_req cp3; + struct hci_cp_sco_pcm_req cp4; + + BT_DBG("Setting the NBC params, hdev = %p", hdev); + + cp1.voice_setting = cpu_to_le16(0x0060); + hci_send_cmd(hdev, HCI_OP_WRITE_VOICE_SETTING, sizeof(cp1), &cp1); + hdev->voice_setting = cpu_to_le16(0x0060); + + cp2.role = 0x00; /* WbDisable */ + cp2.pkt_type = cpu_to_le16(0x0002); + hci_send_cmd(hdev, HCI_BCM_ENABLE_WBS_REQ, sizeof(cp2), &cp2); + + cp3.i2c_enable = 0x00; + cp3.is_master = 0x00; + cp3.pcm_rate = 0x00; + cp3.clock_rate = 0x04; + hci_send_cmd(hdev, HCI_BCM_I2C_PCM_REQ, sizeof(cp3), &cp3); + + cp4.sco_routing = 0x00; + cp4.pcm_rate = 0x04; + cp4.frame_type = 0x00; + cp4.sync_mode = 0x00; + cp4.clock_mode = 0x00; + hci_send_cmd(hdev, HCI_BCM_SCO_PCM_REQ, sizeof(cp4), &cp4); +} + +void sco_connect_set_wbc(struct hci_dev *hdev) +{ + struct hci_cp_write_voice_setting cp1; + struct hci_cp_bcm_wbs_req cp2; + struct hci_cp_i2c_pcm_req cp3; + struct hci_cp_sco_pcm_req cp4; + + BT_DBG("Setting the WBC params, hdev = %p", hdev); + cp1.voice_setting = cpu_to_le16(0x0003 | 0x0060); + hci_send_cmd(hdev, HCI_OP_WRITE_VOICE_SETTING, sizeof(cp1), &cp1); + hdev->voice_setting = cpu_to_le16(0x0003 | 0x0060); + + cp2.role = 0x01; /* Enable */ + cp2.pkt_type = cpu_to_le16(0x0002); + hci_send_cmd(hdev, HCI_BCM_ENABLE_WBS_REQ, sizeof(cp2), &cp2); + + cp3.i2c_enable = 0x00; + cp3.is_master = 0x00; + cp3.pcm_rate = 0x01; + cp3.clock_rate = 0x04; + hci_send_cmd(hdev, HCI_BCM_I2C_PCM_REQ, sizeof(cp3), &cp3); + + cp4.sco_routing = 0x00; + cp4.pcm_rate = 0x04; + cp4.frame_type = 0x00; + cp4.sync_mode = 0x00; + cp4.clock_mode = 0x00; + hci_send_cmd(hdev, HCI_BCM_SCO_PCM_REQ, sizeof(cp4), &cp4); +} +#endif + /* ----- SCO interface with lower layer (HCI) ----- */ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags) { @@ -1330,8 +1476,14 @@ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags) if (sk->sk_state != BT_LISTEN) continue; +#ifdef TIZEN_BT + /* Multiple SCO accept feature */ + if (!bacmp(&sco_pi(sk)->src, bdaddr) || + !bacmp(&sco_pi(sk)->src, BDADDR_ANY)) { +#else if (!bacmp(&sco_pi(sk)->src, &hdev->bdaddr) || !bacmp(&sco_pi(sk)->src, BDADDR_ANY)) { +#endif lm |= HCI_LM_ACCEPT; if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) @@ -1341,6 +1493,36 @@ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags) } read_unlock(&sco_sk_list.lock); +#ifdef TIZEN_BT + /* WBC/NBC feature */ + if ((lm & HCI_LM_ACCEPT) && !hci_conn_hash_lookup_sco(hdev)) { + struct hci_conn *hcon_acl; + + hcon_acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr); + if (!hcon_acl) { + BT_ERR("ACL doesn't alive. Use 0x%X", + hdev->voice_setting); + + if (hdev->voice_setting == 0x0063) + sco_connect_set_wbc(hdev); + else + sco_connect_set_nbc(hdev); + } else if (hcon_acl->sco_role == MGMT_SCO_ROLE_HANDSFREE) { + BT_DBG("Handsfree SCO 0x%X", hcon_acl->voice_setting); + if (hcon_acl->voice_setting == 0x0063) + sco_connect_set_wbc(hdev); + else + sco_connect_set_nbc(hdev); + } else { + BT_DBG("Gateway SCO 0x%X", hcon_acl->voice_setting); + if (hcon_acl->voice_setting == 0x0063) + sco_connect_set_gw_wbc(hdev); + else + sco_connect_set_gw_nbc(hdev); + } + } +#endif + return lm; } -- 2.7.4 From eb40dcf3dc1fc8a6baa98db2172c05da280e40ae Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Wed, 7 Sep 2016 15:22:08 +0530 Subject: [PATCH 14/16] Bluetooth: Get Advertising TX power This patch adds MGMT command to read the advertising TX power. Change-Id: Ic2f6a8dedc949d6114fc22f1a595fc2c6c6b4d69 Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung --- include/net/bluetooth/mgmt_tizen.h | 6 ++++++ net/bluetooth/mgmt.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/include/net/bluetooth/mgmt_tizen.h b/include/net/bluetooth/mgmt_tizen.h index 4eaa867..982c00d 100644 --- a/include/net/bluetooth/mgmt_tizen.h +++ b/include/net/bluetooth/mgmt_tizen.h @@ -161,6 +161,12 @@ struct mgmt_cp_set_voice_setting { } __packed; #define MGMT_SET_VOICE_SETTING_SIZE 9 +#define MGMT_OP_GET_ADV_TX_POWER (TIZEN_OP_CODE_BASE + 0x11) +#define MGMT_GET_ADV_TX_POWER_SIZE 0 +struct mgmt_rp_get_adv_tx_power { + __s8 adv_tx_power; +} __packed; + /* EVENTS */ /* For device name update changes */ diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 74142dd..4f1c159 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -8886,6 +8886,37 @@ unlock: return err; } +static int get_adv_tx_power(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + struct mgmt_rp_get_adv_tx_power *rp; + size_t rp_len; + int err; + + BT_DBG("%s", hdev->name); + + hci_dev_lock(hdev); + + rp_len = sizeof(*rp); + rp = kmalloc(rp_len, GFP_KERNEL); + if (!rp) { + err = -ENOMEM; + goto unlock; + } + + rp->adv_tx_power = hdev->adv_tx_power; + + err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_TX_POWER, 0, rp, + rp_len); + + kfree(rp); + +unlock: + hci_dev_unlock(hdev); + + return err; +} + void mgmt_hardware_error(struct hci_dev *hdev, u8 err_code) { struct mgmt_ev_hardware_error ev; @@ -11249,6 +11280,7 @@ static const struct hci_mgmt_handler tizen_mgmt_handlers[] = { { set_manufacturer_data, MGMT_SET_MANUFACTURER_DATA_SIZE }, { le_set_scan_params, MGMT_LE_SET_SCAN_PARAMS_SIZE }, { set_voice_setting, MGMT_SET_VOICE_SETTING_SIZE }, + { get_adv_tx_power, MGMT_GET_ADV_TX_POWER_SIZE }, }; #endif -- 2.7.4 From 9c095c6488f652838c0e34d8fce180aa4f6ae00e Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 8 Sep 2016 11:21:06 +0530 Subject: [PATCH 15/16] Bluetooth: Set filter policy for LE connection This patch sets the filter policy to a default value 0x01 during LE auto connection if the destination address is not set. And it updates the destination address once the LE connection complete event is recieved during LE auto connection. And for it checks valid destination address before cancelling LE connection when connection timeout occurs. Signed-off-by: Sudha Bheemanna [squash patches, LE connection policy, set dest address and check dest address before cancelling connection] Signed-off-by: Seung-Woo Kim Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung Change-Id: I6a5ae486f39e1adb9451ea1768d93f0d800ce596 --- net/bluetooth/hci_event.c | 4 ++++ net/bluetooth/hci_sync.c | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index ea450a1..8368ea0 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -6078,6 +6078,10 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status, } } } else { +#ifdef TIZEN_BT + /* LE auto connect */ + bacpy(&conn->dst, bdaddr); +#endif cancel_delayed_work(&conn->le_conn_timeout); } diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 0d0e061..f416080 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -5296,7 +5296,11 @@ static int hci_le_connect_cancel_sync(struct hci_dev *hdev, static int hci_connect_cancel_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason) { +#ifdef TIZEN_BT + if (conn->type == LE_LINK && bacmp(&conn->dst, BDADDR_ANY)) +#else if (conn->type == LE_LINK) +#endif return hci_le_connect_cancel_sync(hdev, conn, reason); if (conn->type == ISO_LINK) { @@ -6339,7 +6343,15 @@ int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn) cp.scan_interval = cpu_to_le16(hdev->le_scan_int_connect); cp.scan_window = cpu_to_le16(hdev->le_scan_window_connect); +#ifdef TIZEN_BT + /* LE auto connect */ + if (!bacmp(&conn->dst, BDADDR_ANY)) + cp.filter_policy = 0x1; + else + bacpy(&cp.peer_addr, &conn->dst); +#else bacpy(&cp.peer_addr, &conn->dst); +#endif cp.peer_addr_type = conn->dst_type; cp.own_address_type = own_addr_type; cp.conn_interval_min = cpu_to_le16(conn->le_conn_min_interval); -- 2.7.4 From 6bb1125a577724d2da4cbb7a23f85185efa955a4 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 8 Sep 2016 12:24:43 +0530 Subject: [PATCH 16/16] Bluetooth: Set link Supervision timeout for a connection This patch allows to set the supervision timeout for a connection if the device role is master. Change-Id: I204ebea960235ab4f858c9b57d57989e4426740e Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung --- include/net/bluetooth/bluetooth.h | 7 +++++++ include/net/bluetooth/hci.h | 15 +++++++++++++++ include/net/bluetooth/hci_core.h | 8 ++++++++ net/bluetooth/hci_conn.c | 27 +++++++++++++++++++++++++++ net/bluetooth/hci_core.c | 8 +++++++- net/bluetooth/hci_event.c | 11 +++++++++++ 6 files changed, 75 insertions(+), 1 deletion(-) diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 5a3d66e..bbc7571 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -330,6 +330,13 @@ typedef struct { __u8 b[6]; } __packed bdaddr_t; +#ifdef TIZEN_BT +/* Automatically enable sniff mode for connection. + * In case of normal phone this timeout would be 5 seconds + */ +#define TIZEN_SNIFF_TIMEOUT 5 /* 5 seconds */ +#endif + /* BD Address type */ #define BDADDR_BREDR 0x00 #define BDADDR_LE_PUBLIC 0x01 diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 4b9df2d..eb1a3ba9 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1233,6 +1233,21 @@ struct hci_cp_host_buffer_size { __le16 sco_max_pkt; } __packed; +#ifdef TIZEN_BT +/* Set Link supervision timeout */ +#define HCI_OP_WRITE_LINK_SUPERVISION_TIMEOUT 0x0c37 +struct hci_cp_write_link_supervision_timeout { + __le16 handle; + __le16 timeout; +} __packed; + +struct hci_rp_write_link_supervision_timeout { + __u8 status; + __le16 handle; +} __packed; +/* Set Link supervision timeout */ +#endif /* TIZEN_BT */ + #define HCI_OP_READ_NUM_SUPPORTED_IAC 0x0c38 struct hci_rp_read_num_supported_iac { __u8 status; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 8258305..fc9ad74 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -974,6 +974,10 @@ u32 hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, void hci_inquiry_cache_flush(struct hci_dev *hdev); /* ----- HCI Connections ----- */ +#ifdef TIZEN_BT +#define LINK_SUPERVISION_TIMEOUT 0x1F40 /* n * 0.625 = 5 seconds */ +#endif /* TIZEN_BT */ + enum { HCI_CONN_AUTH_PEND, HCI_CONN_ENCRYPT_PEND, @@ -1529,6 +1533,7 @@ static inline int hci_conn_hash_lookup_rssi_count(struct hci_dev *hdev) return count; } +int hci_conn_change_supervision_timeout(struct hci_conn *conn, __u16 timeout); bool hci_le_discovery_active(struct hci_dev *hdev); void hci_le_discovery_set_state(struct hci_dev *hdev, int state); @@ -1782,6 +1787,9 @@ int hci_get_dev_info(void __user *arg); int hci_get_conn_list(void __user *arg); int hci_get_conn_info(struct hci_dev *hdev, void __user *arg); int hci_get_auth_info(struct hci_dev *hdev, void __user *arg); +#ifdef TIZEN_BT +u32 get_link_mode(struct hci_conn *conn); +#endif int hci_inquiry(void __user *arg); struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *list, diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 66e6a128..f22d277 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -2546,6 +2546,29 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role) } EXPORT_SYMBOL(hci_conn_switch_role); +#ifdef TIZEN_BT +int hci_conn_change_supervision_timeout(struct hci_conn *conn, __u16 timeout) +{ + struct hci_cp_write_link_supervision_timeout cp; + + if (!((get_link_mode(conn)) & HCI_LM_MASTER)) + return 1; + + if (conn->handle == 0) + return 1; + + memset(&cp, 0, sizeof(cp)); + cp.handle = cpu_to_le16(conn->handle); + cp.timeout = cpu_to_le16(timeout); + + if (hci_send_cmd(conn->hdev, HCI_OP_WRITE_LINK_SUPERVISION_TIMEOUT, + sizeof(cp), &cp) < 0) + BT_ERR("HCI_OP_WRITE_LINK_SUPERVISION_TIMEOUT is failed"); + + return 0; +} +#endif + /* Enter active mode */ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active) { @@ -2608,7 +2631,11 @@ void hci_conn_check_pending(struct hci_dev *hdev) hci_dev_unlock(hdev); } +#ifndef TIZEN_BT static u32 get_link_mode(struct hci_conn *conn) +#else +u32 get_link_mode(struct hci_conn *conn) +#endif { u32 link_mode = 0; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 3a87f4f..df0025a 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2541,12 +2541,18 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv) hdev->enable_advmon_interleave_scan = 0x00; /* Default to disable */ hdev->sniff_max_interval = 800; +#ifdef TIZEN_BT + hdev->sniff_min_interval = 400; +#else hdev->sniff_min_interval = 80; - +#endif hdev->le_adv_channel_map = 0x07; hdev->le_adv_min_interval = 0x0800; hdev->le_adv_max_interval = 0x0800; #ifdef TIZEN_BT + /* automatically enable sniff mode for connection */ + hdev->idle_timeout = TIZEN_SNIFF_TIMEOUT * 1000; + hdev->adv_filter_policy = 0x00; hdev->adv_type = 0x00; #endif diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 8368ea0..8a49704 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3370,6 +3370,12 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data, hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE, sizeof(cp), &cp); } + +#ifdef TIZEN_BT + if (get_link_mode(conn) & HCI_LM_MASTER) + hci_conn_change_supervision_timeout(conn, + LINK_SUPERVISION_TIMEOUT); +#endif } if (conn->type == ACL_LINK) @@ -4579,6 +4585,11 @@ static void hci_role_change_evt(struct hci_dev *hdev, void *data, clear_bit(HCI_CONN_RSWITCH_PEND, &conn->flags); hci_role_switch_cfm(conn, ev->status, ev->role); +#ifdef TIZEN_BT + if (!ev->status && (get_link_mode(conn) & HCI_LM_MASTER)) + hci_conn_change_supervision_timeout(conn, + LINK_SUPERVISION_TIMEOUT); +#endif } hci_dev_unlock(hdev); -- 2.7.4