struct hci_rp_write_link_policy *rp = (void *) skb->data;
struct hci_conn *conn;
void *sent;
+#ifdef TIZEN_BT
+ struct hci_cp_write_link_policy cp;
+ struct hci_conn *sco_conn;
+#endif
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
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);
}
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+#ifdef TIZEN_BT
+ hci_dev_lock(hdev);
+#else
if (rp->status)
return;
+#endif
hdev->le_def_tx_len = le16_to_cpu(rp->tx_len);
hdev->le_def_tx_time = le16_to_cpu(rp->tx_time);
+
+#ifdef TIZEN_BT
+ mgmt_le_read_host_suggested_data_length_complete(hdev, rp->status);
+
+ hci_dev_unlock(hdev);
+#endif
}
static void hci_cc_le_write_def_data_len(struct hci_dev *hdev,
BT_DBG("%s status 0x%2.2x", hdev->name, status);
if (status)
+#ifndef TIZEN_BT
return;
+#else
+ goto unblock;
+#endif
sent = hci_sent_cmd_data(hdev, HCI_OP_LE_WRITE_DEF_DATA_LEN);
if (!sent)
+#ifndef TIZEN_BT
return;
+#else
+ goto unblock;
+#endif
hdev->le_def_tx_len = le16_to_cpu(sent->tx_len);
hdev->le_def_tx_time = le16_to_cpu(sent->tx_time);
+
+#ifdef TIZEN_BT
+unblock:
+ mgmt_le_write_host_suggested_data_length_complete(hdev, status);
+#endif
}
static void hci_cc_le_add_to_resolv_list(struct hci_dev *hdev,
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+#ifndef TIZEN_BT
if (rp->status)
return;
+#else
+ hci_dev_lock(hdev);
+#endif
hdev->le_max_tx_len = le16_to_cpu(rp->tx_len);
hdev->le_max_tx_time = le16_to_cpu(rp->tx_time);
hdev->le_max_rx_len = le16_to_cpu(rp->rx_len);
hdev->le_max_rx_time = le16_to_cpu(rp->rx_time);
+
+#ifdef TIZEN_BT
+ mgmt_le_read_maximum_data_length_complete(hdev, rp->status);
+ hci_dev_unlock(hdev);
+#endif
}
static void hci_cc_write_le_host_supported(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, struct sk_buff *skb)
{
struct hci_ev_vendor_specific *ev = (void *)skb->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;
}
}
+
+static void hci_le_data_length_changed_complete_evt(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ struct hci_ev_le_data_len_change *ev = (void *)skb->data;
+ struct hci_conn *conn;
+
+ BT_DBG("%s status", hdev->name);
+
+ hci_dev_lock(hdev);
+
+ conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
+ if (conn) {
+ conn->tx_len = le16_to_cpu(ev->tx_len);
+ conn->tx_time = le16_to_cpu(ev->tx_time);
+ conn->rx_len = le16_to_cpu(ev->rx_len);
+ conn->rx_time = le16_to_cpu(ev->rx_time);
+
+ mgmt_le_data_length_change_complete(hdev, &conn->dst,
+ conn->tx_len, conn->tx_time,
+ conn->rx_len, conn->rx_time);
+ }
+
+ hci_dev_unlock(hdev);
+}
#endif
static void hci_cc_read_rssi(struct hci_dev *hdev, struct sk_buff *skb)
if (conn &&
(conn->state == BT_CONFIG || conn->state == BT_CONNECTED)) {
if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
- mgmt_device_connected(hdev, conn, 0, name, name_len);
+ mgmt_device_connected(hdev, conn, name, name_len);
else
mgmt_device_name_update(hdev, bdaddr, name, name_len);
}
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
} else {
conn->state = BT_CLOSED;
if (conn->type == ACL_LINK)
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) {
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);
}
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);
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);
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)
}
}
} else {
+#ifdef TIZEN_BT
+ /* LE auto connect */
+ bacpy(&conn->dst, bdaddr);
+#endif
cancel_delayed_work(&conn->le_conn_timeout);
}
case HCI_EV_LE_EXT_ADV_SET_TERM:
hci_le_ext_adv_term_evt(hdev, skb);
break;
+#ifdef TIZEN_BT
+ case HCI_EV_LE_DATA_LEN_CHANGE:
+ hci_le_data_length_changed_complete_evt(hdev, skb);
+ break;
+#endif
default:
break;