[Bluetooth] Hangup TTY before releasing rfcomm_dev
[safe/jmp/linux-2.6] / net / bluetooth / hci_event.c
index c6cd243..447ba71 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
    BlueZ - Bluetooth protocol stack for Linux
    Copyright (C) 2000-2001 Qualcomm Incorporated
 
    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
    IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
    SOFTWARE IS DISCLAIMED.
 */
 
@@ -29,7 +29,6 @@
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/poll.h>
 #include <linux/fcntl.h>
@@ -57,6 +56,7 @@
 static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
 {
        __u8 status;
+       struct hci_conn *pend;
 
        BT_DBG("%s ocf 0x%x", hdev->name, ocf);
 
@@ -71,6 +71,15 @@ static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb
                        clear_bit(HCI_INQUIRY, &hdev->flags);
                        hci_req_complete(hdev, status);
                }
+
+               hci_dev_lock(hdev);
+
+               pend = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
+               if (pend)
+                       hci_acl_connect(pend);
+
+               hci_dev_unlock(hdev);
+
                break;
 
        default:
@@ -90,7 +99,7 @@ static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *
        BT_DBG("%s ocf 0x%x", hdev->name, ocf);
 
        switch (ocf) {
-       case OCF_ROLE_DISCOVERY: 
+       case OCF_ROLE_DISCOVERY:
                rd = (void *) skb->data;
 
                if (rd->status)
@@ -131,7 +140,7 @@ static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *
                break;
 
        default:
-               BT_DBG("%s: Command complete: ogf LINK_POLICY ocf %x", 
+               BT_DBG("%s: Command complete: ogf LINK_POLICY ocf %x",
                                hdev->name, ocf);
                break;
        }
@@ -227,10 +236,10 @@ static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb
                if (!status) {
                        clear_bit(HCI_PSCAN, &hdev->flags);
                        clear_bit(HCI_ISCAN, &hdev->flags);
-                       if (param & SCAN_INQUIRY) 
+                       if (param & SCAN_INQUIRY)
                                set_bit(HCI_ISCAN, &hdev->flags);
 
-                       if (param & SCAN_PAGE) 
+                       if (param & SCAN_PAGE)
                                set_bit(HCI_PSCAN, &hdev->flags);
                }
                hci_req_complete(hdev, status);
@@ -298,6 +307,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_version *lv;
        struct hci_rp_read_local_features *lf;
        struct hci_rp_read_buffer_size *bs;
        struct hci_rp_read_bd_addr *ba;
@@ -305,6 +315,23 @@ static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *s
        BT_DBG("%s ocf 0x%x", hdev->name, ocf);
 
        switch (ocf) {
+       case OCF_READ_LOCAL_VERSION:
+               lv = (struct hci_rp_read_loc_version *) skb->data;
+
+               if (lv->status) {
+                       BT_DBG("%s READ_LOCAL_VERSION failed %d", hdev->name, lf->status);
+                       break;
+               }
+
+               hdev->hci_ver = lv->hci_ver;
+               hdev->hci_rev = btohs(lv->hci_rev);
+               hdev->manufacturer = btohs(lv->manufacturer);
+
+               BT_DBG("%s: manufacturer %d hci_ver %d hci_rev %d", hdev->name,
+                               hdev->manufacturer, hdev->hci_ver, hdev->hci_rev);
+
+               break;
+
        case OCF_READ_LOCAL_FEATURES:
                lf = (struct hci_rp_read_local_features *) skb->data;
 
@@ -315,7 +342,7 @@ static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *s
 
                memcpy(hdev->features, lf->features, sizeof(hdev->features));
 
-               /* Adjust default settings according to features 
+               /* Adjust default settings according to features
                 * supported by device. */
                if (hdev->features[0] & LMP_3SLOT)
                        hdev->pkt_type |= (HCI_DM3 | HCI_DH3);
@@ -329,7 +356,8 @@ static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *s
                if (hdev->features[1] & LMP_HV3)
                        hdev->pkt_type |= (HCI_HV3);
 
-               BT_DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, lf->features[0], lf->features[1], lf->features[2]);
+               BT_DBG("%s: features 0x%x 0x%x 0x%x", hdev->name,
+                               lf->features[0], lf->features[1], lf->features[2]);
 
                break;
 
@@ -395,9 +423,12 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
 
        if (status) {
                if (conn && conn->state == BT_CONNECT) {
-                       conn->state = BT_CLOSED;
-                       hci_proto_connect_cfm(conn, status);
-                       hci_conn_del(conn);
+                       if (status != 0x0c || conn->attempt > 2) {
+                               conn->state = BT_CLOSED;
+                               hci_proto_connect_cfm(conn, status);
+                               hci_conn_del(conn);
+                       } else
+                               conn->state = BT_CONNECT2;
                }
        } else {
                if (!conn) {
@@ -459,7 +490,7 @@ static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
                break;
 
        default:
-               BT_DBG("%s Command status: ogf LINK_CTL ocf %x status %d", 
+               BT_DBG("%s Command status: ogf LINK_CTL ocf %x status %d",
                        hdev->name, ocf, status);
                break;
        }
@@ -543,11 +574,20 @@ static void hci_cs_info_param(struct hci_dev *hdev, __u16 ocf, __u8 status)
 static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        __u8 status = *((__u8 *) skb->data);
+       struct hci_conn *pend;
 
        BT_DBG("%s status %d", hdev->name, status);
 
        clear_bit(HCI_INQUIRY, &hdev->flags);
        hci_req_complete(hdev, status);
+
+       hci_dev_lock(hdev);
+
+       pend = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
+       if (pend)
+               hci_acl_connect(pend);
+
+       hci_dev_unlock(hdev);
 }
 
 /* Inquiry Result */
@@ -709,7 +749,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;
+       struct hci_conn *conn, *pend;
 
        BT_DBG("%s", hdev->name);
 
@@ -743,7 +783,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                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);
+                       cp.policy = cpu_to_le16(hdev->link_policy);
                        hci_send_cmd(hdev, OGF_LINK_POLICY,
                                OCF_WRITE_LINK_POLICY, sizeof(cp), &cp);
                }
@@ -752,12 +792,16 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                if (!conn->out) {
                        struct hci_cp_change_conn_ptype cp;
                        cp.handle = ev->handle;
-                       cp.pkt_type = (conn->type == ACL_LINK) ? 
-                               __cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK):
-                               __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
+                       cp.pkt_type = (conn->type == ACL_LINK) ?
+                               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);
+               } else {
+                       /* Update disconnect timer */
+                       hci_conn_hold(conn);
+                       hci_conn_put(conn);
                }
        } else
                conn->state = BT_CLOSED;
@@ -778,6 +822,10 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
        if (ev->status)
                hci_conn_del(conn);
 
+       pend = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
+       if (pend)
+               hci_acl_connect(pend);
+
        hci_dev_unlock(hdev);
 }
 
@@ -922,7 +970,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
                        if (!ev->status) {
                                struct hci_cp_set_conn_encrypt cp;
-                               cp.handle  = __cpu_to_le16(conn->handle);
+                               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);