]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/bluetooth/hci_event.c
Bluetooth: mgmt: Fix updating EIR when updating the name
[karo-tx-linux.git] / net / bluetooth / hci_event.c
index 97152d9d7116b4f38c8874708cf3012cec853e36..e44e3fd68628faa16a8743d35e1d874f1e588fa1 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/init.h>
 #include <linux/skbuff.h>
 #include <linux/interrupt.h>
-#include <linux/notifier.h>
 #include <net/sock.h>
 
 #include <asm/system.h>
@@ -45,8 +44,6 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
-static bool enable_le;
-
 /* Handle HCI Event packets */
 
 static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
@@ -195,9 +192,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
 
        hci_req_complete(hdev, HCI_OP_RESET, status);
 
-       /* Reset all flags, except persistent ones */
-       hdev->dev_flags &= BIT(HCI_MGMT) | BIT(HCI_SETUP) | BIT(HCI_AUTO_OFF) |
-                               BIT(HCI_LINK_KEYS) | BIT(HCI_DEBUG_KEYS);
+       /* Reset all non-persistent flags */
+       hdev->dev_flags &= ~(BIT(HCI_LE_SCAN));
 }
 
 static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
@@ -213,12 +209,12 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
 
        hci_dev_lock(hdev);
 
-       if (test_bit(HCI_MGMT, &hdev->dev_flags))
-               mgmt_set_local_name_complete(hdev, sent, status);
-
        if (status == 0)
                memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);
 
+       if (test_bit(HCI_MGMT, &hdev->dev_flags))
+               mgmt_set_local_name_complete(hdev, sent, status);
+
        hci_dev_unlock(hdev);
 }
 
@@ -254,6 +250,9 @@ static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
                        clear_bit(HCI_AUTH, &hdev->flags);
        }
 
+       if (test_bit(HCI_MGMT, &hdev->dev_flags))
+               mgmt_auth_enable_complete(hdev, status);
+
        hci_req_complete(hdev, HCI_OP_WRITE_AUTH_ENABLE, status);
 }
 
@@ -421,21 +420,6 @@ static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
        hci_req_complete(hdev, HCI_OP_HOST_BUFFER_SIZE, status);
 }
 
-static void hci_cc_read_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
-{
-       struct hci_rp_read_ssp_mode *rp = (void *) skb->data;
-
-       BT_DBG("%s status 0x%x", hdev->name, rp->status);
-
-       if (rp->status)
-               return;
-
-       if (rp->mode)
-               set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
-       else
-               clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
-}
-
 static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
 {
        __u8 status = *((__u8 *) skb->data);
@@ -443,17 +427,18 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
 
        BT_DBG("%s status 0x%x", hdev->name, status);
 
-       if (status)
-               return;
-
        sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SSP_MODE);
        if (!sent)
                return;
 
-       if (*((u8 *) sent))
-               set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
-       else
-               clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
+       if (test_bit(HCI_MGMT, &hdev->dev_flags))
+               mgmt_ssp_enable_complete(hdev, *((u8 *) sent), status);
+       else if (!status) {
+               if (*((u8 *) sent))
+                       set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
+               else
+                       clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
+       }
 }
 
 static u8 hci_get_inquiry_mode(struct hci_dev *hdev)
@@ -554,7 +539,7 @@ static void hci_set_le_support(struct hci_dev *hdev)
 
        memset(&cp, 0, sizeof(cp));
 
-       if (enable_le) {
+       if (enable_le && test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
                cp.le = 1;
                cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
        }
@@ -573,8 +558,18 @@ static void hci_setup(struct hci_dev *hdev)
                hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
 
        if (hdev->features[6] & LMP_SIMPLE_PAIR) {
-               u8 mode = 0x01;
-               hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode);
+               if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
+                       u8 mode = 0x01;
+                       hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE,
+                                                       sizeof(mode), &mode);
+               } else {
+                       struct hci_cp_write_eir cp;
+
+                       memset(hdev->eir, 0, sizeof(hdev->eir));
+                       memset(&cp, 0, sizeof(cp));
+
+                       hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
+               }
        }
 
        if (hdev->features[3] & LMP_RSSI_INQ)
@@ -591,6 +586,12 @@ static void hci_setup(struct hci_dev *hdev)
                                                        sizeof(cp), &cp);
        }
 
+       if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags)) {
+               u8 enable = 1;
+               hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE,
+                                               sizeof(enable), &enable);
+       }
+
        if (hdev->features[4] & LMP_LE)
                hci_set_le_support(hdev);
 }
@@ -960,8 +961,8 @@ static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
        hci_dev_lock(hdev);
 
        if (test_bit(HCI_MGMT, &hdev->dev_flags))
-               mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr,
-                                                               rp->status);
+               mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr, ACL_LINK,
+                                                               0, rp->status);
 
        hci_dev_unlock(hdev);
 }
@@ -977,6 +978,7 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
 
        if (test_bit(HCI_MGMT, &hdev->dev_flags))
                mgmt_user_confirm_neg_reply_complete(hdev, &rp->bdaddr,
+                                                               ACL_LINK, 0,
                                                                rp->status);
 
        hci_dev_unlock(hdev);
@@ -991,8 +993,8 @@ static void hci_cc_user_passkey_reply(struct hci_dev *hdev, struct sk_buff *skb)
        hci_dev_lock(hdev);
 
        if (test_bit(HCI_MGMT, &hdev->dev_flags))
-               mgmt_user_passkey_reply_complete(hdev, &rp->bdaddr,
-                                                               rp->status);
+               mgmt_user_passkey_reply_complete(hdev, &rp->bdaddr, ACL_LINK,
+                                                               0, rp->status);
 
        hci_dev_unlock(hdev);
 }
@@ -1008,6 +1010,7 @@ static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev,
 
        if (test_bit(HCI_MGMT, &hdev->dev_flags))
                mgmt_user_passkey_neg_reply_complete(hdev, &rp->bdaddr,
+                                                               ACL_LINK, 0,
                                                                rp->status);
 
        hci_dev_unlock(hdev);
@@ -1033,6 +1036,13 @@ static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
        BT_DBG("%s status 0x%x", hdev->name, status);
 
        hci_req_complete(hdev, HCI_OP_LE_SET_SCAN_PARAM, status);
+
+       if (status) {
+               hci_dev_lock(hdev);
+               mgmt_start_discovery_failed(hdev, status);
+               hci_dev_unlock(hdev);
+               return;
+       }
 }
 
 static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
@@ -1051,8 +1061,12 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
        case LE_SCANNING_ENABLED:
                hci_req_complete(hdev, HCI_OP_LE_SET_SCAN_ENABLE, status);
 
-               if (status)
+               if (status) {
+                       hci_dev_lock(hdev);
+                       mgmt_start_discovery_failed(hdev, status);
+                       hci_dev_unlock(hdev);
                        return;
+               }
 
                set_bit(HCI_LE_SCAN, &hdev->dev_flags);
 
@@ -1060,7 +1074,7 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
 
                hci_dev_lock(hdev);
                hci_adv_entries_clear(hdev);
-               hci_discovery_set_state(hdev, DISCOVERY_LE_SCAN);
+               hci_discovery_set_state(hdev, DISCOVERY_FINDING);
                hci_dev_unlock(hdev);
                break;
 
@@ -1070,11 +1084,16 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
 
                clear_bit(HCI_LE_SCAN, &hdev->dev_flags);
 
-               hci_dev_lock(hdev);
-               hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
-               hci_dev_unlock(hdev);
-
                schedule_delayed_work(&hdev->adv_work, ADV_CLEAR_TIMEOUT);
+
+               if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED) {
+                       mgmt_interleaved_discovery(hdev);
+               } else {
+                       hci_dev_lock(hdev);
+                       hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+                       hci_dev_unlock(hdev);
+               }
+
                break;
 
        default:
@@ -1111,10 +1130,15 @@ static inline void hci_cc_write_le_host_supported(struct hci_dev *hdev,
                                                        struct sk_buff *skb)
 {
        struct hci_cp_read_local_ext_features cp;
+       struct hci_cp_write_le_host_supported *sent;
        __u8 status = *((__u8 *) skb->data);
 
        BT_DBG("%s status 0x%x", hdev->name, status);
 
+       sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED);
+       if (sent && test_bit(HCI_MGMT, &hdev->dev_flags))
+               mgmt_le_enable_complete(hdev, sent->le, status);
+
        if (status)
                return;
 
@@ -1139,7 +1163,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
        set_bit(HCI_INQUIRY, &hdev->flags);
 
        hci_dev_lock(hdev);
-       hci_discovery_set_state(hdev, DISCOVERY_INQUIRY);
+       hci_discovery_set_state(hdev, DISCOVERY_FINDING);
        hci_dev_unlock(hdev);
 }
 
@@ -1539,6 +1563,28 @@ static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status)
        hci_dev_unlock(hdev);
 }
 
+static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
+{
+       struct hci_cp_disconnect *cp;
+       struct hci_conn *conn;
+
+       if (!status)
+               return;
+
+       cp = hci_sent_cmd_data(hdev, HCI_OP_DISCONNECT);
+       if (!cp)
+               return;
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
+       if (conn)
+               mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
+                                               conn->dst_type, status);
+
+       hci_dev_unlock(hdev);
+}
+
 static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
 {
        struct hci_cp_le_create_conn *cp;
@@ -1603,7 +1649,7 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff
 
        hci_dev_lock(hdev);
 
-       if (discov->state != DISCOVERY_INQUIRY)
+       if (discov->state != DISCOVERY_FINDING)
                goto unlock;
 
        if (list_empty(&discov->resolve)) {
@@ -1828,7 +1874,8 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
        if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) &&
                        (conn->type == ACL_LINK || conn->type == LE_LINK)) {
                if (ev->status != 0)
-                       mgmt_disconnect_failed(hdev, &conn->dst, ev->status);
+                       mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
+                                               conn->dst_type, ev->status);
                else
                        mgmt_device_disconnected(hdev, &conn->dst, conn->type,
                                                        conn->dst_type);
@@ -1865,7 +1912,8 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                        conn->sec_level = conn->pending_sec_level;
                }
        } else {
-               mgmt_auth_failed(hdev, &conn->dst, ev->status);
+               mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type,
+                                                               ev->status);
        }
 
        clear_bit(HCI_CONN_AUTH_PEND, &conn->flags);
@@ -2150,10 +2198,6 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
                hci_cc_host_buffer_size(hdev, skb);
                break;
 
-       case HCI_OP_READ_SSP_MODE:
-               hci_cc_read_ssp_mode(hdev, skb);
-               break;
-
        case HCI_OP_WRITE_SSP_MODE:
                hci_cc_write_ssp_mode(hdev, skb);
                break;
@@ -2339,8 +2383,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
                break;
 
        case HCI_OP_DISCONNECT:
-               if (ev->status != 0)
-                       mgmt_disconnect_failed(hdev, NULL, ev->status);
+               hci_cs_disconnect(hdev, ev->status);
                break;
 
        case HCI_OP_LE_CREATE_CONN:
@@ -3090,7 +3133,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
        }
 
 confirm:
-       mgmt_user_confirm_request(hdev, &ev->bdaddr, ev->passkey,
+       mgmt_user_confirm_request(hdev, &ev->bdaddr, ACL_LINK, 0, ev->passkey,
                                                                confirm_hint);
 
 unlock:
@@ -3107,7 +3150,7 @@ static inline void hci_user_passkey_request_evt(struct hci_dev *hdev,
        hci_dev_lock(hdev);
 
        if (test_bit(HCI_MGMT, &hdev->dev_flags))
-               mgmt_user_passkey_request(hdev, &ev->bdaddr);
+               mgmt_user_passkey_request(hdev, &ev->bdaddr, ACL_LINK, 0);
 
        hci_dev_unlock(hdev);
 }
@@ -3131,7 +3174,8 @@ static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_
         * event gets always produced as initiator and is also mapped to
         * the mgmt_auth_failed event */
        if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && ev->status != 0)
-               mgmt_auth_failed(hdev, &conn->dst, ev->status);
+               mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type,
+                                                               ev->status);
 
        hci_conn_put(conn);
 
@@ -3497,34 +3541,3 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
        kfree_skb(skb);
        hdev->stat.evt_rx++;
 }
-
-/* Generate internal stack event */
-void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
-{
-       struct hci_event_hdr *hdr;
-       struct hci_ev_stack_internal *ev;
-       struct sk_buff *skb;
-
-       skb = bt_skb_alloc(HCI_EVENT_HDR_SIZE + sizeof(*ev) + dlen, GFP_ATOMIC);
-       if (!skb)
-               return;
-
-       hdr = (void *) skb_put(skb, HCI_EVENT_HDR_SIZE);
-       hdr->evt  = HCI_EV_STACK_INTERNAL;
-       hdr->plen = sizeof(*ev) + dlen;
-
-       ev  = (void *) skb_put(skb, sizeof(*ev) + dlen);
-       ev->type = type;
-       memcpy(ev->data, data, dlen);
-
-       bt_cb(skb)->incoming = 1;
-       __net_timestamp(skb);
-
-       bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
-       skb->dev = (void *) hdev;
-       hci_send_to_sock(hdev, skb, NULL);
-       kfree_skb(skb);
-}
-
-module_param(enable_le, bool, 0644);
-MODULE_PARM_DESC(enable_le, "Enable LE support");