]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth...
authorJohn W. Linville <linville@tuxdriver.com>
Mon, 24 Sep 2012 18:39:16 +0000 (14:39 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 24 Sep 2012 18:39:16 +0000 (14:39 -0400)
18 files changed:
drivers/bluetooth/bluecard_cs.c
drivers/bluetooth/btmrvl_sdio.c
drivers/bluetooth/btuart_cs.c
drivers/bluetooth/btusb.c
drivers/bluetooth/btwilink.c
drivers/bluetooth/hci_ldisc.c
drivers/bluetooth/hci_ll.c
drivers/bluetooth/hci_vhci.c
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/l2cap.h
include/net/bluetooth/mgmt.h
net/bluetooth/af_bluetooth.c
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/l2cap_core.c
net/bluetooth/mgmt.c

index 0c0838d9b56c2ec266c9ad92448787576a5170d6..0d26851d6e495a8624e611394709a1bf1246ef90 100644 (file)
@@ -681,7 +681,7 @@ static int bluecard_hci_send_frame(struct sk_buff *skb)
        case HCI_SCODATA_PKT:
                hdev->stat.sco_tx++;
                break;
-       };
+       }
 
        /* Prepend skb with frame type */
        memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
index 03b3acba61431a4cf7f0bfc0e5cadab2ef9b76ce..3f4bfc814dc7d5a0382635dbe16a41af413e59fe 100644 (file)
@@ -600,8 +600,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
 exit:
        if (ret) {
                hdev->stat.err_rx++;
-               if (skb)
-                       kfree_skb(skb);
+               kfree_skb(skb);
        }
 
        return ret;
index 2f510a87b28f90ae1c01370cb1df21882108868e..35a553a90616d85f07bf5c03d5d24e5373494ac6 100644 (file)
@@ -446,7 +446,7 @@ static int btuart_hci_send_frame(struct sk_buff *skb)
        case HCI_SCODATA_PKT:
                hdev->stat.sco_tx++;
                break;
-       };
+       }
 
        /* Prepend skb with frame type */
        memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
index e5921d681ddb551677a0900d4c1d82d4e6fdc53a..debda27df9b0452e3d7f3e5d2b06855c1b7af1f4 100644 (file)
@@ -96,11 +96,12 @@ static struct usb_device_id btusb_table[] = {
        { USB_DEVICE(0x0c10, 0x0000) },
 
        /* Broadcom BCM20702A0 */
+       { USB_DEVICE(0x04ca, 0x2003) },
        { USB_DEVICE(0x0489, 0xe042) },
        { USB_DEVICE(0x413c, 0x8197) },
 
        /* Foxconn - Hon Hai */
-       { USB_DEVICE(0x0489, 0xe033) },
+       { USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) },
 
        /*Broadcom devices with vendor specific id */
        { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
index 4ad7b35cfc0e1b46d0285e64d77aca460ae8b2bd..60abf596f60ea21f9354ae1b3d3608bb04e4142e 100644 (file)
@@ -358,21 +358,7 @@ static struct platform_driver btwilink_driver = {
        },
 };
 
-/* ------- Module Init/Exit interfaces ------ */
-static int __init btwilink_init(void)
-{
-       BT_INFO("Bluetooth Driver for TI WiLink - Version %s", VERSION);
-
-       return platform_driver_register(&btwilink_driver);
-}
-
-static void __exit btwilink_exit(void)
-{
-       platform_driver_unregister(&btwilink_driver);
-}
-
-module_init(btwilink_init);
-module_exit(btwilink_exit);
+module_platform_driver(btwilink_driver);
 
 /* ------ Module Info ------ */
 
index 74e0966b3ead0bbcf3678ebea52ea6886a65baee..c8abce3d2d9c0618f2092c94398e3197d0396b27 100644 (file)
@@ -531,7 +531,7 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
        default:
                err = n_tty_ioctl_helper(tty, file, cmd, arg);
                break;
-       };
+       }
 
        return err;
 }
index ff6d589c34a5e900eff0eb498782f5597a6a8bee..cfc7679385890b6e0feaadee1462a1e85330cc59 100644 (file)
@@ -481,7 +481,7 @@ static int ll_recv(struct hci_uart *hu, void *data, int count)
                        hu->hdev->stat.err_rx++;
                        ptr++; count--;
                        continue;
-               };
+               }
 
                ptr++; count--;
 
index 3f72595a60178a7f23ca45ac6418c6e5cb53faa6..d8b7aed6e4a96f6d6997ab9fac2a1ac84fbc4700 100644 (file)
@@ -156,7 +156,7 @@ static inline ssize_t vhci_put_user(struct vhci_data *data,
        case HCI_SCODATA_PKT:
                data->hdev->stat.sco_tx++;
                break;
-       };
+       }
 
        return total;
 }
index 23cf413e2acf3d72073c183fb2dc4dab3d16fa45..76b2b6bdcf36a281d558925a2a7a707ca2e1dddf 100644 (file)
@@ -302,8 +302,11 @@ enum {
 
 /* ---- HCI Error Codes ---- */
 #define HCI_ERROR_AUTH_FAILURE         0x05
+#define HCI_ERROR_CONNECTION_TIMEOUT   0x08
 #define HCI_ERROR_REJ_BAD_ADDR         0x0f
 #define HCI_ERROR_REMOTE_USER_TERM     0x13
+#define HCI_ERROR_REMOTE_LOW_RESOURCES 0x14
+#define HCI_ERROR_REMOTE_POWER_OFF     0x15
 #define HCI_ERROR_LOCAL_HOST_TERM      0x16
 #define HCI_ERROR_PAIRING_NOT_ALLOWED  0x18
 
@@ -1246,6 +1249,24 @@ struct hci_ev_simple_pair_complete {
        bdaddr_t bdaddr;
 } __packed;
 
+#define HCI_EV_USER_PASSKEY_NOTIFY     0x3b
+struct hci_ev_user_passkey_notify {
+       bdaddr_t        bdaddr;
+       __le32          passkey;
+} __packed;
+
+#define HCI_KEYPRESS_STARTED           0
+#define HCI_KEYPRESS_ENTERED           1
+#define HCI_KEYPRESS_ERASED            2
+#define HCI_KEYPRESS_CLEARED           3
+#define HCI_KEYPRESS_COMPLETED         4
+
+#define HCI_EV_KEYPRESS_NOTIFY         0x3c
+struct hci_ev_keypress_notify {
+       bdaddr_t        bdaddr;
+       __u8            type;
+} __packed;
+
 #define HCI_EV_REMOTE_HOST_FEATURES    0x3d
 struct hci_ev_remote_host_features {
        bdaddr_t bdaddr;
index 41d943926d2c3aa063ed5297b8ffef69ab1dabcd..e7d454609881a30d929ec8aa613390df157c8b43 100644 (file)
@@ -303,6 +303,8 @@ struct hci_conn {
        __u8            pin_length;
        __u8            enc_key_size;
        __u8            io_capability;
+       __u32           passkey_notify;
+       __u8            passkey_entered;
        __u16           disc_timeout;
        unsigned long   flags;
 
@@ -428,15 +430,6 @@ static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
               test_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
 }
 
-static inline void hci_conn_hash_init(struct hci_dev *hdev)
-{
-       struct hci_conn_hash *h = &hdev->conn_hash;
-       INIT_LIST_HEAD(&h->list);
-       h->acl_num = 0;
-       h->sco_num = 0;
-       h->le_num = 0;
-}
-
 static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
 {
        struct hci_conn_hash *h = &hdev->conn_hash;
@@ -551,9 +544,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
        return NULL;
 }
 
-void hci_acl_connect(struct hci_conn *conn);
 void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
-void hci_add_sco(struct hci_conn *conn, __u16 handle);
 void hci_setup_sync(struct hci_conn *conn, __u16 handle);
 void hci_sco_setup(struct hci_conn *conn, __u8 status);
 
@@ -563,7 +554,7 @@ void hci_conn_hash_flush(struct hci_dev *hdev);
 void hci_conn_check_pending(struct hci_dev *hdev);
 
 struct hci_chan *hci_chan_create(struct hci_conn *conn);
-int hci_chan_del(struct hci_chan *chan);
+void hci_chan_del(struct hci_chan *chan);
 void hci_chan_list_flush(struct hci_conn *conn);
 
 struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
@@ -614,11 +605,17 @@ static inline void hci_conn_put(struct hci_conn *conn)
 /* ----- HCI Devices ----- */
 static inline void hci_dev_put(struct hci_dev *d)
 {
+       BT_DBG("%s orig refcnt %d", d->name,
+              atomic_read(&d->dev.kobj.kref.refcount));
+
        put_device(&d->dev);
 }
 
 static inline struct hci_dev *hci_dev_hold(struct hci_dev *d)
 {
+       BT_DBG("%s orig refcnt %d", d->name,
+              atomic_read(&d->dev.kobj.kref.refcount));
+
        get_device(&d->dev);
        return d;
 }
@@ -1004,7 +1001,7 @@ int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
                          u8 addr_type, u32 flags, u8 *name, u8 name_len,
                          u8 *dev_class);
 int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
-                            u8 link_type, u8 addr_type);
+                            u8 link_type, u8 addr_type, u8 reason);
 int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
                           u8 link_type, u8 addr_type, u8 status);
 int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
@@ -1027,6 +1024,9 @@ int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
                                     u8 link_type, u8 addr_type, u8 status);
 int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
                                         u8 link_type, u8 addr_type, u8 status);
+int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                            u8 link_type, u8 addr_type, u32 passkey,
+                            u8 entered);
 int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
                     u8 addr_type, u8 status);
 int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status);
index d206296137e2b4fb50aa49bcee18dae9f0d687fb..7ed8e356425a16dc33c5afd5e4a80eaafdd6ea64 100644 (file)
@@ -433,11 +433,10 @@ struct l2cap_chan {
        struct sock *sk;
 
        struct l2cap_conn       *conn;
+       struct kref     kref;
 
        __u8            state;
 
-       atomic_t        refcnt;
-
        __le16          psm;
        __u16           dcid;
        __u16           scid;
index 4348ee8bda6993a15193a4e1e6adb640c9512e1f..22980a7c38730f53305b181e338dc29009cf62d6 100644 (file)
@@ -405,7 +405,16 @@ struct mgmt_ev_device_connected {
        __u8    eir[0];
 } __packed;
 
+#define MGMT_DEV_DISCONN_UNKNOWN       0x00
+#define MGMT_DEV_DISCONN_TIMEOUT       0x01
+#define MGMT_DEV_DISCONN_LOCAL_HOST    0x02
+#define MGMT_DEV_DISCONN_REMOTE                0x03
+
 #define MGMT_EV_DEVICE_DISCONNECTED    0x000C
+struct mgmt_ev_device_disconnected {
+       struct mgmt_addr_info addr;
+       __u8    reason;
+} __packed;
 
 #define MGMT_EV_CONNECT_FAILED         0x000D
 struct mgmt_ev_connect_failed {
@@ -469,3 +478,10 @@ struct mgmt_ev_device_unblocked {
 struct mgmt_ev_device_unpaired {
        struct mgmt_addr_info addr;
 } __packed;
+
+#define MGMT_EV_PASSKEY_NOTIFY         0x0017
+struct mgmt_ev_passkey_notify {
+       struct mgmt_addr_info addr;
+       __le32  passkey;
+       __u8    entered;
+} __packed;
index 58f9762b339aa7809554e9a7990970fff9a22231..9d49ee6d72190c8f9b727ed98ee1ba9f0c256f48 100644 (file)
@@ -567,8 +567,6 @@ static void bt_seq_stop(struct seq_file *seq, void *v)
 
 static int bt_seq_show(struct seq_file *seq, void *v)
 {
-       struct sock *sk;
-       struct bt_sock *bt;
        struct bt_seq_state *s = seq->private;
        struct bt_sock_list *l = s->l;
        bdaddr_t src_baswapped, dst_baswapped;
@@ -583,8 +581,8 @@ static int bt_seq_show(struct seq_file *seq, void *v)
 
                seq_putc(seq, '\n');
        } else {
-               sk = sk_entry(v);
-               bt = bt_sk(sk);
+               struct sock *sk = sk_entry(v);
+               struct bt_sock *bt = bt_sk(sk);
                baswap(&src_baswapped, &bt->src);
                baswap(&dst_baswapped, &bt->dst);
 
@@ -624,7 +622,7 @@ static int bt_seq_open(struct inode *inode, struct file *file)
        sk_list = PDE(inode)->data;
        s = __seq_open_private(file, &bt_seq_ops,
                               sizeof(struct bt_seq_state));
-       if (s == NULL)
+       if (!s)
                return -ENOMEM;
 
        s->l = sk_list;
@@ -646,7 +644,7 @@ int bt_procfs_init(struct module* module, struct net *net, const char *name,
        sk_list->fops.release   = seq_release_private;
 
        pde = proc_net_fops_create(net, name, 0, &sk_list->fops);
-       if (pde == NULL)
+       if (!pde)
                return -ENOMEM;
 
        pde->data = sk_list;
index 3c094e78dde98cafed3ac893abd3b2fa86b76a92..b9196a44f7598bf33b0c2bff6d0764eeeba8fc11 100644 (file)
@@ -31,7 +31,7 @@
 #include <net/bluetooth/a2mp.h>
 #include <net/bluetooth/smp.h>
 
-static void hci_le_connect(struct hci_conn *conn)
+static void hci_le_create_connection(struct hci_conn *conn)
 {
        struct hci_dev *hdev = conn->hdev;
        struct hci_cp_le_create_conn cp;
@@ -55,12 +55,12 @@ static void hci_le_connect(struct hci_conn *conn)
        hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
 }
 
-static void hci_le_connect_cancel(struct hci_conn *conn)
+static void hci_le_create_connection_cancel(struct hci_conn *conn)
 {
        hci_send_cmd(conn->hdev, HCI_OP_LE_CREATE_CONN_CANCEL, 0, NULL);
 }
 
-void hci_acl_connect(struct hci_conn *conn)
+static void hci_acl_create_connection(struct hci_conn *conn)
 {
        struct hci_dev *hdev = conn->hdev;
        struct inquiry_entry *ie;
@@ -104,7 +104,7 @@ void hci_acl_connect(struct hci_conn *conn)
        hci_send_cmd(hdev, HCI_OP_CREATE_CONN, sizeof(cp), &cp);
 }
 
-static void hci_acl_connect_cancel(struct hci_conn *conn)
+static void hci_acl_create_connection_cancel(struct hci_conn *conn)
 {
        struct hci_cp_create_conn_cancel cp;
 
@@ -130,7 +130,7 @@ void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
        hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp);
 }
 
-void hci_add_sco(struct hci_conn *conn, __u16 handle)
+static void hci_add_sco(struct hci_conn *conn, __u16 handle)
 {
        struct hci_dev *hdev = conn->hdev;
        struct hci_cp_add_sco cp;
@@ -246,9 +246,9 @@ static void hci_conn_timeout(struct work_struct *work)
        case BT_CONNECT2:
                if (conn->out) {
                        if (conn->type == ACL_LINK)
-                               hci_acl_connect_cancel(conn);
+                               hci_acl_create_connection_cancel(conn);
                        else if (conn->type == LE_LINK)
-                               hci_le_connect_cancel(conn);
+                               hci_le_create_connection_cancel(conn);
                }
                break;
        case BT_CONFIG:
@@ -471,40 +471,37 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
 }
 EXPORT_SYMBOL(hci_get_route);
 
-/* Create SCO, ACL or LE connection.
- * Device _must_ be locked */
-struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
-                            __u8 dst_type, __u8 sec_level, __u8 auth_type)
+static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
+                                   u8 dst_type, u8 sec_level, u8 auth_type)
 {
-       struct hci_conn *acl;
-       struct hci_conn *sco;
        struct hci_conn *le;
 
-       BT_DBG("%s dst %s", hdev->name, batostr(dst));
+       le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
+       if (!le) {
+               le = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
+               if (le)
+                       return ERR_PTR(-EBUSY);
 
-       if (type == LE_LINK) {
-               le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
-               if (!le) {
-                       le = hci_conn_hash_lookup_state(hdev, LE_LINK,
-                                                       BT_CONNECT);
-                       if (le)
-                               return ERR_PTR(-EBUSY);
+               le = hci_conn_add(hdev, LE_LINK, dst);
+               if (!le)
+                       return ERR_PTR(-ENOMEM);
 
-                       le = hci_conn_add(hdev, LE_LINK, dst);
-                       if (!le)
-                               return ERR_PTR(-ENOMEM);
+               le->dst_type = bdaddr_to_le(dst_type);
+               hci_le_create_connection(le);
+       }
 
-                       le->dst_type = bdaddr_to_le(dst_type);
-                       hci_le_connect(le);
-               }
+       le->pending_sec_level = sec_level;
+       le->auth_type = auth_type;
 
-               le->pending_sec_level = sec_level;
-               le->auth_type = auth_type;
+       hci_conn_hold(le);
 
-               hci_conn_hold(le);
+       return le;
+}
 
-               return le;
-       }
+static struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
+                                               u8 sec_level, u8 auth_type)
+{
+       struct hci_conn *acl;
 
        acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
        if (!acl) {
@@ -519,10 +516,20 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
                acl->sec_level = BT_SECURITY_LOW;
                acl->pending_sec_level = sec_level;
                acl->auth_type = auth_type;
-               hci_acl_connect(acl);
+               hci_acl_create_connection(acl);
        }
 
-       if (type == ACL_LINK)
+       return acl;
+}
+
+static struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type,
+                               bdaddr_t *dst, u8 sec_level, u8 auth_type)
+{
+       struct hci_conn *acl;
+       struct hci_conn *sco;
+
+       acl = hci_connect_acl(hdev, dst, sec_level, auth_type);
+       if (IS_ERR(acl))
                return acl;
 
        sco = hci_conn_hash_lookup_ba(hdev, type, dst);
@@ -556,6 +563,25 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
        return sco;
 }
 
+/* Create SCO, ACL or LE connection. */
+struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
+                            __u8 dst_type, __u8 sec_level, __u8 auth_type)
+{
+       BT_DBG("%s dst %s type 0x%x", hdev->name, batostr(dst), type);
+
+       switch (type) {
+       case LE_LINK:
+               return hci_connect_le(hdev, dst, dst_type, sec_level, auth_type);
+       case ACL_LINK:
+               return hci_connect_acl(hdev, dst, sec_level, auth_type);
+       case SCO_LINK:
+       case ESCO_LINK:
+               return hci_connect_sco(hdev, type, dst, sec_level, auth_type);
+       }
+
+       return ERR_PTR(-EINVAL);
+}
+
 /* Check link security requirement */
 int hci_conn_check_link_mode(struct hci_conn *conn)
 {
@@ -775,7 +801,7 @@ void hci_conn_check_pending(struct hci_dev *hdev)
 
        conn = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
        if (conn)
-               hci_acl_connect(conn);
+               hci_acl_create_connection(conn);
 
        hci_dev_unlock(hdev);
 }
@@ -913,7 +939,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn)
        return chan;
 }
 
-int hci_chan_del(struct hci_chan *chan)
+void hci_chan_del(struct hci_chan *chan)
 {
        struct hci_conn *conn = chan->conn;
        struct hci_dev *hdev = conn->hdev;
@@ -926,8 +952,6 @@ int hci_chan_del(struct hci_chan *chan)
 
        skb_queue_purge(&chan->data_q);
        kfree(chan);
-
-       return 0;
 }
 
 void hci_chan_list_flush(struct hci_conn *conn)
index fa974a19d365e78031cc53977871a1e2b8df2016..e4070517ff3b3decf3b61a5194874c7e2a039e7a 100644 (file)
@@ -231,6 +231,9 @@ static void amp_init(struct hci_dev *hdev)
 
        /* Read Local AMP Info */
        hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL);
+
+       /* Read Data Blk size */
+       hci_send_cmd(hdev, HCI_OP_READ_DATA_BLOCK_SIZE, 0, NULL);
 }
 
 static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
@@ -268,7 +271,6 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
                BT_ERR("Unknown device type %d", hdev->dev_type);
                break;
        }
-
 }
 
 static void hci_le_init_req(struct hci_dev *hdev, unsigned long opt)
@@ -1652,6 +1654,7 @@ struct hci_dev *hci_alloc_dev(void)
        INIT_LIST_HEAD(&hdev->link_keys);
        INIT_LIST_HEAD(&hdev->long_term_keys);
        INIT_LIST_HEAD(&hdev->remote_oob_data);
+       INIT_LIST_HEAD(&hdev->conn_hash.list);
 
        INIT_WORK(&hdev->rx_work, hci_rx_work);
        INIT_WORK(&hdev->cmd_work, hci_cmd_work);
@@ -1674,7 +1677,6 @@ struct hci_dev *hci_alloc_dev(void)
 
        hci_init_sysfs(hdev);
        discovery_init(hdev);
-       hci_conn_hash_init(hdev);
 
        return hdev;
 }
index 4fd2cf3bcd0577f418d622d3d81007867b52b283..2022b43c7353ee98d7546d6c9e0ef67c43811d3f 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/mgmt.h>
 
 /* Handle HCI Event packets */
 
@@ -303,7 +304,7 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
 
        hci_dev_lock(hdev);
 
-       if (status != 0) {
+       if (status) {
                mgmt_write_scan_failed(hdev, param, status);
                hdev->discov_timeout = 0;
                goto done;
@@ -925,7 +926,7 @@ static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb)
        if (test_bit(HCI_MGMT, &hdev->dev_flags))
                mgmt_pin_code_reply_complete(hdev, &rp->bdaddr, rp->status);
 
-       if (rp->status != 0)
+       if (rp->status)
                goto unlock;
 
        cp = hci_sent_cmd_data(hdev, HCI_OP_PIN_CODE_REPLY);
@@ -1891,6 +1892,22 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
        }
 }
 
+static u8 hci_to_mgmt_reason(u8 err)
+{
+       switch (err) {
+       case HCI_ERROR_CONNECTION_TIMEOUT:
+               return MGMT_DEV_DISCONN_TIMEOUT;
+       case HCI_ERROR_REMOTE_USER_TERM:
+       case HCI_ERROR_REMOTE_LOW_RESOURCES:
+       case HCI_ERROR_REMOTE_POWER_OFF:
+               return MGMT_DEV_DISCONN_REMOTE;
+       case HCI_ERROR_LOCAL_HOST_TERM:
+               return MGMT_DEV_DISCONN_LOCAL_HOST;
+       default:
+               return MGMT_DEV_DISCONN_UNKNOWN;
+       }
+}
+
 static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_disconn_complete *ev = (void *) skb->data;
@@ -1909,12 +1926,15 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
        if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) &&
            (conn->type == ACL_LINK || conn->type == LE_LINK)) {
-               if (ev->status != 0)
+               if (ev->status) {
                        mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
                                               conn->dst_type, ev->status);
-               else
+               } else {
+                       u8 reason = hci_to_mgmt_reason(ev->reason);
+
                        mgmt_device_disconnected(hdev, &conn->dst, conn->type,
-                                                conn->dst_type);
+                                                conn->dst_type, reason);
+               }
        }
 
        if (ev->status == 0) {
@@ -3259,6 +3279,65 @@ static void hci_user_passkey_request_evt(struct hci_dev *hdev,
                mgmt_user_passkey_request(hdev, &ev->bdaddr, ACL_LINK, 0);
 }
 
+static void hci_user_passkey_notify_evt(struct hci_dev *hdev,
+                                       struct sk_buff *skb)
+{
+       struct hci_ev_user_passkey_notify *ev = (void *) skb->data;
+       struct hci_conn *conn;
+
+       BT_DBG("%s", hdev->name);
+
+       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
+       if (!conn)
+               return;
+
+       conn->passkey_notify = __le32_to_cpu(ev->passkey);
+       conn->passkey_entered = 0;
+
+       if (test_bit(HCI_MGMT, &hdev->dev_flags))
+               mgmt_user_passkey_notify(hdev, &conn->dst, conn->type,
+                                        conn->dst_type, conn->passkey_notify,
+                                        conn->passkey_entered);
+}
+
+static void hci_keypress_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_ev_keypress_notify *ev = (void *) skb->data;
+       struct hci_conn *conn;
+
+       BT_DBG("%s", hdev->name);
+
+       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
+       if (!conn)
+               return;
+
+       switch (ev->type) {
+       case HCI_KEYPRESS_STARTED:
+               conn->passkey_entered = 0;
+               return;
+
+       case HCI_KEYPRESS_ENTERED:
+               conn->passkey_entered++;
+               break;
+
+       case HCI_KEYPRESS_ERASED:
+               conn->passkey_entered--;
+               break;
+
+       case HCI_KEYPRESS_CLEARED:
+               conn->passkey_entered = 0;
+               break;
+
+       case HCI_KEYPRESS_COMPLETED:
+               return;
+       }
+
+       if (test_bit(HCI_MGMT, &hdev->dev_flags))
+               mgmt_user_passkey_notify(hdev, &conn->dst, conn->type,
+                                        conn->dst_type, conn->passkey_notify,
+                                        conn->passkey_entered);
+}
+
 static void hci_simple_pair_complete_evt(struct hci_dev *hdev,
                                         struct sk_buff *skb)
 {
@@ -3278,7 +3357,7 @@ static void hci_simple_pair_complete_evt(struct hci_dev *hdev,
         * initiated the authentication. A traditional auth_complete
         * 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)
+       if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && ev->status)
                mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type,
                                 ev->status);
 
@@ -3623,6 +3702,14 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
                hci_user_passkey_request_evt(hdev, skb);
                break;
 
+       case HCI_EV_USER_PASSKEY_NOTIFY:
+               hci_user_passkey_notify_evt(hdev, skb);
+               break;
+
+       case HCI_EV_KEYPRESS_NOTIFY:
+               hci_keypress_notify_evt(hdev, skb);
+               break;
+
        case HCI_EV_SIMPLE_PAIR_COMPLETE:
                hci_simple_pair_complete_evt(hdev, skb);
                break;
index e0abaf3cb6a59976c8a5b814d9ae088211ffe741..7a59e929febcfbc5522beac888e6682324a698d4 100644 (file)
@@ -406,7 +406,7 @@ struct l2cap_chan *l2cap_chan_create(void)
 
        chan->state = BT_OPEN;
 
-       atomic_set(&chan->refcnt, 1);
+       kref_init(&chan->kref);
 
        /* This flag is cleared in l2cap_chan_ready() */
        set_bit(CONF_NOT_COMPLETE, &chan->conf_state);
@@ -416,8 +416,10 @@ struct l2cap_chan *l2cap_chan_create(void)
        return chan;
 }
 
-static void l2cap_chan_destroy(struct l2cap_chan *chan)
+static void l2cap_chan_destroy(struct kref *kref)
 {
+       struct l2cap_chan *chan = container_of(kref, struct l2cap_chan, kref);
+
        BT_DBG("chan %p", chan);
 
        write_lock(&chan_list_lock);
@@ -429,17 +431,16 @@ static void l2cap_chan_destroy(struct l2cap_chan *chan)
 
 void l2cap_chan_hold(struct l2cap_chan *c)
 {
-       BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->refcnt));
+       BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->kref.refcount));
 
-       atomic_inc(&c->refcnt);
+       kref_get(&c->kref);
 }
 
 void l2cap_chan_put(struct l2cap_chan *c)
 {
-       BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->refcnt));
+       BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->kref.refcount));
 
-       if (atomic_dec_and_test(&c->refcnt))
-               l2cap_chan_destroy(c);
+       kref_put(&c->kref, l2cap_chan_destroy);
 }
 
 void l2cap_chan_set_defaults(struct l2cap_chan *chan)
@@ -1448,7 +1449,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
        int err;
 
        BT_DBG("%s -> %s (type %u) psm 0x%2.2x", batostr(src), batostr(dst),
-              dst_type, __le16_to_cpu(chan->psm));
+              dst_type, __le16_to_cpu(psm));
 
        hdev = hci_get_route(dst, src);
        if (!hdev)
index a3329cbd3e4da52dc36987b40c9102262cea8e6b..8934343be0ea57f443a4445c78428967047c5332 100644 (file)
@@ -35,7 +35,7 @@
 bool enable_hs;
 
 #define MGMT_VERSION   1
-#define MGMT_REVISION  1
+#define MGMT_REVISION  2
 
 static const u16 mgmt_commands[] = {
        MGMT_OP_READ_INDEX_LIST,
@@ -99,6 +99,7 @@ static const u16 mgmt_events[] = {
        MGMT_EV_DEVICE_BLOCKED,
        MGMT_EV_DEVICE_UNBLOCKED,
        MGMT_EV_DEVICE_UNPAIRED,
+       MGMT_EV_PASSKEY_NOTIFY,
 };
 
 /*
@@ -3077,16 +3078,17 @@ static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
 }
 
 int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
-                            u8 link_type, u8 addr_type)
+                            u8 link_type, u8 addr_type, u8 reason)
 {
-       struct mgmt_addr_info ev;
+       struct mgmt_ev_device_disconnected ev;
        struct sock *sk = NULL;
        int err;
 
        mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
 
-       bacpy(&ev.bdaddr, bdaddr);
-       ev.type = link_to_bdaddr(link_type, addr_type);
+       bacpy(&ev.addr.bdaddr, bdaddr);
+       ev.addr.type = link_to_bdaddr(link_type, addr_type);
+       ev.reason = reason;
 
        err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
                         sk);
@@ -3275,6 +3277,22 @@ int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
                                          MGMT_OP_USER_PASSKEY_NEG_REPLY);
 }
 
+int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                            u8 link_type, u8 addr_type, u32 passkey,
+                            u8 entered)
+{
+       struct mgmt_ev_passkey_notify ev;
+
+       BT_DBG("%s", hdev->name);
+
+       bacpy(&ev.addr.bdaddr, bdaddr);
+       ev.addr.type = link_to_bdaddr(link_type, addr_type);
+       ev.passkey = __cpu_to_le32(passkey);
+       ev.entered = entered;
+
+       return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
+}
+
 int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
                     u8 addr_type, u8 status)
 {