Commit bb8f2cb2 authored by John W. Linville's avatar John W. Linville

Merge branch 'master' of git://github.com/padovan/bluetooth-next

parents ed46fdfc ab0ff76d
...@@ -716,6 +716,16 @@ struct hci_rp_read_bd_addr { ...@@ -716,6 +716,16 @@ struct hci_rp_read_bd_addr {
bdaddr_t bdaddr; bdaddr_t bdaddr;
} __packed; } __packed;
#define HCI_OP_WRITE_PAGE_SCAN_ACTIVITY 0x0c1c
struct hci_cp_write_page_scan_activity {
__le16 interval;
__le16 window;
} __packed;
#define HCI_OP_WRITE_PAGE_SCAN_TYPE 0x0c47
#define PAGE_SCAN_TYPE_STANDARD 0x00
#define PAGE_SCAN_TYPE_INTERLACED 0x01
#define HCI_OP_LE_SET_EVENT_MASK 0x2001 #define HCI_OP_LE_SET_EVENT_MASK 0x2001
struct hci_cp_le_set_event_mask { struct hci_cp_le_set_event_mask {
__u8 mask[8]; __u8 mask[8];
......
...@@ -195,8 +195,6 @@ struct hci_dev { ...@@ -195,8 +195,6 @@ struct hci_dev {
__u16 init_last_cmd; __u16 init_last_cmd;
struct crypto_blkcipher *tfm;
struct inquiry_cache inq_cache; struct inquiry_cache inq_cache;
struct hci_conn_hash conn_hash; struct hci_conn_hash conn_hash;
struct list_head blacklist; struct list_head blacklist;
...@@ -348,6 +346,7 @@ enum { ...@@ -348,6 +346,7 @@ enum {
HCI_CONN_RSWITCH_PEND, HCI_CONN_RSWITCH_PEND,
HCI_CONN_MODE_CHANGE_PEND, HCI_CONN_MODE_CHANGE_PEND,
HCI_CONN_SCO_SETUP_PEND, HCI_CONN_SCO_SETUP_PEND,
HCI_CONN_LE_SMP_PEND,
}; };
static inline void hci_conn_hash_init(struct hci_dev *hdev) static inline void hci_conn_hash_init(struct hci_dev *hdev)
...@@ -395,6 +394,22 @@ static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c) ...@@ -395,6 +394,22 @@ static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
} }
} }
static inline unsigned int hci_conn_num(struct hci_dev *hdev, __u8 type)
{
struct hci_conn_hash *h = &hdev->conn_hash;
switch (type) {
case ACL_LINK:
return h->acl_num;
case LE_LINK:
return h->le_num;
case SCO_LINK:
case ESCO_LINK:
return h->sco_num;
default:
return 0;
}
}
static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev, static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev,
__u16 handle) __u16 handle)
{ {
...@@ -475,7 +490,7 @@ static inline void hci_conn_put(struct hci_conn *conn) ...@@ -475,7 +490,7 @@ static inline void hci_conn_put(struct hci_conn *conn)
{ {
if (atomic_dec_and_test(&conn->refcnt)) { if (atomic_dec_and_test(&conn->refcnt)) {
unsigned long timeo; unsigned long timeo;
if (conn->type == ACL_LINK) { if (conn->type == ACL_LINK || conn->type == LE_LINK) {
del_timer(&conn->idle_timer); del_timer(&conn->idle_timer);
if (conn->state == BT_CONNECTED) { if (conn->state == BT_CONNECTED) {
timeo = msecs_to_jiffies(conn->disc_timeout); timeo = msecs_to_jiffies(conn->disc_timeout);
...@@ -838,7 +853,7 @@ int mgmt_powered(u16 index, u8 powered); ...@@ -838,7 +853,7 @@ int mgmt_powered(u16 index, u8 powered);
int mgmt_discoverable(u16 index, u8 discoverable); int mgmt_discoverable(u16 index, u8 discoverable);
int mgmt_connectable(u16 index, u8 connectable); int mgmt_connectable(u16 index, u8 connectable);
int mgmt_new_key(u16 index, struct link_key *key, u8 persistent); int mgmt_new_key(u16 index, struct link_key *key, u8 persistent);
int mgmt_connected(u16 index, bdaddr_t *bdaddr); int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type);
int mgmt_disconnected(u16 index, bdaddr_t *bdaddr); int mgmt_disconnected(u16 index, bdaddr_t *bdaddr);
int mgmt_disconnect_failed(u16 index); int mgmt_disconnect_failed(u16 index);
int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status); int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status);
...@@ -858,6 +873,8 @@ int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi, ...@@ -858,6 +873,8 @@ int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
u8 *eir); u8 *eir);
int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name); int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name);
int mgmt_discovering(u16 index, u8 discovering); int mgmt_discovering(u16 index, u8 discovering);
int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr);
int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr);
/* HCI info for socket */ /* HCI info for socket */
#define hci_pi(sk) ((struct hci_pinfo *) sk) #define hci_pi(sk) ((struct hci_pinfo *) sk)
......
...@@ -409,14 +409,8 @@ struct l2cap_conn { ...@@ -409,14 +409,8 @@ struct l2cap_conn {
__u8 disc_reason; __u8 disc_reason;
__u8 preq[7]; /* SMP Pairing Request */
__u8 prsp[7]; /* SMP Pairing Response */
__u8 prnd[16]; /* SMP Pairing Random */
__u8 pcnf[16]; /* SMP Pairing Confirm */
__u8 tk[16]; /* SMP Temporary Key */
__u8 smp_key_size;
struct timer_list security_timer; struct timer_list security_timer;
struct smp_chan *smp_chan;
struct list_head chan_l; struct list_head chan_l;
rwlock_t chan_lock; rwlock_t chan_lock;
......
...@@ -211,6 +211,11 @@ struct mgmt_cp_unblock_device { ...@@ -211,6 +211,11 @@ struct mgmt_cp_unblock_device {
bdaddr_t bdaddr; bdaddr_t bdaddr;
} __packed; } __packed;
#define MGMT_OP_SET_FAST_CONNECTABLE 0x001F
struct mgmt_cp_set_fast_connectable {
__u8 enable;
} __packed;
#define MGMT_EV_CMD_COMPLETE 0x0001 #define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete { struct mgmt_ev_cmd_complete {
__le16 opcode; __le16 opcode;
...@@ -249,6 +254,7 @@ struct mgmt_ev_new_key { ...@@ -249,6 +254,7 @@ struct mgmt_ev_new_key {
#define MGMT_EV_CONNECTED 0x000B #define MGMT_EV_CONNECTED 0x000B
struct mgmt_ev_connected { struct mgmt_ev_connected {
bdaddr_t bdaddr; bdaddr_t bdaddr;
__u8 link_type;
} __packed; } __packed;
#define MGMT_EV_DISCONNECTED 0x000C #define MGMT_EV_DISCONNECTED 0x000C
...@@ -301,3 +307,13 @@ struct mgmt_ev_remote_name { ...@@ -301,3 +307,13 @@ struct mgmt_ev_remote_name {
} __packed; } __packed;
#define MGMT_EV_DISCOVERING 0x0014 #define MGMT_EV_DISCOVERING 0x0014
#define MGMT_EV_DEVICE_BLOCKED 0x0015
struct mgmt_ev_device_blocked {
bdaddr_t bdaddr;
} __packed;
#define MGMT_EV_DEVICE_UNBLOCKED 0x0016
struct mgmt_ev_device_unblocked {
bdaddr_t bdaddr;
} __packed;
...@@ -115,9 +115,26 @@ struct smp_cmd_security_req { ...@@ -115,9 +115,26 @@ 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
struct smp_chan {
struct l2cap_conn *conn;
u8 preq[7]; /* SMP Pairing Request */
u8 prsp[7]; /* SMP Pairing Response */
u8 prnd[16]; /* SMP Pairing Random (local) */
u8 rrnd[16]; /* SMP Pairing Random (remote) */
u8 pcnf[16]; /* SMP Pairing Confirm */
u8 tk[16]; /* SMP Temporary Key */
u8 smp_key_size;
struct crypto_blkcipher *tfm;
struct work_struct confirm;
struct work_struct random;
};
/* 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); int smp_distribute_keys(struct l2cap_conn *conn, __u8 force);
void smp_chan_destroy(struct l2cap_conn *conn);
#endif /* __SMP_H */ #endif /* __SMP_H */
...@@ -218,7 +218,7 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8], ...@@ -218,7 +218,7 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
cp.handle = cpu_to_le16(conn->handle); cp.handle = cpu_to_le16(conn->handle);
memcpy(cp.ltk, ltk, sizeof(cp.ltk)); memcpy(cp.ltk, ltk, sizeof(cp.ltk));
cp.ediv = ediv; cp.ediv = ediv;
memcpy(cp.rand, rand, sizeof(rand)); memcpy(cp.rand, rand, sizeof(cp.rand));
hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp); hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp);
} }
......
...@@ -1312,59 +1312,41 @@ int hci_blacklist_clear(struct hci_dev *hdev) ...@@ -1312,59 +1312,41 @@ int hci_blacklist_clear(struct hci_dev *hdev)
int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr) int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr)
{ {
struct bdaddr_list *entry; struct bdaddr_list *entry;
int err;
if (bacmp(bdaddr, BDADDR_ANY) == 0) if (bacmp(bdaddr, BDADDR_ANY) == 0)
return -EBADF; return -EBADF;
hci_dev_lock_bh(hdev); if (hci_blacklist_lookup(hdev, bdaddr))
return -EEXIST;
if (hci_blacklist_lookup(hdev, bdaddr)) {
err = -EEXIST;
goto err;
}
entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL); entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL);
if (!entry) { if (!entry)
err = -ENOMEM; return -ENOMEM;
goto err;
}
bacpy(&entry->bdaddr, bdaddr); bacpy(&entry->bdaddr, bdaddr);
list_add(&entry->list, &hdev->blacklist); list_add(&entry->list, &hdev->blacklist);
err = 0; return mgmt_device_blocked(hdev->id, bdaddr);
err:
hci_dev_unlock_bh(hdev);
return err;
} }
int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr) int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
{ {
struct bdaddr_list *entry; struct bdaddr_list *entry;
int err = 0;
hci_dev_lock_bh(hdev);
if (bacmp(bdaddr, BDADDR_ANY) == 0) { if (bacmp(bdaddr, BDADDR_ANY) == 0) {
hci_blacklist_clear(hdev); return hci_blacklist_clear(hdev);
goto done;
} }
entry = hci_blacklist_lookup(hdev, bdaddr); entry = hci_blacklist_lookup(hdev, bdaddr);
if (!entry) { if (!entry) {
err = -ENOENT; return -ENOENT;
goto done;
} }
list_del(&entry->list); list_del(&entry->list);
kfree(entry); kfree(entry);
done: return mgmt_device_unblocked(hdev->id, bdaddr);
hci_dev_unlock_bh(hdev);
return err;
} }
static void hci_clear_adv_cache(unsigned long arg) static void hci_clear_adv_cache(unsigned long arg)
...@@ -1523,11 +1505,6 @@ int hci_register_dev(struct hci_dev *hdev) ...@@ -1523,11 +1505,6 @@ int hci_register_dev(struct hci_dev *hdev)
if (!hdev->workqueue) if (!hdev->workqueue)
goto nomem; goto nomem;
hdev->tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(hdev->tfm))
BT_INFO("Failed to load transform for ecb(aes): %ld",
PTR_ERR(hdev->tfm));
hci_register_sysfs(hdev); hci_register_sysfs(hdev);
hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev, hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
...@@ -1576,9 +1553,6 @@ int hci_unregister_dev(struct hci_dev *hdev) ...@@ -1576,9 +1553,6 @@ int hci_unregister_dev(struct hci_dev *hdev)
!test_bit(HCI_SETUP, &hdev->flags)) !test_bit(HCI_SETUP, &hdev->flags))
mgmt_index_removed(hdev->id); mgmt_index_removed(hdev->id);
if (!IS_ERR(hdev->tfm))
crypto_free_blkcipher(hdev->tfm);
hci_notify(hdev, HCI_DEV_UNREG); hci_notify(hdev, HCI_DEV_UNREG);
if (hdev->rfkill) { if (hdev->rfkill) {
...@@ -2074,6 +2048,9 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int ...@@ -2074,6 +2048,9 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
min = c->sent; min = c->sent;
conn = c; conn = c;
} }
if (hci_conn_num(hdev, type) == num)
break;
} }
if (conn) { if (conn) {
...@@ -2131,6 +2108,9 @@ static inline void hci_sched_acl(struct hci_dev *hdev) ...@@ -2131,6 +2108,9 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
BT_DBG("%s", hdev->name); BT_DBG("%s", hdev->name);
if (!hci_conn_num(hdev, ACL_LINK))
return;
if (!test_bit(HCI_RAW, &hdev->flags)) { if (!test_bit(HCI_RAW, &hdev->flags)) {
/* ACL tx timeout must be longer than maximum /* ACL tx timeout must be longer than maximum
* link supervision timeout (40.9 seconds) */ * link supervision timeout (40.9 seconds) */
...@@ -2162,6 +2142,9 @@ static inline void hci_sched_sco(struct hci_dev *hdev) ...@@ -2162,6 +2142,9 @@ static inline void hci_sched_sco(struct hci_dev *hdev)
BT_DBG("%s", hdev->name); BT_DBG("%s", hdev->name);
if (!hci_conn_num(hdev, SCO_LINK))
return;
while (hdev->sco_cnt && (conn = hci_low_sent(hdev, SCO_LINK, &quote))) { while (hdev->sco_cnt && (conn = hci_low_sent(hdev, SCO_LINK, &quote))) {
while (quote-- && (skb = skb_dequeue(&conn->data_q))) { while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
BT_DBG("skb %p len %d", skb, skb->len); BT_DBG("skb %p len %d", skb, skb->len);
...@@ -2182,6 +2165,9 @@ static inline void hci_sched_esco(struct hci_dev *hdev) ...@@ -2182,6 +2165,9 @@ static inline void hci_sched_esco(struct hci_dev *hdev)
BT_DBG("%s", hdev->name); BT_DBG("%s", hdev->name);
if (!hci_conn_num(hdev, ESCO_LINK))
return;
while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK, &quote))) { while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK, &quote))) {
while (quote-- && (skb = skb_dequeue(&conn->data_q))) { while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
BT_DBG("skb %p len %d", skb, skb->len); BT_DBG("skb %p len %d", skb, skb->len);
...@@ -2202,6 +2188,9 @@ static inline void hci_sched_le(struct hci_dev *hdev) ...@@ -2202,6 +2188,9 @@ static inline void hci_sched_le(struct hci_dev *hdev)
BT_DBG("%s", hdev->name); BT_DBG("%s", hdev->name);
if (!hci_conn_num(hdev, LE_LINK))
return;
if (!test_bit(HCI_RAW, &hdev->flags)) { if (!test_bit(HCI_RAW, &hdev->flags)) {
/* LE tx timeout must be longer than maximum /* LE tx timeout must be longer than maximum
* link supervision timeout (40.9 seconds) */ * link supervision timeout (40.9 seconds) */
......
...@@ -898,16 +898,15 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, ...@@ -898,16 +898,15 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
if (!cp) if (!cp)
return; return;
hci_dev_lock(hdev);
if (cp->enable == 0x01) { if (cp->enable == 0x01) {
del_timer(&hdev->adv_timer); del_timer(&hdev->adv_timer);
hci_dev_lock(hdev);
hci_adv_entries_clear(hdev); hci_adv_entries_clear(hdev);
hci_dev_unlock(hdev);
} else if (cp->enable == 0x00) { } else if (cp->enable == 0x00) {
mod_timer(&hdev->adv_timer, jiffies + ADV_CLEAR_TIMEOUT); mod_timer(&hdev->adv_timer, jiffies + ADV_CLEAR_TIMEOUT);
} }
hci_dev_unlock(hdev);
} }
static void hci_cc_le_ltk_reply(struct hci_dev *hdev, struct sk_buff *skb) static void hci_cc_le_ltk_reply(struct hci_dev *hdev, struct sk_buff *skb)
...@@ -1103,9 +1102,10 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev, ...@@ -1103,9 +1102,10 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev,
return 0; return 0;
/* Only request authentication for SSP connections or non-SSP /* Only request authentication for SSP connections or non-SSP
* devices with sec_level HIGH */ * devices with sec_level HIGH or if MITM protection is requested */
if (!(hdev->ssp_mode > 0 && conn->ssp_mode > 0) && if (!(hdev->ssp_mode > 0 && conn->ssp_mode > 0) &&
conn->pending_sec_level != BT_SECURITY_HIGH) conn->pending_sec_level != BT_SECURITY_HIGH &&
!(conn->auth_type & 0x01))
return 0; return 0;
return 1; return 1;
...@@ -1412,7 +1412,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s ...@@ -1412,7 +1412,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
conn->state = BT_CONFIG; conn->state = BT_CONFIG;
hci_conn_hold(conn); hci_conn_hold(conn);
conn->disc_timeout = HCI_DISCONN_TIMEOUT; conn->disc_timeout = HCI_DISCONN_TIMEOUT;
mgmt_connected(hdev->id, &ev->bdaddr); mgmt_connected(hdev->id, &ev->bdaddr, conn->type);
} else } else
conn->state = BT_CONNECTED; conn->state = BT_CONNECTED;
...@@ -2816,7 +2816,7 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff ...@@ -2816,7 +2816,7 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
goto unlock; goto unlock;
} }
mgmt_connected(hdev->id, &ev->bdaddr); mgmt_connected(hdev->id, &ev->bdaddr, conn->type);
conn->sec_level = BT_SECURITY_LOW; conn->sec_level = BT_SECURITY_LOW;
conn->handle = __le16_to_cpu(ev->handle); conn->handle = __le16_to_cpu(ev->handle);
......
...@@ -183,21 +183,35 @@ static int hci_sock_release(struct socket *sock) ...@@ -183,21 +183,35 @@ static int hci_sock_release(struct socket *sock)
static int hci_sock_blacklist_add(struct hci_dev *hdev, void __user *arg) static int hci_sock_blacklist_add(struct hci_dev *hdev, void __user *arg)
{ {
bdaddr_t bdaddr; bdaddr_t bdaddr;
int err;
if (copy_from_user(&bdaddr, arg, sizeof(bdaddr))) if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
return -EFAULT; return -EFAULT;
return hci_blacklist_add(hdev, &bdaddr); hci_dev_lock_bh(hdev);
err = hci_blacklist_add(hdev, &bdaddr);
hci_dev_unlock_bh(hdev);
return err;
} }
static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg) static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg)
{ {
bdaddr_t bdaddr; bdaddr_t bdaddr;
int err;
if (copy_from_user(&bdaddr, arg, sizeof(bdaddr))) if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
return -EFAULT; return -EFAULT;
return hci_blacklist_del(hdev, &bdaddr); hci_dev_lock_bh(hdev);
err = hci_blacklist_del(hdev, &bdaddr);
hci_dev_unlock_bh(hdev);
return err;
} }
/* Ioctls that require bound socket */ /* Ioctls that require bound socket */
......
...@@ -23,6 +23,8 @@ static inline char *link_typetostr(int type) ...@@ -23,6 +23,8 @@ static inline char *link_typetostr(int type)
return "SCO"; return "SCO";
case ESCO_LINK: case ESCO_LINK:
return "eSCO"; return "eSCO";
case LE_LINK:
return "LE";
default: default:
return "UNKNOWN"; return "UNKNOWN";
} }
......
...@@ -872,6 +872,9 @@ static int hidp_start(struct hid_device *hid) ...@@ -872,6 +872,9 @@ static int hidp_start(struct hid_device *hid)
struct hidp_session *session = hid->driver_data; struct hidp_session *session = hid->driver_data;
struct hid_report *report; struct hid_report *report;
if (hid->quirks & HID_QUIRK_NO_INIT_REPORTS)
return 0;
list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT]. list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].
report_list, list) report_list, list)
hidp_send_report(session, report); hidp_send_report(session, report);
......
...@@ -907,6 +907,9 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) ...@@ -907,6 +907,9 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
if (!conn->hcon->out && conn->hcon->type == LE_LINK) if (!conn->hcon->out && conn->hcon->type == LE_LINK)
l2cap_le_conn_ready(conn); l2cap_le_conn_ready(conn);
if (conn->hcon->out && conn->hcon->type == LE_LINK)
smp_conn_security(conn, conn->hcon->pending_sec_level);
read_lock(&conn->chan_lock); read_lock(&conn->chan_lock);
list_for_each_entry(chan, &conn->chan_l, list) { list_for_each_entry(chan, &conn->chan_l, list) {
...@@ -986,8 +989,10 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) ...@@ -986,8 +989,10 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
del_timer_sync(&conn->info_timer); del_timer_sync(&conn->info_timer);
if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) {
del_timer(&conn->security_timer); del_timer(&conn->security_timer);
smp_chan_destroy(conn);
}
hcon->l2cap_data = NULL; hcon->l2cap_data = NULL;
kfree(conn); kfree(conn);
...@@ -1519,7 +1524,9 @@ struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *m ...@@ -1519,7 +1524,9 @@ struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *m
return skb; return skb;
} }
struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u16 control, u16 sdulen) static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
struct msghdr *msg, size_t len,
u16 control, u16 sdulen)
{ {
struct sock *sk = chan->sk; struct sock *sk = chan->sk;
struct l2cap_conn *conn = chan->conn; struct l2cap_conn *conn = chan->conn;
...@@ -4093,6 +4100,11 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) ...@@ -4093,6 +4100,11 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
BT_DBG("conn %p", conn); BT_DBG("conn %p", conn);
if (hcon->type == LE_LINK) {
smp_distribute_keys(conn, 0);
del_timer(&conn->security_timer);
}
read_lock(&conn->chan_lock); read_lock(&conn->chan_lock);
list_for_each_entry(chan, &conn->chan_l, list) { list_for_each_entry(chan, &conn->chan_l, list) {
...@@ -4105,9 +4117,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) ...@@ -4105,9 +4117,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
if (chan->scid == L2CAP_CID_LE_DATA) { if (chan->scid == L2CAP_CID_LE_DATA) {
if (!status && encrypt) { if (!status && encrypt) {
chan->sec_level = hcon->sec_level; chan->sec_level = hcon->sec_level;
del_timer(&conn->security_timer);
l2cap_chan_ready(sk); l2cap_chan_ready(sk);
smp_distribute_keys(conn, 0);
} }
bh_unlock_sock(sk); bh_unlock_sock(sk);
......
...@@ -908,7 +908,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len) ...@@ -908,7 +908,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
struct hci_dev *hdev; struct hci_dev *hdev;
struct mgmt_cp_load_keys *cp; struct mgmt_cp_load_keys *cp;
u16 key_count, expected_len; u16 key_count, expected_len;
int i, err; int i;
cp = (void *) data; cp = (void *) data;
...@@ -918,9 +918,9 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len) ...@@ -918,9 +918,9 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
key_count = get_unaligned_le16(&cp->key_count); key_count = get_unaligned_le16(&cp->key_count);
expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info); expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
if (expected_len > len) { if (expected_len != len) {
BT_ERR("load_keys: expected at least %u bytes, got %u bytes", BT_ERR("load_keys: expected %u bytes, got %u bytes",
expected_len, len); len, expected_len);
return -EINVAL; return -EINVAL;
} }
...@@ -942,36 +942,17 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len) ...@@ -942,36 +942,17 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
else else
clear_bit(HCI_DEBUG_KEYS, &hdev->flags); clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
len -= sizeof(*cp); for (i = 0; i < key_count; i++) {
i = 0; struct mgmt_key_info *key = &cp->keys[i];
while (i < len) {
struct mgmt_key_info *key = (void *) cp->keys + i;
i += sizeof(*key) + key->dlen;
if (key->type == HCI_LK_SMP_LTK) {
struct key_master_id *id = (void *) key->data;
if (key->dlen != sizeof(struct key_master_id))
continue;
hci_add_ltk(hdev, 0, &key->bdaddr, key->pin_len,
id->ediv, id->rand, key->val);
continue;
}
hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type, hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
key->pin_len); key->pin_len);
} }
err = cmd_complete(sk, index, MGMT_OP_LOAD_KEYS, NULL, 0);
hci_dev_unlock_bh(hdev); hci_dev_unlock_bh(hdev);
hci_dev_put(hdev); hci_dev_put(hdev);
return err; return 0;
} }
static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len) static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
...@@ -1347,6 +1328,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) ...@@ -1347,6 +1328,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
struct hci_dev *hdev; struct hci_dev *hdev;
struct mgmt_cp_pair_device *cp; struct mgmt_cp_pair_device *cp;
struct pending_cmd *cmd; struct pending_cmd *cmd;
struct adv_entry *entry;
u8 sec_level, auth_type; u8 sec_level, auth_type;
struct hci_conn *conn; struct hci_conn *conn;
int err; int err;
...@@ -1364,15 +1346,20 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) ...@@ -1364,15 +1346,20 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
hci_dev_lock_bh(hdev); hci_dev_lock_bh(hdev);
if (cp->io_cap == 0x03) {
sec_level = BT_SECURITY_MEDIUM; sec_level = BT_SECURITY_MEDIUM;
if (cp->io_cap == 0x03)
auth_type = HCI_AT_DEDICATED_BONDING; auth_type = HCI_AT_DEDICATED_BONDING;
} else { else
sec_level = BT_SECURITY_HIGH;
auth_type = HCI_AT_DEDICATED_BONDING_MITM; auth_type = HCI_AT_DEDICATED_BONDING_MITM;
}
conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level, auth_type); entry = hci_find_adv_entry(hdev, &cp->bdaddr);
if (entry)
conn = hci_connect(hdev, LE_LINK, &cp->bdaddr, sec_level,
auth_type);
else
conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level,
auth_type);
if (IS_ERR(conn)) { if (IS_ERR(conn)) {
err = PTR_ERR(conn); err = PTR_ERR(conn);
goto unlock; goto unlock;
...@@ -1391,7 +1378,10 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) ...@@ -1391,7 +1378,10 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
goto unlock; goto unlock;
} }
/* For LE, just connecting isn't a proof that the pairing finished */
if (!entry)
conn->connect_cfm_cb = pairing_complete_cb; conn->connect_cfm_cb = pairing_complete_cb;
conn->security_cfm_cb = pairing_complete_cb; conn->security_cfm_cb = pairing_complete_cb;
conn->disconn_cfm_cb = pairing_complete_cb; conn->disconn_cfm_cb = pairing_complete_cb;
conn->io_capability = cp->io_cap; conn->io_capability = cp->io_cap;
...@@ -1689,13 +1679,12 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data, ...@@ -1689,13 +1679,12 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
u16 len) u16 len)
{ {
struct hci_dev *hdev; struct hci_dev *hdev;
struct mgmt_cp_block_device *cp; struct pending_cmd *cmd;
struct mgmt_cp_block_device *cp = (void *) data;
int err; int err;
BT_DBG("hci%u", index); BT_DBG("hci%u", index);
cp = (void *) data;
if (len != sizeof(*cp)) if (len != sizeof(*cp))
return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
EINVAL); EINVAL);
...@@ -1705,6 +1694,14 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data, ...@@ -1705,6 +1694,14 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
ENODEV); ENODEV);
hci_dev_lock_bh(hdev);
cmd = mgmt_pending_add(sk, MGMT_OP_BLOCK_DEVICE, index, NULL, 0);
if (!cmd) {
err = -ENOMEM;
goto failed;
}
err = hci_blacklist_add(hdev, &cp->bdaddr); err = hci_blacklist_add(hdev, &cp->bdaddr);
if (err < 0) if (err < 0)
...@@ -1712,6 +1709,11 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data, ...@@ -1712,6 +1709,11 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
else else
err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
NULL, 0); NULL, 0);
mgmt_pending_remove(cmd);
failed:
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev); hci_dev_put(hdev);
return err; return err;
...@@ -1721,13 +1723,12 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data, ...@@ -1721,13 +1723,12 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
u16 len) u16 len)
{ {
struct hci_dev *hdev; struct hci_dev *hdev;
struct mgmt_cp_unblock_device *cp; struct pending_cmd *cmd;
struct mgmt_cp_unblock_device *cp = (void *) data;
int err; int err;
BT_DBG("hci%u", index); BT_DBG("hci%u", index);
cp = (void *) data;
if (len != sizeof(*cp)) if (len != sizeof(*cp))
return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
EINVAL); EINVAL);
...@@ -1737,6 +1738,14 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data, ...@@ -1737,6 +1738,14 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
ENODEV); ENODEV);
hci_dev_lock_bh(hdev);
cmd = mgmt_pending_add(sk, MGMT_OP_UNBLOCK_DEVICE, index, NULL, 0);
if (!cmd) {
err = -ENOMEM;
goto failed;
}
err = hci_blacklist_del(hdev, &cp->bdaddr); err = hci_blacklist_del(hdev, &cp->bdaddr);
if (err < 0) if (err < 0)
...@@ -1744,6 +1753,67 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data, ...@@ -1744,6 +1753,67 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
else else
err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
NULL, 0); NULL, 0);
mgmt_pending_remove(cmd);
failed:
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return err;
}
static int set_fast_connectable(struct sock *sk, u16 index,
unsigned char *data, u16 len)
{
struct hci_dev *hdev;
struct mgmt_cp_set_fast_connectable *cp = (void *) data;
struct hci_cp_write_page_scan_activity acp;
u8 type;
int err;
BT_DBG("hci%u", index);
if (len != sizeof(*cp))
return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
EINVAL);
hdev = hci_dev_get(index);
if (!hdev)
return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
ENODEV);
hci_dev_lock(hdev);
if (cp->enable) {
type = PAGE_SCAN_TYPE_INTERLACED;
acp.interval = 0x0024; /* 22.5 msec page scan interval */
} else {
type = PAGE_SCAN_TYPE_STANDARD; /* default */
acp.interval = 0x0800; /* default 1.28 sec page scan */
}
acp.window = 0x0012; /* default 11.25 msec page scan window */
err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
sizeof(acp), &acp);
if (err < 0) {
err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
-err);
goto done;
}
err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
if (err < 0) {
err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
-err);
goto done;
}
err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
NULL, 0);
done:
hci_dev_unlock(hdev);
hci_dev_put(hdev); hci_dev_put(hdev);
return err; return err;
...@@ -1869,6 +1939,10 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) ...@@ -1869,6 +1939,10 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
case MGMT_OP_UNBLOCK_DEVICE: case MGMT_OP_UNBLOCK_DEVICE:
err = unblock_device(sk, index, buf + sizeof(*hdr), len); err = unblock_device(sk, index, buf + sizeof(*hdr), len);
break; break;
case MGMT_OP_SET_FAST_CONNECTABLE:
err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
len);
break;
default: default:
BT_DBG("Unknown op %u", opcode); BT_DBG("Unknown op %u", opcode);
err = cmd_status(sk, index, opcode, 0x01); err = cmd_status(sk, index, opcode, 0x01);
...@@ -1977,35 +2051,25 @@ int mgmt_connectable(u16 index, u8 connectable) ...@@ -1977,35 +2051,25 @@ int mgmt_connectable(u16 index, u8 connectable)
int mgmt_new_key(u16 index, struct link_key *key, u8 persistent) int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
{ {
struct mgmt_ev_new_key *ev; struct mgmt_ev_new_key ev;
int err, total;
total = sizeof(struct mgmt_ev_new_key) + key->dlen;
ev = kzalloc(total, GFP_ATOMIC);
if (!ev)
return -ENOMEM;
bacpy(&ev->key.bdaddr, &key->bdaddr); memset(&ev, 0, sizeof(ev));
ev->key.type = key->type;
memcpy(ev->key.val, key->val, 16);
ev->key.pin_len = key->pin_len;
ev->key.dlen = key->dlen;
ev->store_hint = persistent;
memcpy(ev->key.data, key->data, key->dlen);
err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
kfree(ev); ev.store_hint = persistent;
bacpy(&ev.key.bdaddr, &key->bdaddr);
ev.key.type = key->type;
memcpy(ev.key.val, key->val, 16);
ev.key.pin_len = key->pin_len;
return err; return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
} }
int mgmt_connected(u16 index, bdaddr_t *bdaddr) int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type)
{ {
struct mgmt_ev_connected ev; struct mgmt_ev_connected ev;
bacpy(&ev.bdaddr, bdaddr); bacpy(&ev.bdaddr, bdaddr);
ev.link_type = link_type;
return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL); return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
} }
...@@ -2260,12 +2324,14 @@ int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi, ...@@ -2260,12 +2324,14 @@ int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
memset(&ev, 0, sizeof(ev)); memset(&ev, 0, sizeof(ev));
bacpy(&ev.bdaddr, bdaddr); bacpy(&ev.bdaddr, bdaddr);
memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
ev.rssi = rssi; ev.rssi = rssi;
if (eir) if (eir)
memcpy(ev.eir, eir, sizeof(ev.eir)); memcpy(ev.eir, eir, sizeof(ev.eir));
if (dev_class)
memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL); return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
} }
...@@ -2286,3 +2352,29 @@ int mgmt_discovering(u16 index, u8 discovering) ...@@ -2286,3 +2352,29 @@ int mgmt_discovering(u16 index, u8 discovering)
return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering, return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering,
sizeof(discovering), NULL); sizeof(discovering), NULL);
} }
int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr)
{
struct pending_cmd *cmd;
struct mgmt_ev_device_blocked ev;
cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, index);
bacpy(&ev.bdaddr, bdaddr);
return mgmt_event(MGMT_EV_DEVICE_BLOCKED, index, &ev, sizeof(ev),
cmd ? cmd->sk : NULL);
}
int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr)
{
struct pending_cmd *cmd;
struct mgmt_ev_device_unblocked ev;
cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, index);
bacpy(&ev.bdaddr, bdaddr);
return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, index, &ev, sizeof(ev),
cmd ? cmd->sk : NULL);
}
This diff is collapsed.
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