|
@@ -1022,8 +1022,44 @@ struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
|
|
return NULL;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
-int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
|
|
|
|
- u8 *val, u8 type, u8 pin_len)
|
|
|
|
|
|
+static int hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn,
|
|
|
|
+ u8 key_type, u8 old_key_type)
|
|
|
|
+{
|
|
|
|
+ /* Legacy key */
|
|
|
|
+ if (key_type < 0x03)
|
|
|
|
+ return 1;
|
|
|
|
+
|
|
|
|
+ /* Debug keys are insecure so don't store them persistently */
|
|
|
|
+ if (key_type == HCI_LK_DEBUG_COMBINATION)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ /* Changed combination key and there's no previous one */
|
|
|
|
+ if (key_type == HCI_LK_CHANGED_COMBINATION && old_key_type == 0xff)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ /* Security mode 3 case */
|
|
|
|
+ if (!conn)
|
|
|
|
+ return 1;
|
|
|
|
+
|
|
|
|
+ /* Neither local nor remote side had no-bonding as requirement */
|
|
|
|
+ if (conn->auth_type > 0x01 && conn->remote_auth > 0x01)
|
|
|
|
+ return 1;
|
|
|
|
+
|
|
|
|
+ /* Local side had dedicated bonding as requirement */
|
|
|
|
+ if (conn->auth_type == 0x02 || conn->auth_type == 0x03)
|
|
|
|
+ return 1;
|
|
|
|
+
|
|
|
|
+ /* Remote side had dedicated bonding as requirement */
|
|
|
|
+ if (conn->remote_auth == 0x02 || conn->remote_auth == 0x03)
|
|
|
|
+ return 1;
|
|
|
|
+
|
|
|
|
+ /* If none of the above criteria match, then don't store the key
|
|
|
|
+ * persistently */
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+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)
|
|
{
|
|
{
|
|
struct link_key *key, *old_key;
|
|
struct link_key *key, *old_key;
|
|
u8 old_key_type;
|
|
u8 old_key_type;
|
|
@@ -1042,6 +1078,20 @@ int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
|
|
|
|
|
|
BT_DBG("%s key for %s type %u", hdev->name, batostr(bdaddr), type);
|
|
BT_DBG("%s key for %s type %u", hdev->name, batostr(bdaddr), type);
|
|
|
|
|
|
|
|
+ /* Some buggy controller combinations generate a changed
|
|
|
|
+ * combination key for legacy pairing even when there's no
|
|
|
|
+ * previous key */
|
|
|
|
+ if (type == HCI_LK_CHANGED_COMBINATION &&
|
|
|
|
+ (!conn || conn->remote_auth == 0xff) &&
|
|
|
|
+ old_key_type == 0xff)
|
|
|
|
+ type = HCI_LK_COMBINATION;
|
|
|
|
+
|
|
|
|
+ if (new_key && !hci_persistent_key(hdev, conn, type, old_key_type)) {
|
|
|
|
+ list_del(&key->list);
|
|
|
|
+ kfree(key);
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
bacpy(&key->bdaddr, bdaddr);
|
|
bacpy(&key->bdaddr, bdaddr);
|
|
memcpy(key->val, val, 16);
|
|
memcpy(key->val, val, 16);
|
|
key->type = type;
|
|
key->type = type;
|