Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / net / bluetooth / hci_event.c
index 47a1e90..eb64555 100644 (file)
@@ -30,7 +30,6 @@
 #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>
@@ -243,7 +242,7 @@ 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;
@@ -485,14 +484,18 @@ 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--) {
-               struct inquiry_data data;
                bacpy(&data.bdaddr, &info->bdaddr);
                data.pscan_rep_mode     = info->pscan_rep_mode;
                data.pscan_period_mode  = info->pscan_period_mode;
@@ -503,30 +506,84 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
                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_data data;
                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;
+               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;
+               data.clock_offset       = info->clock_offset;
+               data.rssi               = info->rssi;
                info++;
                hci_inquiry_cache_update(hdev, &data);
        }
+
        hci_dev_unlock(hdev);
 }
 
@@ -671,7 +728,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));
@@ -685,7 +742,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;
 
@@ -718,17 +775,20 @@ static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb
 
        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);
@@ -749,6 +809,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
        if (conn) {
                if (!ev->status)
                        conn->link_mode |= HCI_LM_AUTH;
+
                clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
 
                hci_auth_cfm(conn, ev->status);
@@ -790,6 +851,7 @@ 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_encrypt_cfm(conn, ev->status, ev->encrypt);
@@ -801,6 +863,25 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *
 /* 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 = NULL;
+       __u16 handle = __le16_to_cpu(ev->handle);
+
+       BT_DBG("%s status %d", hdev->name, ev->status);
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_handle(hdev, 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*/
@@ -842,6 +923,24 @@ static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *sk
        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);
+}
+
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_event_hdr *hdr = (struct hci_event_hdr *) skb->data;
@@ -870,6 +969,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;
@@ -914,6 +1017,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
                hci_clock_offset_evt(hdev, skb);
                break;
 
+       case HCI_EV_PSCAN_REP_MODE:
+               hci_pscan_rep_mode_evt(hdev, skb);
+               break;
+
        case HCI_EV_CMD_STATUS:
                cs = (struct hci_ev_cmd_status *) skb->data;
                skb_pull(skb, sizeof(cs));
@@ -1012,9 +1119,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);