diff options
author | John W. Linville <linville@tuxdriver.com> | 2011-05-05 13:32:35 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-05-05 13:32:35 -0400 |
commit | a70171dce9cd44cb06c7d299eba9fa87a8933045 (patch) | |
tree | 5425df5f33fadc617c7dec99578d06f0d933578e /net/bluetooth/hci_core.c | |
parent | 5a412ad7f4c95bb5b756aa12b52646e857e7c75d (diff) | |
parent | eaef6a93bd52a2cc47b9fce201310010707afdb4 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6 into for-davem
Conflicts:
drivers/net/wireless/libertas/if_cs.c
drivers/net/wireless/rtlwifi/pci.c
net/bluetooth/l2cap_sock.c
Diffstat (limited to 'net/bluetooth/hci_core.c')
-rw-r--r-- | net/bluetooth/hci_core.c | 75 |
1 files changed, 66 insertions, 9 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index e057d123599..815269b07f2 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -1020,18 +1020,54 @@ struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) | |||
1020 | return NULL; | 1020 | return NULL; |
1021 | } | 1021 | } |
1022 | 1022 | ||
1023 | int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, | 1023 | static int hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn, |
1024 | u8 *val, u8 type, u8 pin_len) | 1024 | u8 key_type, u8 old_key_type) |
1025 | { | ||
1026 | /* Legacy key */ | ||
1027 | if (key_type < 0x03) | ||
1028 | return 1; | ||
1029 | |||
1030 | /* Debug keys are insecure so don't store them persistently */ | ||
1031 | if (key_type == HCI_LK_DEBUG_COMBINATION) | ||
1032 | return 0; | ||
1033 | |||
1034 | /* Changed combination key and there's no previous one */ | ||
1035 | if (key_type == HCI_LK_CHANGED_COMBINATION && old_key_type == 0xff) | ||
1036 | return 0; | ||
1037 | |||
1038 | /* Security mode 3 case */ | ||
1039 | if (!conn) | ||
1040 | return 1; | ||
1041 | |||
1042 | /* Neither local nor remote side had no-bonding as requirement */ | ||
1043 | if (conn->auth_type > 0x01 && conn->remote_auth > 0x01) | ||
1044 | return 1; | ||
1045 | |||
1046 | /* Local side had dedicated bonding as requirement */ | ||
1047 | if (conn->auth_type == 0x02 || conn->auth_type == 0x03) | ||
1048 | return 1; | ||
1049 | |||
1050 | /* Remote side had dedicated bonding as requirement */ | ||
1051 | if (conn->remote_auth == 0x02 || conn->remote_auth == 0x03) | ||
1052 | return 1; | ||
1053 | |||
1054 | /* If none of the above criteria match, then don't store the key | ||
1055 | * persistently */ | ||
1056 | return 0; | ||
1057 | } | ||
1058 | |||
1059 | int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, | ||
1060 | bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len) | ||
1025 | { | 1061 | { |
1026 | struct link_key *key, *old_key; | 1062 | struct link_key *key, *old_key; |
1027 | u8 old_key_type; | 1063 | u8 old_key_type, persistent; |
1028 | 1064 | ||
1029 | old_key = hci_find_link_key(hdev, bdaddr); | 1065 | old_key = hci_find_link_key(hdev, bdaddr); |
1030 | if (old_key) { | 1066 | if (old_key) { |
1031 | old_key_type = old_key->type; | 1067 | old_key_type = old_key->type; |
1032 | key = old_key; | 1068 | key = old_key; |
1033 | } else { | 1069 | } else { |
1034 | old_key_type = 0xff; | 1070 | old_key_type = conn ? conn->key_type : 0xff; |
1035 | key = kzalloc(sizeof(*key), GFP_ATOMIC); | 1071 | key = kzalloc(sizeof(*key), GFP_ATOMIC); |
1036 | if (!key) | 1072 | if (!key) |
1037 | return -ENOMEM; | 1073 | return -ENOMEM; |
@@ -1040,16 +1076,37 @@ int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, | |||
1040 | 1076 | ||
1041 | BT_DBG("%s key for %s type %u", hdev->name, batostr(bdaddr), type); | 1077 | BT_DBG("%s key for %s type %u", hdev->name, batostr(bdaddr), type); |
1042 | 1078 | ||
1079 | /* Some buggy controller combinations generate a changed | ||
1080 | * combination key for legacy pairing even when there's no | ||
1081 | * previous key */ | ||
1082 | if (type == HCI_LK_CHANGED_COMBINATION && | ||
1083 | (!conn || conn->remote_auth == 0xff) && | ||
1084 | old_key_type == 0xff) { | ||
1085 | type = HCI_LK_COMBINATION; | ||
1086 | if (conn) | ||
1087 | conn->key_type = type; | ||
1088 | } | ||
1089 | |||
1043 | bacpy(&key->bdaddr, bdaddr); | 1090 | bacpy(&key->bdaddr, bdaddr); |
1044 | memcpy(key->val, val, 16); | 1091 | memcpy(key->val, val, 16); |
1045 | key->type = type; | ||
1046 | key->pin_len = pin_len; | 1092 | key->pin_len = pin_len; |
1047 | 1093 | ||
1048 | if (new_key) | 1094 | if (type == HCI_LK_CHANGED_COMBINATION) |
1049 | mgmt_new_key(hdev->id, key, old_key_type); | ||
1050 | |||
1051 | if (type == 0x06) | ||
1052 | key->type = old_key_type; | 1095 | key->type = old_key_type; |
1096 | else | ||
1097 | key->type = type; | ||
1098 | |||
1099 | if (!new_key) | ||
1100 | return 0; | ||
1101 | |||
1102 | persistent = hci_persistent_key(hdev, conn, type, old_key_type); | ||
1103 | |||
1104 | mgmt_new_key(hdev->id, key, persistent); | ||
1105 | |||
1106 | if (!persistent) { | ||
1107 | list_del(&key->list); | ||
1108 | kfree(key); | ||
1109 | } | ||
1053 | 1110 | ||
1054 | return 0; | 1111 | return 0; |
1055 | } | 1112 | } |