Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
This commit is contained in:
commit
791ef39cd1
18 changed files with 258 additions and 106 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) },
|
||||
|
|
|
@ -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 ------ */
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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--;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue