Bluetooth: Set the link for SCO connection
authorSudha Bheemanna <b.sudha@samsung.com>
Thu, 8 Sep 2016 07:07:45 +0000 (12:37 +0530)
committerSeung-Woo Kim <sw0312.kim@samsung.com>
Wed, 14 Dec 2016 04:53:15 +0000 (13:53 +0900)
This patch sets the link policy for SCO/eSCO connection.

Change-Id: I71caef5a3887f73a10329b6886c8cf52b80e8d37
Signed-off-by: Sudha Bheemanna <b.sudha@samsung.com>
[add link policy setting in sco connection]
Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com>
net/bluetooth/hci_event.c
net/bluetooth/sco.c

index c2a4451..697a140 100644 (file)
@@ -136,6 +136,10 @@ static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
        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);
 
@@ -152,6 +156,17 @@ static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
        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);
 }
 
@@ -2461,6 +2476,20 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
        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) {
index 805282b..b203458 100644 (file)
@@ -1081,6 +1081,29 @@ static void sco_conn_ready(struct sco_conn *conn)
 }
 
 #ifdef TIZEN_BT
+/* Link policy */
+static int hci_write_acl_link_policy(struct hci_conn *hcon, uint16_t policy)
+{
+       struct hci_conn *hcon_acl;
+       struct hci_cp_write_link_policy cp;
+
+       BT_DBG("Write link Policy %d", policy);
+
+       hcon_acl = hci_conn_hash_lookup_ba(hcon->hdev, ACL_LINK, &hcon->dst);
+       if (!hcon_acl) {
+               BT_ERR("ACL does not alive");
+               return -1;
+       }
+
+       memset(&cp, 0, sizeof(cp));
+       cp.handle = __cpu_to_le16(hcon_acl->handle);
+       cp.policy = __cpu_to_le16(policy);
+
+       hci_send_cmd(hcon_acl->hdev, HCI_OP_WRITE_LINK_POLICY, sizeof(cp), &cp);
+
+       return 0;
+}
+
 /* WBC/NBC feature */
 void sco_connect_set_gw_nbc(struct hci_dev *hdev)
 {
@@ -1282,6 +1305,11 @@ static void sco_connect_cfm(struct hci_conn *hcon, __u8 status)
                conn = sco_conn_add(hcon);
                if (conn)
                        sco_conn_ready(conn);
+
+#ifdef TIZEN_BT
+               /* Link policy */
+               hci_write_acl_link_policy(hcon, HCI_LP_RSWITCH);
+#endif
        } else
                sco_conn_del(hcon, bt_to_errno(status));
 }
@@ -1293,6 +1321,11 @@ static void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
 
        BT_DBG("hcon %p reason %d", hcon, reason);
 
+#ifdef TIZEN_BT
+       /* Link policy */
+       hci_write_acl_link_policy(hcon, HCI_LP_SNIFF | HCI_LP_RSWITCH);
+#endif
+
        sco_conn_del(hcon, bt_to_errno(reason));
 }