diff --git a/[refs] b/[refs] index d93d054c1a69..aa5733090dc6 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: bb8f2cb284f1afa430a252d306d2bb29f6b9ce64 +refs/heads/master: 6cd9d21a0c1e2648c07c32c66bb25795ad3208aa diff --git a/trunk/drivers/net/wireless/wl12xx/scan.c b/trunk/drivers/net/wireless/wl12xx/scan.c index eeccc9f095bb..08f7e826d27b 100644 --- a/trunk/drivers/net/wireless/wl12xx/scan.c +++ b/trunk/drivers/net/wireless/wl12xx/scan.c @@ -99,14 +99,18 @@ static int wl1271_get_scan_channels(struct wl1271 *wl, for (i = 0, j = 0; i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS; i++) { - flags = req->channels[i]->flags; if (!test_bit(i, wl->scan.scanned_ch) && !(flags & IEEE80211_CHAN_DISABLED) && - ((!!(flags & IEEE80211_CHAN_PASSIVE_SCAN)) == passive) && - (req->channels[i]->band == band)) { - + (req->channels[i]->band == band) && + /* + * In passive scans, we scan all remaining + * channels, even if not marked as such. + * In active scans, we only scan channels not + * marked as passive. + */ + (passive || !(flags & IEEE80211_CHAN_PASSIVE_SCAN))) { wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ", req->channels[i]->band, req->channels[i]->center_freq); @@ -158,6 +162,10 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, int ret; u16 scan_options = 0; + /* skip active scans if we don't have SSIDs */ + if (!passive && wl->scan.req->n_ssids == 0) + return WL1271_NOTHING_TO_SCAN; + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); if (!cmd || !trigger) { @@ -165,8 +173,7 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, goto out; } - /* No SSIDs means that we have a forced passive scan */ - if (passive || wl->scan.req->n_ssids == 0) + if (passive) scan_options |= WL1271_SCAN_OPT_PASSIVE; if (WARN_ON(wl->role_id == WL12XX_INVALID_ROLE_ID)) { diff --git a/trunk/include/net/bluetooth/hci.h b/trunk/include/net/bluetooth/hci.h index aaf79af72432..be30aabe7b88 100644 --- a/trunk/include/net/bluetooth/hci.h +++ b/trunk/include/net/bluetooth/hci.h @@ -716,16 +716,6 @@ struct hci_rp_read_bd_addr { bdaddr_t bdaddr; } __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 struct hci_cp_le_set_event_mask { __u8 mask[8]; diff --git a/trunk/include/net/bluetooth/hci_core.h b/trunk/include/net/bluetooth/hci_core.h index 5b924423cf20..8f441b8b2963 100644 --- a/trunk/include/net/bluetooth/hci_core.h +++ b/trunk/include/net/bluetooth/hci_core.h @@ -195,6 +195,8 @@ struct hci_dev { __u16 init_last_cmd; + struct crypto_blkcipher *tfm; + struct inquiry_cache inq_cache; struct hci_conn_hash conn_hash; struct list_head blacklist; @@ -346,7 +348,6 @@ enum { HCI_CONN_RSWITCH_PEND, HCI_CONN_MODE_CHANGE_PEND, HCI_CONN_SCO_SETUP_PEND, - HCI_CONN_LE_SMP_PEND, }; static inline void hci_conn_hash_init(struct hci_dev *hdev) @@ -394,22 +395,6 @@ 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, __u16 handle) { @@ -490,7 +475,7 @@ static inline void hci_conn_put(struct hci_conn *conn) { if (atomic_dec_and_test(&conn->refcnt)) { unsigned long timeo; - if (conn->type == ACL_LINK || conn->type == LE_LINK) { + if (conn->type == ACL_LINK) { del_timer(&conn->idle_timer); if (conn->state == BT_CONNECTED) { timeo = msecs_to_jiffies(conn->disc_timeout); @@ -853,7 +838,7 @@ int mgmt_powered(u16 index, u8 powered); int mgmt_discoverable(u16 index, u8 discoverable); int mgmt_connectable(u16 index, u8 connectable); int mgmt_new_key(u16 index, struct link_key *key, u8 persistent); -int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type); +int mgmt_connected(u16 index, bdaddr_t *bdaddr); int mgmt_disconnected(u16 index, bdaddr_t *bdaddr); int mgmt_disconnect_failed(u16 index); int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status); @@ -873,8 +858,6 @@ int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi, u8 *eir); int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name); 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 */ #define hci_pi(sk) ((struct hci_pinfo *) sk) diff --git a/trunk/include/net/bluetooth/l2cap.h b/trunk/include/net/bluetooth/l2cap.h index 7f878b9d5642..4f34ad25e75c 100644 --- a/trunk/include/net/bluetooth/l2cap.h +++ b/trunk/include/net/bluetooth/l2cap.h @@ -409,8 +409,14 @@ struct l2cap_conn { __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 smp_chan *smp_chan; struct list_head chan_l; rwlock_t chan_lock; diff --git a/trunk/include/net/bluetooth/mgmt.h b/trunk/include/net/bluetooth/mgmt.h index d66da0f94f95..5428fd32ccec 100644 --- a/trunk/include/net/bluetooth/mgmt.h +++ b/trunk/include/net/bluetooth/mgmt.h @@ -211,11 +211,6 @@ struct mgmt_cp_unblock_device { bdaddr_t bdaddr; } __packed; -#define MGMT_OP_SET_FAST_CONNECTABLE 0x001F -struct mgmt_cp_set_fast_connectable { - __u8 enable; -} __packed; - #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; @@ -254,7 +249,6 @@ struct mgmt_ev_new_key { #define MGMT_EV_CONNECTED 0x000B struct mgmt_ev_connected { bdaddr_t bdaddr; - __u8 link_type; } __packed; #define MGMT_EV_DISCONNECTED 0x000C @@ -307,13 +301,3 @@ struct mgmt_ev_remote_name { } __packed; #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; diff --git a/trunk/include/net/bluetooth/smp.h b/trunk/include/net/bluetooth/smp.h index 15b97d549441..46c457612300 100644 --- a/trunk/include/net/bluetooth/smp.h +++ b/trunk/include/net/bluetooth/smp.h @@ -115,26 +115,9 @@ struct smp_cmd_security_req { #define SMP_MIN_ENC_KEY_SIZE 7 #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 */ 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_distribute_keys(struct l2cap_conn *conn, __u8 force); -void smp_chan_destroy(struct l2cap_conn *conn); - #endif /* __SMP_H */ diff --git a/trunk/net/bluetooth/hci_conn.c b/trunk/net/bluetooth/hci_conn.c index c2df7bf1d374..ea7f031f3b04 100644 --- a/trunk/net/bluetooth/hci_conn.c +++ b/trunk/net/bluetooth/hci_conn.c @@ -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); memcpy(cp.ltk, ltk, sizeof(cp.ltk)); cp.ediv = ediv; - memcpy(cp.rand, rand, sizeof(cp.rand)); + memcpy(cp.rand, rand, sizeof(rand)); hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp); } diff --git a/trunk/net/bluetooth/hci_core.c b/trunk/net/bluetooth/hci_core.c index b84458dcc226..56943add45cc 100644 --- a/trunk/net/bluetooth/hci_core.c +++ b/trunk/net/bluetooth/hci_core.c @@ -1312,41 +1312,59 @@ int hci_blacklist_clear(struct hci_dev *hdev) int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr) { struct bdaddr_list *entry; + int err; if (bacmp(bdaddr, BDADDR_ANY) == 0) return -EBADF; - if (hci_blacklist_lookup(hdev, bdaddr)) - return -EEXIST; + hci_dev_lock_bh(hdev); + + if (hci_blacklist_lookup(hdev, bdaddr)) { + err = -EEXIST; + goto err; + } entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL); - if (!entry) - return -ENOMEM; + if (!entry) { + err = -ENOMEM; + goto err; + } bacpy(&entry->bdaddr, bdaddr); list_add(&entry->list, &hdev->blacklist); - return mgmt_device_blocked(hdev->id, bdaddr); + err = 0; + +err: + hci_dev_unlock_bh(hdev); + return err; } int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr) { struct bdaddr_list *entry; + int err = 0; + + hci_dev_lock_bh(hdev); if (bacmp(bdaddr, BDADDR_ANY) == 0) { - return hci_blacklist_clear(hdev); + hci_blacklist_clear(hdev); + goto done; } entry = hci_blacklist_lookup(hdev, bdaddr); if (!entry) { - return -ENOENT; + err = -ENOENT; + goto done; } list_del(&entry->list); kfree(entry); - return mgmt_device_unblocked(hdev->id, bdaddr); +done: + hci_dev_unlock_bh(hdev); + return err; } static void hci_clear_adv_cache(unsigned long arg) @@ -1505,6 +1523,11 @@ int hci_register_dev(struct hci_dev *hdev) if (!hdev->workqueue) 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); hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev, @@ -1553,6 +1576,9 @@ int hci_unregister_dev(struct hci_dev *hdev) !test_bit(HCI_SETUP, &hdev->flags)) mgmt_index_removed(hdev->id); + if (!IS_ERR(hdev->tfm)) + crypto_free_blkcipher(hdev->tfm); + hci_notify(hdev, HCI_DEV_UNREG); if (hdev->rfkill) { @@ -2048,9 +2074,6 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int min = c->sent; conn = c; } - - if (hci_conn_num(hdev, type) == num) - break; } if (conn) { @@ -2108,9 +2131,6 @@ static inline void hci_sched_acl(struct hci_dev *hdev) BT_DBG("%s", hdev->name); - if (!hci_conn_num(hdev, ACL_LINK)) - return; - if (!test_bit(HCI_RAW, &hdev->flags)) { /* ACL tx timeout must be longer than maximum * link supervision timeout (40.9 seconds) */ @@ -2142,9 +2162,6 @@ static inline void hci_sched_sco(struct hci_dev *hdev) BT_DBG("%s", hdev->name); - if (!hci_conn_num(hdev, SCO_LINK)) - return; - while (hdev->sco_cnt && (conn = hci_low_sent(hdev, SCO_LINK, "e))) { while (quote-- && (skb = skb_dequeue(&conn->data_q))) { BT_DBG("skb %p len %d", skb, skb->len); @@ -2165,9 +2182,6 @@ static inline void hci_sched_esco(struct hci_dev *hdev) BT_DBG("%s", hdev->name); - if (!hci_conn_num(hdev, ESCO_LINK)) - return; - while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK, "e))) { while (quote-- && (skb = skb_dequeue(&conn->data_q))) { BT_DBG("skb %p len %d", skb, skb->len); @@ -2188,9 +2202,6 @@ static inline void hci_sched_le(struct hci_dev *hdev) BT_DBG("%s", hdev->name); - if (!hci_conn_num(hdev, LE_LINK)) - return; - if (!test_bit(HCI_RAW, &hdev->flags)) { /* LE tx timeout must be longer than maximum * link supervision timeout (40.9 seconds) */ diff --git a/trunk/net/bluetooth/hci_event.c b/trunk/net/bluetooth/hci_event.c index 35083f2aa2ea..7ef4eb4435fb 100644 --- a/trunk/net/bluetooth/hci_event.c +++ b/trunk/net/bluetooth/hci_event.c @@ -898,15 +898,16 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, if (!cp) return; + hci_dev_lock(hdev); + if (cp->enable == 0x01) { del_timer(&hdev->adv_timer); - - hci_dev_lock(hdev); hci_adv_entries_clear(hdev); - hci_dev_unlock(hdev); } else if (cp->enable == 0x00) { 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) @@ -1102,10 +1103,9 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev, return 0; /* Only request authentication for SSP connections or non-SSP - * devices with sec_level HIGH or if MITM protection is requested */ + * devices with sec_level HIGH */ if (!(hdev->ssp_mode > 0 && conn->ssp_mode > 0) && - conn->pending_sec_level != BT_SECURITY_HIGH && - !(conn->auth_type & 0x01)) + conn->pending_sec_level != BT_SECURITY_HIGH) return 0; return 1; @@ -1412,7 +1412,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s conn->state = BT_CONFIG; hci_conn_hold(conn); conn->disc_timeout = HCI_DISCONN_TIMEOUT; - mgmt_connected(hdev->id, &ev->bdaddr, conn->type); + mgmt_connected(hdev->id, &ev->bdaddr); } else conn->state = BT_CONNECTED; @@ -2816,7 +2816,7 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff goto unlock; } - mgmt_connected(hdev->id, &ev->bdaddr, conn->type); + mgmt_connected(hdev->id, &ev->bdaddr); conn->sec_level = BT_SECURITY_LOW; conn->handle = __le16_to_cpu(ev->handle); diff --git a/trunk/net/bluetooth/hci_sock.c b/trunk/net/bluetooth/hci_sock.c index f6afe3d76a66..ff02cf5e77cc 100644 --- a/trunk/net/bluetooth/hci_sock.c +++ b/trunk/net/bluetooth/hci_sock.c @@ -183,35 +183,21 @@ static int hci_sock_release(struct socket *sock) static int hci_sock_blacklist_add(struct hci_dev *hdev, void __user *arg) { bdaddr_t bdaddr; - int err; if (copy_from_user(&bdaddr, arg, sizeof(bdaddr))) return -EFAULT; - hci_dev_lock_bh(hdev); - - err = hci_blacklist_add(hdev, &bdaddr); - - hci_dev_unlock_bh(hdev); - - return err; + return hci_blacklist_add(hdev, &bdaddr); } static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg) { bdaddr_t bdaddr; - int err; if (copy_from_user(&bdaddr, arg, sizeof(bdaddr))) return -EFAULT; - hci_dev_lock_bh(hdev); - - err = hci_blacklist_del(hdev, &bdaddr); - - hci_dev_unlock_bh(hdev); - - return err; + return hci_blacklist_del(hdev, &bdaddr); } /* Ioctls that require bound socket */ diff --git a/trunk/net/bluetooth/hci_sysfs.c b/trunk/net/bluetooth/hci_sysfs.c index 22f1a6c87035..a6c3aa8be1f7 100644 --- a/trunk/net/bluetooth/hci_sysfs.c +++ b/trunk/net/bluetooth/hci_sysfs.c @@ -23,8 +23,6 @@ static inline char *link_typetostr(int type) return "SCO"; case ESCO_LINK: return "eSCO"; - case LE_LINK: - return "LE"; default: return "UNKNOWN"; } diff --git a/trunk/net/bluetooth/hidp/core.c b/trunk/net/bluetooth/hidp/core.c index b83979c548b2..fb68f344c34a 100644 --- a/trunk/net/bluetooth/hidp/core.c +++ b/trunk/net/bluetooth/hidp/core.c @@ -872,9 +872,6 @@ static int hidp_start(struct hid_device *hid) struct hidp_session *session = hid->driver_data; 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]. report_list, list) hidp_send_report(session, report); diff --git a/trunk/net/bluetooth/l2cap_core.c b/trunk/net/bluetooth/l2cap_core.c index 1611b3544bb1..b3bdb482bbe6 100644 --- a/trunk/net/bluetooth/l2cap_core.c +++ b/trunk/net/bluetooth/l2cap_core.c @@ -907,9 +907,6 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) if (!conn->hcon->out && conn->hcon->type == LE_LINK) 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); list_for_each_entry(chan, &conn->chan_l, list) { @@ -989,10 +986,8 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) del_timer_sync(&conn->info_timer); - if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) { + if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) del_timer(&conn->security_timer); - smp_chan_destroy(conn); - } hcon->l2cap_data = NULL; kfree(conn); @@ -1524,9 +1519,7 @@ struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *m return skb; } -static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, - struct msghdr *msg, size_t len, - u16 control, u16 sdulen) +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 l2cap_conn *conn = chan->conn; @@ -4100,11 +4093,6 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) 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); list_for_each_entry(chan, &conn->chan_l, list) { @@ -4117,7 +4105,9 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) if (chan->scid == L2CAP_CID_LE_DATA) { if (!status && encrypt) { chan->sec_level = hcon->sec_level; + del_timer(&conn->security_timer); l2cap_chan_ready(sk); + smp_distribute_keys(conn, 0); } bh_unlock_sock(sk); diff --git a/trunk/net/bluetooth/mgmt.c b/trunk/net/bluetooth/mgmt.c index 5a94eec06caa..53e109eb043e 100644 --- a/trunk/net/bluetooth/mgmt.c +++ b/trunk/net/bluetooth/mgmt.c @@ -908,7 +908,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len) struct hci_dev *hdev; struct mgmt_cp_load_keys *cp; u16 key_count, expected_len; - int i; + int i, err; cp = (void *) data; @@ -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); expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info); - if (expected_len != len) { - BT_ERR("load_keys: expected %u bytes, got %u bytes", - len, expected_len); + if (expected_len > len) { + BT_ERR("load_keys: expected at least %u bytes, got %u bytes", + expected_len, len); return -EINVAL; } @@ -942,17 +942,36 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len) else clear_bit(HCI_DEBUG_KEYS, &hdev->flags); - for (i = 0; i < key_count; i++) { - struct mgmt_key_info *key = &cp->keys[i]; + len -= sizeof(*cp); + i = 0; + + 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, key->pin_len); } + err = cmd_complete(sk, index, MGMT_OP_LOAD_KEYS, NULL, 0); + hci_dev_unlock_bh(hdev); hci_dev_put(hdev); - return 0; + return err; } static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len) @@ -1328,7 +1347,6 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) struct hci_dev *hdev; struct mgmt_cp_pair_device *cp; struct pending_cmd *cmd; - struct adv_entry *entry; u8 sec_level, auth_type; struct hci_conn *conn; int err; @@ -1346,20 +1364,15 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) hci_dev_lock_bh(hdev); - sec_level = BT_SECURITY_MEDIUM; - if (cp->io_cap == 0x03) + if (cp->io_cap == 0x03) { + sec_level = BT_SECURITY_MEDIUM; auth_type = HCI_AT_DEDICATED_BONDING; - else + } else { + sec_level = BT_SECURITY_HIGH; auth_type = HCI_AT_DEDICATED_BONDING_MITM; + } - 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); - + conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level, auth_type); if (IS_ERR(conn)) { err = PTR_ERR(conn); goto unlock; @@ -1378,10 +1391,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) 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->disconn_cfm_cb = pairing_complete_cb; conn->io_capability = cp->io_cap; @@ -1679,12 +1689,13 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data, u16 len) { struct hci_dev *hdev; - struct pending_cmd *cmd; - struct mgmt_cp_block_device *cp = (void *) data; + struct mgmt_cp_block_device *cp; int err; BT_DBG("hci%u", index); + cp = (void *) data; + if (len != sizeof(*cp)) return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, EINVAL); @@ -1694,14 +1705,6 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, 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); if (err < 0) @@ -1709,11 +1712,6 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data, else err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, NULL, 0); - - mgmt_pending_remove(cmd); - -failed: - hci_dev_unlock_bh(hdev); hci_dev_put(hdev); return err; @@ -1723,12 +1721,13 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data, u16 len) { struct hci_dev *hdev; - struct pending_cmd *cmd; - struct mgmt_cp_unblock_device *cp = (void *) data; + struct mgmt_cp_unblock_device *cp; int err; BT_DBG("hci%u", index); + cp = (void *) data; + if (len != sizeof(*cp)) return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, EINVAL); @@ -1738,14 +1737,6 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, 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); if (err < 0) @@ -1753,67 +1744,6 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data, else err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, 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); return err; @@ -1939,10 +1869,6 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_UNBLOCK_DEVICE: err = unblock_device(sk, index, buf + sizeof(*hdr), len); break; - case MGMT_OP_SET_FAST_CONNECTABLE: - err = set_fast_connectable(sk, index, buf + sizeof(*hdr), - len); - break; default: BT_DBG("Unknown op %u", opcode); err = cmd_status(sk, index, opcode, 0x01); @@ -2051,25 +1977,35 @@ int mgmt_connectable(u16 index, u8 connectable) 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; - memset(&ev, 0, sizeof(ev)); + total = sizeof(struct mgmt_ev_new_key) + key->dlen; + ev = kzalloc(total, GFP_ATOMIC); + if (!ev) + return -ENOMEM; + + 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; + ev->key.dlen = key->dlen; + ev->store_hint = persistent; - 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; + memcpy(ev->key.data, key->data, key->dlen); - return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL); + err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL); + + kfree(ev); + + return err; } -int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type) +int mgmt_connected(u16 index, bdaddr_t *bdaddr) { struct mgmt_ev_connected ev; bacpy(&ev.bdaddr, bdaddr); - ev.link_type = link_type; return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL); } @@ -2324,14 +2260,12 @@ int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi, memset(&ev, 0, sizeof(ev)); bacpy(&ev.bdaddr, bdaddr); + memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class)); ev.rssi = rssi; if (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); } @@ -2352,29 +2286,3 @@ int mgmt_discovering(u16 index, u8 discovering) return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering, 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); -} diff --git a/trunk/net/bluetooth/smp.c b/trunk/net/bluetooth/smp.c index 759b63572641..391888b88a92 100644 --- a/trunk/net/bluetooth/smp.c +++ b/trunk/net/bluetooth/smp.c @@ -182,9 +182,18 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data) return; hci_send_acl(conn->hcon, skb, 0); +} - mod_timer(&conn->security_timer, jiffies + - msecs_to_jiffies(SMP_TIMEOUT)); +static __u8 seclevel_to_authreq(__u8 level) +{ + switch (level) { + case BT_SECURITY_HIGH: + /* Right now we don't support bonding */ + return SMP_AUTH_MITM; + + default: + return SMP_AUTH_NONE; + } } static void build_pairing_cmd(struct l2cap_conn *conn, @@ -196,7 +205,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, dist_keys = 0; if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->flags)) { - dist_keys = SMP_DIST_ENC_KEY; + dist_keys = SMP_DIST_ENC_KEY | SMP_DIST_ID_KEY | SMP_DIST_SIGN; authreq |= SMP_AUTH_BONDING; } @@ -220,184 +229,24 @@ static void build_pairing_cmd(struct l2cap_conn *conn, static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size) { - struct smp_chan *smp = conn->smp_chan; - if ((max_key_size > SMP_MAX_ENC_KEY_SIZE) || (max_key_size < SMP_MIN_ENC_KEY_SIZE)) return SMP_ENC_KEY_SIZE; - smp->smp_key_size = max_key_size; + conn->smp_key_size = max_key_size; return 0; } -static void confirm_work(struct work_struct *work) -{ - struct smp_chan *smp = container_of(work, struct smp_chan, confirm); - struct l2cap_conn *conn = smp->conn; - struct crypto_blkcipher *tfm; - struct smp_cmd_pairing_confirm cp; - int ret; - u8 res[16], reason; - - BT_DBG("conn %p", conn); - - tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(tfm)) { - reason = SMP_UNSPECIFIED; - goto error; - } - - smp->tfm = tfm; - - if (conn->hcon->out) - ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, 0, - conn->src, conn->hcon->dst_type, conn->dst, - res); - else - ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, - conn->hcon->dst_type, conn->dst, 0, conn->src, - res); - if (ret) { - reason = SMP_UNSPECIFIED; - goto error; - } - - swap128(res, cp.confirm_val); - smp_send_cmd(smp->conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp); - - return; - -error: - smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason); - smp_chan_destroy(conn); -} - -static void random_work(struct work_struct *work) -{ - struct smp_chan *smp = container_of(work, struct smp_chan, random); - struct l2cap_conn *conn = smp->conn; - struct hci_conn *hcon = conn->hcon; - struct crypto_blkcipher *tfm = smp->tfm; - u8 reason, confirm[16], res[16], key[16]; - int ret; - - if (IS_ERR_OR_NULL(tfm)) { - reason = SMP_UNSPECIFIED; - goto error; - } - - BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); - - if (hcon->out) - ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, 0, - conn->src, hcon->dst_type, conn->dst, - res); - else - ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, - hcon->dst_type, conn->dst, 0, conn->src, - res); - if (ret) { - reason = SMP_UNSPECIFIED; - goto error; - } - - swap128(res, confirm); - - if (memcmp(smp->pcnf, confirm, sizeof(smp->pcnf)) != 0) { - BT_ERR("Pairing failed (confirmation values mismatch)"); - reason = SMP_CONFIRM_FAILED; - goto error; - } - - if (hcon->out) { - u8 stk[16], rand[8]; - __le16 ediv; - - memset(rand, 0, sizeof(rand)); - ediv = 0; - - smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, key); - swap128(key, stk); - - memset(stk + smp->smp_key_size, 0, - SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size); - - if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) { - reason = SMP_UNSPECIFIED; - goto error; - } - - hci_le_start_enc(hcon, ediv, rand, stk); - hcon->enc_key_size = smp->smp_key_size; - } else { - u8 stk[16], r[16], rand[8]; - __le16 ediv; - - memset(rand, 0, sizeof(rand)); - ediv = 0; - - swap128(smp->prnd, r); - smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r); - - smp_s1(tfm, smp->tk, smp->prnd, smp->rrnd, key); - swap128(key, stk); - - memset(stk + smp->smp_key_size, 0, - SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size); - - hci_add_ltk(hcon->hdev, 0, conn->dst, smp->smp_key_size, - ediv, rand, stk); - } - - return; - -error: - smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason); - smp_chan_destroy(conn); -} - -static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) -{ - struct smp_chan *smp; - - smp = kzalloc(sizeof(struct smp_chan), GFP_ATOMIC); - if (!smp) - return NULL; - - INIT_WORK(&smp->confirm, confirm_work); - INIT_WORK(&smp->random, random_work); - - smp->conn = conn; - conn->smp_chan = smp; - - hci_conn_hold(conn->hcon); - - return smp; -} - -void smp_chan_destroy(struct l2cap_conn *conn) -{ - kfree(conn->smp_chan); - hci_conn_put(conn->hcon); -} - 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_chan *smp; u8 key_size; - int ret; BT_DBG("conn %p", conn); - if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend)) - smp = smp_chan_create(conn); - - smp = conn->smp_chan; - - smp->preq[0] = SMP_CMD_PAIRING_REQ; - memcpy(&smp->preq[1], req, sizeof(*req)); + conn->preq[0] = SMP_CMD_PAIRING_REQ; + memcpy(&conn->preq[1], req, sizeof(*req)); skb_pull(skb, sizeof(*req)); if (req->oob_flag) @@ -411,33 +260,32 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) return SMP_ENC_KEY_SIZE; /* Just works */ - memset(smp->tk, 0, sizeof(smp->tk)); - - ret = smp_rand(smp->prnd); - if (ret) - return SMP_UNSPECIFIED; + memset(conn->tk, 0, sizeof(conn->tk)); - smp->prsp[0] = SMP_CMD_PAIRING_RSP; - memcpy(&smp->prsp[1], &rsp, sizeof(rsp)); + conn->prsp[0] = SMP_CMD_PAIRING_RSP; + memcpy(&conn->prsp[1], &rsp, sizeof(rsp)); smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp); + mod_timer(&conn->security_timer, jiffies + + msecs_to_jiffies(SMP_TIMEOUT)); + return 0; } 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_chan *smp = conn->smp_chan; - struct hci_dev *hdev = conn->hcon->hdev; - u8 key_size; + struct smp_cmd_pairing_confirm cp; + struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm; int ret; + u8 res[16], key_size; BT_DBG("conn %p", conn); skb_pull(skb, sizeof(*rsp)); - req = (void *) &smp->preq[1]; + req = (void *) &conn->preq[1]; key_size = min(req->max_key_size, rsp->max_key_size); if (check_enc_key_size(conn, key_size)) @@ -447,154 +295,222 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) return SMP_OOB_NOT_AVAIL; /* Just works */ - memset(smp->tk, 0, sizeof(smp->tk)); + memset(conn->tk, 0, sizeof(conn->tk)); + + conn->prsp[0] = SMP_CMD_PAIRING_RSP; + memcpy(&conn->prsp[1], rsp, sizeof(*rsp)); + + ret = smp_rand(conn->prnd); + if (ret) + return SMP_UNSPECIFIED; - ret = smp_rand(smp->prnd); + ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp, 0, + conn->src, conn->hcon->dst_type, conn->dst, res); if (ret) return SMP_UNSPECIFIED; - smp->prsp[0] = SMP_CMD_PAIRING_RSP; - memcpy(&smp->prsp[1], rsp, sizeof(*rsp)); + swap128(res, cp.confirm_val); - queue_work(hdev->workqueue, &smp->confirm); + smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp); return 0; } static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb) { - struct smp_chan *smp = conn->smp_chan; - struct hci_dev *hdev = conn->hcon->hdev; + struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm; BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); - memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf)); - skb_pull(skb, sizeof(smp->pcnf)); + memcpy(conn->pcnf, skb->data, sizeof(conn->pcnf)); + skb_pull(skb, sizeof(conn->pcnf)); if (conn->hcon->out) { u8 random[16]; - swap128(smp->prnd, random); + swap128(conn->prnd, random); smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(random), random); } else { - queue_work(hdev->workqueue, &smp->confirm); + struct smp_cmd_pairing_confirm cp; + int ret; + u8 res[16]; + + ret = smp_rand(conn->prnd); + if (ret) + return SMP_UNSPECIFIED; + + ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp, + conn->hcon->dst_type, conn->dst, + 0, conn->src, res); + if (ret) + return SMP_CONFIRM_FAILED; + + swap128(res, cp.confirm_val); + + smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp); } + mod_timer(&conn->security_timer, jiffies + + msecs_to_jiffies(SMP_TIMEOUT)); + return 0; } static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) { - struct smp_chan *smp = conn->smp_chan; - struct hci_dev *hdev = conn->hcon->hdev; + struct hci_conn *hcon = conn->hcon; + struct crypto_blkcipher *tfm = hcon->hdev->tfm; + int ret; + u8 key[16], res[16], random[16], confirm[16]; - BT_DBG("conn %p", conn); + swap128(skb->data, random); + skb_pull(skb, sizeof(random)); - swap128(skb->data, smp->rrnd); - skb_pull(skb, sizeof(smp->rrnd)); + if (conn->hcon->out) + ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp, 0, + conn->src, conn->hcon->dst_type, conn->dst, + res); + else + ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp, + conn->hcon->dst_type, conn->dst, 0, conn->src, + res); + if (ret) + return SMP_UNSPECIFIED; - queue_work(hdev->workqueue, &smp->random); + BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); - return 0; -} + swap128(res, confirm); -static u8 smp_ltk_encrypt(struct l2cap_conn *conn) -{ - struct link_key *key; - struct key_master_id *master; - struct hci_conn *hcon = conn->hcon; + if (memcmp(conn->pcnf, confirm, sizeof(conn->pcnf)) != 0) { + BT_ERR("Pairing failed (confirmation values mismatch)"); + return SMP_CONFIRM_FAILED; + } - key = hci_find_link_key_type(hcon->hdev, conn->dst, - HCI_LK_SMP_LTK); - if (!key) - return 0; + if (conn->hcon->out) { + u8 stk[16], rand[8]; + __le16 ediv; - if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, - &hcon->pend)) - return 1; + memset(rand, 0, sizeof(rand)); + ediv = 0; + + smp_s1(tfm, conn->tk, random, conn->prnd, key); + swap128(key, stk); - master = (void *) key->data; - hci_le_start_enc(hcon, master->ediv, master->rand, - key->val); - hcon->enc_key_size = key->pin_len; + memset(stk + conn->smp_key_size, 0, + SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size); - return 1; + 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)); + ediv = 0; + + swap128(conn->prnd, r); + smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r); + + smp_s1(tfm, conn->tk, conn->prnd, random, key); + swap128(key, stk); + + memset(stk + conn->smp_key_size, 0, + 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; } + static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_security_req *rp = (void *) skb->data; struct smp_cmd_pairing cp; struct hci_conn *hcon = conn->hcon; - struct smp_chan *smp; BT_DBG("conn %p", conn); - hcon->pending_sec_level = BT_SECURITY_MEDIUM; - - if (smp_ltk_encrypt(conn)) + if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) return 0; - if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) - return 0; - - smp = smp_chan_create(conn); - skb_pull(skb, sizeof(*rp)); memset(&cp, 0, sizeof(cp)); build_pairing_cmd(conn, &cp, NULL, rp->auth_req); - smp->preq[0] = SMP_CMD_PAIRING_REQ; - memcpy(&smp->preq[1], &cp, sizeof(cp)); + conn->preq[0] = SMP_CMD_PAIRING_REQ; + memcpy(&conn->preq[1], &cp, sizeof(cp)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); + mod_timer(&conn->security_timer, jiffies + + msecs_to_jiffies(SMP_TIMEOUT)); + + set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); + return 0; } int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) { struct hci_conn *hcon = conn->hcon; - struct smp_chan *smp = conn->smp_chan; + __u8 authreq; 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)) + return 1; + + if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) + return 0; + if (sec_level == BT_SECURITY_LOW) return 1; if (hcon->sec_level >= sec_level) return 1; - if (hcon->link_mode & HCI_LM_MASTER) - if (smp_ltk_encrypt(conn)) - goto done; - - if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) - return 0; - - smp = smp_chan_create(conn); + authreq = seclevel_to_authreq(sec_level); if (hcon->link_mode & HCI_LM_MASTER) { struct smp_cmd_pairing cp; + struct link_key *key; - build_pairing_cmd(conn, &cp, NULL, SMP_AUTH_NONE); - smp->preq[0] = SMP_CMD_PAIRING_REQ; - memcpy(&smp->preq[1], &cp, sizeof(cp)); + 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; + memcpy(&conn->preq[1], &cp, sizeof(cp)); + + mod_timer(&conn->security_timer, jiffies + + msecs_to_jiffies(SMP_TIMEOUT)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); } else { 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); } done: hcon->pending_sec_level = sec_level; + set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); return 0; } @@ -602,11 +518,10 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_encrypt_info *rp = (void *) skb->data; - struct smp_chan *smp = conn->smp_chan; skb_pull(skb, sizeof(*rp)); - memcpy(smp->tk, rp->ltk, sizeof(smp->tk)); + memcpy(conn->tk, rp->ltk, sizeof(conn->tk)); return 0; } @@ -614,12 +529,11 @@ static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb) static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_master_ident *rp = (void *) skb->data; - struct smp_chan *smp = conn->smp_chan; skb_pull(skb, sizeof(*rp)); - hci_add_ltk(conn->hcon->hdev, 1, conn->src, smp->smp_key_size, - rp->ediv, rp->rand, smp->tk); + hci_add_ltk(conn->hcon->hdev, 1, conn->src, conn->smp_key_size, + rp->ediv, rp->rand, conn->tk); smp_distribute_keys(conn, 1); @@ -638,6 +552,12 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) goto done; } + if (IS_ERR(conn->hcon->hdev->tfm)) { + err = PTR_ERR(conn->hcon->hdev->tfm); + reason = SMP_PAIRING_NOTSUPP; + goto done; + } + skb_pull(skb, sizeof(code)); switch (code) { @@ -701,21 +621,20 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) { struct smp_cmd_pairing *req, *rsp; - struct smp_chan *smp = conn->smp_chan; __u8 *keydist; BT_DBG("conn %p force %d", conn, force); - if (!test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend)) - return 0; + if (IS_ERR(conn->hcon->hdev->tfm)) + return PTR_ERR(conn->hcon->hdev->tfm); - rsp = (void *) &smp->prsp[1]; + 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 *) &smp->preq[1]; + req = (void *) &conn->preq[1]; if (conn->hcon->out) { keydist = &rsp->init_key_dist; @@ -739,7 +658,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc); - hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->smp_key_size, + hci_add_ltk(conn->hcon->hdev, 1, conn->dst, conn->smp_key_size, ediv, ident.rand, enc.ltk); ident.ediv = cpu_to_le16(ediv); @@ -779,11 +698,5 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) *keydist &= ~SMP_DIST_SIGN; } - if (conn->hcon->out || force) { - clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend); - del_timer(&conn->security_timer); - smp_chan_destroy(conn); - } - return 0; }