Merge branches 'for-3.7/upstream-fixes', 'for-3.8/hidraw', 'for-3.8/i2c-hid', 'for-3.8/multitouch', 'for-3.8/roccat', 'for-3.8/sensors' and 'for-3.8/upstream' into for-linus
Conflicts: drivers/hid/hid-core.c
This commit is contained in:
@@ -316,7 +316,7 @@ send_rsp:
|
||||
static inline int a2mp_cmd_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
|
||||
struct a2mp_cmd *hdr)
|
||||
{
|
||||
BT_DBG("ident %d code %d", hdr->ident, hdr->code);
|
||||
BT_DBG("ident %d code 0x%2.2x", hdr->ident, hdr->code);
|
||||
|
||||
skb_pull(skb, le16_to_cpu(hdr->len));
|
||||
return 0;
|
||||
@@ -325,17 +325,19 @@ static inline int a2mp_cmd_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
|
||||
/* Handle A2MP signalling */
|
||||
static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
|
||||
{
|
||||
struct a2mp_cmd *hdr = (void *) skb->data;
|
||||
struct a2mp_cmd *hdr;
|
||||
struct amp_mgr *mgr = chan->data;
|
||||
int err = 0;
|
||||
|
||||
amp_mgr_get(mgr);
|
||||
|
||||
while (skb->len >= sizeof(*hdr)) {
|
||||
struct a2mp_cmd *hdr = (void *) skb->data;
|
||||
u16 len = le16_to_cpu(hdr->len);
|
||||
u16 len;
|
||||
|
||||
BT_DBG("code 0x%02x id %d len %d", hdr->code, hdr->ident, len);
|
||||
hdr = (void *) skb->data;
|
||||
len = le16_to_cpu(hdr->len);
|
||||
|
||||
BT_DBG("code 0x%2.2x id %d len %u", hdr->code, hdr->ident, len);
|
||||
|
||||
skb_pull(skb, sizeof(*hdr));
|
||||
|
||||
@@ -393,7 +395,9 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
|
||||
|
||||
if (err) {
|
||||
struct a2mp_cmd_rej rej;
|
||||
|
||||
rej.reason = __constant_cpu_to_le16(0);
|
||||
hdr = (void *) skb->data;
|
||||
|
||||
BT_DBG("Send A2MP Rej: cmd 0x%2.2x err %d", hdr->code, err);
|
||||
|
||||
@@ -412,7 +416,7 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
|
||||
|
||||
static void a2mp_chan_close_cb(struct l2cap_chan *chan)
|
||||
{
|
||||
l2cap_chan_destroy(chan);
|
||||
l2cap_chan_put(chan);
|
||||
}
|
||||
|
||||
static void a2mp_chan_state_change_cb(struct l2cap_chan *chan, int state)
|
||||
|
@@ -28,6 +28,7 @@
|
||||
#include <asm/ioctls.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <linux/proc_fs.h>
|
||||
|
||||
#define VERSION "2.16"
|
||||
|
||||
@@ -532,6 +533,144 @@ int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
|
||||
}
|
||||
EXPORT_SYMBOL(bt_sock_wait_state);
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
struct bt_seq_state {
|
||||
struct bt_sock_list *l;
|
||||
};
|
||||
|
||||
static void *bt_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
__acquires(seq->private->l->lock)
|
||||
{
|
||||
struct bt_seq_state *s = seq->private;
|
||||
struct bt_sock_list *l = s->l;
|
||||
|
||||
read_lock(&l->lock);
|
||||
return seq_hlist_start_head(&l->head, *pos);
|
||||
}
|
||||
|
||||
static void *bt_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||
{
|
||||
struct bt_seq_state *s = seq->private;
|
||||
struct bt_sock_list *l = s->l;
|
||||
|
||||
return seq_hlist_next(v, &l->head, pos);
|
||||
}
|
||||
|
||||
static void bt_seq_stop(struct seq_file *seq, void *v)
|
||||
__releases(seq->private->l->lock)
|
||||
{
|
||||
struct bt_seq_state *s = seq->private;
|
||||
struct bt_sock_list *l = s->l;
|
||||
|
||||
read_unlock(&l->lock);
|
||||
}
|
||||
|
||||
static int bt_seq_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
struct bt_seq_state *s = seq->private;
|
||||
struct bt_sock_list *l = s->l;
|
||||
bdaddr_t src_baswapped, dst_baswapped;
|
||||
|
||||
if (v == SEQ_START_TOKEN) {
|
||||
seq_puts(seq ,"sk RefCnt Rmem Wmem User Inode Src Dst Parent");
|
||||
|
||||
if (l->custom_seq_show) {
|
||||
seq_putc(seq, ' ');
|
||||
l->custom_seq_show(seq, v);
|
||||
}
|
||||
|
||||
seq_putc(seq, '\n');
|
||||
} else {
|
||||
struct sock *sk = sk_entry(v);
|
||||
struct bt_sock *bt = bt_sk(sk);
|
||||
baswap(&src_baswapped, &bt->src);
|
||||
baswap(&dst_baswapped, &bt->dst);
|
||||
|
||||
seq_printf(seq, "%pK %-6d %-6u %-6u %-6u %-6lu %pM %pM %-6lu",
|
||||
sk,
|
||||
atomic_read(&sk->sk_refcnt),
|
||||
sk_rmem_alloc_get(sk),
|
||||
sk_wmem_alloc_get(sk),
|
||||
from_kuid(seq_user_ns(seq), sock_i_uid(sk)),
|
||||
sock_i_ino(sk),
|
||||
&src_baswapped,
|
||||
&dst_baswapped,
|
||||
bt->parent? sock_i_ino(bt->parent): 0LU);
|
||||
|
||||
if (l->custom_seq_show) {
|
||||
seq_putc(seq, ' ');
|
||||
l->custom_seq_show(seq, v);
|
||||
}
|
||||
|
||||
seq_putc(seq, '\n');
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct seq_operations bt_seq_ops = {
|
||||
.start = bt_seq_start,
|
||||
.next = bt_seq_next,
|
||||
.stop = bt_seq_stop,
|
||||
.show = bt_seq_show,
|
||||
};
|
||||
|
||||
static int bt_seq_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct bt_sock_list *sk_list;
|
||||
struct bt_seq_state *s;
|
||||
|
||||
sk_list = PDE(inode)->data;
|
||||
s = __seq_open_private(file, &bt_seq_ops,
|
||||
sizeof(struct bt_seq_state));
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
s->l = sk_list;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_procfs_init(struct module* module, struct net *net, const char *name,
|
||||
struct bt_sock_list* sk_list,
|
||||
int (* seq_show)(struct seq_file *, void *))
|
||||
{
|
||||
struct proc_dir_entry * pde;
|
||||
|
||||
sk_list->custom_seq_show = seq_show;
|
||||
|
||||
sk_list->fops.owner = module;
|
||||
sk_list->fops.open = bt_seq_open;
|
||||
sk_list->fops.read = seq_read;
|
||||
sk_list->fops.llseek = seq_lseek;
|
||||
sk_list->fops.release = seq_release_private;
|
||||
|
||||
pde = proc_net_fops_create(net, name, 0, &sk_list->fops);
|
||||
if (!pde)
|
||||
return -ENOMEM;
|
||||
|
||||
pde->data = sk_list;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bt_procfs_cleanup(struct net *net, const char *name)
|
||||
{
|
||||
proc_net_remove(net, name);
|
||||
}
|
||||
#else
|
||||
int bt_procfs_init(struct module* module, struct net *net, const char *name,
|
||||
struct bt_sock_list* sk_list,
|
||||
int (* seq_show)(struct seq_file *, void *))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bt_procfs_cleanup(struct net *net, const char *name)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
EXPORT_SYMBOL(bt_procfs_init);
|
||||
EXPORT_SYMBOL(bt_procfs_cleanup);
|
||||
|
||||
static struct net_proto_family bt_sock_family_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.family = PF_BLUETOOTH,
|
||||
|
@@ -29,6 +29,10 @@
|
||||
|
||||
#include "bnep.h"
|
||||
|
||||
static struct bt_sock_list bnep_sk_list = {
|
||||
.lock = __RW_LOCK_UNLOCKED(bnep_sk_list.lock)
|
||||
};
|
||||
|
||||
static int bnep_sock_release(struct socket *sock)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
@@ -38,6 +42,8 @@ static int bnep_sock_release(struct socket *sock)
|
||||
if (!sk)
|
||||
return 0;
|
||||
|
||||
bt_sock_unlink(&bnep_sk_list, sk);
|
||||
|
||||
sock_orphan(sk);
|
||||
sock_put(sk);
|
||||
return 0;
|
||||
@@ -204,6 +210,7 @@ static int bnep_sock_create(struct net *net, struct socket *sock, int protocol,
|
||||
sk->sk_protocol = protocol;
|
||||
sk->sk_state = BT_OPEN;
|
||||
|
||||
bt_sock_link(&bnep_sk_list, sk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -222,19 +229,30 @@ int __init bnep_sock_init(void)
|
||||
return err;
|
||||
|
||||
err = bt_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops);
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
BT_ERR("Can't register BNEP socket");
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = bt_procfs_init(THIS_MODULE, &init_net, "bnep", &bnep_sk_list, NULL);
|
||||
if (err < 0) {
|
||||
BT_ERR("Failed to create BNEP proc file");
|
||||
bt_sock_unregister(BTPROTO_BNEP);
|
||||
goto error;
|
||||
}
|
||||
|
||||
BT_INFO("BNEP socket layer initialized");
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
BT_ERR("Can't register BNEP socket");
|
||||
proto_unregister(&bnep_proto);
|
||||
return err;
|
||||
}
|
||||
|
||||
void __exit bnep_sock_cleanup(void)
|
||||
{
|
||||
bt_procfs_cleanup(&init_net, "bnep");
|
||||
if (bt_sock_unregister(BTPROTO_BNEP) < 0)
|
||||
BT_ERR("Can't unregister BNEP socket");
|
||||
|
||||
|
@@ -42,6 +42,10 @@
|
||||
|
||||
#include "cmtp.h"
|
||||
|
||||
static struct bt_sock_list cmtp_sk_list = {
|
||||
.lock = __RW_LOCK_UNLOCKED(cmtp_sk_list.lock)
|
||||
};
|
||||
|
||||
static int cmtp_sock_release(struct socket *sock)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
@@ -51,6 +55,8 @@ static int cmtp_sock_release(struct socket *sock)
|
||||
if (!sk)
|
||||
return 0;
|
||||
|
||||
bt_sock_unlink(&cmtp_sk_list, sk);
|
||||
|
||||
sock_orphan(sk);
|
||||
sock_put(sk);
|
||||
|
||||
@@ -214,6 +220,8 @@ static int cmtp_sock_create(struct net *net, struct socket *sock, int protocol,
|
||||
sk->sk_protocol = protocol;
|
||||
sk->sk_state = BT_OPEN;
|
||||
|
||||
bt_sock_link(&cmtp_sk_list, sk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -232,19 +240,30 @@ int cmtp_init_sockets(void)
|
||||
return err;
|
||||
|
||||
err = bt_sock_register(BTPROTO_CMTP, &cmtp_sock_family_ops);
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
BT_ERR("Can't register CMTP socket");
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = bt_procfs_init(THIS_MODULE, &init_net, "cmtp", &cmtp_sk_list, NULL);
|
||||
if (err < 0) {
|
||||
BT_ERR("Failed to create CMTP proc file");
|
||||
bt_sock_unregister(BTPROTO_HIDP);
|
||||
goto error;
|
||||
}
|
||||
|
||||
BT_INFO("CMTP socket layer initialized");
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
BT_ERR("Can't register CMTP socket");
|
||||
proto_unregister(&cmtp_proto);
|
||||
return err;
|
||||
}
|
||||
|
||||
void cmtp_cleanup_sockets(void)
|
||||
{
|
||||
bt_procfs_cleanup(&init_net, "cmtp");
|
||||
if (bt_sock_unregister(BTPROTO_CMTP) < 0)
|
||||
BT_ERR("Can't unregister CMTP socket");
|
||||
|
||||
|
@@ -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,41 +471,38 @@ 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_connect(le);
|
||||
}
|
||||
|
||||
le->pending_sec_level = sec_level;
|
||||
le->auth_type = auth_type;
|
||||
|
||||
hci_conn_hold(le);
|
||||
|
||||
return le;
|
||||
le->dst_type = bdaddr_to_le(dst_type);
|
||||
hci_le_create_connection(le);
|
||||
}
|
||||
|
||||
le->pending_sec_level = sec_level;
|
||||
le->auth_type = auth_type;
|
||||
|
||||
hci_conn_hold(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) {
|
||||
acl = hci_conn_add(hdev, ACL_LINK, dst);
|
||||
@@ -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)
|
||||
|
@@ -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)
|
||||
@@ -696,7 +698,8 @@ int hci_dev_open(__u16 dev)
|
||||
hci_dev_hold(hdev);
|
||||
set_bit(HCI_UP, &hdev->flags);
|
||||
hci_notify(hdev, HCI_DEV_UP);
|
||||
if (!test_bit(HCI_SETUP, &hdev->dev_flags)) {
|
||||
if (!test_bit(HCI_SETUP, &hdev->dev_flags) &&
|
||||
mgmt_valid_hdev(hdev)) {
|
||||
hci_dev_lock(hdev);
|
||||
mgmt_powered(hdev, 1);
|
||||
hci_dev_unlock(hdev);
|
||||
@@ -799,7 +802,8 @@ static int hci_dev_do_close(struct hci_dev *hdev)
|
||||
* and no tasks are scheduled. */
|
||||
hdev->close(hdev);
|
||||
|
||||
if (!test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
|
||||
if (!test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags) &&
|
||||
mgmt_valid_hdev(hdev)) {
|
||||
hci_dev_lock(hdev);
|
||||
mgmt_powered(hdev, 0);
|
||||
hci_dev_unlock(hdev);
|
||||
@@ -1652,6 +1656,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 +1679,6 @@ struct hci_dev *hci_alloc_dev(void)
|
||||
|
||||
hci_init_sysfs(hdev);
|
||||
discovery_init(hdev);
|
||||
hci_conn_hash_init(hdev);
|
||||
|
||||
return hdev;
|
||||
}
|
||||
|
@@ -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;
|
||||
@@ -513,7 +514,7 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
|
||||
if (hdev->features[3] & LMP_RSSI_INQ)
|
||||
events[4] |= 0x02; /* Inquiry Result with RSSI */
|
||||
|
||||
if (hdev->features[5] & LMP_SNIFF_SUBR)
|
||||
if (lmp_sniffsubr_capable(hdev))
|
||||
events[5] |= 0x20; /* Sniff Subrating */
|
||||
|
||||
if (hdev->features[5] & LMP_PAUSE_ENC)
|
||||
@@ -522,13 +523,13 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
|
||||
if (hdev->features[6] & LMP_EXT_INQ)
|
||||
events[5] |= 0x40; /* Extended Inquiry Result */
|
||||
|
||||
if (hdev->features[6] & LMP_NO_FLUSH)
|
||||
if (lmp_no_flush_capable(hdev))
|
||||
events[7] |= 0x01; /* Enhanced Flush Complete */
|
||||
|
||||
if (hdev->features[7] & LMP_LSTO)
|
||||
events[6] |= 0x80; /* Link Supervision Timeout Changed */
|
||||
|
||||
if (hdev->features[6] & LMP_SIMPLE_PAIR) {
|
||||
if (lmp_ssp_capable(hdev)) {
|
||||
events[6] |= 0x01; /* IO Capability Request */
|
||||
events[6] |= 0x02; /* IO Capability Response */
|
||||
events[6] |= 0x04; /* User Confirmation Request */
|
||||
@@ -541,7 +542,7 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
|
||||
* Features Notification */
|
||||
}
|
||||
|
||||
if (hdev->features[4] & LMP_LE)
|
||||
if (lmp_le_capable(hdev))
|
||||
events[7] |= 0x20; /* LE Meta-Event */
|
||||
|
||||
hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
|
||||
@@ -623,11 +624,11 @@ static void hci_setup_link_policy(struct hci_dev *hdev)
|
||||
struct hci_cp_write_def_link_policy cp;
|
||||
u16 link_policy = 0;
|
||||
|
||||
if (hdev->features[0] & LMP_RSWITCH)
|
||||
if (lmp_rswitch_capable(hdev))
|
||||
link_policy |= HCI_LP_RSWITCH;
|
||||
if (hdev->features[0] & LMP_HOLD)
|
||||
link_policy |= HCI_LP_HOLD;
|
||||
if (hdev->features[0] & LMP_SNIFF)
|
||||
if (lmp_sniff_capable(hdev))
|
||||
link_policy |= HCI_LP_SNIFF;
|
||||
if (hdev->features[1] & LMP_PARK)
|
||||
link_policy |= HCI_LP_PARK;
|
||||
@@ -686,7 +687,7 @@ static void hci_cc_read_local_features(struct hci_dev *hdev,
|
||||
hdev->esco_type |= (ESCO_HV3);
|
||||
}
|
||||
|
||||
if (hdev->features[3] & LMP_ESCO)
|
||||
if (lmp_esco_capable(hdev))
|
||||
hdev->esco_type |= (ESCO_EV3);
|
||||
|
||||
if (hdev->features[4] & LMP_EV4)
|
||||
@@ -746,7 +747,7 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
|
||||
break;
|
||||
}
|
||||
|
||||
if (test_bit(HCI_INIT, &hdev->flags) && hdev->features[4] & LMP_LE)
|
||||
if (test_bit(HCI_INIT, &hdev->flags) && lmp_le_capable(hdev))
|
||||
hci_set_le_support(hdev);
|
||||
|
||||
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);
|
||||
@@ -1625,43 +1626,30 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
|
||||
|
||||
static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
|
||||
{
|
||||
struct hci_cp_le_create_conn *cp;
|
||||
struct hci_conn *conn;
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, status);
|
||||
|
||||
cp = hci_sent_cmd_data(hdev, HCI_OP_LE_CREATE_CONN);
|
||||
if (!cp)
|
||||
return;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->peer_addr);
|
||||
|
||||
BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&cp->peer_addr),
|
||||
conn);
|
||||
|
||||
if (status) {
|
||||
if (conn && conn->state == BT_CONNECT) {
|
||||
conn->state = BT_CLOSED;
|
||||
mgmt_connect_failed(hdev, &cp->peer_addr, conn->type,
|
||||
conn->dst_type, status);
|
||||
hci_proto_connect_cfm(conn, status);
|
||||
hci_conn_del(conn);
|
||||
}
|
||||
} else {
|
||||
if (!conn) {
|
||||
conn = hci_conn_add(hdev, LE_LINK, &cp->peer_addr);
|
||||
if (conn) {
|
||||
conn->dst_type = cp->peer_addr_type;
|
||||
conn->out = true;
|
||||
} else {
|
||||
BT_ERR("No memory for new connection");
|
||||
}
|
||||
}
|
||||
}
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
|
||||
if (!conn) {
|
||||
hci_dev_unlock(hdev);
|
||||
return;
|
||||
}
|
||||
|
||||
BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&conn->dst),
|
||||
conn);
|
||||
|
||||
conn->state = BT_CLOSED;
|
||||
mgmt_connect_failed(hdev, &conn->dst, conn->type,
|
||||
conn->dst_type, status);
|
||||
hci_proto_connect_cfm(conn, status);
|
||||
hci_conn_del(conn);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
}
|
||||
|
||||
static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
|
||||
@@ -1904,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;
|
||||
@@ -1922,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) {
|
||||
@@ -3268,12 +3275,67 @@ static void hci_user_passkey_request_evt(struct hci_dev *hdev,
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (test_bit(HCI_MGMT, &hdev->dev_flags))
|
||||
mgmt_user_passkey_request(hdev, &ev->bdaddr, ACL_LINK, 0);
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
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,
|
||||
@@ -3295,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);
|
||||
|
||||
@@ -3366,11 +3428,23 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (ev->status) {
|
||||
conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
|
||||
if (!conn)
|
||||
conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
|
||||
if (!conn) {
|
||||
conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr);
|
||||
if (!conn) {
|
||||
BT_ERR("No memory for new connection");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
conn->dst_type = ev->bdaddr_type;
|
||||
|
||||
if (ev->role == LE_CONN_ROLE_MASTER) {
|
||||
conn->out = true;
|
||||
conn->link_mode |= HCI_LM_MASTER;
|
||||
}
|
||||
}
|
||||
|
||||
if (ev->status) {
|
||||
mgmt_connect_failed(hdev, &conn->dst, conn->type,
|
||||
conn->dst_type, ev->status);
|
||||
hci_proto_connect_cfm(conn, ev->status);
|
||||
@@ -3379,18 +3453,6 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &ev->bdaddr);
|
||||
if (!conn) {
|
||||
conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr);
|
||||
if (!conn) {
|
||||
BT_ERR("No memory for new connection");
|
||||
hci_dev_unlock(hdev);
|
||||
return;
|
||||
}
|
||||
|
||||
conn->dst_type = ev->bdaddr_type;
|
||||
}
|
||||
|
||||
if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
|
||||
mgmt_device_connected(hdev, &ev->bdaddr, conn->type,
|
||||
conn->dst_type, 0, NULL, 0, NULL);
|
||||
@@ -3640,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;
|
||||
|
@@ -1102,21 +1102,30 @@ int __init hci_sock_init(void)
|
||||
return err;
|
||||
|
||||
err = bt_sock_register(BTPROTO_HCI, &hci_sock_family_ops);
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
BT_ERR("HCI socket registration failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = bt_procfs_init(THIS_MODULE, &init_net, "hci", &hci_sk_list, NULL);
|
||||
if (err < 0) {
|
||||
BT_ERR("Failed to create HCI proc file");
|
||||
bt_sock_unregister(BTPROTO_HCI);
|
||||
goto error;
|
||||
}
|
||||
|
||||
BT_INFO("HCI socket layer initialized");
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
BT_ERR("HCI socket registration failed");
|
||||
proto_unregister(&hci_sk_proto);
|
||||
return err;
|
||||
}
|
||||
|
||||
void hci_sock_cleanup(void)
|
||||
{
|
||||
bt_procfs_cleanup(&init_net, "hci");
|
||||
if (bt_sock_unregister(BTPROTO_HCI) < 0)
|
||||
BT_ERR("HCI socket unregistration failed");
|
||||
|
||||
|
@@ -941,6 +941,13 @@ static int hidp_setup_hid(struct hidp_session *session,
|
||||
hid->hid_get_raw_report = hidp_get_raw_report;
|
||||
hid->hid_output_raw_report = hidp_output_raw_report;
|
||||
|
||||
/* True if device is blacklisted in drivers/hid/hid-core.c */
|
||||
if (hid_ignore(hid)) {
|
||||
hid_destroy_device(session->hid);
|
||||
session->hid = NULL;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fault:
|
||||
@@ -1013,7 +1020,7 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
|
||||
|
||||
if (req->rd_size > 0) {
|
||||
err = hidp_setup_hid(session, req);
|
||||
if (err)
|
||||
if (err && err != -ENODEV)
|
||||
goto purge;
|
||||
}
|
||||
|
||||
|
@@ -25,6 +25,10 @@
|
||||
|
||||
#include "hidp.h"
|
||||
|
||||
static struct bt_sock_list hidp_sk_list = {
|
||||
.lock = __RW_LOCK_UNLOCKED(hidp_sk_list.lock)
|
||||
};
|
||||
|
||||
static int hidp_sock_release(struct socket *sock)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
@@ -34,6 +38,8 @@ static int hidp_sock_release(struct socket *sock)
|
||||
if (!sk)
|
||||
return 0;
|
||||
|
||||
bt_sock_unlink(&hidp_sk_list, sk);
|
||||
|
||||
sock_orphan(sk);
|
||||
sock_put(sk);
|
||||
|
||||
@@ -253,6 +259,8 @@ static int hidp_sock_create(struct net *net, struct socket *sock, int protocol,
|
||||
sk->sk_protocol = protocol;
|
||||
sk->sk_state = BT_OPEN;
|
||||
|
||||
bt_sock_link(&hidp_sk_list, sk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -271,8 +279,19 @@ int __init hidp_init_sockets(void)
|
||||
return err;
|
||||
|
||||
err = bt_sock_register(BTPROTO_HIDP, &hidp_sock_family_ops);
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
BT_ERR("Can't register HIDP socket");
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = bt_procfs_init(THIS_MODULE, &init_net, "hidp", &hidp_sk_list, NULL);
|
||||
if (err < 0) {
|
||||
BT_ERR("Failed to create HIDP proc file");
|
||||
bt_sock_unregister(BTPROTO_HIDP);
|
||||
goto error;
|
||||
}
|
||||
|
||||
BT_INFO("HIDP socket layer initialized");
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -284,6 +303,7 @@ error:
|
||||
|
||||
void __exit hidp_cleanup_sockets(void)
|
||||
{
|
||||
bt_procfs_cleanup(&init_net, "hidp");
|
||||
if (bt_sock_unregister(BTPROTO_HIDP) < 0)
|
||||
BT_ERR("Can't unregister HIDP socket");
|
||||
|
||||
|
@@ -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,13 +416,31 @@ struct l2cap_chan *l2cap_chan_create(void)
|
||||
return chan;
|
||||
}
|
||||
|
||||
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);
|
||||
list_del(&chan->global_l);
|
||||
write_unlock(&chan_list_lock);
|
||||
|
||||
l2cap_chan_put(chan);
|
||||
kfree(chan);
|
||||
}
|
||||
|
||||
void l2cap_chan_hold(struct l2cap_chan *c)
|
||||
{
|
||||
BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->kref.refcount));
|
||||
|
||||
kref_get(&c->kref);
|
||||
}
|
||||
|
||||
void l2cap_chan_put(struct l2cap_chan *c)
|
||||
{
|
||||
BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->kref.refcount));
|
||||
|
||||
kref_put(&c->kref, l2cap_chan_destroy);
|
||||
}
|
||||
|
||||
void l2cap_chan_set_defaults(struct l2cap_chan *chan)
|
||||
@@ -1431,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)
|
||||
@@ -5331,7 +5349,7 @@ int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
|
||||
return exact ? lm1 : lm2;
|
||||
}
|
||||
|
||||
int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
|
||||
void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
|
||||
{
|
||||
struct l2cap_conn *conn;
|
||||
|
||||
@@ -5344,7 +5362,6 @@ int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
|
||||
} else
|
||||
l2cap_conn_del(hcon, bt_to_errno(status));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int l2cap_disconn_ind(struct hci_conn *hcon)
|
||||
@@ -5358,12 +5375,11 @@ int l2cap_disconn_ind(struct hci_conn *hcon)
|
||||
return conn->disc_reason;
|
||||
}
|
||||
|
||||
int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
|
||||
void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
|
||||
{
|
||||
BT_DBG("hcon %p reason %d", hcon, reason);
|
||||
|
||||
l2cap_conn_del(hcon, bt_to_errno(reason));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
|
||||
@@ -5406,6 +5422,11 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
|
||||
BT_DBG("chan %p scid 0x%4.4x state %s", chan, chan->scid,
|
||||
state_to_string(chan->state));
|
||||
|
||||
if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
|
||||
l2cap_chan_unlock(chan);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (chan->scid == L2CAP_CID_LE_DATA) {
|
||||
if (!status && encrypt) {
|
||||
chan->sec_level = hcon->sec_level;
|
||||
|
@@ -34,6 +34,10 @@
|
||||
#include <net/bluetooth/l2cap.h>
|
||||
#include <net/bluetooth/smp.h>
|
||||
|
||||
static struct bt_sock_list l2cap_sk_list = {
|
||||
.lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock)
|
||||
};
|
||||
|
||||
static const struct proto_ops l2cap_sock_ops;
|
||||
static void l2cap_sock_init(struct sock *sk, struct sock *parent);
|
||||
static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio);
|
||||
@@ -824,7 +828,7 @@ static void l2cap_sock_kill(struct sock *sk)
|
||||
|
||||
/* Kill poor orphan */
|
||||
|
||||
l2cap_chan_destroy(l2cap_pi(sk)->chan);
|
||||
l2cap_chan_put(l2cap_pi(sk)->chan);
|
||||
sock_set_flag(sk, SOCK_DEAD);
|
||||
sock_put(sk);
|
||||
}
|
||||
@@ -887,6 +891,8 @@ static int l2cap_sock_release(struct socket *sock)
|
||||
if (!sk)
|
||||
return 0;
|
||||
|
||||
bt_sock_unlink(&l2cap_sk_list, sk);
|
||||
|
||||
err = l2cap_sock_shutdown(sock, 2);
|
||||
|
||||
sock_orphan(sk);
|
||||
@@ -1211,6 +1217,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
|
||||
return -ENOMEM;
|
||||
|
||||
l2cap_sock_init(sk, NULL);
|
||||
bt_sock_link(&l2cap_sk_list, sk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1249,21 +1256,30 @@ int __init l2cap_init_sockets(void)
|
||||
return err;
|
||||
|
||||
err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops);
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
BT_ERR("L2CAP socket registration failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = bt_procfs_init(THIS_MODULE, &init_net, "l2cap", &l2cap_sk_list, NULL);
|
||||
if (err < 0) {
|
||||
BT_ERR("Failed to create L2CAP proc file");
|
||||
bt_sock_unregister(BTPROTO_L2CAP);
|
||||
goto error;
|
||||
}
|
||||
|
||||
BT_INFO("L2CAP socket layer initialized");
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
BT_ERR("L2CAP socket registration failed");
|
||||
proto_unregister(&l2cap_proto);
|
||||
return err;
|
||||
}
|
||||
|
||||
void l2cap_cleanup_sockets(void)
|
||||
{
|
||||
bt_procfs_cleanup(&init_net, "l2cap");
|
||||
if (bt_sock_unregister(BTPROTO_L2CAP) < 0)
|
||||
BT_ERR("L2CAP socket unregistration failed");
|
||||
|
||||
|
@@ -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,
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -193,6 +194,11 @@ static u8 mgmt_status_table[] = {
|
||||
MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
|
||||
};
|
||||
|
||||
bool mgmt_valid_hdev(struct hci_dev *hdev)
|
||||
{
|
||||
return hdev->dev_type == HCI_BREDR;
|
||||
}
|
||||
|
||||
static u8 mgmt_status(u8 hci_status)
|
||||
{
|
||||
if (hci_status < ARRAY_SIZE(mgmt_status_table))
|
||||
@@ -317,7 +323,6 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
|
||||
u16 data_len)
|
||||
{
|
||||
struct mgmt_rp_read_index_list *rp;
|
||||
struct list_head *p;
|
||||
struct hci_dev *d;
|
||||
size_t rp_len;
|
||||
u16 count;
|
||||
@@ -328,7 +333,10 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
|
||||
read_lock(&hci_dev_list_lock);
|
||||
|
||||
count = 0;
|
||||
list_for_each(p, &hci_dev_list) {
|
||||
list_for_each_entry(d, &hci_dev_list, list) {
|
||||
if (!mgmt_valid_hdev(d))
|
||||
continue;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
@@ -346,6 +354,9 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
|
||||
if (test_bit(HCI_SETUP, &d->dev_flags))
|
||||
continue;
|
||||
|
||||
if (!mgmt_valid_hdev(d))
|
||||
continue;
|
||||
|
||||
rp->index[i++] = cpu_to_le16(d->id);
|
||||
BT_DBG("Added hci%u", d->id);
|
||||
}
|
||||
@@ -370,10 +381,10 @@ static u32 get_supported_settings(struct hci_dev *hdev)
|
||||
settings |= MGMT_SETTING_DISCOVERABLE;
|
||||
settings |= MGMT_SETTING_PAIRABLE;
|
||||
|
||||
if (hdev->features[6] & LMP_SIMPLE_PAIR)
|
||||
if (lmp_ssp_capable(hdev))
|
||||
settings |= MGMT_SETTING_SSP;
|
||||
|
||||
if (!(hdev->features[4] & LMP_NO_BREDR)) {
|
||||
if (lmp_bredr_capable(hdev)) {
|
||||
settings |= MGMT_SETTING_BREDR;
|
||||
settings |= MGMT_SETTING_LINK_SECURITY;
|
||||
}
|
||||
@@ -381,7 +392,7 @@ static u32 get_supported_settings(struct hci_dev *hdev)
|
||||
if (enable_hs)
|
||||
settings |= MGMT_SETTING_HS;
|
||||
|
||||
if (hdev->features[4] & LMP_LE)
|
||||
if (lmp_le_capable(hdev))
|
||||
settings |= MGMT_SETTING_LE;
|
||||
|
||||
return settings;
|
||||
@@ -403,7 +414,7 @@ static u32 get_current_settings(struct hci_dev *hdev)
|
||||
if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
|
||||
settings |= MGMT_SETTING_PAIRABLE;
|
||||
|
||||
if (!(hdev->features[4] & LMP_NO_BREDR))
|
||||
if (lmp_bredr_capable(hdev))
|
||||
settings |= MGMT_SETTING_BREDR;
|
||||
|
||||
if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
|
||||
@@ -1111,7 +1122,7 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
|
||||
if (!lmp_ssp_capable(hdev)) {
|
||||
err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
|
||||
MGMT_STATUS_NOT_SUPPORTED);
|
||||
goto failed;
|
||||
@@ -1195,7 +1206,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (!(hdev->features[4] & LMP_LE)) {
|
||||
if (!lmp_le_capable(hdev)) {
|
||||
err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
|
||||
MGMT_STATUS_NOT_SUPPORTED);
|
||||
goto unlock;
|
||||
@@ -2191,7 +2202,7 @@ static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
|
||||
if (!lmp_ssp_capable(hdev)) {
|
||||
err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
|
||||
MGMT_STATUS_NOT_SUPPORTED);
|
||||
goto unlock;
|
||||
@@ -2820,6 +2831,9 @@ static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
|
||||
|
||||
int mgmt_index_added(struct hci_dev *hdev)
|
||||
{
|
||||
if (!mgmt_valid_hdev(hdev))
|
||||
return -ENOTSUPP;
|
||||
|
||||
return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
@@ -2827,6 +2841,9 @@ int mgmt_index_removed(struct hci_dev *hdev)
|
||||
{
|
||||
u8 status = MGMT_STATUS_INVALID_INDEX;
|
||||
|
||||
if (!mgmt_valid_hdev(hdev))
|
||||
return -ENOTSUPP;
|
||||
|
||||
mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
|
||||
|
||||
return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
|
||||
@@ -3077,16 +3094,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 +3293,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)
|
||||
{
|
||||
|
@@ -1035,8 +1035,17 @@ int __init rfcomm_init_sockets(void)
|
||||
return err;
|
||||
|
||||
err = bt_sock_register(BTPROTO_RFCOMM, &rfcomm_sock_family_ops);
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
BT_ERR("RFCOMM socket layer registration failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = bt_procfs_init(THIS_MODULE, &init_net, "rfcomm", &rfcomm_sk_list, NULL);
|
||||
if (err < 0) {
|
||||
BT_ERR("Failed to create RFCOMM proc file");
|
||||
bt_sock_unregister(BTPROTO_RFCOMM);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (bt_debugfs) {
|
||||
rfcomm_sock_debugfs = debugfs_create_file("rfcomm", 0444,
|
||||
@@ -1050,13 +1059,14 @@ int __init rfcomm_init_sockets(void)
|
||||
return 0;
|
||||
|
||||
error:
|
||||
BT_ERR("RFCOMM socket layer registration failed");
|
||||
proto_unregister(&rfcomm_proto);
|
||||
return err;
|
||||
}
|
||||
|
||||
void __exit rfcomm_cleanup_sockets(void)
|
||||
{
|
||||
bt_procfs_cleanup(&init_net, "rfcomm");
|
||||
|
||||
debugfs_remove(rfcomm_sock_debugfs);
|
||||
|
||||
if (bt_sock_unregister(BTPROTO_RFCOMM) < 0)
|
||||
|
@@ -278,8 +278,8 @@ out:
|
||||
if (err < 0)
|
||||
goto free;
|
||||
|
||||
dev->tty_dev = tty_register_device(rfcomm_tty_driver, dev->id, NULL);
|
||||
|
||||
dev->tty_dev = tty_port_register_device(&dev->port, rfcomm_tty_driver,
|
||||
dev->id, NULL);
|
||||
if (IS_ERR(dev->tty_dev)) {
|
||||
err = PTR_ERR(dev->tty_dev);
|
||||
list_del(&dev->list);
|
||||
@@ -705,9 +705,9 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
|
||||
break;
|
||||
}
|
||||
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
schedule();
|
||||
tty_lock();
|
||||
tty_lock(tty);
|
||||
}
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&dev->wait, &wait);
|
||||
@@ -861,7 +861,7 @@ static int rfcomm_tty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned l
|
||||
|
||||
static void rfcomm_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
|
||||
{
|
||||
struct ktermios *new = tty->termios;
|
||||
struct ktermios *new = &tty->termios;
|
||||
int old_baud_rate = tty_termios_baud_rate(old);
|
||||
int new_baud_rate = tty_termios_baud_rate(new);
|
||||
|
||||
|
@@ -912,7 +912,7 @@ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
|
||||
return lm;
|
||||
}
|
||||
|
||||
int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
|
||||
void sco_connect_cfm(struct hci_conn *hcon, __u8 status)
|
||||
{
|
||||
BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
|
||||
if (!status) {
|
||||
@@ -923,16 +923,13 @@ int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
|
||||
sco_conn_ready(conn);
|
||||
} else
|
||||
sco_conn_del(hcon, bt_to_errno(status));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
|
||||
void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
|
||||
{
|
||||
BT_DBG("hcon %p reason %d", hcon, reason);
|
||||
|
||||
sco_conn_del(hcon, bt_to_errno(reason));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
|
||||
@@ -1025,6 +1022,13 @@ int __init sco_init(void)
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = bt_procfs_init(THIS_MODULE, &init_net, "sco", &sco_sk_list, NULL);
|
||||
if (err < 0) {
|
||||
BT_ERR("Failed to create SCO proc file");
|
||||
bt_sock_unregister(BTPROTO_SCO);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (bt_debugfs) {
|
||||
sco_debugfs = debugfs_create_file("sco", 0444, bt_debugfs,
|
||||
NULL, &sco_debugfs_fops);
|
||||
@@ -1043,6 +1047,8 @@ error:
|
||||
|
||||
void __exit sco_exit(void)
|
||||
{
|
||||
bt_procfs_cleanup(&init_net, "sco");
|
||||
|
||||
debugfs_remove(sco_debugfs);
|
||||
|
||||
if (bt_sock_unregister(BTPROTO_SCO) < 0)
|
||||
|
@@ -32,6 +32,8 @@
|
||||
|
||||
#define SMP_TIMEOUT msecs_to_jiffies(30000)
|
||||
|
||||
#define AUTH_REQ_MASK 0x07
|
||||
|
||||
static inline void swap128(u8 src[16], u8 dst[16])
|
||||
{
|
||||
int i;
|
||||
@@ -230,7 +232,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
|
||||
req->max_key_size = SMP_MAX_ENC_KEY_SIZE;
|
||||
req->init_key_dist = 0;
|
||||
req->resp_key_dist = dist_keys;
|
||||
req->auth_req = authreq;
|
||||
req->auth_req = (authreq & AUTH_REQ_MASK);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -239,7 +241,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
|
||||
rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
|
||||
rsp->init_key_dist = 0;
|
||||
rsp->resp_key_dist = req->resp_key_dist & dist_keys;
|
||||
rsp->auth_req = authreq;
|
||||
rsp->auth_req = (authreq & AUTH_REQ_MASK);
|
||||
}
|
||||
|
||||
static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
|
||||
|
Reference in New Issue
Block a user