[Bluetooth] Make use of the default link policy settings
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / net / bluetooth / hci_event.c
index 46df2e403df871b131abfa10a8ec22faf8565256..9af181a61650d8aa788cef70c982884ea08a2eb7 100644 (file)
@@ -110,6 +110,25 @@ static void hci_cc_role_discovery(struct hci_dev *hdev, struct sk_buff *skb)
        hci_dev_unlock(hdev);
 }
 
+static void hci_cc_read_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_rp_read_link_policy *rp = (void *) skb->data;
+       struct hci_conn *conn;
+
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+       if (rp->status)
+               return;
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
+       if (conn)
+               conn->link_policy = __le16_to_cpu(rp->policy);
+
+       hci_dev_unlock(hdev);
+}
+
 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;
@@ -128,14 +147,41 @@ static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
        hci_dev_lock(hdev);
 
        conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
-       if (conn) {
-               __le16 policy = get_unaligned((__le16 *) (sent + 2));
-               conn->link_policy = __le16_to_cpu(policy);
-       }
+       if (conn)
+               conn->link_policy = get_unaligned_le16(sent + 2);
 
        hci_dev_unlock(hdev);
 }
 
+static void hci_cc_read_def_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_rp_read_def_link_policy *rp = (void *) skb->data;
+
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+       if (rp->status)
+               return;
+
+       hdev->link_policy = __le16_to_cpu(rp->policy);
+}
+
+static void hci_cc_write_def_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       __u8 status = *((__u8 *) skb->data);
+       void *sent;
+
+       BT_DBG("%s status 0x%x", hdev->name, status);
+
+       sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_DEF_LINK_POLICY);
+       if (!sent)
+               return;
+
+       if (!status)
+               hdev->link_policy = get_unaligned_le16(sent);
+
+       hci_req_complete(hdev, status);
+}
+
 static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
 {
        __u8 status = *((__u8 *) skb->data);
@@ -313,7 +359,7 @@ static void hci_cc_write_voice_setting(struct hci_dev *hdev, struct sk_buff *skb
                return;
 
        if (!status) {
-               __u16 setting = __le16_to_cpu(get_unaligned((__le16 *) sent));
+               __u16 setting = get_unaligned_le16(sent);
 
                if (hdev->voice_setting != setting) {
                        hdev->voice_setting = setting;
@@ -348,8 +394,8 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
                return;
 
        hdev->hci_ver = rp->hci_ver;
-       hdev->hci_rev = btohs(rp->hci_rev);
-       hdev->manufacturer = btohs(rp->manufacturer);
+       hdev->hci_rev = __le16_to_cpu(rp->hci_rev);
+       hdev->manufacturer = __le16_to_cpu(rp->manufacturer);
 
        BT_DBG("%s manufacturer %d hci ver %d:%d", hdev->name,
                                        hdev->manufacturer,
@@ -691,23 +737,13 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                        hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES, sizeof(cp), &cp);
                }
 
-               /* Set link policy */
-               if (conn->type == ACL_LINK && hdev->link_policy) {
-                       struct hci_cp_write_link_policy cp;
-                       cp.handle = ev->handle;
-                       cp.policy = cpu_to_le16(hdev->link_policy);
-                       hci_send_cmd(hdev, HCI_OP_WRITE_LINK_POLICY, sizeof(cp), &cp);
-               }
-
                /* Set packet type for incoming connection */
-               if (!conn->out) {
+               if (!conn->out && hdev->hci_ver < 3) {
                        struct hci_cp_change_conn_ptype cp;
                        cp.handle = ev->handle;
-                       cp.pkt_type = (conn->type == ACL_LINK) ?
-                               cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK):
-                               cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
-
-                       hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE, sizeof(cp), &cp);
+                       cp.pkt_type = cpu_to_le16(conn->pkt_type);
+                       hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE,
+                                                       sizeof(cp), &cp);
                } else {
                        /* Update disconnect timer */
                        hci_conn_hold(conn);
@@ -787,7 +823,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
                        struct hci_cp_accept_sync_conn_req cp;
 
                        bacpy(&cp.bdaddr, &ev->bdaddr);
-                       cp.pkt_type = cpu_to_le16(hdev->esco_type);
+                       cp.pkt_type = cpu_to_le16(conn->pkt_type);
 
                        cp.tx_bandwidth   = cpu_to_le32(0x00001f40);
                        cp.rx_bandwidth   = cpu_to_le32(0x00001f40);
@@ -884,9 +920,11 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *
        conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
        if (conn) {
                if (!ev->status) {
-                       if (ev->encrypt)
+                       if (ev->encrypt) {
+                               /* Encryption implies authentication */
+                               conn->link_mode |= HCI_LM_AUTH;
                                conn->link_mode |= HCI_LM_ENCRYPT;
-                       else
+                       else
                                conn->link_mode &= ~HCI_LM_ENCRYPT;
                }
 
@@ -975,10 +1013,22 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
                hci_cc_role_discovery(hdev, skb);
                break;
 
+       case HCI_OP_READ_LINK_POLICY:
+               hci_cc_read_link_policy(hdev, skb);
+               break;
+
        case HCI_OP_WRITE_LINK_POLICY:
                hci_cc_write_link_policy(hdev, skb);
                break;
 
+       case HCI_OP_READ_DEF_LINK_POLICY:
+               hci_cc_read_def_link_policy(hdev, skb);
+               break;
+
+       case HCI_OP_WRITE_DEF_LINK_POLICY:
+               hci_cc_write_def_link_policy(hdev, skb);
+               break;
+
        case HCI_OP_RESET:
                hci_cc_reset(hdev, skb);
                break;
@@ -1152,8 +1202,8 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
                struct hci_conn *conn;
                __u16  handle, count;
 
-               handle = __le16_to_cpu(get_unaligned(ptr++));
-               count  = __le16_to_cpu(get_unaligned(ptr++));
+               handle = get_unaligned_le16(ptr++);
+               count  = get_unaligned_le16(ptr++);
 
                conn = hci_conn_hash_lookup_handle(hdev, handle);
                if (conn) {
@@ -1236,6 +1286,22 @@ static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *sk
        hci_dev_unlock(hdev);
 }
 
+static inline void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_ev_pkt_type_change *ev = (void *) skb->data;
+       struct hci_conn *conn;
+
+       BT_DBG("%s status %d", hdev->name, ev->status);
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
+       if (conn && !ev->status)
+               conn->pkt_type = __le16_to_cpu(ev->pkt_type);
+
+       hci_dev_unlock(hdev);
+}
+
 static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_pscan_rep_mode *ev = (void *) skb->data;
@@ -1313,8 +1379,16 @@ static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_bu
        hci_dev_lock(hdev);
 
        conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
-       if (!conn)
-               goto unlock;
+       if (!conn) {
+               if (ev->link_type == ESCO_LINK)
+                       goto unlock;
+
+               conn = hci_conn_hash_lookup_ba(hdev, ESCO_LINK, &ev->bdaddr);
+               if (!conn)
+                       goto unlock;
+
+               conn->type = SCO_LINK;
+       }
 
        if (!ev->status) {
                conn->handle = __le16_to_cpu(ev->handle);
@@ -1471,6 +1545,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
                hci_clock_offset_evt(hdev, skb);
                break;
 
+       case HCI_EV_PKT_TYPE_CHANGE:
+               hci_pkt_type_change_evt(hdev, skb);
+               break;
+
        case HCI_EV_PSCAN_REP_MODE:
                hci_pscan_rep_mode_evt(hdev, skb);
                break;