Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[linux-2.6.git] / net / bluetooth / hci_event.c
index 8d8e775..3896dab 100644 (file)
 
 /* Bluetooth HCI event handling. */
 
-#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
-#include <linux/major.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/poll.h>
@@ -85,6 +83,8 @@ static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *
 {
        struct hci_conn *conn;
        struct hci_rp_role_discovery *rd;
+       struct hci_rp_write_link_policy *lp;
+       void *sent;
 
        BT_DBG("%s ocf 0x%x", hdev->name, ocf);
 
@@ -104,7 +104,28 @@ static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *
                        else
                                conn->link_mode |= HCI_LM_MASTER;
                }
-                       
+
+               hci_dev_unlock(hdev);
+               break;
+
+       case OCF_WRITE_LINK_POLICY:
+               sent = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY);
+               if (!sent)
+                       break;
+
+               lp = (struct hci_rp_write_link_policy *) skb->data;
+
+               if (lp->status)
+                       break;
+
+               hci_dev_lock(hdev);
+
+               conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(lp->handle));
+               if (conn) {
+                       __le16 policy = get_unaligned((__le16 *) (sent + 2));
+                       conn->link_policy = __le16_to_cpu(policy);
+               }
+
                hci_dev_unlock(hdev);
                break;
 
@@ -229,8 +250,11 @@ static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb
 
                        BT_DBG("%s: voice setting 0x%04x", hdev->name, setting);
 
-                       if (hdev->notify)
+                       if (hdev->notify) {
+                               tasklet_disable(&hdev->tx_task);
                                hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
+                               tasklet_enable(&hdev->tx_task);
+                       }
                }
                break;
 
@@ -240,15 +264,18 @@ static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb
                        break;
 
                status = *((__u8 *) skb->data);
-               setting = __le16_to_cpu(get_unaligned((__u16 *) sent));
+               setting = __le16_to_cpu(get_unaligned((__le16 *) sent));
 
                if (!status && hdev->voice_setting != setting) {
                        hdev->voice_setting = setting;
 
                        BT_DBG("%s: voice setting 0x%04x", hdev->name, setting);
 
-                       if (hdev->notify)
+                       if (hdev->notify) {
+                               tasklet_disable(&hdev->tx_task);
                                hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
+                               tasklet_enable(&hdev->tx_task);
+                       }
                }
                hci_req_complete(hdev, status);
                break;
@@ -270,7 +297,7 @@ static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb
 /* Command Complete OGF INFO_PARAM  */
 static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
 {
-       struct hci_rp_read_loc_features *lf;
+       struct hci_rp_read_local_features *lf;
        struct hci_rp_read_buffer_size *bs;
        struct hci_rp_read_bd_addr *ba;
 
@@ -278,7 +305,7 @@ static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *s
 
        switch (ocf) {
        case OCF_READ_LOCAL_FEATURES:
-               lf = (struct hci_rp_read_loc_features *) skb->data;
+               lf = (struct hci_rp_read_local_features *) skb->data;
 
                if (lf->status) {
                        BT_DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status);
@@ -315,12 +342,20 @@ static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *s
                }
 
                hdev->acl_mtu  = __le16_to_cpu(bs->acl_mtu);
-               hdev->sco_mtu  = bs->sco_mtu ? bs->sco_mtu : 64;
-               hdev->acl_pkts = hdev->acl_cnt = __le16_to_cpu(bs->acl_max_pkt);
-               hdev->sco_pkts = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt);
+               hdev->sco_mtu  = bs->sco_mtu;
+               hdev->acl_pkts = __le16_to_cpu(bs->acl_max_pkt);
+               hdev->sco_pkts = __le16_to_cpu(bs->sco_max_pkt);
+
+               if (test_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks)) {
+                       hdev->sco_mtu  = 64;
+                       hdev->sco_pkts = 8;
+               }
+
+               hdev->acl_cnt = hdev->acl_pkts;
+               hdev->sco_cnt = hdev->sco_pkts;
 
                BT_DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name,
-                           hdev->acl_mtu, hdev->sco_mtu, hdev->acl_pkts, hdev->sco_pkts);
+                       hdev->acl_mtu, hdev->sco_mtu, hdev->acl_pkts, hdev->sco_pkts);
                break;
 
        case OCF_READ_BD_ADDR:
@@ -400,7 +435,7 @@ static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
                        BT_DBG("%s Add SCO error: handle %d status 0x%x", hdev->name, handle, status);
 
                        hci_dev_lock(hdev);
-       
+
                        acl = hci_conn_hash_lookup_handle(hdev, handle);
                        if (acl && (sco = acl->link)) {
                                sco->state = BT_CLOSED;
@@ -435,8 +470,46 @@ static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status)
        BT_DBG("%s ocf 0x%x", hdev->name, ocf);
 
        switch (ocf) {
+       case OCF_SNIFF_MODE:
+               if (status) {
+                       struct hci_conn *conn;
+                       struct hci_cp_sniff_mode *cp = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_SNIFF_MODE);
+
+                       if (!cp)
+                               break;
+
+                       hci_dev_lock(hdev);
+
+                       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
+                       if (conn) {
+                               clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
+                       }
+
+                       hci_dev_unlock(hdev);
+               }
+               break;
+
+       case OCF_EXIT_SNIFF_MODE:
+               if (status) {
+                       struct hci_conn *conn;
+                       struct hci_cp_exit_sniff_mode *cp = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_EXIT_SNIFF_MODE);
+
+                       if (!cp)
+                               break;
+
+                       hci_dev_lock(hdev);
+
+                       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
+                       if (conn) {
+                               clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
+                       }
+
+                       hci_dev_unlock(hdev);
+               }
+               break;
+
        default:
-               BT_DBG("%s Command status: ogf HOST_POLICY ocf %x", hdev->name, ocf);
+               BT_DBG("%s Command status: ogf LINK_POLICY ocf %x", hdev->name, ocf);
                break;
        }
 }
@@ -479,37 +552,106 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff
 /* Inquiry Result */
 static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
+       struct inquiry_data data;
        struct inquiry_info *info = (struct inquiry_info *) (skb->data + 1);
        int num_rsp = *((__u8 *) skb->data);
 
        BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
 
+       if (!num_rsp)
+               return;
+
        hci_dev_lock(hdev);
-       for (; num_rsp; num_rsp--)
-               hci_inquiry_cache_update(hdev, info++);
+
+       for (; num_rsp; num_rsp--) {
+               bacpy(&data.bdaddr, &info->bdaddr);
+               data.pscan_rep_mode     = info->pscan_rep_mode;
+               data.pscan_period_mode  = info->pscan_period_mode;
+               data.pscan_mode         = info->pscan_mode;
+               memcpy(data.dev_class, info->dev_class, 3);
+               data.clock_offset       = info->clock_offset;
+               data.rssi               = 0x00;
+               info++;
+               hci_inquiry_cache_update(hdev, &data);
+       }
+
        hci_dev_unlock(hdev);
 }
 
 /* Inquiry Result With RSSI */
 static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct inquiry_info_with_rssi *info = (struct inquiry_info_with_rssi *) (skb->data + 1);
+       struct inquiry_data data;
        int num_rsp = *((__u8 *) skb->data);
 
        BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
 
+       if (!num_rsp)
+               return;
+
        hci_dev_lock(hdev);
+
+       if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
+               struct inquiry_info_with_rssi_and_pscan_mode *info =
+                       (struct inquiry_info_with_rssi_and_pscan_mode *) (skb->data + 1);
+
+               for (; num_rsp; num_rsp--) {
+                       bacpy(&data.bdaddr, &info->bdaddr);
+                       data.pscan_rep_mode     = info->pscan_rep_mode;
+                       data.pscan_period_mode  = info->pscan_period_mode;
+                       data.pscan_mode         = info->pscan_mode;
+                       memcpy(data.dev_class, info->dev_class, 3);
+                       data.clock_offset       = info->clock_offset;
+                       data.rssi               = info->rssi;
+                       info++;
+                       hci_inquiry_cache_update(hdev, &data);
+               }
+       } else {
+               struct inquiry_info_with_rssi *info =
+                       (struct inquiry_info_with_rssi *) (skb->data + 1);
+
+               for (; num_rsp; num_rsp--) {
+                       bacpy(&data.bdaddr, &info->bdaddr);
+                       data.pscan_rep_mode     = info->pscan_rep_mode;
+                       data.pscan_period_mode  = info->pscan_period_mode;
+                       data.pscan_mode         = 0x00;
+                       memcpy(data.dev_class, info->dev_class, 3);
+                       data.clock_offset       = info->clock_offset;
+                       data.rssi               = info->rssi;
+                       info++;
+                       hci_inquiry_cache_update(hdev, &data);
+               }
+       }
+
+       hci_dev_unlock(hdev);
+}
+
+/* Extended Inquiry Result */
+static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct inquiry_data data;
+       struct extended_inquiry_info *info = (struct extended_inquiry_info *) (skb->data + 1);
+       int num_rsp = *((__u8 *) skb->data);
+
+       BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
+
+       if (!num_rsp)
+               return;
+
+       hci_dev_lock(hdev);
+
        for (; num_rsp; num_rsp--) {
-               struct inquiry_info tmp;
-               bacpy(&tmp.bdaddr, &info->bdaddr);
-               tmp.pscan_rep_mode    = info->pscan_rep_mode;
-               tmp.pscan_period_mode = info->pscan_period_mode;
-               tmp.pscan_mode        = 0x00;
-               memcpy(tmp.dev_class, &info->dev_class, 3);
-               tmp.clock_offset      = info->clock_offset;
+               bacpy(&data.bdaddr, &info->bdaddr);
+               data.pscan_rep_mode     = info->pscan_rep_mode;
+               data.pscan_period_mode  = info->pscan_period_mode;
+               data.pscan_mode         = 0x00;
+               memcpy(data.dev_class, info->dev_class, 3);
+               data.clock_offset       = info->clock_offset;
+               data.rssi               = info->rssi;
                info++;
-               hci_inquiry_cache_update(hdev, &tmp);
+               hci_inquiry_cache_update(hdev, &data);
        }
+
        hci_dev_unlock(hdev);
 }
 
@@ -538,24 +680,27 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
                                return;
                        }
                }
+               memcpy(conn->dev_class, ev->dev_class, 3);
                conn->state = BT_CONNECT;
                hci_dev_unlock(hdev);
 
                bacpy(&cp.bdaddr, &ev->bdaddr);
-       
+
                if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER))
                        cp.role = 0x00; /* Become master */
                else
                        cp.role = 0x01; /* Remain slave */
 
-               hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ, sizeof(cp), &cp);
+               hci_send_cmd(hdev, OGF_LINK_CTL,
+                               OCF_ACCEPT_CONN_REQ, sizeof(cp), &cp);
        } else {
                /* Connection rejected */
                struct hci_cp_reject_conn_req cp;
 
                bacpy(&cp.bdaddr, &ev->bdaddr);
                cp.reason = 0x0f;
-               hci_send_cmd(hdev, OGF_LINK_CTL, OCF_REJECT_CONN_REQ, sizeof(cp), &cp);
+               hci_send_cmd(hdev, OGF_LINK_CTL,
+                               OCF_REJECT_CONN_REQ, sizeof(cp), &cp);
        }
 }
 
@@ -563,7 +708,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
 static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_conn_complete *ev = (struct hci_ev_conn_complete *) skb->data;
-       struct hci_conn *conn = NULL;
+       struct hci_conn *conn;
 
        BT_DBG("%s", hdev->name);
 
@@ -585,13 +730,21 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                if (test_bit(HCI_ENCRYPT, &hdev->flags))
                        conn->link_mode |= HCI_LM_ENCRYPT;
 
+               /* Get remote features */
+               if (conn->type == ACL_LINK) {
+                       struct hci_cp_read_remote_features cp;
+                       cp.handle = ev->handle;
+                       hci_send_cmd(hdev, OGF_LINK_CTL,
+                               OCF_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, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY, sizeof(cp), &cp);
+                       hci_send_cmd(hdev, OGF_LINK_POLICY,
+                               OCF_WRITE_LINK_POLICY, sizeof(cp), &cp);
                }
 
                /* Set packet type for incoming connection */
@@ -602,7 +755,8 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                                __cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK):
                                __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
 
-                       hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CHANGE_CONN_PTYPE, sizeof(cp), &cp);
+                       hci_send_cmd(hdev, OGF_LINK_CTL,
+                               OCF_CHANGE_CONN_PTYPE, sizeof(cp), &cp);
                }
        } else
                conn->state = BT_CLOSED;
@@ -630,8 +784,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
 static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_disconn_complete *ev = (struct hci_ev_disconn_complete *) skb->data;
-       struct hci_conn *conn = NULL;
-       __u16 handle = __le16_to_cpu(ev->handle);
+       struct hci_conn *conn;
 
        BT_DBG("%s status %d", hdev->name, ev->status);
 
@@ -640,7 +793,7 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
 
        hci_dev_lock(hdev);
 
-       conn = hci_conn_hash_lookup_handle(hdev, handle);
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
        if (conn) {
                conn->state = BT_CLOSED;
                hci_proto_disconn_ind(conn, ev->reason);
@@ -654,7 +807,7 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
 static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_num_comp_pkts *ev = (struct hci_ev_num_comp_pkts *) skb->data;
-       __u16 *ptr;
+       __le16 *ptr;
        int i;
 
        skb_pull(skb, sizeof(*ev));
@@ -668,7 +821,7 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
 
        tasklet_disable(&hdev->tx_task);
 
-       for (i = 0, ptr = (__u16 *) skb->data; i < ev->num_hndl; i++) {
+       for (i = 0, ptr = (__le16 *) skb->data; i < ev->num_hndl; i++) {
                struct hci_conn *conn;
                __u16  handle, count;
 
@@ -697,21 +850,50 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
 static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_role_change *ev = (struct hci_ev_role_change *) skb->data;
-       struct hci_conn *conn = NULL;
+       struct hci_conn *conn;
 
        BT_DBG("%s status %d", hdev->name, ev->status);
 
-       if (ev->status)
-               return;
-
        hci_dev_lock(hdev);
 
        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
        if (conn) {
-               if (ev->role)
-                       conn->link_mode &= ~HCI_LM_MASTER;
-               else 
-                       conn->link_mode |= HCI_LM_MASTER;
+               if (!ev->status) {
+                       if (ev->role)
+                               conn->link_mode &= ~HCI_LM_MASTER;
+                       else
+                               conn->link_mode |= HCI_LM_MASTER;
+               }
+
+               clear_bit(HCI_CONN_RSWITCH_PEND, &conn->pend);
+
+               hci_role_switch_cfm(conn, ev->status, ev->role);
+       }
+
+       hci_dev_unlock(hdev);
+}
+
+/* Mode Change */
+static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_ev_mode_change *ev = (struct hci_ev_mode_change *) 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) {
+               conn->mode = ev->mode;
+               conn->interval = __le16_to_cpu(ev->interval);
+
+               if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
+                       if (conn->mode == HCI_CM_ACTIVE)
+                               conn->power_save = 1;
+                       else
+                               conn->power_save = 0;
+               }
        }
 
        hci_dev_unlock(hdev);
@@ -721,20 +903,20 @@ static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb
 static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_auth_complete *ev = (struct hci_ev_auth_complete *) skb->data;
-       struct hci_conn *conn = NULL;
-       __u16 handle = __le16_to_cpu(ev->handle);
+       struct hci_conn *conn;
 
        BT_DBG("%s status %d", hdev->name, ev->status);
 
        hci_dev_lock(hdev);
 
-       conn = hci_conn_hash_lookup_handle(hdev, handle);
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
        if (conn) {
                if (!ev->status)
                        conn->link_mode |= HCI_LM_AUTH;
+
                clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
 
-               hci_proto_auth_cfm(conn, ev->status);
+               hci_auth_cfm(conn, ev->status);
 
                if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
                        if (!ev->status) {
@@ -742,11 +924,10 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                                cp.handle  = __cpu_to_le16(conn->handle);
                                cp.encrypt = 1;
                                hci_send_cmd(conn->hdev, OGF_LINK_CTL,
-                                               OCF_SET_CONN_ENCRYPT,
-                                               sizeof(cp), &cp);
+                                       OCF_SET_CONN_ENCRYPT, sizeof(cp), &cp);
                        } else {
                                clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
-                               hci_proto_encrypt_cfm(conn, ev->status);
+                               hci_encrypt_cfm(conn, ev->status, 0x00);
                        }
                }
        }
@@ -758,14 +939,13 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
 static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_encrypt_change *ev = (struct hci_ev_encrypt_change *) skb->data;
-       struct hci_conn *conn = NULL;
-       __u16 handle = __le16_to_cpu(ev->handle);
+       struct hci_conn *conn;
 
        BT_DBG("%s status %d", hdev->name, ev->status);
 
        hci_dev_lock(hdev);
 
-       conn = hci_conn_hash_lookup_handle(hdev, handle);
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
        if (conn) {
                if (!ev->status) {
                        if (ev->encrypt)
@@ -773,9 +953,124 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *
                        else
                                conn->link_mode &= ~HCI_LM_ENCRYPT;
                }
+
                clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
-               
-               hci_proto_encrypt_cfm(conn, ev->status);
+
+               hci_encrypt_cfm(conn, ev->status, ev->encrypt);
+       }
+
+       hci_dev_unlock(hdev);
+}
+
+/* Change Connection Link Key Complete */
+static inline void hci_change_conn_link_key_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_ev_change_conn_link_key_complete *ev = (struct hci_ev_change_conn_link_key_complete *) 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) {
+               if (!ev->status)
+                       conn->link_mode |= HCI_LM_SECURE;
+
+               clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
+
+               hci_key_change_cfm(conn, ev->status);
+       }
+
+       hci_dev_unlock(hdev);
+}
+
+/* Pin Code Request*/
+static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+}
+
+/* Link Key Request */
+static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+}
+
+/* Link Key Notification */
+static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+}
+
+/* Remote Features */
+static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_ev_remote_features *ev = (struct hci_ev_remote_features *) 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) {
+               memcpy(conn->features, ev->features, sizeof(conn->features));
+       }
+
+       hci_dev_unlock(hdev);
+}
+
+/* Clock Offset */
+static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_ev_clock_offset *ev = (struct hci_ev_clock_offset *) 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) {
+               struct inquiry_entry *ie;
+
+               if ((ie = hci_inquiry_cache_lookup(hdev, &conn->dst))) {
+                       ie->data.clock_offset = ev->clock_offset;
+                       ie->timestamp = jiffies;
+               }
+       }
+
+       hci_dev_unlock(hdev);
+}
+
+/* Page Scan Repetition Mode */
+static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_ev_pscan_rep_mode *ev = (struct hci_ev_pscan_rep_mode *) skb->data;
+       struct inquiry_entry *ie;
+
+       BT_DBG("%s", hdev->name);
+
+       hci_dev_lock(hdev);
+
+       if ((ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr))) {
+               ie->data.pscan_rep_mode = ev->pscan_rep_mode;
+               ie->timestamp = jiffies;
+       }
+
+       hci_dev_unlock(hdev);
+}
+
+/* Sniff Subrate */
+static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_ev_sniff_subrate *ev = (struct hci_ev_sniff_subrate *) 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) {
        }
 
        hci_dev_unlock(hdev);
@@ -809,6 +1104,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
                hci_inquiry_result_with_rssi_evt(hdev, skb);
                break;
 
+       case HCI_EV_EXTENDED_INQUIRY_RESULT:
+               hci_extended_inquiry_result_evt(hdev, skb);
+               break;
+
        case HCI_EV_CONN_REQUEST:
                hci_conn_request_evt(hdev, skb);
                break;
@@ -825,6 +1124,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
                hci_role_change_evt(hdev, skb);
                break;
 
+       case HCI_EV_MODE_CHANGE:
+               hci_mode_change_evt(hdev, skb);
+               break;
+
        case HCI_EV_AUTH_COMPLETE:
                hci_auth_complete_evt(hdev, skb);
                break;
@@ -833,6 +1136,38 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
                hci_encrypt_change_evt(hdev, skb);
                break;
 
+       case HCI_EV_CHANGE_CONN_LINK_KEY_COMPLETE:
+               hci_change_conn_link_key_complete_evt(hdev, skb);
+               break;
+
+       case HCI_EV_PIN_CODE_REQ:
+               hci_pin_code_request_evt(hdev, skb);
+               break;
+
+       case HCI_EV_LINK_KEY_REQ:
+               hci_link_key_request_evt(hdev, skb);
+               break;
+
+       case HCI_EV_LINK_KEY_NOTIFY:
+               hci_link_key_notify_evt(hdev, skb);
+               break;
+
+       case HCI_EV_REMOTE_FEATURES:
+               hci_remote_features_evt(hdev, skb);
+               break;
+
+       case HCI_EV_CLOCK_OFFSET:
+               hci_clock_offset_evt(hdev, skb);
+               break;
+
+       case HCI_EV_PSCAN_REP_MODE:
+               hci_pscan_rep_mode_evt(hdev, skb);
+               break;
+
+       case HCI_EV_SNIFF_SUBRATE:
+               hci_sniff_subrate_evt(hdev, skb);
+               break;
+
        case HCI_EV_CMD_STATUS:
                cs = (struct hci_ev_cmd_status *) skb->data;
                skb_pull(skb, sizeof(cs));
@@ -931,9 +1266,11 @@ void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
        ev->type = type;
        memcpy(ev->data, data, dlen);
 
-       skb->pkt_type = HCI_EVENT_PKT;
+       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);
        kfree_skb(skb);
 }
-EXPORT_SYMBOL(hci_si_event);