pkt_sched: fq: fix pacing for small frames
[linux-drm-fsl-dcu.git] / net / bluetooth / hci_event.c
index 8db3e89fae354aebb67c6ea7172a3e2e1926b66d..5935f748c0f9a6fe71cb3c0fe8baeaedb7019c37 100644 (file)
@@ -29,8 +29,9 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/mgmt.h>
-#include <net/bluetooth/a2mp.h>
-#include <net/bluetooth/amp.h>
+
+#include "a2mp.h"
+#include "amp.h"
 
 /* Handle HCI Event packets */
 
@@ -194,6 +195,11 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
 
        memset(hdev->adv_data, 0, sizeof(hdev->adv_data));
        hdev->adv_data_len = 0;
+
+       memset(hdev->scan_rsp_data, 0, sizeof(hdev->scan_rsp_data));
+       hdev->scan_rsp_data_len = 0;
+
+       hdev->ssp_debug_mode = 0;
 }
 
 static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
@@ -297,6 +303,11 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
                goto done;
        }
 
+       /* We need to ensure that we set this back on if someone changed
+        * the scan mode through a raw HCI socket.
+        */
+       set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
+
        old_pscan = test_and_clear_bit(HCI_PSCAN, &hdev->flags);
        old_iscan = test_and_clear_bit(HCI_ISCAN, &hdev->flags);
 
@@ -304,11 +315,6 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
                set_bit(HCI_ISCAN, &hdev->flags);
                if (!old_iscan)
                        mgmt_discoverable(hdev, 1);
-               if (hdev->discov_timeout > 0) {
-                       int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
-                       queue_delayed_work(hdev->workqueue, &hdev->discov_off,
-                                          to);
-               }
        } else if (old_iscan)
                mgmt_discoverable(hdev, 0);
 
@@ -412,6 +418,21 @@ static void hci_cc_write_voice_setting(struct hci_dev *hdev,
                hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
 }
 
+static void hci_cc_read_num_supported_iac(struct hci_dev *hdev,
+                                         struct sk_buff *skb)
+{
+       struct hci_rp_read_num_supported_iac *rp = (void *) skb->data;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+       if (rp->status)
+               return;
+
+       hdev->num_iac = rp->num_iac;
+
+       BT_DBG("%s num iac %d", hdev->name, hdev->num_iac);
+}
+
 static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
 {
        __u8 status = *((__u8 *) skb->data);
@@ -449,14 +470,13 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
        if (rp->status)
                return;
 
-       hdev->hci_ver = rp->hci_ver;
-       hdev->hci_rev = __le16_to_cpu(rp->hci_rev);
-       hdev->lmp_ver = rp->lmp_ver;
-       hdev->manufacturer = __le16_to_cpu(rp->manufacturer);
-       hdev->lmp_subver = __le16_to_cpu(rp->lmp_subver);
-
-       BT_DBG("%s manufacturer 0x%4.4x hci ver %d:%d", hdev->name,
-              hdev->manufacturer, hdev->hci_ver, hdev->hci_rev);
+       if (test_bit(HCI_SETUP, &hdev->dev_flags)) {
+               hdev->hci_ver = rp->hci_ver;
+               hdev->hci_rev = __le16_to_cpu(rp->hci_rev);
+               hdev->lmp_ver = rp->lmp_ver;
+               hdev->manufacturer = __le16_to_cpu(rp->manufacturer);
+               hdev->lmp_subver = __le16_to_cpu(rp->lmp_subver);
+       }
 }
 
 static void hci_cc_read_local_commands(struct hci_dev *hdev,
@@ -536,7 +556,8 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
        if (rp->status)
                return;
 
-       hdev->max_page = rp->max_page;
+       if (hdev->max_page < rp->max_page)
+               hdev->max_page = rp->max_page;
 
        if (rp->page < HCI_MAX_PAGES)
                memcpy(hdev->features[rp->page], rp->features, 8);
@@ -913,17 +934,9 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb)
 
        if (!status) {
                if (*sent)
-                       set_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
+                       set_bit(HCI_ADVERTISING, &hdev->dev_flags);
                else
-                       clear_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
-       }
-
-       if (!test_bit(HCI_INIT, &hdev->flags)) {
-               struct hci_request req;
-
-               hci_req_init(&req, hdev);
-               hci_update_ad(&req);
-               hci_req_run(&req, NULL);
+                       clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
        }
 
        hci_dev_unlock(hdev);
@@ -994,20 +1007,20 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
                return;
 
        if (!status) {
-               if (sent->le)
+               if (sent->le) {
                        hdev->features[1][0] |= LMP_HOST_LE;
-               else
+                       set_bit(HCI_LE_ENABLED, &hdev->dev_flags);
+               } else {
                        hdev->features[1][0] &= ~LMP_HOST_LE;
+                       clear_bit(HCI_LE_ENABLED, &hdev->dev_flags);
+                       clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
+               }
 
                if (sent->simul)
                        hdev->features[1][0] |= LMP_HOST_LE_BREDR;
                else
                        hdev->features[1][0] &= ~LMP_HOST_LE_BREDR;
        }
-
-       if (test_bit(HCI_MGMT, &hdev->dev_flags) &&
-           !test_bit(HCI_INIT, &hdev->flags))
-               mgmt_le_enable_complete(hdev, sent->le, status);
 }
 
 static void hci_cc_write_remote_amp_assoc(struct hci_dev *hdev,
@@ -1291,9 +1304,11 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status)
                goto unlock;
 
        if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
-               struct hci_cp_auth_requested cp;
-               cp.handle = __cpu_to_le16(conn->handle);
-               hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
+               struct hci_cp_auth_requested auth_cp;
+
+               auth_cp.handle = __cpu_to_le16(conn->handle);
+               hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED,
+                            sizeof(auth_cp), &auth_cp);
        }
 
 unlock:
@@ -1465,33 +1480,6 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
        hci_dev_unlock(hdev);
 }
 
-static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
-{
-       struct hci_conn *conn;
-
-       BT_DBG("%s status 0x%2.2x", hdev->name, status);
-
-       if (status) {
-               hci_dev_lock(hdev);
-
-               conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
-               if (!conn) {
-                       hci_dev_unlock(hdev);
-                       return;
-               }
-
-               BT_DBG("%s bdaddr %pMR conn %p", hdev->name, &conn->dst, conn);
-
-               conn->state = BT_CLOSED;
-               mgmt_connect_failed(hdev, &conn->dst, conn->type,
-                                   conn->dst_type, status);
-               hci_proto_connect_cfm(conn, status);
-               hci_conn_del(conn);
-
-               hci_dev_unlock(hdev);
-       }
-}
-
 static void hci_cs_create_phylink(struct hci_dev *hdev, u8 status)
 {
        struct hci_cp_create_phy_link *cp;
@@ -1706,7 +1694,7 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
                                      &flags);
 
        if ((mask & HCI_LM_ACCEPT) &&
-           !hci_blacklist_lookup(hdev, &ev->bdaddr)) {
+           !hci_blacklist_lookup(hdev, &ev->bdaddr, BDADDR_BREDR)) {
                /* Connection accepted */
                struct inquiry_entry *ie;
                struct hci_conn *conn;
@@ -1821,10 +1809,25 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
        }
 
        if (ev->status == 0) {
-               if (conn->type == ACL_LINK && conn->flush_key)
+               u8 type = conn->type;
+
+               if (type == ACL_LINK && conn->flush_key)
                        hci_remove_link_key(hdev, &conn->dst);
                hci_proto_disconn_cfm(conn, ev->reason);
                hci_conn_del(conn);
+
+               /* Re-enable advertising if necessary, since it might
+                * have been disabled by the connection. From the
+                * HCI_LE_Set_Advertise_Enable command description in
+                * the core specification (v4.0):
+                * "The Controller shall continue advertising until the Host
+                * issues an LE_Set_Advertise_Enable command with
+                * Advertising_Enable set to 0x00 (Advertising is disabled)
+                * or until a connection is created or until the Advertising
+                * is timed out due to Directed Advertising."
+                */
+               if (type == LE_LINK)
+                       mgmt_reenable_advertising(hdev);
        }
 
 unlock:
@@ -2139,6 +2142,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                hci_cc_write_voice_setting(hdev, skb);
                break;
 
+       case HCI_OP_READ_NUM_SUPPORTED_IAC:
+               hci_cc_read_num_supported_iac(hdev, skb);
+               break;
+
        case HCI_OP_WRITE_SSP_MODE:
                hci_cc_write_ssp_mode(hdev, skb);
                break;
@@ -2342,10 +2349,6 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
                hci_cs_disconnect(hdev, ev->status);
                break;
 
-       case HCI_OP_LE_CREATE_CONN:
-               hci_cs_le_create_conn(hdev, ev->status);
-               break;
-
        case HCI_OP_CREATE_PHY_LINK:
                hci_cs_create_phylink(hdev, ev->status);
                break;
@@ -2548,7 +2551,6 @@ static void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
        conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
        if (conn) {
                conn->mode = ev->mode;
-               conn->interval = __le16_to_cpu(ev->interval);
 
                if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND,
                                        &conn->flags)) {
@@ -2930,6 +2932,23 @@ unlock:
        hci_dev_unlock(hdev);
 }
 
+static inline size_t eir_get_length(u8 *eir, size_t eir_len)
+{
+       size_t parsed = 0;
+
+       while (parsed < eir_len) {
+               u8 field_len = eir[0];
+
+               if (field_len == 0)
+                       return parsed;
+
+               parsed += field_len + 1;
+               eir += field_len + 1;
+       }
+
+       return eir_len;
+}
+
 static void hci_extended_inquiry_result_evt(struct hci_dev *hdev,
                                            struct sk_buff *skb)
 {
@@ -3170,7 +3189,8 @@ static void hci_user_confirm_request_evt(struct hci_dev *hdev,
 
                if (hdev->auto_accept_delay > 0) {
                        int delay = msecs_to_jiffies(hdev->auto_accept_delay);
-                       mod_timer(&conn->auto_accept_timer, jiffies + delay);
+                       queue_delayed_work(conn->hdev->workqueue,
+                                          &conn->auto_accept_work, delay);
                        goto unlock;
                }
 
@@ -3485,6 +3505,17 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
                conn->dst_type = ev->bdaddr_type;
 
+               /* The advertising parameters for own address type
+                * define which source address and source address
+                * type this connections has.
+                */
+               if (bacmp(&conn->src, BDADDR_ANY)) {
+                       conn->src_type = ADDR_LE_DEV_PUBLIC;
+               } else {
+                       bacpy(&conn->src, &hdev->static_addr);
+                       conn->src_type = ADDR_LE_DEV_RANDOM;
+               }
+
                if (ev->role == LE_CONN_ROLE_MASTER) {
                        conn->out = true;
                        conn->link_mode |= HCI_LM_MASTER;
@@ -3640,8 +3671,8 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
        skb_pull(skb, HCI_EVENT_HDR_SIZE);
 
        if (hdev->sent_cmd && bt_cb(hdev->sent_cmd)->req.event == event) {
-               struct hci_command_hdr *hdr = (void *) hdev->sent_cmd->data;
-               u16 opcode = __le16_to_cpu(hdr->opcode);
+               struct hci_command_hdr *cmd_hdr = (void *) hdev->sent_cmd->data;
+               u16 opcode = __le16_to_cpu(cmd_hdr->opcode);
 
                hci_req_cmd_complete(hdev, opcode, 0);
        }