From 04f03369821a31e3bde6e078638a7d4b7c8cca35 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 8 Sep 2016 10:31:17 +0530 Subject: [PATCH 01/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 02/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 03/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 04/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 05/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 06/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 From cee4c4c8129194fdef84fea61643a5085fe83bdc Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 8 Sep 2016 13:04:11 +0530 Subject: [PATCH 07/16] Bluetooth: Change authentication requirement. This patch updates the authentication requirement to general MITM if local and remote device IO capabilities are not NO_INPUT_NO_OUTPUT. Change-Id: Id00b7d7136b5de0f63df98b6d3cee04cde267a21 Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung --- net/bluetooth/hci_event.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 8a49704..5aa25b4 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -5425,6 +5425,14 @@ unlock: static u8 hci_get_auth_req(struct hci_conn *conn) { +#ifdef TIZEN_BT + if (conn->remote_auth == HCI_AT_GENERAL_BONDING_MITM) { + if (conn->remote_cap != HCI_IO_NO_INPUT_OUTPUT && + conn->io_capability != HCI_IO_NO_INPUT_OUTPUT) + return HCI_AT_GENERAL_BONDING_MITM; + } +#endif + /* If remote requests no-bonding follow that lead */ if (conn->remote_auth == HCI_AT_NO_BONDING || conn->remote_auth == HCI_AT_NO_BONDING_MITM) -- 2.7.4 From 3ed1dfdfb6c9885fa7178bd8a13bdcfd66d5bd9f Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 8 Sep 2016 14:54:54 +0530 Subject: [PATCH 08/16] Bluetooth: Enable inquiry and page scan This patch enables the inquiry and page scan after ACL disconnection with one device and if there are no other devices connected. Change-Id: Iabe53b9191544f2db952c8bad988bb367696bd23 Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung --- net/bluetooth/hci_event.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 5aa25b4..8b2f49d 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3629,6 +3629,22 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, void *data, hci_conn_del(conn); +#ifdef TIZEN_BT + if (conn->type == ACL_LINK && !hci_conn_num(hdev, ACL_LINK)) { + int iscan; + int pscan; + + iscan = test_bit(HCI_ISCAN, &hdev->flags); + pscan = test_bit(HCI_PSCAN, &hdev->flags); + if (!iscan && !pscan) { + u8 scan_enable = SCAN_PAGE; + + hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, + sizeof(scan_enable), &scan_enable); + } + } +#endif + unlock: hci_dev_unlock(hdev); } -- 2.7.4 From cb11c395768824edb54f8b459394bc698b1256e3 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 8 Sep 2016 15:11:28 +0530 Subject: [PATCH 09/16] Bluetooth: Send Authentication Request command on pairing failure This patch allows to send HCI_OP_AUTH_REQUESTED command to the remote device if pairing failure happens because of pin or key missing error. Change-Id: I84f5e835507ffa4e4a12d2f40d4765e5068a78df Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung --- net/bluetooth/hci_event.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 8b2f49d..f7eaf5d 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3663,6 +3663,24 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, void *data, if (!conn) goto unlock; +#ifdef TIZEN_BT + /* PIN or Key Missing patch */ + BT_DBG("remote_auth %x, remote_cap %x, auth_type %x, io_capability %x", + conn->remote_auth, conn->remote_cap, + conn->auth_type, conn->io_capability); + + if (ev->status == 0x06 && hci_conn_ssp_enabled(conn)) { + struct hci_cp_auth_requested cp; + + BT_DBG("Pin or key missing"); + hci_remove_link_key(hdev, &conn->dst); + cp.handle = cpu_to_le16(conn->handle); + hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED, + sizeof(cp), &cp); + goto unlock; + } +#endif + if (!ev->status) { clear_bit(HCI_CONN_AUTH_FAILURE, &conn->flags); set_bit(HCI_CONN_AUTH, &conn->flags); -- 2.7.4 From c659c27a3f30cfdaccf35ace14aff9cbeb1bad41 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 8 Sep 2016 16:01:23 +0530 Subject: [PATCH 10/16] Bluetooth: Modify fast connectable type. This patch modifies the fast connectable function to just set the type. Change-Id: I9dfe64e09bcc1bc5152477ab8c7d0b6c386003b3 Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung --- net/bluetooth/hci_sync.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index f416080..58dc155 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -3108,6 +3108,12 @@ int hci_write_fast_connectable_sync(struct hci_dev *hdev, bool enable) memset(&cp, 0, sizeof(cp)); +#ifdef TIZEN_BT + if (enable) + type = PAGE_SCAN_TYPE_INTERLACED; + else + type = PAGE_SCAN_TYPE_STANDARD; /* default */ +#else if (enable) { type = PAGE_SCAN_TYPE_INTERLACED; @@ -3128,6 +3134,7 @@ int hci_write_fast_connectable_sync(struct hci_dev *hdev, bool enable) if (err) return err; } +#endif if (hdev->page_scan_type != type) err = __hci_cmd_sync_status(hdev, -- 2.7.4 From ee8540772966a36bdcf9a8433812ae8e39506aae Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 8 Sep 2016 16:40:50 +0530 Subject: [PATCH 11/16] Bluetooth: Enable sniff mode for incoming connection Add provision to set the link poilicy to enable sniff mode for incoming connection. Change-Id: Iceec461cd620a328646df7889a89e41ce402b8ca Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung --- net/bluetooth/hci_conn.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index f22d277..eac7948 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -982,6 +982,11 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst, conn->max_tx_power = HCI_TX_POWER_INVALID; conn->sync_handle = HCI_SYNC_HANDLE_INVALID; +#ifdef TIZEN_BT + /* enable sniff mode for incoming connection */ + conn->link_policy = hdev->link_policy; +#endif + set_bit(HCI_CONN_POWER_SAVE, &conn->flags); conn->disc_timeout = HCI_DISCONN_TIMEOUT; -- 2.7.4 From be71138ab14c0a800136a045cc20e56803f09e7a Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 8 Sep 2016 17:01:39 +0530 Subject: [PATCH 12/16] Bluetooth: Cancel the Sniff timer This patch adds code to cancel the sniff timer. Change-Id: Ic0e233bf43084e5228866d70de7dcb96a2df1c54 Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung --- net/bluetooth/hci_conn.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index eac7948..a92c0cc 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -2594,9 +2594,18 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active) } timer: +#ifdef TIZEN_BT + if (hdev->idle_timeout > 0) { + /* Sniff timer cancel */ + cancel_delayed_work(&conn->idle_work); + queue_delayed_work(hdev->workqueue, &conn->idle_work, + msecs_to_jiffies(hdev->idle_timeout)); + } +#else if (hdev->idle_timeout > 0) queue_delayed_work(hdev->workqueue, &conn->idle_work, msecs_to_jiffies(hdev->idle_timeout)); +#endif } /* Drop all connection on the device */ -- 2.7.4 From 454ff9867e1f64fd928aa6f6a6756551407ebffd Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Mon, 12 Sep 2016 12:46:44 +0530 Subject: [PATCH 13/16] Bluetooth: Store the key if auth type is P192 This patch allows to store the key after authentication if auth type is "HCI_LK_AUTH_COMBINATION_P192" Change-Id: I8d90830af296e718857d73cbdd1de61b8c7a37f1 Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung --- net/bluetooth/hci_core.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index df0025a..663af3f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1242,6 +1242,14 @@ static bool hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn, if (conn->remote_auth == 0x02 || conn->remote_auth == 0x03) return true; +#ifdef TIZEN_BT + /* In case of auth_type '0x01', it is authenticated by MITM. + * So store it. + */ + if (key_type == HCI_LK_AUTH_COMBINATION_P192) + return true; +#endif + /* If none of the above criteria match, then don't store the key * persistently */ return false; -- 2.7.4 From ad385367f37148cfe844c95a312cc6c763d2e77c Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 8 Sep 2016 16:21:01 +0530 Subject: [PATCH 14/16] Bluetooth: Fix issue in the Set LE privacy function. This patch fixes not to check the hdev power before setting LE Privacy. Change-Id: I465edcfb14945d358dc940e15b10fff1497aca1e 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 --- net/bluetooth/mgmt.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 4f1c159..49ec403 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -7031,9 +7031,14 @@ static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data, return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY, MGMT_STATUS_INVALID_PARAMS); +#ifndef TIZEN_BT + /* commenting out since set privacy command is always rejected + * if this condition is enabled. + */ if (hdev_is_powered(hdev)) return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY, MGMT_STATUS_REJECTED); +#endif hci_dev_lock(hdev); -- 2.7.4 From 24f1e7c8b70fa6e4f6cc3a5fd92debbe76c5d45f Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 15 Sep 2016 10:12:09 +0530 Subject: [PATCH 15/16] Bluetooth: Add support to enable/disable IPSP This patch supports MGMT commands and code to enable or disable IPSP 6LowPan features. Change-Id: Ibbed275162ac0539205502747923603a2a581c36 Signed-off-by: Sudha Bheemanna Signed-off-by: Amit Purwar Signed-off-by: Wootak Jung Signed-off-by: Jaehoon Chung --- include/net/bluetooth/l2cap.h | 11 +++++++++++ include/net/bluetooth/mgmt_tizen.h | 6 ++++++ net/bluetooth/6lowpan.c | 34 ++++++++++++++++++++++++++++++++++ net/bluetooth/mgmt.c | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index cf393e7..a13d22a 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -1006,4 +1006,15 @@ void l2cap_conn_put(struct l2cap_conn *conn); int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user); void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user); +#ifdef TIZEN_BT +#ifdef CONFIG_BT_6LOWPAN +/* IPSP : initialize/deinitialize 6lowpan */ +void bt_6lowpan_enable(void); +void bt_6lowpan_disable(void); +#else +static inline void bt_6lowpan_enable(void) { } +static inline void bt_6lowpan_disable(void) { } +#endif +#endif /* TIZEN_BT */ + #endif /* __L2CAP_H */ diff --git a/include/net/bluetooth/mgmt_tizen.h b/include/net/bluetooth/mgmt_tizen.h index 982c00d..6549be1 100644 --- a/include/net/bluetooth/mgmt_tizen.h +++ b/include/net/bluetooth/mgmt_tizen.h @@ -167,6 +167,12 @@ struct mgmt_rp_get_adv_tx_power { __s8 adv_tx_power; } __packed; +#define MGMT_OP_ENABLE_6LOWPAN (TIZEN_OP_CODE_BASE + 0x12) +struct mgmt_cp_enable_6lowpan { + __u8 enable_6lowpan; +} __packed; +#define MGMT_ENABLE_BT_6LOWPAN_SIZE 1 + /* EVENTS */ /* For device name update changes */ diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index 4eb1b3c..fd15bff 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -1259,6 +1259,40 @@ static int __init bt_6lowpan_init(void) return register_netdevice_notifier(&bt_6lowpan_dev_notifier); } +#ifdef TIZEN_BT +void bt_6lowpan_enable(void) +{ + if (!enable_6lowpan) { + disconnect_all_peers(); + + enable_6lowpan = true; + + if (listen_chan) { + l2cap_chan_close(listen_chan, 0); + l2cap_chan_put(listen_chan); + } + + listen_chan = bt_6lowpan_listen(); + + register_netdevice_notifier(&bt_6lowpan_dev_notifier); + } +} + +void bt_6lowpan_disable(void) +{ + if (enable_6lowpan) { + if (listen_chan) { + l2cap_chan_close(listen_chan, 0); + l2cap_chan_put(listen_chan); + listen_chan = NULL; + } + disconnect_devices(); + unregister_netdevice_notifier(&bt_6lowpan_dev_notifier); + enable_6lowpan = false; + } +} +#endif + static void __exit bt_6lowpan_exit(void) { debugfs_remove(lowpan_enable_debugfs); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 49ec403..bc4614b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -8951,6 +8951,40 @@ void mgmt_multi_adv_state_change_evt(struct hci_dev *hdev, u8 adv_instance, sizeof(struct mgmt_ev_vendor_specific_multi_adv_state_changed), NULL); } + +static int enable_bt_6lowpan(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + int err; + struct mgmt_cp_enable_6lowpan *cp = data; + + BT_DBG("%s", hdev->name); + + hci_dev_lock(hdev); + + if (!hdev_is_powered(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ENABLE_6LOWPAN, + MGMT_STATUS_NOT_POWERED); + goto unlocked; + } + + if (!lmp_le_capable(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ENABLE_6LOWPAN, + MGMT_STATUS_NOT_SUPPORTED); + goto unlocked; + } + + if (cp->enable_6lowpan) + bt_6lowpan_enable(); + else + bt_6lowpan_disable(); + + err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ENABLE_6LOWPAN, + MGMT_STATUS_SUCCESS, NULL, 0); +unlocked: + hci_dev_unlock(hdev); + return err; +} #endif /* TIZEN_BT */ static bool ltk_is_valid(struct mgmt_ltk_info *key) @@ -11286,6 +11320,7 @@ static const struct hci_mgmt_handler tizen_mgmt_handlers[] = { { 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 }, + { enable_bt_6lowpan, MGMT_ENABLE_BT_6LOWPAN_SIZE }, }; #endif -- 2.7.4 From e25dbea713126b21b10d8dad294a31f115156379 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 15 Sep 2016 12:53:03 +0530 Subject: [PATCH 16/16] Bluetooth: IPSP Connect/Disconnect apis This patch adds MGMT code to support IPSP connect and disconnect apis and handle connection state changed event. Change-Id: I6139603a9614217637f109b2d724e1bf9ffb8f93 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 | 2 + include/net/bluetooth/l2cap.h | 5 ++ include/net/bluetooth/mgmt_tizen.h | 18 +++++ net/bluetooth/6lowpan.c | 16 ++++ net/bluetooth/mgmt.c | 150 +++++++++++++++++++++++++++++++++++++ 5 files changed, 191 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index fc9ad74..6dd3d0f 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -2424,6 +2424,8 @@ void mgmt_le_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, 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); +void mgmt_6lowpan_conn_changed(struct hci_dev *hdev, char if_name[16], + bdaddr_t *bdaddr, u8 addr_type, bool connected); #endif int hci_abort_conn(struct hci_conn *conn, u8 reason); diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index a13d22a..4bd23ae 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -1011,9 +1011,14 @@ void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user); /* IPSP : initialize/deinitialize 6lowpan */ void bt_6lowpan_enable(void); void bt_6lowpan_disable(void); +/* IPSP: Connect and Disconnect */ +int _bt_6lowpan_connect(bdaddr_t *addr, u8 dst_type); +int _bt_6lowpan_disconnect(struct l2cap_conn *conn, u8 dst_type); #else static inline void bt_6lowpan_enable(void) { } static inline void bt_6lowpan_disable(void) { } +static inline int _bt_6lowpan_connect(bdaddr_t *addr, u8 dst_type) { return -ENODEV; } +static inline int _bt_6lowpan_disconnect(struct l2cap_conn *conn, u8 dst_type) { return -ENODEV; } #endif #endif /* TIZEN_BT */ diff --git a/include/net/bluetooth/mgmt_tizen.h b/include/net/bluetooth/mgmt_tizen.h index 6549be1..52a36f9 100644 --- a/include/net/bluetooth/mgmt_tizen.h +++ b/include/net/bluetooth/mgmt_tizen.h @@ -173,6 +173,18 @@ struct mgmt_cp_enable_6lowpan { } __packed; #define MGMT_ENABLE_BT_6LOWPAN_SIZE 1 +#define MGMT_OP_CONNECT_6LOWPAN (TIZEN_OP_CODE_BASE + 0x13) +struct mgmt_cp_connect_6lowpan { + struct mgmt_addr_info addr; +} __packed; +#define MGMT_CONNECT_6LOWPAN_SIZE 7 + +#define MGMT_OP_DISCONNECT_6LOWPAN (TIZEN_OP_CODE_BASE + 0x14) +struct mgmt_cp_disconnect_6lowpan { + struct mgmt_addr_info addr; +} __packed; +#define MGMT_DISCONNECT_6LOWPAN_SIZE 7 + /* EVENTS */ /* For device name update changes */ @@ -254,5 +266,11 @@ struct mgmt_ev_vendor_specific_multi_adv_state_changed { } __packed; /* LE advertisement state changed event */ +#define MGMT_EV_6LOWPAN_CONN_STATE_CHANGED (TIZEN_EV_BASE + 0x0c) +struct mgmt_ev_6lowpan_conn_state_changed { + struct mgmt_addr_info addr; + __u8 connected; + __u8 ifname[16]; +} __packed; #endif /* __MGMT_TIZEN_H */ diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index fd15bff..bcb4407 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -732,6 +732,12 @@ static inline void chan_ready_cb(struct l2cap_chan *chan) add_peer_chan(chan, dev, new_netdev); ifup(dev->netdev); + +#ifdef TIZEN_BT + /* IPSP: Send connection changed state info to bluez */ + mgmt_6lowpan_conn_changed(dev->hdev, dev->netdev->name, &chan->dst, + chan->dst_type, true); +#endif } static inline struct l2cap_chan *chan_new_conn_cb(struct l2cap_chan *pchan) @@ -1291,6 +1297,16 @@ void bt_6lowpan_disable(void) enable_6lowpan = false; } } + +int _bt_6lowpan_connect(bdaddr_t *addr, u8 dst_type) +{ + return bt_6lowpan_connect(addr, dst_type); +} + +int _bt_6lowpan_disconnect(struct l2cap_conn *conn, u8 dst_type) +{ + return bt_6lowpan_disconnect(conn, dst_type); +} #endif static void __exit bt_6lowpan_exit(void) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index bc4614b..caaf1f4 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -8985,6 +8985,154 @@ unlocked: hci_dev_unlock(hdev); return err; } + +static int connect_bt_6lowpan(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + struct mgmt_cp_connect_6lowpan *cp = data; + __u8 addr_type = ADDR_LE_DEV_PUBLIC; + int err; + + BT_DBG("%s", hdev->name); + + hci_dev_lock(hdev); + + if (!lmp_le_capable(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CONNECT_6LOWPAN, + MGMT_STATUS_NOT_SUPPORTED); + goto unlocked; + } + + if (!hdev_is_powered(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CONNECT_6LOWPAN, + MGMT_STATUS_REJECTED); + goto unlocked; + } + + if (bdaddr_type_is_le(cp->addr.type)) { + if (cp->addr.type == BDADDR_LE_PUBLIC) + addr_type = ADDR_LE_DEV_PUBLIC; + else + addr_type = ADDR_LE_DEV_RANDOM; + } else { + err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONNECT_6LOWPAN, + MGMT_STATUS_INVALID_PARAMS, NULL, 0); + goto unlocked; + } + + hci_dev_unlock(hdev); + + /* 6lowpan Connect */ + err = _bt_6lowpan_connect(&cp->addr.bdaddr, cp->addr.type); + + hci_dev_lock(hdev); + + if (err < 0) { + err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONNECT_6LOWPAN, + MGMT_STATUS_REJECTED, NULL, 0); + + goto unlocked; + } + + err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONNECT_6LOWPAN, 0, + NULL, 0); +unlocked: + hci_dev_unlock(hdev); + return err; +} + +static int disconnect_bt_6lowpan(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + struct mgmt_cp_disconnect_6lowpan *cp = data; + struct hci_conn *conn = NULL; + __u8 addr_type = ADDR_LE_DEV_PUBLIC; + int err; + + BT_DBG("%s", hdev->name); + + hci_dev_lock(hdev); + + if (!lmp_le_capable(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT_6LOWPAN, + MGMT_STATUS_NOT_SUPPORTED); + goto unlocked; + } + + if (!hdev_is_powered(hdev)) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT_6LOWPAN, + MGMT_STATUS_REJECTED); + goto unlocked; + } + + if (bdaddr_type_is_le(cp->addr.type)) { + if (cp->addr.type == BDADDR_LE_PUBLIC) + addr_type = ADDR_LE_DEV_PUBLIC; + else + addr_type = ADDR_LE_DEV_RANDOM; + } else { + err = mgmt_cmd_complete(sk, hdev->id, + MGMT_OP_DISCONNECT_6LOWPAN, + MGMT_STATUS_INVALID_PARAMS, NULL, 0); + goto unlocked; + } + + conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr); + if (!conn) { + err = mgmt_cmd_complete(sk, hdev->id, + MGMT_OP_DISCONNECT_6LOWPAN, + MGMT_STATUS_NOT_CONNECTED, NULL, 0); + goto unlocked; + } + + if (conn->dst_type != addr_type) { + err = mgmt_cmd_complete(sk, hdev->id, + MGMT_OP_DISCONNECT_6LOWPAN, + MGMT_STATUS_INVALID_PARAMS, NULL, 0); + goto unlocked; + } + + if (conn->state != BT_CONNECTED) { + err = mgmt_cmd_complete(sk, hdev->id, + MGMT_OP_DISCONNECT_6LOWPAN, + MGMT_STATUS_NOT_CONNECTED, NULL, 0); + goto unlocked; + } + + /* 6lowpan Disconnect */ + err = _bt_6lowpan_disconnect(conn->l2cap_data, cp->addr.type); + if (err < 0) { + err = mgmt_cmd_complete(sk, hdev->id, + MGMT_OP_DISCONNECT_6LOWPAN, + MGMT_STATUS_REJECTED, NULL, 0); + goto unlocked; + } + + err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONNECT_6LOWPAN, 0, + NULL, 0); + +unlocked: + hci_dev_unlock(hdev); + return err; +} + +void mgmt_6lowpan_conn_changed(struct hci_dev *hdev, char if_name[16], + bdaddr_t *bdaddr, u8 addr_type, bool connected) +{ + char buf[512]; + struct mgmt_ev_6lowpan_conn_state_changed *ev = (void *)buf; + size_t ev_size; + + memset(buf, 0, sizeof(buf)); + bacpy(&ev->addr.bdaddr, bdaddr); + ev->addr.type = addr_type; + ev->connected = connected; + memcpy(ev->ifname, (__u8 *)if_name, 16); + + ev_size = sizeof(*ev); + + mgmt_event(MGMT_EV_6LOWPAN_CONN_STATE_CHANGED, hdev, ev, ev_size, NULL); +} #endif /* TIZEN_BT */ static bool ltk_is_valid(struct mgmt_ltk_info *key) @@ -11321,6 +11469,8 @@ static const struct hci_mgmt_handler tizen_mgmt_handlers[] = { { set_voice_setting, MGMT_SET_VOICE_SETTING_SIZE }, { get_adv_tx_power, MGMT_GET_ADV_TX_POWER_SIZE }, { enable_bt_6lowpan, MGMT_ENABLE_BT_6LOWPAN_SIZE }, + { connect_bt_6lowpan, MGMT_CONNECT_6LOWPAN_SIZE }, + { disconnect_bt_6lowpan, MGMT_DISCONNECT_6LOWPAN_SIZE }, }; #endif -- 2.7.4