vserver 1.9.5.x5
[linux-2.6.git] / net / bluetooth / hci_event.c
index c515f28..47a1e90 100644 (file)
    SOFTWARE IS DISCLAIMED.
 */
 
-/*
- * HCI Events.
- *
- * $Id: hci_event.c,v 1.3 2002/04/17 17:37:16 maxk Exp $
- */
+/* Bluetooth HCI event handling. */
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -54,7 +50,7 @@
 
 #ifndef CONFIG_BT_HCI_CORE_DEBUG
 #undef  BT_DBG
-#define BT_DBG( A... )
+#define BT_DBG(D...)
 #endif
 
 /* Handle HCI Event packets */
@@ -98,9 +94,9 @@ static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *
 
                if (rd->status)
                        break;
-               
+
                hci_dev_lock(hdev);
-       
+
                conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rd->handle));
                if (conn) {
                        if (rd->role)
@@ -108,7 +104,7 @@ 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;
 
@@ -233,8 +229,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;
 
@@ -251,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);
+                       }
                }
                hci_req_complete(hdev, status);
                break;
@@ -324,7 +326,7 @@ static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *s
                hdev->sco_pkts = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt);
 
                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:
@@ -355,14 +357,14 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
                return;
 
        hci_dev_lock(hdev);
-       
+
        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
 
        BT_DBG("%s status 0x%x bdaddr %s conn %p", hdev->name,
                        status, batostr(&cp->bdaddr), conn);
 
        if (status) {
-               if (conn) {
+               if (conn && conn->state == BT_CONNECT) {
                        conn->state = BT_CLOSED;
                        hci_proto_connect_cfm(conn, status);
                        hci_conn_del(conn);
@@ -404,7 +406,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;
@@ -489,8 +491,18 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
        BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
 
        hci_dev_lock(hdev);
-       for (; num_rsp; num_rsp--)
-               inquiry_cache_update(hdev, info++);
+       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         = 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);
 }
 
@@ -504,15 +516,16 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
 
        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;
+               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;
+               memcpy(data.dev_class, info->dev_class, 3);
+               data.clock_offset       = info->clock_offset;
+               data.rssi               = info->rssi;
                info++;
-               inquiry_cache_update(hdev, &tmp);
+               hci_inquiry_cache_update(hdev, &data);
        }
        hci_dev_unlock(hdev);
 }
@@ -542,11 +555,12 @@ 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
@@ -572,7 +586,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
        BT_DBG("%s", hdev->name);
 
        hci_dev_lock(hdev);
-       
+
        conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
        if (!conn) {
                hci_dev_unlock(hdev);
@@ -585,11 +599,10 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
 
                if (test_bit(HCI_AUTH, &hdev->flags))
                        conn->link_mode |= HCI_LM_AUTH;
-               
+
                if (test_bit(HCI_ENCRYPT, &hdev->flags))
                        conn->link_mode |= HCI_LM_ENCRYPT;
 
-
                /* Set link policy */
                if (conn->type == ACL_LINK && hdev->link_policy) {
                        struct hci_cp_write_link_policy cp;
@@ -643,7 +656,7 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
                return;
 
        hci_dev_lock(hdev);
-       
+
        conn = hci_conn_hash_lookup_handle(hdev, handle);
        if (conn) {
                conn->state = BT_CLOSED;
@@ -709,12 +722,12 @@ static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb
                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 
+               else
                        conn->link_mode |= HCI_LM_MASTER;
        }
 
@@ -731,15 +744,15 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
        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_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) {
                                struct hci_cp_set_conn_encrypt cp;
@@ -750,7 +763,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                                                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);
                        }
                }
        }
@@ -768,18 +781,62 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *
        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) {
-                       if (ev->encrypt)
+                       if (ev->encrypt)
                                conn->link_mode |= HCI_LM_ENCRYPT;
                        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)
+{
+}
+
+/* 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)
+{
+}
+
+/* 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 = 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 && !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);
@@ -837,10 +894,30 @@ 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_CLOCK_OFFSET:
+               hci_clock_offset_evt(hdev, skb);
+               break;
+
        case HCI_EV_CMD_STATUS:
                cs = (struct hci_ev_cmd_status *) skb->data;
                skb_pull(skb, sizeof(cs));
-                               
+
                opcode = __le16_to_cpu(cs->opcode);
                ogf = hci_opcode_ogf(opcode);
                ocf = hci_opcode_ocf(opcode);
@@ -928,15 +1005,16 @@ void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
                return;
 
        hdr = (void *) skb_put(skb, HCI_EVENT_HDR_SIZE);
-               hdr->evt  = HCI_EV_STACK_INTERNAL;
+       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);
-       
+
        skb->pkt_type = HCI_EVENT_PKT;
        skb->dev = (void *) hdev;
        hci_send_to_sock(hdev, skb);
        kfree_skb(skb);
 }
+EXPORT_SYMBOL(hci_si_event);