Commit 4b42c542 authored by John W. Linville's avatar John W. Linville

Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/padovan/bluetooth-next-2.6

Conflicts:
	net/bluetooth/l2cap_core.c
parents d8598981 e2fd318e
...@@ -375,6 +375,11 @@ static int ath3k_probe(struct usb_interface *intf, ...@@ -375,6 +375,11 @@ static int ath3k_probe(struct usb_interface *intf,
/* load patch and sysconfig files for AR3012 */ /* load patch and sysconfig files for AR3012 */
if (id->driver_info & BTUSB_ATH3012) { if (id->driver_info & BTUSB_ATH3012) {
/* New firmware with patch and sysconfig files already loaded */
if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x0001)
return -ENODEV;
ret = ath3k_load_patch(udev); ret = ath3k_load_patch(udev);
if (ret < 0) { if (ret < 0) {
BT_ERR("Loading patch file failed"); BT_ERR("Loading patch file failed");
......
...@@ -54,6 +54,7 @@ static struct usb_driver btusb_driver; ...@@ -54,6 +54,7 @@ static struct usb_driver btusb_driver;
#define BTUSB_BCM92035 0x10 #define BTUSB_BCM92035 0x10
#define BTUSB_BROKEN_ISOC 0x20 #define BTUSB_BROKEN_ISOC 0x20
#define BTUSB_WRONG_SCO_MTU 0x40 #define BTUSB_WRONG_SCO_MTU 0x40
#define BTUSB_ATH3012 0x80
static struct usb_device_id btusb_table[] = { static struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */ /* Generic Bluetooth USB device */
...@@ -110,7 +111,7 @@ static struct usb_device_id blacklist_table[] = { ...@@ -110,7 +111,7 @@ static struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
/* Atheros 3012 with sflash firmware */ /* Atheros 3012 with sflash firmware */
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU12 with sflash firmware */ /* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
...@@ -914,6 +915,15 @@ static int btusb_probe(struct usb_interface *intf, ...@@ -914,6 +915,15 @@ static int btusb_probe(struct usb_interface *intf,
if (ignore_sniffer && id->driver_info & BTUSB_SNIFFER) if (ignore_sniffer && id->driver_info & BTUSB_SNIFFER)
return -ENODEV; return -ENODEV;
if (id->driver_info & BTUSB_ATH3012) {
struct usb_device *udev = interface_to_usbdev(intf);
/* Old firmware would otherwise let ath3k driver load
* patch and sysconfig files */
if (le16_to_cpu(udev->descriptor.bcdDevice) <= 0x0001)
return -ENODEV;
}
data = kzalloc(sizeof(*data), GFP_KERNEL); data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data) if (!data)
return -ENOMEM; return -ENOMEM;
......
...@@ -56,6 +56,7 @@ ...@@ -56,6 +56,7 @@
#define BT_SECURITY 4 #define BT_SECURITY 4
struct bt_security { struct bt_security {
__u8 level; __u8 level;
__u8 key_size;
}; };
#define BT_SECURITY_SDP 0 #define BT_SECURITY_SDP 0
#define BT_SECURITY_LOW 1 #define BT_SECURITY_LOW 1
...@@ -76,9 +77,12 @@ struct bt_power { ...@@ -76,9 +77,12 @@ struct bt_power {
#define BT_POWER_FORCE_ACTIVE_OFF 0 #define BT_POWER_FORCE_ACTIVE_OFF 0
#define BT_POWER_FORCE_ACTIVE_ON 1 #define BT_POWER_FORCE_ACTIVE_ON 1
#define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg) __attribute__((format (printf, 2, 3)))
#define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg) int bt_printk(const char *level, const char *fmt, ...);
#define BT_DBG(fmt, arg...) pr_debug("%s: " fmt "\n" , __func__ , ## arg)
#define BT_INFO(fmt, arg...) bt_printk(KERN_INFO, pr_fmt(fmt), ##arg)
#define BT_ERR(fmt, arg...) bt_printk(KERN_ERR, pr_fmt(fmt), ##arg)
#define BT_DBG(fmt, arg...) pr_debug(fmt "\n", ##arg)
/* Connection and socket states */ /* Connection and socket states */
enum { enum {
...@@ -204,7 +208,7 @@ static inline struct sk_buff *bt_skb_send_alloc(struct sock *sk, ...@@ -204,7 +208,7 @@ static inline struct sk_buff *bt_skb_send_alloc(struct sock *sk,
return NULL; return NULL;
} }
int bt_err(__u16 code); int bt_to_errno(__u16 code);
extern int hci_sock_init(void); extern int hci_sock_init(void);
extern void hci_sock_cleanup(void); extern void hci_sock_cleanup(void);
......
...@@ -211,11 +211,16 @@ enum { ...@@ -211,11 +211,16 @@ enum {
#define LMP_EDR_3S_ESCO 0x80 #define LMP_EDR_3S_ESCO 0x80
#define LMP_EXT_INQ 0x01 #define LMP_EXT_INQ 0x01
#define LMP_SIMUL_LE_BR 0x02
#define LMP_SIMPLE_PAIR 0x08 #define LMP_SIMPLE_PAIR 0x08
#define LMP_NO_FLUSH 0x40 #define LMP_NO_FLUSH 0x40
#define LMP_LSTO 0x01 #define LMP_LSTO 0x01
#define LMP_INQ_TX_PWR 0x02 #define LMP_INQ_TX_PWR 0x02
#define LMP_EXTFEATURES 0x80
/* Extended LMP features */
#define LMP_HOST_LE 0x02
/* Connection modes */ /* Connection modes */
#define HCI_CM_ACTIVE 0x0000 #define HCI_CM_ACTIVE 0x0000
...@@ -254,6 +259,10 @@ enum { ...@@ -254,6 +259,10 @@ enum {
#define HCI_LK_UNAUTH_COMBINATION 0x04 #define HCI_LK_UNAUTH_COMBINATION 0x04
#define HCI_LK_AUTH_COMBINATION 0x05 #define HCI_LK_AUTH_COMBINATION 0x05
#define HCI_LK_CHANGED_COMBINATION 0x06 #define HCI_LK_CHANGED_COMBINATION 0x06
/* The spec doesn't define types for SMP keys */
#define HCI_LK_SMP_LTK 0x81
#define HCI_LK_SMP_IRK 0x82
#define HCI_LK_SMP_CSRK 0x83
/* ----- HCI Commands ---- */ /* ----- HCI Commands ---- */
#define HCI_OP_NOP 0x0000 #define HCI_OP_NOP 0x0000
...@@ -653,6 +662,12 @@ struct hci_rp_read_local_oob_data { ...@@ -653,6 +662,12 @@ struct hci_rp_read_local_oob_data {
#define HCI_OP_READ_INQ_RSP_TX_POWER 0x0c58 #define HCI_OP_READ_INQ_RSP_TX_POWER 0x0c58
#define HCI_OP_WRITE_LE_HOST_SUPPORTED 0x0c6d
struct hci_cp_write_le_host_supported {
__u8 le;
__u8 simul;
} __packed;
#define HCI_OP_READ_LOCAL_VERSION 0x1001 #define HCI_OP_READ_LOCAL_VERSION 0x1001
struct hci_rp_read_local_version { struct hci_rp_read_local_version {
__u8 status; __u8 status;
...@@ -676,6 +691,9 @@ struct hci_rp_read_local_features { ...@@ -676,6 +691,9 @@ struct hci_rp_read_local_features {
} __packed; } __packed;
#define HCI_OP_READ_LOCAL_EXT_FEATURES 0x1004 #define HCI_OP_READ_LOCAL_EXT_FEATURES 0x1004
struct hci_cp_read_local_ext_features {
__u8 page;
} __packed;
struct hci_rp_read_local_ext_features { struct hci_rp_read_local_ext_features {
__u8 status; __u8 status;
__u8 page; __u8 page;
......
...@@ -74,12 +74,28 @@ struct bt_uuid { ...@@ -74,12 +74,28 @@ struct bt_uuid {
u8 svc_hint; u8 svc_hint;
}; };
struct key_master_id {
__le16 ediv;
u8 rand[8];
} __packed;
struct link_key_data {
bdaddr_t bdaddr;
u8 type;
u8 val[16];
u8 pin_len;
u8 dlen;
u8 data[0];
} __packed;
struct link_key { struct link_key {
struct list_head list; struct list_head list;
bdaddr_t bdaddr; bdaddr_t bdaddr;
u8 type; u8 type;
u8 val[16]; u8 val[16];
u8 pin_len; u8 pin_len;
u8 dlen;
u8 data[0];
}; };
struct oob_data { struct oob_data {
...@@ -113,6 +129,7 @@ struct hci_dev { ...@@ -113,6 +129,7 @@ struct hci_dev {
__u8 major_class; __u8 major_class;
__u8 minor_class; __u8 minor_class;
__u8 features[8]; __u8 features[8];
__u8 extfeatures[8];
__u8 commands[64]; __u8 commands[64];
__u8 ssp_mode; __u8 ssp_mode;
__u8 hci_ver; __u8 hci_ver;
...@@ -223,7 +240,6 @@ struct hci_conn { ...@@ -223,7 +240,6 @@ struct hci_conn {
struct list_head list; struct list_head list;
atomic_t refcnt; atomic_t refcnt;
spinlock_t lock;
bdaddr_t dst; bdaddr_t dst;
__u8 dst_type; __u8 dst_type;
...@@ -245,11 +261,11 @@ struct hci_conn { ...@@ -245,11 +261,11 @@ struct hci_conn {
__u8 sec_level; __u8 sec_level;
__u8 pending_sec_level; __u8 pending_sec_level;
__u8 pin_length; __u8 pin_length;
__u8 enc_key_size;
__u8 io_capability; __u8 io_capability;
__u8 power_save; __u8 power_save;
__u16 disc_timeout; __u16 disc_timeout;
unsigned long pend; unsigned long pend;
__u8 ltk[16];
__u8 remote_cap; __u8 remote_cap;
__u8 remote_oob; __u8 remote_oob;
...@@ -272,7 +288,6 @@ struct hci_conn { ...@@ -272,7 +288,6 @@ struct hci_conn {
struct hci_dev *hdev; struct hci_dev *hdev;
void *l2cap_data; void *l2cap_data;
void *sco_data; void *sco_data;
void *priv;
struct hci_conn *link; struct hci_conn *link;
...@@ -538,6 +553,11 @@ int hci_link_keys_clear(struct hci_dev *hdev); ...@@ -538,6 +553,11 @@ int hci_link_keys_clear(struct hci_dev *hdev);
struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len); bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len);
struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]);
struct link_key *hci_find_link_key_type(struct hci_dev *hdev,
bdaddr_t *bdaddr, u8 type);
int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
u8 key_size, __le16 ediv, u8 rand[8], u8 ltk[16]);
int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
int hci_remote_oob_data_clear(struct hci_dev *hdev); int hci_remote_oob_data_clear(struct hci_dev *hdev);
...@@ -579,6 +599,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn); ...@@ -579,6 +599,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define lmp_no_flush_capable(dev) ((dev)->features[6] & LMP_NO_FLUSH) #define lmp_no_flush_capable(dev) ((dev)->features[6] & LMP_NO_FLUSH)
#define lmp_le_capable(dev) ((dev)->features[4] & LMP_LE) #define lmp_le_capable(dev) ((dev)->features[4] & LMP_LE)
/* ----- Extended LMP capabilities ----- */
#define lmp_host_le_capable(dev) ((dev)->extfeatures[0] & LMP_HOST_LE)
/* ----- HCI protocols ----- */ /* ----- HCI protocols ----- */
struct hci_proto { struct hci_proto {
char *name; char *name;
......
...@@ -37,7 +37,6 @@ ...@@ -37,7 +37,6 @@
#define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */ #define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */
#define L2CAP_DEFAULT_MAX_PDU_SIZE 1009 /* Sized for 3-DH5 packet */ #define L2CAP_DEFAULT_MAX_PDU_SIZE 1009 /* Sized for 3-DH5 packet */
#define L2CAP_DEFAULT_ACK_TO 200 #define L2CAP_DEFAULT_ACK_TO 200
#define L2CAP_LOCAL_BUSY_TRIES 12
#define L2CAP_LE_DEFAULT_MTU 23 #define L2CAP_LE_DEFAULT_MTU 23
#define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */ #define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */
...@@ -130,6 +129,12 @@ struct l2cap_conninfo { ...@@ -130,6 +129,12 @@ struct l2cap_conninfo {
#define L2CAP_SDU_END 0x8000 #define L2CAP_SDU_END 0x8000
#define L2CAP_SDU_CONTINUE 0xC000 #define L2CAP_SDU_CONTINUE 0xC000
/* L2CAP Command rej. reasons */
#define L2CAP_REJ_NOT_UNDERSTOOD 0x0000
#define L2CAP_REJ_MTU_EXCEEDED 0x0001
#define L2CAP_REJ_INVALID_CID 0x0002
/* L2CAP structures */ /* L2CAP structures */
struct l2cap_hdr { struct l2cap_hdr {
__le16 len; __le16 len;
...@@ -144,8 +149,19 @@ struct l2cap_cmd_hdr { ...@@ -144,8 +149,19 @@ struct l2cap_cmd_hdr {
} __packed; } __packed;
#define L2CAP_CMD_HDR_SIZE 4 #define L2CAP_CMD_HDR_SIZE 4
struct l2cap_cmd_rej { struct l2cap_cmd_rej_unk {
__le16 reason;
} __packed;
struct l2cap_cmd_rej_mtu {
__le16 reason; __le16 reason;
__le16 max_mtu;
} __packed;
struct l2cap_cmd_rej_cid {
__le16 reason;
__le16 scid;
__le16 dcid;
} __packed; } __packed;
struct l2cap_conn_req { struct l2cap_conn_req {
...@@ -352,8 +368,6 @@ struct l2cap_chan { ...@@ -352,8 +368,6 @@ struct l2cap_chan {
struct sk_buff *tx_send_head; struct sk_buff *tx_send_head;
struct sk_buff_head tx_q; struct sk_buff_head tx_q;
struct sk_buff_head srej_q; struct sk_buff_head srej_q;
struct sk_buff_head busy_q;
struct work_struct busy_work;
struct list_head srej_l; struct list_head srej_l;
struct list_head list; struct list_head list;
...@@ -422,6 +436,7 @@ struct l2cap_conn { ...@@ -422,6 +436,7 @@ struct l2cap_conn {
struct l2cap_pinfo { struct l2cap_pinfo {
struct bt_sock bt; struct bt_sock bt;
struct l2cap_chan *chan; struct l2cap_chan *chan;
struct sk_buff *rx_busy_skb;
}; };
enum { enum {
...@@ -449,7 +464,6 @@ enum { ...@@ -449,7 +464,6 @@ enum {
CONN_REJ_ACT, CONN_REJ_ACT,
CONN_SEND_FBIT, CONN_SEND_FBIT,
CONN_RNR_SENT, CONN_RNR_SENT,
CONN_SAR_RETRY,
}; };
#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))
...@@ -498,5 +512,6 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason); ...@@ -498,5 +512,6 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason);
void l2cap_chan_destroy(struct l2cap_chan *chan); void l2cap_chan_destroy(struct l2cap_chan *chan);
int l2cap_chan_connect(struct l2cap_chan *chan); int l2cap_chan_connect(struct l2cap_chan *chan);
int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len); int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len);
void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
#endif /* __L2CAP_H */ #endif /* __L2CAP_H */
...@@ -101,6 +101,8 @@ struct mgmt_key_info { ...@@ -101,6 +101,8 @@ struct mgmt_key_info {
u8 type; u8 type;
u8 val[16]; u8 val[16];
u8 pin_len; u8 pin_len;
u8 dlen;
u8 data[0];
} __packed; } __packed;
#define MGMT_OP_LOAD_KEYS 0x000D #define MGMT_OP_LOAD_KEYS 0x000D
......
...@@ -118,5 +118,6 @@ struct smp_cmd_security_req { ...@@ -118,5 +118,6 @@ struct smp_cmd_security_req {
/* SMP Commands */ /* SMP Commands */
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);
#endif /* __SMP_H */ #endif /* __SMP_H */
...@@ -60,8 +60,6 @@ static void hci_tx_task(unsigned long arg); ...@@ -60,8 +60,6 @@ static void hci_tx_task(unsigned long arg);
static DEFINE_RWLOCK(hci_task_lock); static DEFINE_RWLOCK(hci_task_lock);
static int enable_smp;
/* 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);
...@@ -148,7 +146,7 @@ static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, ...@@ -148,7 +146,7 @@ static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev,
switch (hdev->req_status) { switch (hdev->req_status) {
case HCI_REQ_DONE: case HCI_REQ_DONE:
err = -bt_err(hdev->req_result); err = -bt_to_errno(hdev->req_result);
break; break;
case HCI_REQ_CANCELED: case HCI_REQ_CANCELED:
...@@ -542,7 +540,7 @@ int hci_dev_open(__u16 dev) ...@@ -542,7 +540,7 @@ int hci_dev_open(__u16 dev)
ret = __hci_request(hdev, hci_init_req, 0, ret = __hci_request(hdev, hci_init_req, 0,
msecs_to_jiffies(HCI_INIT_TIMEOUT)); msecs_to_jiffies(HCI_INIT_TIMEOUT));
if (lmp_le_capable(hdev)) if (lmp_host_le_capable(hdev))
ret = __hci_request(hdev, hci_le_init_req, 0, ret = __hci_request(hdev, hci_le_init_req, 0,
msecs_to_jiffies(HCI_INIT_TIMEOUT)); msecs_to_jiffies(HCI_INIT_TIMEOUT));
...@@ -1059,6 +1057,42 @@ static int hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn, ...@@ -1059,6 +1057,42 @@ static int hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn,
return 0; return 0;
} }
struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8])
{
struct link_key *k;
list_for_each_entry(k, &hdev->link_keys, list) {
struct key_master_id *id;
if (k->type != HCI_LK_SMP_LTK)
continue;
if (k->dlen != sizeof(*id))
continue;
id = (void *) &k->data;
if (id->ediv == ediv &&
(memcmp(rand, id->rand, sizeof(id->rand)) == 0))
return k;
}
return NULL;
}
EXPORT_SYMBOL(hci_find_ltk);
struct link_key *hci_find_link_key_type(struct hci_dev *hdev,
bdaddr_t *bdaddr, u8 type)
{
struct link_key *k;
list_for_each_entry(k, &hdev->link_keys, list)
if (k->type == type && bacmp(bdaddr, &k->bdaddr) == 0)
return k;
return NULL;
}
EXPORT_SYMBOL(hci_find_link_key_type);
int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len) bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len)
{ {
...@@ -1114,6 +1148,44 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, ...@@ -1114,6 +1148,44 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
return 0; return 0;
} }
int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
u8 key_size, __le16 ediv, u8 rand[8], u8 ltk[16])
{
struct link_key *key, *old_key;
struct key_master_id *id;
u8 old_key_type;
BT_DBG("%s addr %s", hdev->name, batostr(bdaddr));
old_key = hci_find_link_key_type(hdev, bdaddr, HCI_LK_SMP_LTK);
if (old_key) {
key = old_key;
old_key_type = old_key->type;
} else {
key = kzalloc(sizeof(*key) + sizeof(*id), GFP_ATOMIC);
if (!key)
return -ENOMEM;
list_add(&key->list, &hdev->link_keys);
old_key_type = 0xff;
}
key->dlen = sizeof(*id);
bacpy(&key->bdaddr, bdaddr);
memcpy(key->val, ltk, sizeof(key->val));
key->type = HCI_LK_SMP_LTK;
key->pin_len = key_size;
id = (void *) &key->data;
id->ediv = ediv;
memcpy(id->rand, rand, sizeof(id->rand));
if (new_key)
mgmt_new_key(hdev->id, key, old_key_type);
return 0;
}
int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
{ {
struct link_key *key; struct link_key *key;
...@@ -1246,7 +1318,7 @@ int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr) ...@@ -1246,7 +1318,7 @@ int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr)
if (bacmp(bdaddr, BDADDR_ANY) == 0) if (bacmp(bdaddr, BDADDR_ANY) == 0)
return -EBADF; return -EBADF;
hci_dev_lock(hdev); hci_dev_lock_bh(hdev);
if (hci_blacklist_lookup(hdev, bdaddr)) { if (hci_blacklist_lookup(hdev, bdaddr)) {
err = -EEXIST; err = -EEXIST;
...@@ -1266,7 +1338,7 @@ int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr) ...@@ -1266,7 +1338,7 @@ int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr)
err = 0; err = 0;
err: err:
hci_dev_unlock(hdev); hci_dev_unlock_bh(hdev);
return err; return err;
} }
...@@ -1275,7 +1347,7 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr) ...@@ -1275,7 +1347,7 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
struct bdaddr_list *entry; struct bdaddr_list *entry;
int err = 0; int err = 0;
hci_dev_lock(hdev); hci_dev_lock_bh(hdev);
if (bacmp(bdaddr, BDADDR_ANY) == 0) { if (bacmp(bdaddr, BDADDR_ANY) == 0) {
hci_blacklist_clear(hdev); hci_blacklist_clear(hdev);
...@@ -1292,7 +1364,7 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr) ...@@ -1292,7 +1364,7 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
kfree(entry); kfree(entry);
done: done:
hci_dev_unlock(hdev); hci_dev_unlock_bh(hdev);
return err; return err;
} }
...@@ -1368,14 +1440,6 @@ int hci_add_adv_entry(struct hci_dev *hdev, ...@@ -1368,14 +1440,6 @@ int hci_add_adv_entry(struct hci_dev *hdev,
return 0; return 0;
} }
static struct crypto_blkcipher *alloc_cypher(void)
{
if (enable_smp)
return crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
return ERR_PTR(-ENOTSUPP);
}
/* Register HCI device */ /* Register HCI device */
int hci_register_dev(struct hci_dev *hdev) int hci_register_dev(struct hci_dev *hdev)
{ {
...@@ -1460,7 +1524,7 @@ int hci_register_dev(struct hci_dev *hdev) ...@@ -1460,7 +1524,7 @@ int hci_register_dev(struct hci_dev *hdev)
if (!hdev->workqueue) if (!hdev->workqueue)
goto nomem; goto nomem;
hdev->tfm = alloc_cypher(); hdev->tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(hdev->tfm)) if (IS_ERR(hdev->tfm))
BT_INFO("Failed to load transform for ecb(aes): %ld", BT_INFO("Failed to load transform for ecb(aes): %ld",
PTR_ERR(hdev->tfm)); PTR_ERR(hdev->tfm));
...@@ -2352,6 +2416,3 @@ static void hci_cmd_task(unsigned long arg) ...@@ -2352,6 +2416,3 @@ static void hci_cmd_task(unsigned long arg)
} }
} }
} }
module_param(enable_smp, bool, 0644);
MODULE_PARM_DESC(enable_smp, "Enable SMP support (LE only)");
...@@ -45,6 +45,8 @@ ...@@ -45,6 +45,8 @@
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h> #include <net/bluetooth/hci_core.h>
static int enable_le;
/* Handle HCI Event packets */ /* Handle HCI Event packets */
static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb) static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
...@@ -525,6 +527,20 @@ static void hci_setup_event_mask(struct hci_dev *hdev) ...@@ -525,6 +527,20 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events); hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
} }
static void hci_set_le_support(struct hci_dev *hdev)
{
struct hci_cp_write_le_host_supported cp;
memset(&cp, 0, sizeof(cp));
if (enable_le) {
cp.le = 1;
cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
}
hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp), &cp);
}
static void hci_setup(struct hci_dev *hdev) static void hci_setup(struct hci_dev *hdev)
{ {
hci_setup_event_mask(hdev); hci_setup_event_mask(hdev);
...@@ -542,6 +558,17 @@ static void hci_setup(struct hci_dev *hdev) ...@@ -542,6 +558,17 @@ static void hci_setup(struct hci_dev *hdev)
if (hdev->features[7] & LMP_INQ_TX_PWR) if (hdev->features[7] & LMP_INQ_TX_PWR)
hci_send_cmd(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, 0, NULL); hci_send_cmd(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, 0, NULL);
if (hdev->features[7] & LMP_EXTFEATURES) {
struct hci_cp_read_local_ext_features cp;
cp.page = 0x01;
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES,
sizeof(cp), &cp);
}
if (hdev->features[4] & LMP_LE)
hci_set_le_support(hdev);
} }
static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb) static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
...@@ -658,6 +685,21 @@ static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb ...@@ -658,6 +685,21 @@ static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb
hdev->features[6], hdev->features[7]); hdev->features[6], hdev->features[7]);
} }
static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_rp_read_local_ext_features *rp = (void *) skb->data;
BT_DBG("%s status 0x%x", hdev->name, rp->status);
if (rp->status)
return;
memcpy(hdev->extfeatures, rp->features, 8);
hci_req_complete(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, rp->status);
}
static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb) static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
{ {
struct hci_rp_read_buffer_size *rp = (void *) skb->data; struct hci_rp_read_buffer_size *rp = (void *) skb->data;
...@@ -892,6 +934,21 @@ static void hci_cc_le_ltk_neg_reply(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -892,6 +934,21 @@ static void hci_cc_le_ltk_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
hci_req_complete(hdev, HCI_OP_LE_LTK_NEG_REPLY, rp->status); hci_req_complete(hdev, HCI_OP_LE_LTK_NEG_REPLY, rp->status);
} }
static inline void hci_cc_write_le_host_supported(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_cp_read_local_ext_features cp;
__u8 status = *((__u8 *) skb->data);
BT_DBG("%s status 0x%x", hdev->name, status);
if (status)
return;
cp.page = 0x01;
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, sizeof(cp), &cp);
}
static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
{ {
BT_DBG("%s status 0x%x", hdev->name, status); BT_DBG("%s status 0x%x", hdev->name, status);
...@@ -1826,6 +1883,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk ...@@ -1826,6 +1883,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_cc_read_local_features(hdev, skb); hci_cc_read_local_features(hdev, skb);
break; break;
case HCI_OP_READ_LOCAL_EXT_FEATURES:
hci_cc_read_local_ext_features(hdev, skb);
break;
case HCI_OP_READ_BUFFER_SIZE: case HCI_OP_READ_BUFFER_SIZE:
hci_cc_read_buffer_size(hdev, skb); hci_cc_read_buffer_size(hdev, skb);
break; break;
...@@ -1894,6 +1955,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk ...@@ -1894,6 +1955,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_cc_le_ltk_neg_reply(hdev, skb); hci_cc_le_ltk_neg_reply(hdev, skb);
break; break;
case HCI_OP_WRITE_LE_HOST_SUPPORTED:
hci_cc_write_le_host_supported(hdev, skb);
break;
default: default:
BT_DBG("%s opcode 0x%x", hdev->name, opcode); BT_DBG("%s opcode 0x%x", hdev->name, opcode);
break; break;
...@@ -2793,21 +2858,36 @@ static inline void hci_le_ltk_request_evt(struct hci_dev *hdev, ...@@ -2793,21 +2858,36 @@ static inline void hci_le_ltk_request_evt(struct hci_dev *hdev,
{ {
struct hci_ev_le_ltk_req *ev = (void *) skb->data; struct hci_ev_le_ltk_req *ev = (void *) skb->data;
struct hci_cp_le_ltk_reply cp; struct hci_cp_le_ltk_reply cp;
struct hci_cp_le_ltk_neg_reply neg;
struct hci_conn *conn; struct hci_conn *conn;
struct link_key *ltk;
BT_DBG("%s handle %d", hdev->name, cpu_to_le16(ev->handle)); BT_DBG("%s handle %d", hdev->name, cpu_to_le16(ev->handle));
hci_dev_lock(hdev); hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
if (conn == NULL)
goto not_found;
memset(&cp, 0, sizeof(cp)); ltk = hci_find_ltk(hdev, ev->ediv, ev->random);
if (ltk == NULL)
goto not_found;
memcpy(cp.ltk, ltk->val, sizeof(ltk->val));
cp.handle = cpu_to_le16(conn->handle); cp.handle = cpu_to_le16(conn->handle);
memcpy(cp.ltk, conn->ltk, sizeof(conn->ltk)); conn->pin_length = ltk->pin_len;
hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp); hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp);
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
return;
not_found:
neg.handle = ev->handle;
hci_send_cmd(hdev, HCI_OP_LE_LTK_NEG_REPLY, sizeof(neg), &neg);
hci_dev_unlock(hdev);
} }
static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb) static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
...@@ -3022,3 +3102,6 @@ void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data) ...@@ -3022,3 +3102,6 @@ void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
hci_send_to_sock(hdev, skb, NULL); hci_send_to_sock(hdev, skb, NULL);
kfree_skb(skb); kfree_skb(skb);
} }
module_param(enable_le, bool, 0444);
MODULE_PARM_DESC(enable_le, "Enable LE support");
This diff is collapsed.
...@@ -422,8 +422,12 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch ...@@ -422,8 +422,12 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
break; break;
} }
memset(&sec, 0, sizeof(sec));
sec.level = chan->sec_level; sec.level = chan->sec_level;
if (sk->sk_state == BT_CONNECTED)
sec.key_size = chan->conn->hcon->enc_key_size;
len = min_t(unsigned int, len, sizeof(sec)); len = min_t(unsigned int, len, sizeof(sec));
if (copy_to_user(optval, (char *) &sec, len)) if (copy_to_user(optval, (char *) &sec, len))
err = -EFAULT; err = -EFAULT;
...@@ -711,13 +715,15 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms ...@@ -711,13 +715,15 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags) static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct l2cap_pinfo *pi = l2cap_pi(sk);
int err;
lock_sock(sk); lock_sock(sk);
if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) { if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) {
sk->sk_state = BT_CONFIG; sk->sk_state = BT_CONFIG;
__l2cap_connect_rsp_defer(l2cap_pi(sk)->chan); __l2cap_connect_rsp_defer(pi->chan);
release_sock(sk); release_sock(sk);
return 0; return 0;
} }
...@@ -725,9 +731,37 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms ...@@ -725,9 +731,37 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms
release_sock(sk); release_sock(sk);
if (sock->type == SOCK_STREAM) if (sock->type == SOCK_STREAM)
return bt_sock_stream_recvmsg(iocb, sock, msg, len, flags); err = bt_sock_stream_recvmsg(iocb, sock, msg, len, flags);
else
err = bt_sock_recvmsg(iocb, sock, msg, len, flags);
if (pi->chan->mode != L2CAP_MODE_ERTM)
return err;
/* Attempt to put pending rx data in the socket buffer */
lock_sock(sk);
if (!test_bit(CONN_LOCAL_BUSY, &pi->chan->conn_state))
goto done;
if (pi->rx_busy_skb) {
if (!sock_queue_rcv_skb(sk, pi->rx_busy_skb))
pi->rx_busy_skb = NULL;
else
goto done;
}
return bt_sock_recvmsg(iocb, sock, msg, len, flags); /* Restore data flow when half of the receive buffer is
* available. This avoids resending large numbers of
* frames.
*/
if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf >> 1)
l2cap_chan_busy(pi->chan, 0);
done:
release_sock(sk);
return err;
} }
/* Kill socket (only if zapped and orphan) /* Kill socket (only if zapped and orphan)
...@@ -811,9 +845,31 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(void *data) ...@@ -811,9 +845,31 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(void *data)
static int l2cap_sock_recv_cb(void *data, struct sk_buff *skb) static int l2cap_sock_recv_cb(void *data, struct sk_buff *skb)
{ {
int err;
struct sock *sk = data; struct sock *sk = data;
struct l2cap_pinfo *pi = l2cap_pi(sk);
return sock_queue_rcv_skb(sk, skb); if (pi->rx_busy_skb)
return -ENOMEM;
err = sock_queue_rcv_skb(sk, skb);
/* For ERTM, handle one skb that doesn't fit into the recv
* buffer. This is important to do because the data frames
* have already been acked, so the skb cannot be discarded.
*
* Notify the l2cap core that the buffer is full, so the
* LOCAL_BUSY state is entered and no more frames are
* acked and reassembled until there is buffer space
* available.
*/
if (err < 0 && pi->chan->mode == L2CAP_MODE_ERTM) {
pi->rx_busy_skb = skb;
l2cap_chan_busy(pi->chan, 1);
err = 0;
}
return err;
} }
static void l2cap_sock_close_cb(void *data) static void l2cap_sock_close_cb(void *data)
...@@ -842,6 +898,11 @@ static void l2cap_sock_destruct(struct sock *sk) ...@@ -842,6 +898,11 @@ static void l2cap_sock_destruct(struct sock *sk)
{ {
BT_DBG("sk %p", sk); BT_DBG("sk %p", sk);
if (l2cap_pi(sk)->rx_busy_skb) {
kfree_skb(l2cap_pi(sk)->rx_busy_skb);
l2cap_pi(sk)->rx_busy_skb = NULL;
}
skb_queue_purge(&sk->sk_receive_queue); skb_queue_purge(&sk->sk_receive_queue);
skb_queue_purge(&sk->sk_write_queue); skb_queue_purge(&sk->sk_write_queue);
} }
......
...@@ -59,7 +59,7 @@ char *batostr(bdaddr_t *ba) ...@@ -59,7 +59,7 @@ char *batostr(bdaddr_t *ba)
EXPORT_SYMBOL(batostr); EXPORT_SYMBOL(batostr);
/* Bluetooth error codes to Unix errno mapping */ /* Bluetooth error codes to Unix errno mapping */
int bt_err(__u16 code) int bt_to_errno(__u16 code)
{ {
switch (code) { switch (code) {
case 0: case 0:
...@@ -149,4 +149,23 @@ int bt_err(__u16 code) ...@@ -149,4 +149,23 @@ int bt_err(__u16 code)
return ENOSYS; return ENOSYS;
} }
} }
EXPORT_SYMBOL(bt_err); EXPORT_SYMBOL(bt_to_errno);
int bt_printk(const char *level, const char *format, ...)
{
struct va_format vaf;
va_list args;
int r;
va_start(args, format);
vaf.fmt = format;
vaf.va = &args;
r = printk("%sBluetooth: %pV\n", level, &vaf);
va_end(args);
return r;
}
EXPORT_SYMBOL(bt_printk);
This diff is collapsed.
...@@ -932,7 +932,7 @@ static int sco_connect_cfm(struct hci_conn *hcon, __u8 status) ...@@ -932,7 +932,7 @@ static int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
if (conn) if (conn)
sco_conn_ready(conn); sco_conn_ready(conn);
} else } else
sco_conn_del(hcon, bt_err(status)); sco_conn_del(hcon, bt_to_errno(status));
return 0; return 0;
} }
...@@ -944,7 +944,7 @@ static int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason) ...@@ -944,7 +944,7 @@ static int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK) if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
return -EINVAL; return -EINVAL;
sco_conn_del(hcon, bt_err(reason)); sco_conn_del(hcon, bt_to_errno(reason));
return 0; return 0;
} }
......
...@@ -197,14 +197,34 @@ static __u8 seclevel_to_authreq(__u8 level) ...@@ -197,14 +197,34 @@ static __u8 seclevel_to_authreq(__u8 level)
} }
static void build_pairing_cmd(struct l2cap_conn *conn, static void build_pairing_cmd(struct l2cap_conn *conn,
struct smp_cmd_pairing *cmd, __u8 authreq) struct smp_cmd_pairing *req,
struct smp_cmd_pairing *rsp,
__u8 authreq)
{ {
cmd->io_capability = conn->hcon->io_capability; u8 dist_keys;
cmd->oob_flag = SMP_OOB_NOT_PRESENT;
cmd->max_key_size = SMP_MAX_ENC_KEY_SIZE; dist_keys = 0;
cmd->init_key_dist = 0x00; if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->flags)) {
cmd->resp_key_dist = 0x00; dist_keys = SMP_DIST_ENC_KEY | SMP_DIST_ID_KEY | SMP_DIST_SIGN;
cmd->auth_req = authreq; authreq |= SMP_AUTH_BONDING;
}
if (rsp == NULL) {
req->io_capability = conn->hcon->io_capability;
req->oob_flag = SMP_OOB_NOT_PRESENT;
req->max_key_size = SMP_MAX_ENC_KEY_SIZE;
req->init_key_dist = dist_keys;
req->resp_key_dist = dist_keys;
req->auth_req = authreq;
return;
}
rsp->io_capability = conn->hcon->io_capability;
rsp->oob_flag = SMP_OOB_NOT_PRESENT;
rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
rsp->init_key_dist = req->init_key_dist & dist_keys;
rsp->resp_key_dist = req->resp_key_dist & dist_keys;
rsp->auth_req = authreq;
} }
static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size) static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
...@@ -233,7 +253,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -233,7 +253,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
return SMP_OOB_NOT_AVAIL; return SMP_OOB_NOT_AVAIL;
/* We didn't start the pairing, so no requirements */ /* We didn't start the pairing, so no requirements */
build_pairing_cmd(conn, &rsp, SMP_AUTH_NONE); 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))
...@@ -347,8 +367,6 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -347,8 +367,6 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
swap128(skb->data, random); swap128(skb->data, random);
skb_pull(skb, sizeof(random)); skb_pull(skb, sizeof(random));
memset(hcon->ltk, 0, sizeof(hcon->ltk));
if (conn->hcon->out) if (conn->hcon->out)
ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp, 0, ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp, 0,
conn->src, conn->hcon->dst_type, conn->dst, conn->src, conn->hcon->dst_type, conn->dst,
...@@ -370,29 +388,38 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -370,29 +388,38 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
} }
if (conn->hcon->out) { if (conn->hcon->out) {
u8 stk[16], rand[8];
__le16 ediv; __le16 ediv;
u8 rand[8];
memset(rand, 0, sizeof(rand));
ediv = 0;
smp_s1(tfm, conn->tk, random, conn->prnd, key); smp_s1(tfm, conn->tk, random, conn->prnd, key);
swap128(key, hcon->ltk); swap128(key, stk);
memset(hcon->ltk + conn->smp_key_size, 0, memset(stk + conn->smp_key_size, 0,
SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size); SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size);
hci_le_start_enc(hcon, ediv, rand, stk);
hcon->enc_key_size = conn->smp_key_size;
} else {
u8 stk[16], r[16], rand[8];
__le16 ediv;
memset(rand, 0, sizeof(rand)); memset(rand, 0, sizeof(rand));
ediv = 0; ediv = 0;
hci_le_start_enc(hcon, ediv, rand, hcon->ltk);
} else {
u8 r[16];
swap128(conn->prnd, r); swap128(conn->prnd, r);
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r); smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r);
smp_s1(tfm, conn->tk, conn->prnd, random, key); smp_s1(tfm, conn->tk, conn->prnd, random, key);
swap128(key, hcon->ltk); swap128(key, stk);
memset(hcon->ltk + conn->smp_key_size, 0, memset(stk + conn->smp_key_size, 0,
SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size); SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size);
hci_add_ltk(conn->hcon->hdev, 0, conn->dst, conn->smp_key_size,
ediv, rand, stk);
} }
return 0; return 0;
...@@ -412,7 +439,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -412,7 +439,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
skb_pull(skb, sizeof(*rp)); skb_pull(skb, sizeof(*rp));
memset(&cp, 0, sizeof(cp)); memset(&cp, 0, sizeof(cp));
build_pairing_cmd(conn, &cp, rp->auth_req); build_pairing_cmd(conn, &cp, NULL, rp->auth_req);
conn->preq[0] = SMP_CMD_PAIRING_REQ; conn->preq[0] = SMP_CMD_PAIRING_REQ;
memcpy(&conn->preq[1], &cp, sizeof(cp)); memcpy(&conn->preq[1], &cp, sizeof(cp));
...@@ -434,6 +461,9 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) ...@@ -434,6 +461,9 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
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);
if (!lmp_host_le_capable(hcon->hdev))
return 1;
if (IS_ERR(hcon->hdev->tfm)) if (IS_ERR(hcon->hdev->tfm))
return 1; return 1;
...@@ -450,8 +480,21 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) ...@@ -450,8 +480,21 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 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;
struct link_key *key;
build_pairing_cmd(conn, &cp, authreq); key = hci_find_link_key_type(hcon->hdev, conn->dst,
HCI_LK_SMP_LTK);
if (key) {
struct key_master_id *master = (void *) key->data;
hci_le_start_enc(hcon, master->ediv, master->rand,
key->val);
hcon->enc_key_size = key->pin_len;
goto done;
}
build_pairing_cmd(conn, &cp, NULL, authreq);
conn->preq[0] = SMP_CMD_PAIRING_REQ; conn->preq[0] = SMP_CMD_PAIRING_REQ;
memcpy(&conn->preq[1], &cp, sizeof(cp)); memcpy(&conn->preq[1], &cp, sizeof(cp));
...@@ -465,18 +508,50 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) ...@@ -465,18 +508,50 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp); smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp);
} }
done:
hcon->pending_sec_level = sec_level; hcon->pending_sec_level = sec_level;
set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
return 0; return 0;
} }
static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct smp_cmd_encrypt_info *rp = (void *) skb->data;
skb_pull(skb, sizeof(*rp));
memcpy(conn->tk, rp->ltk, sizeof(conn->tk));
return 0;
}
static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct smp_cmd_master_ident *rp = (void *) skb->data;
skb_pull(skb, sizeof(*rp));
hci_add_ltk(conn->hcon->hdev, 1, conn->src, conn->smp_key_size,
rp->ediv, rp->rand, conn->tk);
smp_distribute_keys(conn, 1);
return 0;
}
int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
{ {
__u8 code = skb->data[0]; __u8 code = skb->data[0];
__u8 reason; __u8 reason;
int err = 0; int err = 0;
if (!lmp_host_le_capable(conn->hcon->hdev)) {
err = -ENOTSUPP;
reason = SMP_PAIRING_NOTSUPP;
goto done;
}
if (IS_ERR(conn->hcon->hdev->tfm)) { if (IS_ERR(conn->hcon->hdev->tfm)) {
err = PTR_ERR(conn->hcon->hdev->tfm); err = PTR_ERR(conn->hcon->hdev->tfm);
reason = SMP_PAIRING_NOTSUPP; reason = SMP_PAIRING_NOTSUPP;
...@@ -512,10 +587,20 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -512,10 +587,20 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
break; break;
case SMP_CMD_ENCRYPT_INFO: case SMP_CMD_ENCRYPT_INFO:
reason = smp_cmd_encrypt_info(conn, skb);
break;
case SMP_CMD_MASTER_IDENT: case SMP_CMD_MASTER_IDENT:
reason = smp_cmd_master_ident(conn, skb);
break;
case SMP_CMD_IDENT_INFO: case SMP_CMD_IDENT_INFO:
case SMP_CMD_IDENT_ADDR_INFO: case SMP_CMD_IDENT_ADDR_INFO:
case SMP_CMD_SIGN_INFO: case SMP_CMD_SIGN_INFO:
/* Just ignored */
reason = 0;
break;
default: default:
BT_DBG("Unknown command code 0x%2.2x", code); BT_DBG("Unknown command code 0x%2.2x", code);
...@@ -532,3 +617,86 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -532,3 +617,86 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
kfree_skb(skb); kfree_skb(skb);
return err; return err;
} }
int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
{
struct smp_cmd_pairing *req, *rsp;
__u8 *keydist;
BT_DBG("conn %p force %d", conn, force);
if (IS_ERR(conn->hcon->hdev->tfm))
return PTR_ERR(conn->hcon->hdev->tfm);
rsp = (void *) &conn->prsp[1];
/* The responder sends its keys first */
if (!force && conn->hcon->out && (rsp->resp_key_dist & 0x07))
return 0;
req = (void *) &conn->preq[1];
if (conn->hcon->out) {
keydist = &rsp->init_key_dist;
*keydist &= req->init_key_dist;
} else {
keydist = &rsp->resp_key_dist;
*keydist &= req->resp_key_dist;
}
BT_DBG("keydist 0x%x", *keydist);
if (*keydist & SMP_DIST_ENC_KEY) {
struct smp_cmd_encrypt_info enc;
struct smp_cmd_master_ident ident;
__le16 ediv;
get_random_bytes(enc.ltk, sizeof(enc.ltk));
get_random_bytes(&ediv, sizeof(ediv));
get_random_bytes(ident.rand, sizeof(ident.rand));
smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc);
hci_add_ltk(conn->hcon->hdev, 1, conn->dst, conn->smp_key_size,
ediv, ident.rand, enc.ltk);
ident.ediv = cpu_to_le16(ediv);
smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident);
*keydist &= ~SMP_DIST_ENC_KEY;
}
if (*keydist & SMP_DIST_ID_KEY) {
struct smp_cmd_ident_addr_info addrinfo;
struct smp_cmd_ident_info idinfo;
/* Send a dummy key */
get_random_bytes(idinfo.irk, sizeof(idinfo.irk));
smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo);
/* Just public address */
memset(&addrinfo, 0, sizeof(addrinfo));
bacpy(&addrinfo.bdaddr, conn->src);
smp_send_cmd(conn, SMP_CMD_IDENT_ADDR_INFO, sizeof(addrinfo),
&addrinfo);
*keydist &= ~SMP_DIST_ID_KEY;
}
if (*keydist & SMP_DIST_SIGN) {
struct smp_cmd_sign_info sign;
/* Send a dummy key */
get_random_bytes(sign.csrk, sizeof(sign.csrk));
smp_send_cmd(conn, SMP_CMD_SIGN_INFO, sizeof(sign), &sign);
*keydist &= ~SMP_DIST_SIGN;
}
return 0;
}
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