Bluetooth: fix vendor ext rssi link alert event
[platform/kernel/linux-starfive.git] / net / bluetooth / hci_event.c
index faca701..5594826 100644 (file)
@@ -881,8 +881,13 @@ static u8 hci_cc_read_local_ext_features(struct hci_dev *hdev, void *data,
        if (rp->status)
                return rp->status;
 
-       if (hdev->max_page < rp->max_page)
-               hdev->max_page = rp->max_page;
+       if (hdev->max_page < rp->max_page) {
+               if (test_bit(HCI_QUIRK_BROKEN_LOCAL_EXT_FEATURES_PAGE_2,
+                            &hdev->quirks))
+                       bt_dev_warn(hdev, "broken local ext features page 2");
+               else
+                       hdev->max_page = rp->max_page;
+       }
 
        if (rp->page < HCI_MAX_PAGES)
                memcpy(hdev->features[rp->page], rp->features, 8);
@@ -1787,7 +1792,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);
@@ -2205,6 +2214,88 @@ static u8 hci_cc_set_ext_adv_param(struct hci_dev *hdev, void *data,
        return rp->status;
 }
 
+#ifdef TIZEN_BT
+static u8 hci_cc_enable_rssi(struct hci_dev *hdev, void *data,
+                            struct sk_buff *skb)
+{
+       struct hci_cc_rsp_enable_rssi *rp = data;
+
+       BT_DBG("hci_cc_enable_rssi - %s status 0x%2.2x Event_LE_ext_Opcode 0x%2.2x",
+              hdev->name, rp->status, rp->le_ext_opcode);
+
+       mgmt_enable_rssi_cc(hdev, rp, rp->status);
+
+       return rp->status;
+}
+
+static u8 hci_cc_get_raw_rssi(struct hci_dev *hdev, void *data,
+                             struct sk_buff *skb)
+{
+       struct hci_cc_rp_get_raw_rssi *rp = data;
+
+       BT_DBG("hci_cc_get_raw_rssi- %s Get Raw Rssi Response[%2.2x %4.4x %2.2X]",
+              hdev->name, rp->status, rp->conn_handle, rp->rssi_dbm);
+
+       mgmt_raw_rssi_response(hdev, rp, rp->status);
+
+       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)
+{
+       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:
+               hci_vendor_ext_rssi_link_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,
                           struct sk_buff *skb)
 {
@@ -2489,15 +2580,25 @@ static void hci_check_pending_name(struct hci_dev *hdev, struct hci_conn *conn,
        struct discovery_state *discov = &hdev->discovery;
        struct inquiry_entry *e;
 
+#ifdef TIZEN_BT
        /* Update the mgmt connected state if necessary. Be careful with
         * conn objects that exist but are not (yet) connected however.
         * Only those in BT_CONFIG or BT_CONNECTED states can be
         * considered connected.
         */
        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);
+               else
+                       mgmt_device_name_update(hdev, bdaddr, name, name_len);
+       }
+#else
+       if (conn &&
            (conn->state == BT_CONFIG || conn->state == BT_CONNECTED) &&
            !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
                mgmt_device_connected(hdev, conn, name, name_len);
+#endif
 
        if (discov->state == DISCOVERY_STOPPED)
                return;
@@ -2876,16 +2977,6 @@ static void cs_le_create_conn(struct hci_dev *hdev, bdaddr_t *peer_addr,
 
        conn->resp_addr_type = peer_addr_type;
        bacpy(&conn->resp_addr, peer_addr);
-
-       /* We don't want the connection attempt to stick around
-        * indefinitely since LE doesn't have a page timeout concept
-        * like BR/EDR. Set a timer for any connection that doesn't use
-        * the accept list for connecting.
-        */
-       if (filter_policy == HCI_LE_USE_PEER_ADDR)
-               queue_delayed_work(conn->hdev->workqueue,
-                                  &conn->le_conn_timeout,
-                                  conn->conn_timeout);
 }
 
 static void hci_cs_le_create_conn(struct hci_dev *hdev, u8 status)
@@ -3838,8 +3929,11 @@ static u8 hci_cc_le_set_cig_params(struct hci_dev *hdev, void *data,
                           conn->handle, conn->link);
 
                /* Create CIS if LE is already connected */
-               if (conn->link && conn->link->state == BT_CONNECTED)
+               if (conn->link && conn->link->state == BT_CONNECTED) {
+                       rcu_read_unlock();
                        hci_le_create_cis(conn->link);
+                       rcu_read_lock();
+               }
 
                if (i == rp->num_handles)
                        break;
@@ -4130,6 +4224,12 @@ static const struct hci_cc {
                      hci_cc_le_set_per_adv_enable),
        HCI_CC(HCI_OP_LE_READ_TRANSMIT_POWER, hci_cc_le_read_transmit_power,
               sizeof(struct hci_rp_le_read_transmit_power)),
+#ifdef TIZEN_BT
+       HCI_CC(HCI_OP_ENABLE_RSSI, hci_cc_enable_rssi,
+              sizeof(struct hci_cc_rsp_enable_rssi)),
+       HCI_CC(HCI_OP_GET_RAW_RSSI, hci_cc_get_raw_rssi,
+              sizeof(struct hci_cc_rp_get_raw_rssi)),
+#endif
        HCI_CC_STATUS(HCI_OP_LE_SET_PRIVACY_MODE, hci_cc_le_set_privacy_mode),
        HCI_CC(HCI_OP_LE_READ_BUFFER_SIZE_V2, hci_cc_le_read_buffer_size_v2,
               sizeof(struct hci_rp_le_read_buffer_size_v2)),
@@ -4327,6 +4427,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);
@@ -5889,6 +5994,12 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
        if (status)
                goto unlock;
 
+       /* Drop the connection if it has been aborted */
+       if (test_bit(HCI_CONN_CANCEL, &conn->flags)) {
+               hci_conn_drop(conn);
+               goto unlock;
+       }
+
        if (conn->dst_type == ADDR_LE_DEV_PUBLIC)
                addr_type = BDADDR_LE_PUBLIC;
        else
@@ -6074,12 +6185,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 */
@@ -6303,23 +6428,18 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
                return;
        }
 
-       /* When receiving non-connectable or scannable undirected
-        * advertising reports, this means that the remote device is
-        * not connectable and then clearly indicate this in the
-        * device found event.
-        *
-        * When receiving a scan response, then there is no way to
+       /* When receiving a scan response, then there is no way to
         * know if the remote device is connectable or not. However
         * since scan responses are merged with a previously seen
         * advertising report, the flags field from that report
         * will be used.
         *
-        * In the really unlikely case that a controller get confused
-        * and just sends a scan response event, then it is marked as
-        * not connectable as well.
+        * In the unlikely case that a controller just sends a scan
+        * response event that doesn't match the pending report, then
+        * it is marked as a standalone SCAN_RSP.
         */
        if (type == LE_ADV_SCAN_RSP)
-               flags = MGMT_DEV_FOUND_NOT_CONNECTABLE;
+               flags = MGMT_DEV_FOUND_SCAN_RSP;
 
        /* If there's nothing pending either store the data from this
         * event or send an immediate device found event if the data
@@ -6982,7 +7102,7 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
                bis->iso_qos.in.latency = le16_to_cpu(ev->interval) * 125 / 100;
                bis->iso_qos.in.sdu = le16_to_cpu(ev->max_pdu);
 
-               hci_connect_cfm(bis, ev->status);
+               hci_iso_setup_path(bis);
        }
 
        hci_dev_unlock(hdev);
@@ -7431,8 +7551,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,