Commit dc0d633e authored by John W. Linville's avatar John W. Linville
parents aef6c928 4ae1652e
...@@ -101,6 +101,7 @@ static struct usb_device_id btusb_table[] = { ...@@ -101,6 +101,7 @@ static struct usb_device_id btusb_table[] = {
{ USB_DEVICE(0x0c10, 0x0000) }, { USB_DEVICE(0x0c10, 0x0000) },
/* Broadcom BCM20702A0 */ /* Broadcom BCM20702A0 */
{ USB_DEVICE(0x0a5c, 0x21e3) },
{ USB_DEVICE(0x413c, 0x8197) }, { USB_DEVICE(0x413c, 0x8197) },
{ } /* Terminating entry */ { } /* Terminating entry */
...@@ -508,15 +509,10 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags) ...@@ -508,15 +509,10 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
pipe = usb_rcvisocpipe(data->udev, data->isoc_rx_ep->bEndpointAddress); pipe = usb_rcvisocpipe(data->udev, data->isoc_rx_ep->bEndpointAddress);
urb->dev = data->udev; usb_fill_int_urb(urb, data->udev, pipe, buf, size, btusb_isoc_complete,
urb->pipe = pipe; hdev, data->isoc_rx_ep->bInterval);
urb->context = hdev;
urb->complete = btusb_isoc_complete;
urb->interval = data->isoc_rx_ep->bInterval;
urb->transfer_flags = URB_FREE_BUFFER | URB_ISO_ASAP; urb->transfer_flags = URB_FREE_BUFFER | URB_ISO_ASAP;
urb->transfer_buffer = buf;
urb->transfer_buffer_length = size;
__fill_isoc_descriptor(urb, size, __fill_isoc_descriptor(urb, size,
le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize)); le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize));
......
...@@ -250,32 +250,10 @@ extern void bt_sysfs_cleanup(void); ...@@ -250,32 +250,10 @@ extern void bt_sysfs_cleanup(void);
extern struct dentry *bt_debugfs; extern struct dentry *bt_debugfs;
#ifdef CONFIG_BT_L2CAP
int l2cap_init(void); int l2cap_init(void);
void l2cap_exit(void); void l2cap_exit(void);
#else
static inline int l2cap_init(void)
{
return 0;
}
static inline void l2cap_exit(void)
{
}
#endif
#ifdef CONFIG_BT_SCO
int sco_init(void); int sco_init(void);
void sco_exit(void); void sco_exit(void);
#else
static inline int sco_init(void)
{
return 0;
}
static inline void sco_exit(void)
{
}
#endif
#endif /* __BLUETOOTH_H */ #endif /* __BLUETOOTH_H */
...@@ -280,6 +280,10 @@ enum { ...@@ -280,6 +280,10 @@ enum {
#define HCI_ERROR_LOCAL_HOST_TERM 0x16 #define HCI_ERROR_LOCAL_HOST_TERM 0x16
#define HCI_ERROR_PAIRING_NOT_ALLOWED 0x18 #define HCI_ERROR_PAIRING_NOT_ALLOWED 0x18
/* Flow control modes */
#define HCI_FLOW_CTL_MODE_PACKET_BASED 0x00
#define HCI_FLOW_CTL_MODE_BLOCK_BASED 0x01
/* ----- HCI Commands ---- */ /* ----- HCI Commands ---- */
#define HCI_OP_NOP 0x0000 #define HCI_OP_NOP 0x0000
...@@ -800,6 +804,9 @@ struct hci_cp_le_set_scan_param { ...@@ -800,6 +804,9 @@ struct hci_cp_le_set_scan_param {
__u8 filter_policy; __u8 filter_policy;
} __packed; } __packed;
#define LE_SCANNING_DISABLED 0x00
#define LE_SCANNING_ENABLED 0x01
#define HCI_OP_LE_SET_SCAN_ENABLE 0x200c #define HCI_OP_LE_SET_SCAN_ENABLE 0x200c
struct hci_cp_le_set_scan_enable { struct hci_cp_le_set_scan_enable {
__u8 enable; __u8 enable;
...@@ -975,9 +982,14 @@ struct hci_ev_role_change { ...@@ -975,9 +982,14 @@ struct hci_ev_role_change {
} __packed; } __packed;
#define HCI_EV_NUM_COMP_PKTS 0x13 #define HCI_EV_NUM_COMP_PKTS 0x13
struct hci_comp_pkts_info {
__le16 handle;
__le16 count;
} __packed;
struct hci_ev_num_comp_pkts { struct hci_ev_num_comp_pkts {
__u8 num_hndl; __u8 num_hndl;
/* variable length part */ struct hci_comp_pkts_info handles[0];
} __packed; } __packed;
#define HCI_EV_MODE_CHANGE 0x14 #define HCI_EV_MODE_CHANGE 0x14
......
...@@ -28,10 +28,6 @@ ...@@ -28,10 +28,6 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <net/bluetooth/hci.h> #include <net/bluetooth/hci.h>
/* HCI upper protocols */
#define HCI_PROTO_L2CAP 0
#define HCI_PROTO_SCO 1
/* HCI priority */ /* HCI priority */
#define HCI_PRIO_MAX 7 #define HCI_PRIO_MAX 7
...@@ -54,7 +50,6 @@ struct inquiry_entry { ...@@ -54,7 +50,6 @@ struct inquiry_entry {
}; };
struct inquiry_cache { struct inquiry_cache {
spinlock_t lock;
__u32 timestamp; __u32 timestamp;
struct inquiry_entry *list; struct inquiry_entry *list;
}; };
...@@ -314,6 +309,7 @@ struct hci_conn { ...@@ -314,6 +309,7 @@ struct hci_conn {
struct hci_dev *hdev; struct hci_dev *hdev;
void *l2cap_data; void *l2cap_data;
void *sco_data; void *sco_data;
void *smp_conn;
struct hci_conn *link; struct hci_conn *link;
...@@ -330,25 +326,31 @@ struct hci_chan { ...@@ -330,25 +326,31 @@ struct hci_chan {
unsigned int sent; unsigned int sent;
}; };
extern struct hci_proto *hci_proto[];
extern struct list_head hci_dev_list; extern struct list_head hci_dev_list;
extern struct list_head hci_cb_list; extern struct list_head hci_cb_list;
extern rwlock_t hci_dev_list_lock; extern rwlock_t hci_dev_list_lock;
extern rwlock_t hci_cb_list_lock; extern rwlock_t hci_cb_list_lock;
/* ----- HCI interface to upper protocols ----- */
extern int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr);
extern int l2cap_connect_cfm(struct hci_conn *hcon, u8 status);
extern int l2cap_disconn_ind(struct hci_conn *hcon);
extern int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason);
extern int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt);
extern int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags);
extern int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr);
extern int sco_connect_cfm(struct hci_conn *hcon, __u8 status);
extern int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason);
extern int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb);
/* ----- Inquiry cache ----- */ /* ----- Inquiry cache ----- */
#define INQUIRY_CACHE_AGE_MAX (HZ*30) /* 30 seconds */ #define INQUIRY_CACHE_AGE_MAX (HZ*30) /* 30 seconds */
#define INQUIRY_ENTRY_AGE_MAX (HZ*60) /* 60 seconds */ #define INQUIRY_ENTRY_AGE_MAX (HZ*60) /* 60 seconds */
#define inquiry_cache_lock(c) spin_lock(&c->lock)
#define inquiry_cache_unlock(c) spin_unlock(&c->lock)
#define inquiry_cache_lock_bh(c) spin_lock_bh(&c->lock)
#define inquiry_cache_unlock_bh(c) spin_unlock_bh(&c->lock)
static inline void inquiry_cache_init(struct hci_dev *hdev) static inline void inquiry_cache_init(struct hci_dev *hdev)
{ {
struct inquiry_cache *c = &hdev->inq_cache; struct inquiry_cache *c = &hdev->inq_cache;
spin_lock_init(&c->lock);
c->list = NULL; c->list = NULL;
} }
...@@ -677,53 +679,40 @@ void hci_conn_del_sysfs(struct hci_conn *conn); ...@@ -677,53 +679,40 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define lmp_host_le_capable(dev) ((dev)->extfeatures[0] & LMP_HOST_LE) #define lmp_host_le_capable(dev) ((dev)->extfeatures[0] & LMP_HOST_LE)
/* ----- HCI protocols ----- */ /* ----- HCI protocols ----- */
struct hci_proto {
char *name;
unsigned int id;
unsigned long flags;
void *priv;
int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr,
__u8 type);
int (*connect_cfm) (struct hci_conn *conn, __u8 status);
int (*disconn_ind) (struct hci_conn *conn);
int (*disconn_cfm) (struct hci_conn *conn, __u8 reason);
int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb,
__u16 flags);
int (*recv_scodata) (struct hci_conn *conn, struct sk_buff *skb);
int (*security_cfm) (struct hci_conn *conn, __u8 status,
__u8 encrypt);
};
static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr,
__u8 type) __u8 type)
{ {
register struct hci_proto *hp; switch (type) {
int mask = 0; case ACL_LINK:
return l2cap_connect_ind(hdev, bdaddr);
hp = hci_proto[HCI_PROTO_L2CAP];
if (hp && hp->connect_ind)
mask |= hp->connect_ind(hdev, bdaddr, type);
hp = hci_proto[HCI_PROTO_SCO]; case SCO_LINK:
if (hp && hp->connect_ind) case ESCO_LINK:
mask |= hp->connect_ind(hdev, bdaddr, type); return sco_connect_ind(hdev, bdaddr);
return mask; default:
BT_ERR("unknown link type %d", type);
return -EINVAL;
}
} }
static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status) static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status)
{ {
register struct hci_proto *hp; switch (conn->type) {
case ACL_LINK:
case LE_LINK:
l2cap_connect_cfm(conn, status);
break;
hp = hci_proto[HCI_PROTO_L2CAP]; case SCO_LINK:
if (hp && hp->connect_cfm) case ESCO_LINK:
hp->connect_cfm(conn, status); sco_connect_cfm(conn, status);
break;
hp = hci_proto[HCI_PROTO_SCO]; default:
if (hp && hp->connect_cfm) BT_ERR("unknown link type %d", conn->type);
hp->connect_cfm(conn, status); break;
}
if (conn->connect_cfm_cb) if (conn->connect_cfm_cb)
conn->connect_cfm_cb(conn, status); conn->connect_cfm_cb(conn, status);
...@@ -731,31 +720,29 @@ static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status) ...@@ -731,31 +720,29 @@ static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status)
static inline int hci_proto_disconn_ind(struct hci_conn *conn) static inline int hci_proto_disconn_ind(struct hci_conn *conn)
{ {
register struct hci_proto *hp; if (conn->type != ACL_LINK && conn->type != LE_LINK)
int reason = HCI_ERROR_REMOTE_USER_TERM; return HCI_ERROR_REMOTE_USER_TERM;
hp = hci_proto[HCI_PROTO_L2CAP]; return l2cap_disconn_ind(conn);
if (hp && hp->disconn_ind)
reason = hp->disconn_ind(conn);
hp = hci_proto[HCI_PROTO_SCO];
if (hp && hp->disconn_ind)
reason = hp->disconn_ind(conn);
return reason;
} }
static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason) static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason)
{ {
register struct hci_proto *hp; switch (conn->type) {
case ACL_LINK:
case LE_LINK:
l2cap_disconn_cfm(conn, reason);
break;
hp = hci_proto[HCI_PROTO_L2CAP]; case SCO_LINK:
if (hp && hp->disconn_cfm) case ESCO_LINK:
hp->disconn_cfm(conn, reason); sco_disconn_cfm(conn, reason);
break;
hp = hci_proto[HCI_PROTO_SCO]; default:
if (hp && hp->disconn_cfm) BT_ERR("unknown link type %d", conn->type);
hp->disconn_cfm(conn, reason); break;
}
if (conn->disconn_cfm_cb) if (conn->disconn_cfm_cb)
conn->disconn_cfm_cb(conn, reason); conn->disconn_cfm_cb(conn, reason);
...@@ -763,21 +750,16 @@ static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason) ...@@ -763,21 +750,16 @@ static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason)
static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status) static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
{ {
register struct hci_proto *hp;
__u8 encrypt; __u8 encrypt;
if (conn->type != ACL_LINK && conn->type != LE_LINK)
return;
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
return; return;
encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00; encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00;
l2cap_security_cfm(conn, status, encrypt);
hp = hci_proto[HCI_PROTO_L2CAP];
if (hp && hp->security_cfm)
hp->security_cfm(conn, status, encrypt);
hp = hci_proto[HCI_PROTO_SCO];
if (hp && hp->security_cfm)
hp->security_cfm(conn, status, encrypt);
if (conn->security_cfm_cb) if (conn->security_cfm_cb)
conn->security_cfm_cb(conn, status); conn->security_cfm_cb(conn, status);
...@@ -786,23 +768,15 @@ static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status) ...@@ -786,23 +768,15 @@ static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status, static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status,
__u8 encrypt) __u8 encrypt)
{ {
register struct hci_proto *hp; if (conn->type != ACL_LINK && conn->type != LE_LINK)
return;
hp = hci_proto[HCI_PROTO_L2CAP];
if (hp && hp->security_cfm)
hp->security_cfm(conn, status, encrypt);
hp = hci_proto[HCI_PROTO_SCO]; l2cap_security_cfm(conn, status, encrypt);
if (hp && hp->security_cfm)
hp->security_cfm(conn, status, encrypt);
if (conn->security_cfm_cb) if (conn->security_cfm_cb)
conn->security_cfm_cb(conn, status); conn->security_cfm_cb(conn, status);
} }
int hci_register_proto(struct hci_proto *hproto);
int hci_unregister_proto(struct hci_proto *hproto);
/* ----- HCI callbacks ----- */ /* ----- HCI callbacks ----- */
struct hci_cb { struct hci_cb {
struct list_head list; struct list_head list;
...@@ -827,13 +801,13 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status) ...@@ -827,13 +801,13 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)
encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00; encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00;
read_lock_bh(&hci_cb_list_lock); read_lock(&hci_cb_list_lock);
list_for_each(p, &hci_cb_list) { list_for_each(p, &hci_cb_list) {
struct hci_cb *cb = list_entry(p, struct hci_cb, list); struct hci_cb *cb = list_entry(p, struct hci_cb, list);
if (cb->security_cfm) if (cb->security_cfm)
cb->security_cfm(conn, status, encrypt); cb->security_cfm(conn, status, encrypt);
} }
read_unlock_bh(&hci_cb_list_lock); read_unlock(&hci_cb_list_lock);
} }
static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status, static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status,
...@@ -849,26 +823,26 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status, ...@@ -849,26 +823,26 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status,
hci_proto_encrypt_cfm(conn, status, encrypt); hci_proto_encrypt_cfm(conn, status, encrypt);
read_lock_bh(&hci_cb_list_lock); read_lock(&hci_cb_list_lock);
list_for_each(p, &hci_cb_list) { list_for_each(p, &hci_cb_list) {
struct hci_cb *cb = list_entry(p, struct hci_cb, list); struct hci_cb *cb = list_entry(p, struct hci_cb, list);
if (cb->security_cfm) if (cb->security_cfm)
cb->security_cfm(conn, status, encrypt); cb->security_cfm(conn, status, encrypt);
} }
read_unlock_bh(&hci_cb_list_lock); read_unlock(&hci_cb_list_lock);
} }
static inline void hci_key_change_cfm(struct hci_conn *conn, __u8 status) static inline void hci_key_change_cfm(struct hci_conn *conn, __u8 status)
{ {
struct list_head *p; struct list_head *p;
read_lock_bh(&hci_cb_list_lock); read_lock(&hci_cb_list_lock);
list_for_each(p, &hci_cb_list) { list_for_each(p, &hci_cb_list) {
struct hci_cb *cb = list_entry(p, struct hci_cb, list); struct hci_cb *cb = list_entry(p, struct hci_cb, list);
if (cb->key_change_cfm) if (cb->key_change_cfm)
cb->key_change_cfm(conn, status); cb->key_change_cfm(conn, status);
} }
read_unlock_bh(&hci_cb_list_lock); read_unlock(&hci_cb_list_lock);
} }
static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status, static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status,
...@@ -876,13 +850,13 @@ static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status, ...@@ -876,13 +850,13 @@ static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status,
{ {
struct list_head *p; struct list_head *p;
read_lock_bh(&hci_cb_list_lock); read_lock(&hci_cb_list_lock);
list_for_each(p, &hci_cb_list) { list_for_each(p, &hci_cb_list) {
struct hci_cb *cb = list_entry(p, struct hci_cb, list); struct hci_cb *cb = list_entry(p, struct hci_cb, list);
if (cb->role_switch_cfm) if (cb->role_switch_cfm)
cb->role_switch_cfm(conn, status, role); cb->role_switch_cfm(conn, status, role);
} }
read_unlock_bh(&hci_cb_list_lock); read_unlock(&hci_cb_list_lock);
} }
int hci_register_cb(struct hci_cb *hcb); int hci_register_cb(struct hci_cb *hcb);
......
...@@ -522,7 +522,7 @@ struct l2cap_conn { ...@@ -522,7 +522,7 @@ struct l2cap_conn {
__u8 info_state; __u8 info_state;
__u8 info_ident; __u8 info_ident;
struct delayed_work info_work; struct delayed_work info_timer;
spinlock_t lock; spinlock_t lock;
...@@ -532,7 +532,7 @@ struct l2cap_conn { ...@@ -532,7 +532,7 @@ struct l2cap_conn {
__u8 disc_reason; __u8 disc_reason;
struct timer_list security_timer; struct delayed_work security_timer;
struct smp_chan *smp_chan; struct smp_chan *smp_chan;
struct list_head chan_l; struct list_head chan_l;
...@@ -595,17 +595,45 @@ enum { ...@@ -595,17 +595,45 @@ enum {
FLAG_EFS_ENABLE, FLAG_EFS_ENABLE,
}; };
static inline void l2cap_chan_hold(struct l2cap_chan *c)
{
atomic_inc(&c->refcnt);
}
static inline void l2cap_chan_put(struct l2cap_chan *c)
{
if (atomic_dec_and_test(&c->refcnt))
kfree(c);
}
static inline void l2cap_set_timer(struct l2cap_chan *chan,
struct delayed_work *work, long timeout)
{
BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout);
if (!__cancel_delayed_work(work))
l2cap_chan_hold(chan);
schedule_delayed_work(work, timeout);
}
static inline void l2cap_clear_timer(struct l2cap_chan *chan,
struct delayed_work *work)
{
if (__cancel_delayed_work(work))
l2cap_chan_put(chan);
}
#define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t)) #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
#define __clear_chan_timer(c) l2cap_clear_timer(&c->chan_timer) #define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer)
#define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \ #define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \
L2CAP_DEFAULT_RETRANS_TO); L2CAP_DEFAULT_RETRANS_TO);
#define __clear_retrans_timer(c) l2cap_clear_timer(&c->retrans_timer) #define __clear_retrans_timer(c) l2cap_clear_timer(c, &c->retrans_timer)
#define __set_monitor_timer(c) l2cap_set_timer(c, &c->monitor_timer, \ #define __set_monitor_timer(c) l2cap_set_timer(c, &c->monitor_timer, \
L2CAP_DEFAULT_MONITOR_TO); L2CAP_DEFAULT_MONITOR_TO);
#define __clear_monitor_timer(c) l2cap_clear_timer(&c->monitor_timer) #define __clear_monitor_timer(c) l2cap_clear_timer(c, &c->monitor_timer)
#define __set_ack_timer(c) l2cap_set_timer(c, &chan->ack_timer, \ #define __set_ack_timer(c) l2cap_set_timer(c, &chan->ack_timer, \
L2CAP_DEFAULT_ACK_TO); L2CAP_DEFAULT_ACK_TO);
#define __clear_ack_timer(c) l2cap_clear_timer(&c->ack_timer) #define __clear_ack_timer(c) l2cap_clear_timer(c, &c->ack_timer)
static inline int __seq_offset(struct l2cap_chan *chan, __u16 seq1, __u16 seq2) static inline int __seq_offset(struct l2cap_chan *chan, __u16 seq1, __u16 seq2)
{ {
......
...@@ -115,6 +115,10 @@ struct smp_cmd_security_req { ...@@ -115,6 +115,10 @@ struct smp_cmd_security_req {
#define SMP_MIN_ENC_KEY_SIZE 7 #define SMP_MIN_ENC_KEY_SIZE 7
#define SMP_MAX_ENC_KEY_SIZE 16 #define SMP_MAX_ENC_KEY_SIZE 16
#define SMP_FLAG_TK_VALID 1
#define SMP_FLAG_CFM_PENDING 2
#define SMP_FLAG_MITM_AUTH 3
struct smp_chan { struct smp_chan {
struct l2cap_conn *conn; struct l2cap_conn *conn;
u8 preq[7]; /* SMP Pairing Request */ u8 preq[7]; /* SMP Pairing Request */
...@@ -124,6 +128,7 @@ struct smp_chan { ...@@ -124,6 +128,7 @@ struct smp_chan {
u8 pcnf[16]; /* SMP Pairing Confirm */ u8 pcnf[16]; /* SMP Pairing Confirm */
u8 tk[16]; /* SMP Temporary Key */ u8 tk[16]; /* SMP Temporary Key */
u8 smp_key_size; u8 smp_key_size;
unsigned long smp_flags;
struct crypto_blkcipher *tfm; struct crypto_blkcipher *tfm;
struct work_struct confirm; struct work_struct confirm;
struct work_struct random; struct work_struct random;
...@@ -134,6 +139,7 @@ struct smp_chan { ...@@ -134,6 +139,7 @@ struct smp_chan {
int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level); int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level);
int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb); int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb);
int smp_distribute_keys(struct l2cap_conn *conn, __u8 force); int smp_distribute_keys(struct l2cap_conn *conn, __u8 force);
int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey);
void smp_chan_destroy(struct l2cap_conn *conn); void smp_chan_destroy(struct l2cap_conn *conn);
......
...@@ -6,7 +6,11 @@ menuconfig BT ...@@ -6,7 +6,11 @@ menuconfig BT
tristate "Bluetooth subsystem support" tristate "Bluetooth subsystem support"
depends on NET && !S390 depends on NET && !S390
depends on RFKILL || !RFKILL depends on RFKILL || !RFKILL
select CRC16
select CRYPTO select CRYPTO
select CRYPTO_BLKCIPHER
select CRYPTO_AES
select CRYPTO_ECB
help help
Bluetooth is low-cost, low-power, short-range wireless technology. Bluetooth is low-cost, low-power, short-range wireless technology.
It was designed as a replacement for cables and other short-range It was designed as a replacement for cables and other short-range
...@@ -15,10 +19,12 @@ menuconfig BT ...@@ -15,10 +19,12 @@ menuconfig BT
Bluetooth can be found at <http://www.bluetooth.com/>. Bluetooth can be found at <http://www.bluetooth.com/>.
Linux Bluetooth subsystem consist of several layers: Linux Bluetooth subsystem consist of several layers:
Bluetooth Core (HCI device and connection manager, scheduler) Bluetooth Core
HCI device and connection manager, scheduler
SCO audio links
L2CAP (Logical Link Control and Adaptation Protocol)
SMP (Security Manager Protocol) on LE (Low Energy) links
HCI Device drivers (Interface to the hardware) HCI Device drivers (Interface to the hardware)
SCO Module (SCO audio links)
L2CAP Module (Logical Link Control and Adaptation Protocol)
RFCOMM Module (RFCOMM Protocol) RFCOMM Module (RFCOMM Protocol)
BNEP Module (Bluetooth Network Encapsulation Protocol) BNEP Module (Bluetooth Network Encapsulation Protocol)
CMTP Module (CAPI Message Transport Protocol) CMTP Module (CAPI Message Transport Protocol)
...@@ -33,31 +39,6 @@ menuconfig BT ...@@ -33,31 +39,6 @@ menuconfig BT
to Bluetooth kernel modules are provided in the BlueZ packages. For to Bluetooth kernel modules are provided in the BlueZ packages. For
more information, see <http://www.bluez.org/>. more information, see <http://www.bluez.org/>.
if BT != n
config BT_L2CAP
bool "L2CAP protocol support"
select CRC16
select CRYPTO
select CRYPTO_BLKCIPHER
select CRYPTO_AES
select CRYPTO_ECB
help
L2CAP (Logical Link Control and Adaptation Protocol) provides
connection oriented and connection-less data transport. L2CAP
support is required for most Bluetooth applications.
Also included is support for SMP (Security Manager Protocol) which
is the security layer on top of LE (Low Energy) links.
config BT_SCO
bool "SCO links support"
help
SCO link provides voice transport over Bluetooth. SCO support is
required for voice applications like Headset and Audio.
endif
source "net/bluetooth/rfcomm/Kconfig" source "net/bluetooth/rfcomm/Kconfig"
source "net/bluetooth/bnep/Kconfig" source "net/bluetooth/bnep/Kconfig"
......
...@@ -8,6 +8,5 @@ obj-$(CONFIG_BT_BNEP) += bnep/ ...@@ -8,6 +8,5 @@ obj-$(CONFIG_BT_BNEP) += bnep/
obj-$(CONFIG_BT_CMTP) += cmtp/ obj-$(CONFIG_BT_CMTP) += cmtp/
obj-$(CONFIG_BT_HIDP) += hidp/ obj-$(CONFIG_BT_HIDP) += hidp/
bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o hci_sock.o hci_sysfs.o lib.o bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
bluetooth-$(CONFIG_BT_L2CAP) += l2cap_core.o l2cap_sock.o smp.o hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o
bluetooth-$(CONFIG_BT_SCO) += sco.o
...@@ -199,15 +199,14 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock) ...@@ -199,15 +199,14 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
BT_DBG("parent %p", parent); BT_DBG("parent %p", parent);
local_bh_disable();
list_for_each_safe(p, n, &bt_sk(parent)->accept_q) { list_for_each_safe(p, n, &bt_sk(parent)->accept_q) {
sk = (struct sock *) list_entry(p, struct bt_sock, accept_q); sk = (struct sock *) list_entry(p, struct bt_sock, accept_q);
bh_lock_sock(sk); lock_sock(sk);
/* FIXME: Is this check still needed */ /* FIXME: Is this check still needed */
if (sk->sk_state == BT_CLOSED) { if (sk->sk_state == BT_CLOSED) {
bh_unlock_sock(sk); release_sock(sk);
bt_accept_unlink(sk); bt_accept_unlink(sk);
continue; continue;
} }
...@@ -218,14 +217,12 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock) ...@@ -218,14 +217,12 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
if (newsock) if (newsock)
sock_graft(sk, newsock); sock_graft(sk, newsock);
bh_unlock_sock(sk); release_sock(sk);
local_bh_enable();
return sk; return sk;
} }
bh_unlock_sock(sk); release_sock(sk);
} }
local_bh_enable();
return NULL; return NULL;
} }
......
config BT_BNEP config BT_BNEP
tristate "BNEP protocol support" tristate "BNEP protocol support"
depends on BT && BT_L2CAP depends on BT
select CRC32 select CRC32
help help
BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet
......
config BT_CMTP config BT_CMTP
tristate "CMTP protocol support" tristate "CMTP protocol support"
depends on BT && BT_L2CAP && ISDN_CAPI depends on BT && ISDN_CAPI
help help
CMTP (CAPI Message Transport Protocol) is a transport layer CMTP (CAPI Message Transport Protocol) is a transport layer
for CAPI messages. CMTP is required for the Bluetooth Common for CAPI messages. CMTP is required for the Bluetooth Common
......
...@@ -487,7 +487,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src) ...@@ -487,7 +487,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
BT_DBG("%s -> %s", batostr(src), batostr(dst)); BT_DBG("%s -> %s", batostr(src), batostr(dst));
read_lock_bh(&hci_dev_list_lock); read_lock(&hci_dev_list_lock);
list_for_each_entry(d, &hci_dev_list, list) { list_for_each_entry(d, &hci_dev_list, list) {
if (!test_bit(HCI_UP, &d->flags) || test_bit(HCI_RAW, &d->flags)) if (!test_bit(HCI_UP, &d->flags) || test_bit(HCI_RAW, &d->flags))
...@@ -512,7 +512,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src) ...@@ -512,7 +512,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
if (hdev) if (hdev)
hdev = hci_dev_hold(hdev); hdev = hci_dev_hold(hdev);
read_unlock_bh(&hci_dev_list_lock); read_unlock(&hci_dev_list_lock);
return hdev; return hdev;
} }
EXPORT_SYMBOL(hci_get_route); EXPORT_SYMBOL(hci_get_route);
......
...@@ -61,8 +61,6 @@ static void hci_rx_work(struct work_struct *work); ...@@ -61,8 +61,6 @@ static void hci_rx_work(struct work_struct *work);
static void hci_cmd_work(struct work_struct *work); static void hci_cmd_work(struct work_struct *work);
static void hci_tx_work(struct work_struct *work); static void hci_tx_work(struct work_struct *work);
static DEFINE_MUTEX(hci_task_lock);
/* HCI device list */ /* HCI device list */
LIST_HEAD(hci_dev_list); LIST_HEAD(hci_dev_list);
DEFINE_RWLOCK(hci_dev_list_lock); DEFINE_RWLOCK(hci_dev_list_lock);
...@@ -71,10 +69,6 @@ DEFINE_RWLOCK(hci_dev_list_lock); ...@@ -71,10 +69,6 @@ DEFINE_RWLOCK(hci_dev_list_lock);
LIST_HEAD(hci_cb_list); LIST_HEAD(hci_cb_list);
DEFINE_RWLOCK(hci_cb_list_lock); DEFINE_RWLOCK(hci_cb_list_lock);
/* HCI protocols */
#define HCI_MAX_PROTO 2
struct hci_proto *hci_proto[HCI_MAX_PROTO];
/* HCI notifiers list */ /* HCI notifiers list */
static ATOMIC_NOTIFIER_HEAD(hci_notifier); static ATOMIC_NOTIFIER_HEAD(hci_notifier);
...@@ -193,33 +187,20 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt) ...@@ -193,33 +187,20 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL); hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
} }
static void hci_init_req(struct hci_dev *hdev, unsigned long opt) static void bredr_init(struct hci_dev *hdev)
{ {
struct hci_cp_delete_stored_link_key cp; struct hci_cp_delete_stored_link_key cp;
struct sk_buff *skb;
__le16 param; __le16 param;
__u8 flt_type; __u8 flt_type;
BT_DBG("%s %ld", hdev->name, opt); hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_PACKET_BASED;
/* Driver initialization */
/* Special commands */
while ((skb = skb_dequeue(&hdev->driver_init))) {
bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
skb->dev = (void *) hdev;
skb_queue_tail(&hdev->cmd_q, skb);
queue_work(hdev->workqueue, &hdev->cmd_work);
}
skb_queue_purge(&hdev->driver_init);
/* Mandatory initialization */ /* Mandatory initialization */
/* Reset */ /* Reset */
if (!test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) { if (!test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) {
set_bit(HCI_RESET, &hdev->flags); set_bit(HCI_RESET, &hdev->flags);
hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL); hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
} }
/* Read Local Supported Features */ /* Read Local Supported Features */
...@@ -258,6 +239,51 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) ...@@ -258,6 +239,51 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp); hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp);
} }
static void amp_init(struct hci_dev *hdev)
{
hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_BLOCK_BASED;
/* Reset */
hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
/* Read Local Version */
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
}
static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
{
struct sk_buff *skb;
BT_DBG("%s %ld", hdev->name, opt);
/* Driver initialization */
/* Special commands */
while ((skb = skb_dequeue(&hdev->driver_init))) {
bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
skb->dev = (void *) hdev;
skb_queue_tail(&hdev->cmd_q, skb);
queue_work(hdev->workqueue, &hdev->cmd_work);
}
skb_queue_purge(&hdev->driver_init);
switch (hdev->dev_type) {
case HCI_BREDR:
bredr_init(hdev);
break;
case HCI_AMP:
amp_init(hdev);
break;
default:
BT_ERR("Unknown device type %d", hdev->dev_type);
break;
}
}
static void hci_le_init_req(struct hci_dev *hdev, unsigned long opt) static void hci_le_init_req(struct hci_dev *hdev, unsigned long opt)
{ {
BT_DBG("%s", hdev->name); BT_DBG("%s", hdev->name);
...@@ -818,7 +844,7 @@ int hci_get_dev_list(void __user *arg) ...@@ -818,7 +844,7 @@ int hci_get_dev_list(void __user *arg)
dr = dl->dev_req; dr = dl->dev_req;
read_lock_bh(&hci_dev_list_lock); read_lock(&hci_dev_list_lock);
list_for_each_entry(hdev, &hci_dev_list, list) { list_for_each_entry(hdev, &hci_dev_list, list) {
if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags)) if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
cancel_delayed_work(&hdev->power_off); cancel_delayed_work(&hdev->power_off);
...@@ -832,7 +858,7 @@ int hci_get_dev_list(void __user *arg) ...@@ -832,7 +858,7 @@ int hci_get_dev_list(void __user *arg)
if (++n >= dev_num) if (++n >= dev_num)
break; break;
} }
read_unlock_bh(&hci_dev_list_lock); read_unlock(&hci_dev_list_lock);
dl->dev_num = n; dl->dev_num = n;
size = sizeof(*dl) + n * sizeof(*dr); size = sizeof(*dl) + n * sizeof(*dr);
...@@ -1432,7 +1458,7 @@ int hci_register_dev(struct hci_dev *hdev) ...@@ -1432,7 +1458,7 @@ int hci_register_dev(struct hci_dev *hdev)
*/ */
id = (hdev->dev_type == HCI_BREDR) ? 0 : 1; id = (hdev->dev_type == HCI_BREDR) ? 0 : 1;
write_lock_bh(&hci_dev_list_lock); write_lock(&hci_dev_list_lock);
/* Find first available device id */ /* Find first available device id */
list_for_each(p, &hci_dev_list) { list_for_each(p, &hci_dev_list) {
...@@ -1502,7 +1528,7 @@ int hci_register_dev(struct hci_dev *hdev) ...@@ -1502,7 +1528,7 @@ int hci_register_dev(struct hci_dev *hdev)
atomic_set(&hdev->promisc, 0); atomic_set(&hdev->promisc, 0);
write_unlock_bh(&hci_dev_list_lock); write_unlock(&hci_dev_list_lock);
hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI | WQ_UNBOUND | hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI | WQ_UNBOUND |
WQ_MEM_RECLAIM, 1); WQ_MEM_RECLAIM, 1);
...@@ -1535,9 +1561,9 @@ int hci_register_dev(struct hci_dev *hdev) ...@@ -1535,9 +1561,9 @@ int hci_register_dev(struct hci_dev *hdev)
err_wqueue: err_wqueue:
destroy_workqueue(hdev->workqueue); destroy_workqueue(hdev->workqueue);
err: err:
write_lock_bh(&hci_dev_list_lock); write_lock(&hci_dev_list_lock);
list_del(&hdev->list); list_del(&hdev->list);
write_unlock_bh(&hci_dev_list_lock); write_unlock(&hci_dev_list_lock);
return error; return error;
} }
...@@ -1550,9 +1576,9 @@ void hci_unregister_dev(struct hci_dev *hdev) ...@@ -1550,9 +1576,9 @@ void hci_unregister_dev(struct hci_dev *hdev)
BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus); BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
write_lock_bh(&hci_dev_list_lock); write_lock(&hci_dev_list_lock);
list_del(&hdev->list); list_del(&hdev->list);
write_unlock_bh(&hci_dev_list_lock); write_unlock(&hci_dev_list_lock);
hci_dev_do_close(hdev); hci_dev_do_close(hdev);
...@@ -1800,59 +1826,13 @@ EXPORT_SYMBOL(hci_recv_stream_fragment); ...@@ -1800,59 +1826,13 @@ EXPORT_SYMBOL(hci_recv_stream_fragment);
/* ---- Interface to upper protocols ---- */ /* ---- Interface to upper protocols ---- */
/* Register/Unregister protocols.
* hci_task_lock is used to ensure that no tasks are running. */
int hci_register_proto(struct hci_proto *hp)
{
int err = 0;
BT_DBG("%p name %s id %d", hp, hp->name, hp->id);
if (hp->id >= HCI_MAX_PROTO)
return -EINVAL;
mutex_lock(&hci_task_lock);
if (!hci_proto[hp->id])
hci_proto[hp->id] = hp;
else
err = -EEXIST;
mutex_unlock(&hci_task_lock);
return err;
}
EXPORT_SYMBOL(hci_register_proto);
int hci_unregister_proto(struct hci_proto *hp)
{
int err = 0;
BT_DBG("%p name %s id %d", hp, hp->name, hp->id);
if (hp->id >= HCI_MAX_PROTO)
return -EINVAL;
mutex_lock(&hci_task_lock);
if (hci_proto[hp->id])
hci_proto[hp->id] = NULL;
else
err = -ENOENT;
mutex_unlock(&hci_task_lock);
return err;
}
EXPORT_SYMBOL(hci_unregister_proto);
int hci_register_cb(struct hci_cb *cb) int hci_register_cb(struct hci_cb *cb)
{ {
BT_DBG("%p name %s", cb, cb->name); BT_DBG("%p name %s", cb, cb->name);
write_lock_bh(&hci_cb_list_lock); write_lock(&hci_cb_list_lock);
list_add(&cb->list, &hci_cb_list); list_add(&cb->list, &hci_cb_list);
write_unlock_bh(&hci_cb_list_lock); write_unlock(&hci_cb_list_lock);
return 0; return 0;
} }
...@@ -1862,9 +1842,9 @@ int hci_unregister_cb(struct hci_cb *cb) ...@@ -1862,9 +1842,9 @@ int hci_unregister_cb(struct hci_cb *cb)
{ {
BT_DBG("%p name %s", cb, cb->name); BT_DBG("%p name %s", cb, cb->name);
write_lock_bh(&hci_cb_list_lock); write_lock(&hci_cb_list_lock);
list_del(&cb->list); list_del(&cb->list);
write_unlock_bh(&hci_cb_list_lock); write_unlock(&hci_cb_list_lock);
return 0; return 0;
} }
...@@ -1980,7 +1960,7 @@ static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue, ...@@ -1980,7 +1960,7 @@ static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
skb_shinfo(skb)->frag_list = NULL; skb_shinfo(skb)->frag_list = NULL;
/* Queue all fragments atomically */ /* Queue all fragments atomically */
spin_lock_bh(&queue->lock); spin_lock(&queue->lock);
__skb_queue_tail(queue, skb); __skb_queue_tail(queue, skb);
...@@ -1998,7 +1978,7 @@ static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue, ...@@ -1998,7 +1978,7 @@ static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
__skb_queue_tail(queue, skb); __skb_queue_tail(queue, skb);
} while (list); } while (list);
spin_unlock_bh(&queue->lock); spin_unlock(&queue->lock);
} }
} }
...@@ -2407,8 +2387,6 @@ static void hci_tx_work(struct work_struct *work) ...@@ -2407,8 +2387,6 @@ static void hci_tx_work(struct work_struct *work)
struct hci_dev *hdev = container_of(work, struct hci_dev, tx_work); struct hci_dev *hdev = container_of(work, struct hci_dev, tx_work);
struct sk_buff *skb; struct sk_buff *skb;
mutex_lock(&hci_task_lock);
BT_DBG("%s acl %d sco %d le %d", hdev->name, hdev->acl_cnt, BT_DBG("%s acl %d sco %d le %d", hdev->name, hdev->acl_cnt,
hdev->sco_cnt, hdev->le_cnt); hdev->sco_cnt, hdev->le_cnt);
...@@ -2425,8 +2403,6 @@ static void hci_tx_work(struct work_struct *work) ...@@ -2425,8 +2403,6 @@ static void hci_tx_work(struct work_struct *work)
/* Send next queued raw (unknown type) packet */ /* Send next queued raw (unknown type) packet */
while ((skb = skb_dequeue(&hdev->raw_q))) while ((skb = skb_dequeue(&hdev->raw_q)))
hci_send_frame(skb); hci_send_frame(skb);
mutex_unlock(&hci_task_lock);
} }
/* ----- HCI RX task (incoming data processing) ----- */ /* ----- HCI RX task (incoming data processing) ----- */
...@@ -2453,16 +2429,11 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -2453,16 +2429,11 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
if (conn) { if (conn) {
register struct hci_proto *hp;
hci_conn_enter_active_mode(conn, BT_POWER_FORCE_ACTIVE_OFF); hci_conn_enter_active_mode(conn, BT_POWER_FORCE_ACTIVE_OFF);
/* Send to upper protocol */ /* Send to upper protocol */
hp = hci_proto[HCI_PROTO_L2CAP]; l2cap_recv_acldata(conn, skb, flags);
if (hp && hp->recv_acldata) { return;
hp->recv_acldata(conn, skb, flags);
return;
}
} else { } else {
BT_ERR("%s ACL packet for unknown connection handle %d", BT_ERR("%s ACL packet for unknown connection handle %d",
hdev->name, handle); hdev->name, handle);
...@@ -2491,14 +2462,9 @@ static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -2491,14 +2462,9 @@ static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
if (conn) { if (conn) {
register struct hci_proto *hp;
/* Send to upper protocol */ /* Send to upper protocol */
hp = hci_proto[HCI_PROTO_SCO]; sco_recv_scodata(conn, skb);
if (hp && hp->recv_scodata) { return;
hp->recv_scodata(conn, skb);
return;
}
} else { } else {
BT_ERR("%s SCO packet for unknown connection handle %d", BT_ERR("%s SCO packet for unknown connection handle %d",
hdev->name, handle); hdev->name, handle);
...@@ -2514,8 +2480,6 @@ static void hci_rx_work(struct work_struct *work) ...@@ -2514,8 +2480,6 @@ static void hci_rx_work(struct work_struct *work)
BT_DBG("%s", hdev->name); BT_DBG("%s", hdev->name);
mutex_lock(&hci_task_lock);
while ((skb = skb_dequeue(&hdev->rx_q))) { while ((skb = skb_dequeue(&hdev->rx_q))) {
if (atomic_read(&hdev->promisc)) { if (atomic_read(&hdev->promisc)) {
/* Send copy to the sockets */ /* Send copy to the sockets */
...@@ -2559,8 +2523,6 @@ static void hci_rx_work(struct work_struct *work) ...@@ -2559,8 +2523,6 @@ static void hci_rx_work(struct work_struct *work)
break; break;
} }
} }
mutex_unlock(&hci_task_lock);
} }
static void hci_cmd_work(struct work_struct *work) static void hci_cmd_work(struct work_struct *work)
......
...@@ -556,6 +556,9 @@ static void hci_set_le_support(struct hci_dev *hdev) ...@@ -556,6 +556,9 @@ static void hci_set_le_support(struct hci_dev *hdev)
static void hci_setup(struct hci_dev *hdev) static void hci_setup(struct hci_dev *hdev)
{ {
if (hdev->dev_type != HCI_BREDR)
return;
hci_setup_event_mask(hdev); hci_setup_event_mask(hdev);
if (hdev->hci_ver > BLUETOOTH_VER_1_1) if (hdev->hci_ver > BLUETOOTH_VER_1_1)
...@@ -1030,7 +1033,8 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, ...@@ -1030,7 +1033,8 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
if (!cp) if (!cp)
return; return;
if (cp->enable == 0x01) { switch (cp->enable) {
case LE_SCANNING_ENABLED:
set_bit(HCI_LE_SCAN, &hdev->dev_flags); set_bit(HCI_LE_SCAN, &hdev->dev_flags);
cancel_delayed_work_sync(&hdev->adv_work); cancel_delayed_work_sync(&hdev->adv_work);
...@@ -1038,12 +1042,19 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, ...@@ -1038,12 +1042,19 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
hci_dev_lock(hdev); hci_dev_lock(hdev);
hci_adv_entries_clear(hdev); hci_adv_entries_clear(hdev);
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} else if (cp->enable == 0x00) { break;
case LE_SCANNING_DISABLED:
clear_bit(HCI_LE_SCAN, &hdev->dev_flags); clear_bit(HCI_LE_SCAN, &hdev->dev_flags);
cancel_delayed_work_sync(&hdev->adv_work); cancel_delayed_work_sync(&hdev->adv_work);
queue_delayed_work(hdev->workqueue, &hdev->adv_work, queue_delayed_work(hdev->workqueue, &hdev->adv_work,
jiffies + ADV_CLEAR_TIMEOUT); jiffies + ADV_CLEAR_TIMEOUT);
break;
default:
BT_ERR("Used reserved LE_Scan_Enable param %d", cp->enable);
break;
} }
} }
...@@ -2253,24 +2264,29 @@ static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb ...@@ -2253,24 +2264,29 @@ static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb
static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb) static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
struct hci_ev_num_comp_pkts *ev = (void *) skb->data; struct hci_ev_num_comp_pkts *ev = (void *) skb->data;
__le16 *ptr;
int i; int i;
skb_pull(skb, sizeof(*ev)); skb_pull(skb, sizeof(*ev));
BT_DBG("%s num_hndl %d", hdev->name, ev->num_hndl); BT_DBG("%s num_hndl %d", hdev->name, ev->num_hndl);
if (hdev->flow_ctl_mode != HCI_FLOW_CTL_MODE_PACKET_BASED) {
BT_ERR("Wrong event for mode %d", hdev->flow_ctl_mode);
return;
}
if (skb->len < ev->num_hndl * 4) { if (skb->len < ev->num_hndl * 4) {
BT_DBG("%s bad parameters", hdev->name); BT_DBG("%s bad parameters", hdev->name);
return; return;
} }
for (i = 0, ptr = (__le16 *) skb->data; i < ev->num_hndl; i++) { for (i = 0; i < ev->num_hndl; i++) {
struct hci_comp_pkts_info *info = &ev->handles[i];
struct hci_conn *conn; struct hci_conn *conn;
__u16 handle, count; __u16 handle, count;
handle = get_unaligned_le16(ptr++); handle = __le16_to_cpu(info->handle);
count = get_unaligned_le16(ptr++); count = __le16_to_cpu(info->count);
conn = hci_conn_hash_lookup_handle(hdev, handle); conn = hci_conn_hash_lookup_handle(hdev, handle);
if (!conn) if (!conn)
......
config BT_HIDP config BT_HIDP
tristate "HIDP protocol support" tristate "HIDP protocol support"
depends on BT && BT_L2CAP && INPUT && HID_SUPPORT depends on BT && INPUT && HID_SUPPORT
select HID select HID
help help
HIDP (Human Interface Device Protocol) is a transport layer HIDP (Human Interface Device Protocol) is a transport layer
......
...@@ -77,17 +77,6 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb); ...@@ -77,17 +77,6 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
/* ---- L2CAP channels ---- */ /* ---- L2CAP channels ---- */
static inline void chan_hold(struct l2cap_chan *c)
{
atomic_inc(&c->refcnt);
}
static inline void chan_put(struct l2cap_chan *c)
{
if (atomic_dec_and_test(&c->refcnt))
kfree(c);
}
static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid) static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
{ {
struct l2cap_chan *c, *r = NULL; struct l2cap_chan *c, *r = NULL;
...@@ -228,20 +217,6 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn) ...@@ -228,20 +217,6 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
return 0; return 0;
} }
static void l2cap_set_timer(struct l2cap_chan *chan, struct delayed_work *work, long timeout)
{
BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout);
cancel_delayed_work_sync(work);
schedule_delayed_work(work, timeout);
}
static void l2cap_clear_timer(struct delayed_work *work)
{
cancel_delayed_work_sync(work);
}
static char *state_to_string(int state) static char *state_to_string(int state)
{ {
switch(state) { switch(state) {
...@@ -301,7 +276,7 @@ static void l2cap_chan_timeout(struct work_struct *work) ...@@ -301,7 +276,7 @@ static void l2cap_chan_timeout(struct work_struct *work)
release_sock(sk); release_sock(sk);
chan->ops->close(chan->data); chan->ops->close(chan->data);
chan_put(chan); l2cap_chan_put(chan);
} }
struct l2cap_chan *l2cap_chan_create(struct sock *sk) struct l2cap_chan *l2cap_chan_create(struct sock *sk)
...@@ -335,7 +310,7 @@ void l2cap_chan_destroy(struct l2cap_chan *chan) ...@@ -335,7 +310,7 @@ void l2cap_chan_destroy(struct l2cap_chan *chan)
list_del(&chan->global_l); list_del(&chan->global_l);
write_unlock_bh(&chan_list_lock); write_unlock_bh(&chan_list_lock);
chan_put(chan); l2cap_chan_put(chan);
} }
static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
...@@ -377,7 +352,7 @@ static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) ...@@ -377,7 +352,7 @@ static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
chan->local_acc_lat = L2CAP_DEFAULT_ACC_LAT; chan->local_acc_lat = L2CAP_DEFAULT_ACC_LAT;
chan->local_flush_to = L2CAP_DEFAULT_FLUSH_TO; chan->local_flush_to = L2CAP_DEFAULT_FLUSH_TO;
chan_hold(chan); l2cap_chan_hold(chan);
list_add_rcu(&chan->list, &conn->chan_l); list_add_rcu(&chan->list, &conn->chan_l);
} }
...@@ -399,7 +374,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) ...@@ -399,7 +374,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
list_del_rcu(&chan->list); list_del_rcu(&chan->list);
synchronize_rcu(); synchronize_rcu();
chan_put(chan); l2cap_chan_put(chan);
chan->conn = NULL; chan->conn = NULL;
hci_conn_put(conn->hcon); hci_conn_put(conn->hcon);
...@@ -713,7 +688,7 @@ static void l2cap_do_start(struct l2cap_chan *chan) ...@@ -713,7 +688,7 @@ static void l2cap_do_start(struct l2cap_chan *chan)
conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
conn->info_ident = l2cap_get_ident(conn); conn->info_ident = l2cap_get_ident(conn);
schedule_delayed_work(&conn->info_work, schedule_delayed_work(&conn->info_timer,
msecs_to_jiffies(L2CAP_INFO_TIMEOUT)); msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
l2cap_send_cmd(conn, conn->info_ident, l2cap_send_cmd(conn, conn->info_ident,
...@@ -1010,7 +985,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) ...@@ -1010,7 +985,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
static void l2cap_info_timeout(struct work_struct *work) static void l2cap_info_timeout(struct work_struct *work)
{ {
struct l2cap_conn *conn = container_of(work, struct l2cap_conn, struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
info_work.work); info_timer.work);
conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
conn->info_ident = 0; conn->info_ident = 0;
...@@ -1043,10 +1018,10 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) ...@@ -1043,10 +1018,10 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
hci_chan_del(conn->hchan); hci_chan_del(conn->hchan);
if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
cancel_delayed_work_sync(&conn->info_work); __cancel_delayed_work(&conn->info_timer);
if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) { if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) {
del_timer(&conn->security_timer); __cancel_delayed_work(&conn->security_timer);
smp_chan_destroy(conn); smp_chan_destroy(conn);
} }
...@@ -1054,9 +1029,10 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) ...@@ -1054,9 +1029,10 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
kfree(conn); kfree(conn);
} }
static void security_timeout(unsigned long arg) static void security_timeout(struct work_struct *work)
{ {
struct l2cap_conn *conn = (void *) arg; struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
security_timer.work);
l2cap_conn_del(conn->hcon, ETIMEDOUT); l2cap_conn_del(conn->hcon, ETIMEDOUT);
} }
...@@ -1100,10 +1076,9 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) ...@@ -1100,10 +1076,9 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
INIT_LIST_HEAD(&conn->chan_l); INIT_LIST_HEAD(&conn->chan_l);
if (hcon->type == LE_LINK) if (hcon->type == LE_LINK)
setup_timer(&conn->security_timer, security_timeout, INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
(unsigned long) conn);
else else
INIT_DELAYED_WORK(&conn->info_work, l2cap_info_timeout); INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM; conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
...@@ -2010,6 +1985,8 @@ static void l2cap_ack_timeout(struct work_struct *work) ...@@ -2010,6 +1985,8 @@ static void l2cap_ack_timeout(struct work_struct *work)
struct l2cap_chan *chan = container_of(work, struct l2cap_chan, struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
ack_timer.work); ack_timer.work);
BT_DBG("chan %p", chan);
lock_sock(chan->sk); lock_sock(chan->sk);
l2cap_send_ack(chan); l2cap_send_ack(chan);
release_sock(chan->sk); release_sock(chan->sk);
...@@ -2597,7 +2574,7 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd ...@@ -2597,7 +2574,7 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd
if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) && if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
cmd->ident == conn->info_ident) { cmd->ident == conn->info_ident) {
cancel_delayed_work_sync(&conn->info_work); __cancel_delayed_work(&conn->info_timer);
conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
conn->info_ident = 0; conn->info_ident = 0;
...@@ -2718,7 +2695,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd ...@@ -2718,7 +2695,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
conn->info_ident = l2cap_get_ident(conn); conn->info_ident = l2cap_get_ident(conn);
schedule_delayed_work(&conn->info_work, schedule_delayed_work(&conn->info_timer,
msecs_to_jiffies(L2CAP_INFO_TIMEOUT)); msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
l2cap_send_cmd(conn, conn->info_ident, l2cap_send_cmd(conn, conn->info_ident,
...@@ -3143,7 +3120,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm ...@@ -3143,7 +3120,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
return 0; return 0;
cancel_delayed_work_sync(&conn->info_work); __cancel_delayed_work(&conn->info_timer);
if (result != L2CAP_IR_SUCCESS) { if (result != L2CAP_IR_SUCCESS) {
conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
...@@ -4427,14 +4404,11 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -4427,14 +4404,11 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
/* ---- L2CAP interface with lower layer (HCI) ---- */ /* ---- L2CAP interface with lower layer (HCI) ---- */
static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
{ {
int exact = 0, lm1 = 0, lm2 = 0; int exact = 0, lm1 = 0, lm2 = 0;
struct l2cap_chan *c; struct l2cap_chan *c;
if (type != ACL_LINK)
return -EINVAL;
BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr)); BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
/* Find listening sockets and check their link_mode */ /* Find listening sockets and check their link_mode */
...@@ -4461,15 +4435,12 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) ...@@ -4461,15 +4435,12 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
return exact ? lm1 : lm2; return exact ? lm1 : lm2;
} }
static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status) int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
{ {
struct l2cap_conn *conn; struct l2cap_conn *conn;
BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status); BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
return -EINVAL;
if (!status) { if (!status) {
conn = l2cap_conn_add(hcon, status); conn = l2cap_conn_add(hcon, status);
if (conn) if (conn)
...@@ -4480,27 +4451,22 @@ static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status) ...@@ -4480,27 +4451,22 @@ static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
return 0; return 0;
} }
static int l2cap_disconn_ind(struct hci_conn *hcon) int l2cap_disconn_ind(struct hci_conn *hcon)
{ {
struct l2cap_conn *conn = hcon->l2cap_data; struct l2cap_conn *conn = hcon->l2cap_data;
BT_DBG("hcon %p", hcon); BT_DBG("hcon %p", hcon);
if ((hcon->type != ACL_LINK && hcon->type != LE_LINK) || !conn) if (!conn)
return HCI_ERROR_REMOTE_USER_TERM; return HCI_ERROR_REMOTE_USER_TERM;
return conn->disc_reason; return conn->disc_reason;
} }
static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason) int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
{ {
BT_DBG("hcon %p reason %d", hcon, reason); BT_DBG("hcon %p reason %d", hcon, reason);
if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
return -EINVAL;
l2cap_conn_del(hcon, bt_to_errno(reason)); l2cap_conn_del(hcon, bt_to_errno(reason));
return 0; return 0;
} }
...@@ -4521,7 +4487,7 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt) ...@@ -4521,7 +4487,7 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
} }
} }
static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
{ {
struct l2cap_conn *conn = hcon->l2cap_data; struct l2cap_conn *conn = hcon->l2cap_data;
struct l2cap_chan *chan; struct l2cap_chan *chan;
...@@ -4533,7 +4499,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) ...@@ -4533,7 +4499,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
if (hcon->type == LE_LINK) { if (hcon->type == LE_LINK) {
smp_distribute_keys(conn, 0); smp_distribute_keys(conn, 0);
del_timer(&conn->security_timer); __cancel_delayed_work(&conn->security_timer);
} }
rcu_read_lock(); rcu_read_lock();
...@@ -4621,7 +4587,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) ...@@ -4621,7 +4587,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
return 0; return 0;
} }
static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
{ {
struct l2cap_conn *conn = hcon->l2cap_data; struct l2cap_conn *conn = hcon->l2cap_data;
...@@ -4768,17 +4734,6 @@ static const struct file_operations l2cap_debugfs_fops = { ...@@ -4768,17 +4734,6 @@ static const struct file_operations l2cap_debugfs_fops = {
static struct dentry *l2cap_debugfs; static struct dentry *l2cap_debugfs;
static struct hci_proto l2cap_hci_proto = {
.name = "L2CAP",
.id = HCI_PROTO_L2CAP,
.connect_ind = l2cap_connect_ind,
.connect_cfm = l2cap_connect_cfm,
.disconn_ind = l2cap_disconn_ind,
.disconn_cfm = l2cap_disconn_cfm,
.security_cfm = l2cap_security_cfm,
.recv_acldata = l2cap_recv_acldata
};
int __init l2cap_init(void) int __init l2cap_init(void)
{ {
int err; int err;
...@@ -4787,13 +4742,6 @@ int __init l2cap_init(void) ...@@ -4787,13 +4742,6 @@ int __init l2cap_init(void)
if (err < 0) if (err < 0)
return err; return err;
err = hci_register_proto(&l2cap_hci_proto);
if (err < 0) {
BT_ERR("L2CAP protocol registration failed");
bt_sock_unregister(BTPROTO_L2CAP);
goto error;
}
if (bt_debugfs) { if (bt_debugfs) {
l2cap_debugfs = debugfs_create_file("l2cap", 0444, l2cap_debugfs = debugfs_create_file("l2cap", 0444,
bt_debugfs, NULL, &l2cap_debugfs_fops); bt_debugfs, NULL, &l2cap_debugfs_fops);
...@@ -4802,19 +4750,11 @@ int __init l2cap_init(void) ...@@ -4802,19 +4750,11 @@ int __init l2cap_init(void)
} }
return 0; return 0;
error:
l2cap_cleanup_sockets();
return err;
} }
void l2cap_exit(void) void l2cap_exit(void)
{ {
debugfs_remove(l2cap_debugfs); debugfs_remove(l2cap_debugfs);
if (hci_unregister_proto(&l2cap_hci_proto) < 0)
BT_ERR("L2CAP protocol unregistration failed");
l2cap_cleanup_sockets(); l2cap_cleanup_sockets();
} }
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h> #include <net/bluetooth/hci_core.h>
#include <net/bluetooth/mgmt.h> #include <net/bluetooth/mgmt.h>
#include <net/bluetooth/smp.h>
#define MGMT_VERSION 0 #define MGMT_VERSION 0
#define MGMT_REVISION 1 #define MGMT_REVISION 1
...@@ -1642,8 +1643,15 @@ static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr, ...@@ -1642,8 +1643,15 @@ static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
} }
/* Continue with pairing via SMP */ /* Continue with pairing via SMP */
err = smp_user_confirm_reply(conn, mgmt_op, passkey);
if (!err)
err = cmd_status(sk, index, mgmt_op,
MGMT_STATUS_SUCCESS);
else
err = cmd_status(sk, index, mgmt_op,
MGMT_STATUS_FAILED);
err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_SUCCESS);
goto done; goto done;
} }
......
config BT_RFCOMM config BT_RFCOMM
tristate "RFCOMM protocol support" tristate "RFCOMM protocol support"
depends on BT && BT_L2CAP depends on BT
help help
RFCOMM provides connection oriented stream transport. RFCOMM RFCOMM provides connection oriented stream transport. RFCOMM
support is required for Dialup Networking, OBEX and other Bluetooth support is required for Dialup Networking, OBEX and other Bluetooth
......
...@@ -65,8 +65,7 @@ static DEFINE_MUTEX(rfcomm_mutex); ...@@ -65,8 +65,7 @@ static DEFINE_MUTEX(rfcomm_mutex);
static LIST_HEAD(session_list); static LIST_HEAD(session_list);
static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len, static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len);
u32 priority);
static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci); static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci);
static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci); static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci);
static int rfcomm_queue_disc(struct rfcomm_dlc *d); static int rfcomm_queue_disc(struct rfcomm_dlc *d);
...@@ -748,32 +747,23 @@ void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *d ...@@ -748,32 +747,23 @@ void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *d
} }
/* ---- RFCOMM frame sending ---- */ /* ---- RFCOMM frame sending ---- */
static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len, static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len)
u32 priority)
{ {
struct socket *sock = s->sock;
struct sock *sk = sock->sk;
struct kvec iv = { data, len }; struct kvec iv = { data, len };
struct msghdr msg; struct msghdr msg;
BT_DBG("session %p len %d priority %u", s, len, priority); BT_DBG("session %p len %d", s, len);
if (sk->sk_priority != priority) {
lock_sock(sk);
sk->sk_priority = priority;
release_sock(sk);
}
memset(&msg, 0, sizeof(msg)); memset(&msg, 0, sizeof(msg));
return kernel_sendmsg(sock, &msg, &iv, 1, len); return kernel_sendmsg(s->sock, &msg, &iv, 1, len);
} }
static int rfcomm_send_cmd(struct rfcomm_session *s, struct rfcomm_cmd *cmd) static int rfcomm_send_cmd(struct rfcomm_session *s, struct rfcomm_cmd *cmd)
{ {
BT_DBG("%p cmd %u", s, cmd->ctrl); BT_DBG("%p cmd %u", s, cmd->ctrl);
return rfcomm_send_frame(s, (void *) cmd, sizeof(*cmd), HCI_PRIO_MAX); return rfcomm_send_frame(s, (void *) cmd, sizeof(*cmd));
} }
static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci) static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci)
...@@ -829,8 +819,6 @@ static int rfcomm_queue_disc(struct rfcomm_dlc *d) ...@@ -829,8 +819,6 @@ static int rfcomm_queue_disc(struct rfcomm_dlc *d)
if (!skb) if (!skb)
return -ENOMEM; return -ENOMEM;
skb->priority = HCI_PRIO_MAX;
cmd = (void *) __skb_put(skb, sizeof(*cmd)); cmd = (void *) __skb_put(skb, sizeof(*cmd));
cmd->addr = d->addr; cmd->addr = d->addr;
cmd->ctrl = __ctrl(RFCOMM_DISC, 1); cmd->ctrl = __ctrl(RFCOMM_DISC, 1);
...@@ -878,7 +866,7 @@ static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type) ...@@ -878,7 +866,7 @@ static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type)
*ptr = __fcs(buf); ptr++; *ptr = __fcs(buf); ptr++;
return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX); return rfcomm_send_frame(s, buf, ptr - buf);
} }
static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d) static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d)
...@@ -920,7 +908,7 @@ static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d ...@@ -920,7 +908,7 @@ static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d
*ptr = __fcs(buf); ptr++; *ptr = __fcs(buf); ptr++;
return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX); return rfcomm_send_frame(s, buf, ptr - buf);
} }
int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci, int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
...@@ -958,7 +946,7 @@ int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci, ...@@ -958,7 +946,7 @@ int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
*ptr = __fcs(buf); ptr++; *ptr = __fcs(buf); ptr++;
return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX); return rfcomm_send_frame(s, buf, ptr - buf);
} }
static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status) static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status)
...@@ -985,7 +973,7 @@ static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status) ...@@ -985,7 +973,7 @@ static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status)
*ptr = __fcs(buf); ptr++; *ptr = __fcs(buf); ptr++;
return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX); return rfcomm_send_frame(s, buf, ptr - buf);
} }
static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig) static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig)
...@@ -1012,7 +1000,7 @@ static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig ...@@ -1012,7 +1000,7 @@ static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig
*ptr = __fcs(buf); ptr++; *ptr = __fcs(buf); ptr++;
return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX); return rfcomm_send_frame(s, buf, ptr - buf);
} }
static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr) static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr)
...@@ -1034,7 +1022,7 @@ static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr) ...@@ -1034,7 +1022,7 @@ static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr)
*ptr = __fcs(buf); ptr++; *ptr = __fcs(buf); ptr++;
return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX); return rfcomm_send_frame(s, buf, ptr - buf);
} }
static int rfcomm_send_fcon(struct rfcomm_session *s, int cr) static int rfcomm_send_fcon(struct rfcomm_session *s, int cr)
...@@ -1056,7 +1044,7 @@ static int rfcomm_send_fcon(struct rfcomm_session *s, int cr) ...@@ -1056,7 +1044,7 @@ static int rfcomm_send_fcon(struct rfcomm_session *s, int cr)
*ptr = __fcs(buf); ptr++; *ptr = __fcs(buf); ptr++;
return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX); return rfcomm_send_frame(s, buf, ptr - buf);
} }
static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len) static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len)
...@@ -1107,7 +1095,7 @@ static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits) ...@@ -1107,7 +1095,7 @@ static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits)
*ptr = __fcs(buf); ptr++; *ptr = __fcs(buf); ptr++;
return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX); return rfcomm_send_frame(s, buf, ptr - buf);
} }
static void rfcomm_make_uih(struct sk_buff *skb, u8 addr) static void rfcomm_make_uih(struct sk_buff *skb, u8 addr)
...@@ -1786,8 +1774,7 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d) ...@@ -1786,8 +1774,7 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
return skb_queue_len(&d->tx_queue); return skb_queue_len(&d->tx_queue);
while (d->tx_credits && (skb = skb_dequeue(&d->tx_queue))) { while (d->tx_credits && (skb = skb_dequeue(&d->tx_queue))) {
err = rfcomm_send_frame(d->session, skb->data, skb->len, err = rfcomm_send_frame(d->session, skb->data, skb->len);
skb->priority);
if (err < 0) { if (err < 0) {
skb_queue_head(&d->tx_queue, skb); skb_queue_head(&d->tx_queue, skb);
break; break;
......
...@@ -893,15 +893,12 @@ static void sco_conn_ready(struct sco_conn *conn) ...@@ -893,15 +893,12 @@ static void sco_conn_ready(struct sco_conn *conn)
} }
/* ----- SCO interface with lower layer (HCI) ----- */ /* ----- SCO interface with lower layer (HCI) ----- */
static int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type) int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
{ {
register struct sock *sk; register struct sock *sk;
struct hlist_node *node; struct hlist_node *node;
int lm = 0; int lm = 0;
if (type != SCO_LINK && type != ESCO_LINK)
return -EINVAL;
BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr)); BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
/* Find listening sockets */ /* Find listening sockets */
...@@ -921,13 +918,9 @@ static int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type) ...@@ -921,13 +918,9 @@ static int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
return lm; return lm;
} }
static int sco_connect_cfm(struct hci_conn *hcon, __u8 status) int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
{ {
BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status); BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
return -EINVAL;
if (!status) { if (!status) {
struct sco_conn *conn; struct sco_conn *conn;
...@@ -940,19 +933,15 @@ static int sco_connect_cfm(struct hci_conn *hcon, __u8 status) ...@@ -940,19 +933,15 @@ static int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
return 0; return 0;
} }
static int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason) int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
{ {
BT_DBG("hcon %p reason %d", hcon, reason); BT_DBG("hcon %p reason %d", hcon, reason);
if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
return -EINVAL;
sco_conn_del(hcon, bt_to_errno(reason)); sco_conn_del(hcon, bt_to_errno(reason));
return 0; return 0;
} }
static int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb) int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
{ {
struct sco_conn *conn = hcon->sco_data; struct sco_conn *conn = hcon->sco_data;
...@@ -1028,15 +1017,6 @@ static const struct net_proto_family sco_sock_family_ops = { ...@@ -1028,15 +1017,6 @@ static const struct net_proto_family sco_sock_family_ops = {
.create = sco_sock_create, .create = sco_sock_create,
}; };
static struct hci_proto sco_hci_proto = {
.name = "SCO",
.id = HCI_PROTO_SCO,
.connect_ind = sco_connect_ind,
.connect_cfm = sco_connect_cfm,
.disconn_cfm = sco_disconn_cfm,
.recv_scodata = sco_recv_scodata
};
int __init sco_init(void) int __init sco_init(void)
{ {
int err; int err;
...@@ -1051,13 +1031,6 @@ int __init sco_init(void) ...@@ -1051,13 +1031,6 @@ int __init sco_init(void)
goto error; goto error;
} }
err = hci_register_proto(&sco_hci_proto);
if (err < 0) {
BT_ERR("SCO protocol registration failed");
bt_sock_unregister(BTPROTO_SCO);
goto error;
}
if (bt_debugfs) { if (bt_debugfs) {
sco_debugfs = debugfs_create_file("sco", 0444, sco_debugfs = debugfs_create_file("sco", 0444,
bt_debugfs, NULL, &sco_debugfs_fops); bt_debugfs, NULL, &sco_debugfs_fops);
...@@ -1081,9 +1054,6 @@ void __exit sco_exit(void) ...@@ -1081,9 +1054,6 @@ void __exit sco_exit(void)
if (bt_sock_unregister(BTPROTO_SCO) < 0) if (bt_sock_unregister(BTPROTO_SCO) < 0)
BT_ERR("SCO socket unregistration failed"); BT_ERR("SCO socket unregistration failed");
if (hci_unregister_proto(&sco_hci_proto) < 0)
BT_ERR("SCO protocol unregistration failed");
proto_unregister(&sco_proto); proto_unregister(&sco_proto);
} }
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h> #include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h> #include <net/bluetooth/l2cap.h>
#include <net/bluetooth/mgmt.h>
#include <net/bluetooth/smp.h> #include <net/bluetooth/smp.h>
#include <linux/crypto.h> #include <linux/crypto.h>
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
...@@ -184,28 +185,50 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data) ...@@ -184,28 +185,50 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
skb->priority = HCI_PRIO_MAX; skb->priority = HCI_PRIO_MAX;
hci_send_acl(conn->hchan, skb, 0); hci_send_acl(conn->hchan, skb, 0);
mod_timer(&conn->security_timer, jiffies + cancel_delayed_work_sync(&conn->security_timer);
schedule_delayed_work(&conn->security_timer,
msecs_to_jiffies(SMP_TIMEOUT)); msecs_to_jiffies(SMP_TIMEOUT));
} }
static __u8 authreq_to_seclevel(__u8 authreq)
{
if (authreq & SMP_AUTH_MITM)
return BT_SECURITY_HIGH;
else
return BT_SECURITY_MEDIUM;
}
static __u8 seclevel_to_authreq(__u8 sec_level)
{
switch (sec_level) {
case BT_SECURITY_HIGH:
return SMP_AUTH_MITM | SMP_AUTH_BONDING;
case BT_SECURITY_MEDIUM:
return SMP_AUTH_BONDING;
default:
return SMP_AUTH_NONE;
}
}
static void build_pairing_cmd(struct l2cap_conn *conn, static void build_pairing_cmd(struct l2cap_conn *conn,
struct smp_cmd_pairing *req, struct smp_cmd_pairing *req,
struct smp_cmd_pairing *rsp, struct smp_cmd_pairing *rsp,
__u8 authreq) __u8 authreq)
{ {
u8 dist_keys; u8 dist_keys = 0;
dist_keys = 0;
if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->flags)) { if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->flags)) {
dist_keys = SMP_DIST_ENC_KEY; dist_keys = SMP_DIST_ENC_KEY;
authreq |= SMP_AUTH_BONDING; authreq |= SMP_AUTH_BONDING;
} else {
authreq &= ~SMP_AUTH_BONDING;
} }
if (rsp == NULL) { if (rsp == NULL) {
req->io_capability = conn->hcon->io_capability; req->io_capability = conn->hcon->io_capability;
req->oob_flag = SMP_OOB_NOT_PRESENT; req->oob_flag = SMP_OOB_NOT_PRESENT;
req->max_key_size = SMP_MAX_ENC_KEY_SIZE; req->max_key_size = SMP_MAX_ENC_KEY_SIZE;
req->init_key_dist = dist_keys; req->init_key_dist = 0;
req->resp_key_dist = dist_keys; req->resp_key_dist = dist_keys;
req->auth_req = authreq; req->auth_req = authreq;
return; return;
...@@ -214,7 +237,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, ...@@ -214,7 +237,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
rsp->io_capability = conn->hcon->io_capability; rsp->io_capability = conn->hcon->io_capability;
rsp->oob_flag = SMP_OOB_NOT_PRESENT; rsp->oob_flag = SMP_OOB_NOT_PRESENT;
rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE; rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
rsp->init_key_dist = req->init_key_dist & dist_keys; rsp->init_key_dist = 0;
rsp->resp_key_dist = req->resp_key_dist & dist_keys; rsp->resp_key_dist = req->resp_key_dist & dist_keys;
rsp->auth_req = authreq; rsp->auth_req = authreq;
} }
...@@ -240,10 +263,99 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send) ...@@ -240,10 +263,99 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send)
clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->pend); clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->pend);
mgmt_auth_failed(conn->hcon->hdev, conn->dst, reason); mgmt_auth_failed(conn->hcon->hdev, conn->dst, reason);
del_timer(&conn->security_timer); cancel_delayed_work_sync(&conn->security_timer);
smp_chan_destroy(conn); smp_chan_destroy(conn);
} }
#define JUST_WORKS 0x00
#define JUST_CFM 0x01
#define REQ_PASSKEY 0x02
#define CFM_PASSKEY 0x03
#define REQ_OOB 0x04
#define OVERLAP 0xFF
static const u8 gen_method[5][5] = {
{ JUST_WORKS, JUST_CFM, REQ_PASSKEY, JUST_WORKS, REQ_PASSKEY },
{ JUST_WORKS, JUST_CFM, REQ_PASSKEY, JUST_WORKS, REQ_PASSKEY },
{ CFM_PASSKEY, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, CFM_PASSKEY },
{ JUST_WORKS, JUST_CFM, JUST_WORKS, JUST_WORKS, JUST_CFM },
{ CFM_PASSKEY, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, OVERLAP },
};
static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
u8 local_io, u8 remote_io)
{
struct hci_conn *hcon = conn->hcon;
struct smp_chan *smp = conn->smp_chan;
u8 method;
u32 passkey = 0;
int ret = 0;
/* Initialize key for JUST WORKS */
memset(smp->tk, 0, sizeof(smp->tk));
clear_bit(SMP_FLAG_TK_VALID, &smp->smp_flags);
BT_DBG("tk_request: auth:%d lcl:%d rem:%d", auth, local_io, remote_io);
/* If neither side wants MITM, use JUST WORKS */
/* If either side has unknown io_caps, use JUST WORKS */
/* Otherwise, look up method from the table */
if (!(auth & SMP_AUTH_MITM) ||
local_io > SMP_IO_KEYBOARD_DISPLAY ||
remote_io > SMP_IO_KEYBOARD_DISPLAY)
method = JUST_WORKS;
else
method = gen_method[local_io][remote_io];
/* If not bonding, don't ask user to confirm a Zero TK */
if (!(auth & SMP_AUTH_BONDING) && method == JUST_CFM)
method = JUST_WORKS;
/* If Just Works, Continue with Zero TK */
if (method == JUST_WORKS) {
set_bit(SMP_FLAG_TK_VALID, &smp->smp_flags);
return 0;
}
/* Not Just Works/Confirm results in MITM Authentication */
if (method != JUST_CFM)
set_bit(SMP_FLAG_MITM_AUTH, &smp->smp_flags);
/* If both devices have Keyoard-Display I/O, the master
* Confirms and the slave Enters the passkey.
*/
if (method == OVERLAP) {
if (hcon->link_mode & HCI_LM_MASTER)
method = CFM_PASSKEY;
else
method = REQ_PASSKEY;
}
/* Generate random passkey. Not valid until confirmed. */
if (method == CFM_PASSKEY) {
u8 key[16];
memset(key, 0, sizeof(key));
get_random_bytes(&passkey, sizeof(passkey));
passkey %= 1000000;
put_unaligned_le32(passkey, key);
swap128(key, smp->tk);
BT_DBG("PassKey: %d", passkey);
}
hci_dev_lock(hcon->hdev);
if (method == REQ_PASSKEY)
ret = mgmt_user_passkey_request(hcon->hdev, conn->dst);
else
ret = mgmt_user_confirm_request(hcon->hdev, conn->dst,
cpu_to_le32(passkey), 0);
hci_dev_unlock(hcon->hdev);
return ret;
}
static void confirm_work(struct work_struct *work) static void confirm_work(struct work_struct *work)
{ {
struct smp_chan *smp = container_of(work, struct smp_chan, confirm); struct smp_chan *smp = container_of(work, struct smp_chan, confirm);
...@@ -276,6 +388,8 @@ static void confirm_work(struct work_struct *work) ...@@ -276,6 +388,8 @@ static void confirm_work(struct work_struct *work)
goto error; goto error;
} }
clear_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags);
swap128(res, cp.confirm_val); swap128(res, cp.confirm_val);
smp_send_cmd(smp->conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp); smp_send_cmd(smp->conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
...@@ -381,6 +495,7 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) ...@@ -381,6 +495,7 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
smp->conn = conn; smp->conn = conn;
conn->smp_chan = smp; conn->smp_chan = smp;
conn->hcon->smp_conn = conn;
hci_conn_hold(conn->hcon); hci_conn_hold(conn->hcon);
...@@ -398,18 +513,64 @@ void smp_chan_destroy(struct l2cap_conn *conn) ...@@ -398,18 +513,64 @@ void smp_chan_destroy(struct l2cap_conn *conn)
kfree(smp); kfree(smp);
conn->smp_chan = NULL; conn->smp_chan = NULL;
conn->hcon->smp_conn = NULL;
hci_conn_put(conn->hcon); hci_conn_put(conn->hcon);
} }
int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
{
struct l2cap_conn *conn = hcon->smp_conn;
struct smp_chan *smp;
u32 value;
u8 key[16];
BT_DBG("");
if (!conn)
return -ENOTCONN;
smp = conn->smp_chan;
switch (mgmt_op) {
case MGMT_OP_USER_PASSKEY_REPLY:
value = le32_to_cpu(passkey);
memset(key, 0, sizeof(key));
BT_DBG("PassKey: %d", value);
put_unaligned_le32(value, key);
swap128(key, smp->tk);
/* Fall Through */
case MGMT_OP_USER_CONFIRM_REPLY:
set_bit(SMP_FLAG_TK_VALID, &smp->smp_flags);
break;
case MGMT_OP_USER_PASSKEY_NEG_REPLY:
case MGMT_OP_USER_CONFIRM_NEG_REPLY:
smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED, 1);
return 0;
default:
smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED, 1);
return -EOPNOTSUPP;
}
/* If it is our turn to send Pairing Confirm, do so now */
if (test_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags))
queue_work(hcon->hdev->workqueue, &smp->confirm);
return 0;
}
static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
{ {
struct smp_cmd_pairing rsp, *req = (void *) skb->data; struct smp_cmd_pairing rsp, *req = (void *) skb->data;
struct smp_chan *smp; struct smp_chan *smp;
u8 key_size; u8 key_size;
u8 auth = SMP_AUTH_NONE;
int ret; int ret;
BT_DBG("conn %p", conn); BT_DBG("conn %p", conn);
if (conn->hcon->link_mode & HCI_LM_MASTER)
return SMP_CMD_NOTSUPP;
if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend)) if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend))
smp = smp_chan_create(conn); smp = smp_chan_create(conn);
...@@ -419,19 +580,16 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -419,19 +580,16 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
memcpy(&smp->preq[1], req, sizeof(*req)); memcpy(&smp->preq[1], req, sizeof(*req));
skb_pull(skb, sizeof(*req)); skb_pull(skb, sizeof(*req));
if (req->oob_flag) /* We didn't start the pairing, so match remote */
return SMP_OOB_NOT_AVAIL; if (req->auth_req & SMP_AUTH_BONDING)
auth = req->auth_req;
/* We didn't start the pairing, so no requirements */ build_pairing_cmd(conn, req, &rsp, auth);
build_pairing_cmd(conn, req, &rsp, SMP_AUTH_NONE);
key_size = min(req->max_key_size, rsp.max_key_size); key_size = min(req->max_key_size, rsp.max_key_size);
if (check_enc_key_size(conn, key_size)) if (check_enc_key_size(conn, key_size))
return SMP_ENC_KEY_SIZE; return SMP_ENC_KEY_SIZE;
/* Just works */
memset(smp->tk, 0, sizeof(smp->tk));
ret = smp_rand(smp->prnd); ret = smp_rand(smp->prnd);
if (ret) if (ret)
return SMP_UNSPECIFIED; return SMP_UNSPECIFIED;
...@@ -441,6 +599,11 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -441,6 +599,11 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp); smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp);
/* Request setup of TK */
ret = tk_request(conn, 0, auth, rsp.io_capability, req->io_capability);
if (ret)
return SMP_UNSPECIFIED;
return 0; return 0;
} }
...@@ -449,11 +612,14 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -449,11 +612,14 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
struct smp_cmd_pairing *req, *rsp = (void *) skb->data; struct smp_cmd_pairing *req, *rsp = (void *) skb->data;
struct smp_chan *smp = conn->smp_chan; struct smp_chan *smp = conn->smp_chan;
struct hci_dev *hdev = conn->hcon->hdev; struct hci_dev *hdev = conn->hcon->hdev;
u8 key_size; u8 key_size, auth = SMP_AUTH_NONE;
int ret; int ret;
BT_DBG("conn %p", conn); BT_DBG("conn %p", conn);
if (!(conn->hcon->link_mode & HCI_LM_MASTER))
return SMP_CMD_NOTSUPP;
skb_pull(skb, sizeof(*rsp)); skb_pull(skb, sizeof(*rsp));
req = (void *) &smp->preq[1]; req = (void *) &smp->preq[1];
...@@ -462,12 +628,6 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -462,12 +628,6 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
if (check_enc_key_size(conn, key_size)) if (check_enc_key_size(conn, key_size))
return SMP_ENC_KEY_SIZE; return SMP_ENC_KEY_SIZE;
if (rsp->oob_flag)
return SMP_OOB_NOT_AVAIL;
/* Just works */
memset(smp->tk, 0, sizeof(smp->tk));
ret = smp_rand(smp->prnd); ret = smp_rand(smp->prnd);
if (ret) if (ret)
return SMP_UNSPECIFIED; return SMP_UNSPECIFIED;
...@@ -475,6 +635,22 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -475,6 +635,22 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
smp->prsp[0] = SMP_CMD_PAIRING_RSP; smp->prsp[0] = SMP_CMD_PAIRING_RSP;
memcpy(&smp->prsp[1], rsp, sizeof(*rsp)); memcpy(&smp->prsp[1], rsp, sizeof(*rsp));
if ((req->auth_req & SMP_AUTH_BONDING) &&
(rsp->auth_req & SMP_AUTH_BONDING))
auth = SMP_AUTH_BONDING;
auth |= (req->auth_req | rsp->auth_req) & SMP_AUTH_MITM;
ret = tk_request(conn, 0, auth, rsp->io_capability, req->io_capability);
if (ret)
return SMP_UNSPECIFIED;
set_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags);
/* Can't compose response until we have been confirmed */
if (!test_bit(SMP_FLAG_TK_VALID, &smp->smp_flags))
return 0;
queue_work(hdev->workqueue, &smp->confirm); queue_work(hdev->workqueue, &smp->confirm);
return 0; return 0;
...@@ -496,8 +672,10 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -496,8 +672,10 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
swap128(smp->prnd, random); swap128(smp->prnd, random);
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(random), smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(random),
random); random);
} else { } else if (test_bit(SMP_FLAG_TK_VALID, &smp->smp_flags)) {
queue_work(hdev->workqueue, &smp->confirm); queue_work(hdev->workqueue, &smp->confirm);
} else {
set_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags);
} }
return 0; return 0;
...@@ -550,7 +728,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -550,7 +728,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
BT_DBG("conn %p", conn); BT_DBG("conn %p", conn);
hcon->pending_sec_level = BT_SECURITY_MEDIUM; hcon->pending_sec_level = authreq_to_seclevel(rp->auth_req);
if (smp_ltk_encrypt(conn)) if (smp_ltk_encrypt(conn))
return 0; return 0;
...@@ -577,6 +755,7 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) ...@@ -577,6 +755,7 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
{ {
struct hci_conn *hcon = conn->hcon; struct hci_conn *hcon = conn->hcon;
struct smp_chan *smp = conn->smp_chan; struct smp_chan *smp = conn->smp_chan;
__u8 authreq;
BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level); BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level);
...@@ -597,18 +776,22 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) ...@@ -597,18 +776,22 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
return 0; return 0;
smp = smp_chan_create(conn); smp = smp_chan_create(conn);
if (!smp)
return 1;
authreq = seclevel_to_authreq(sec_level);
if (hcon->link_mode & HCI_LM_MASTER) { if (hcon->link_mode & HCI_LM_MASTER) {
struct smp_cmd_pairing cp; struct smp_cmd_pairing cp;
build_pairing_cmd(conn, &cp, NULL, SMP_AUTH_NONE); build_pairing_cmd(conn, &cp, NULL, authreq);
smp->preq[0] = SMP_CMD_PAIRING_REQ; smp->preq[0] = SMP_CMD_PAIRING_REQ;
memcpy(&smp->preq[1], &cp, sizeof(cp)); memcpy(&smp->preq[1], &cp, sizeof(cp));
smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
} else { } else {
struct smp_cmd_security_req cp; struct smp_cmd_security_req cp;
cp.auth_req = SMP_AUTH_NONE; cp.auth_req = authreq;
smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp); smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp);
} }
...@@ -637,7 +820,7 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -637,7 +820,7 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
skb_pull(skb, sizeof(*rp)); skb_pull(skb, sizeof(*rp));
hci_add_ltk(conn->hcon->hdev, 1, conn->src, smp->smp_key_size, hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->smp_key_size,
rp->ediv, rp->rand, smp->tk); rp->ediv, rp->rand, smp->tk);
smp_distribute_keys(conn, 1); smp_distribute_keys(conn, 1);
...@@ -800,7 +983,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) ...@@ -800,7 +983,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
if (conn->hcon->out || force) { if (conn->hcon->out || force) {
clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend); clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend);
del_timer(&conn->security_timer); cancel_delayed_work_sync(&conn->security_timer);
smp_chan_destroy(conn); smp_chan_destroy(conn);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment