diff options
author | Johan Hedberg <johan.hedberg@nokia.com> | 2011-01-17 07:41:05 -0500 |
---|---|---|
committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-02-07 22:40:07 -0500 |
commit | 55ed8ca10f3530de8edbbf138acb50992bf5005b (patch) | |
tree | 3145b2b995758b2cb64493fc8ec29e63d0e9f0b4 /net/bluetooth/hci_core.c | |
parent | 1aff6f09491f454d4cd9f405c783fa5e9d3168a0 (diff) |
Bluetooth: Implement link key handling for the management interface
This patch adds a management commands to feed the kernel with all stored
link keys as well as remove specific ones or all of them. Once the
load_keys command has been called the kernel takes over link key
replies. A new_key event is also added to inform userspace of newly
created link keys that should be stored permanently.
Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Diffstat (limited to 'net/bluetooth/hci_core.c')
-rw-r--r-- | net/bluetooth/hci_core.c | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 748f5a65caf4..8ca8cf147058 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -970,6 +970,88 @@ int hci_uuids_clear(struct hci_dev *hdev) | |||
970 | return 0; | 970 | return 0; |
971 | } | 971 | } |
972 | 972 | ||
973 | int hci_link_keys_clear(struct hci_dev *hdev) | ||
974 | { | ||
975 | struct list_head *p, *n; | ||
976 | |||
977 | list_for_each_safe(p, n, &hdev->link_keys) { | ||
978 | struct link_key *key; | ||
979 | |||
980 | key = list_entry(p, struct link_key, list); | ||
981 | |||
982 | list_del(p); | ||
983 | kfree(key); | ||
984 | } | ||
985 | |||
986 | return 0; | ||
987 | } | ||
988 | |||
989 | struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) | ||
990 | { | ||
991 | struct list_head *p; | ||
992 | |||
993 | list_for_each(p, &hdev->link_keys) { | ||
994 | struct link_key *k; | ||
995 | |||
996 | k = list_entry(p, struct link_key, list); | ||
997 | |||
998 | if (bacmp(bdaddr, &k->bdaddr) == 0) | ||
999 | return k; | ||
1000 | } | ||
1001 | |||
1002 | return NULL; | ||
1003 | } | ||
1004 | |||
1005 | int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, | ||
1006 | u8 *val, u8 type, u8 pin_len) | ||
1007 | { | ||
1008 | struct link_key *key, *old_key; | ||
1009 | u8 old_key_type; | ||
1010 | |||
1011 | old_key = hci_find_link_key(hdev, bdaddr); | ||
1012 | if (old_key) { | ||
1013 | old_key_type = old_key->type; | ||
1014 | key = old_key; | ||
1015 | } else { | ||
1016 | old_key_type = 0xff; | ||
1017 | key = kzalloc(sizeof(*key), GFP_ATOMIC); | ||
1018 | if (!key) | ||
1019 | return -ENOMEM; | ||
1020 | list_add(&key->list, &hdev->link_keys); | ||
1021 | } | ||
1022 | |||
1023 | BT_DBG("%s key for %s type %u", hdev->name, batostr(bdaddr), type); | ||
1024 | |||
1025 | bacpy(&key->bdaddr, bdaddr); | ||
1026 | memcpy(key->val, val, 16); | ||
1027 | key->type = type; | ||
1028 | key->pin_len = pin_len; | ||
1029 | |||
1030 | if (new_key) | ||
1031 | mgmt_new_key(hdev->id, key, old_key_type); | ||
1032 | |||
1033 | if (type == 0x06) | ||
1034 | key->type = old_key_type; | ||
1035 | |||
1036 | return 0; | ||
1037 | } | ||
1038 | |||
1039 | int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) | ||
1040 | { | ||
1041 | struct link_key *key; | ||
1042 | |||
1043 | key = hci_find_link_key(hdev, bdaddr); | ||
1044 | if (!key) | ||
1045 | return -ENOENT; | ||
1046 | |||
1047 | BT_DBG("%s removing %s", hdev->name, batostr(bdaddr)); | ||
1048 | |||
1049 | list_del(&key->list); | ||
1050 | kfree(key); | ||
1051 | |||
1052 | return 0; | ||
1053 | } | ||
1054 | |||
973 | /* Register HCI device */ | 1055 | /* Register HCI device */ |
974 | int hci_register_dev(struct hci_dev *hdev) | 1056 | int hci_register_dev(struct hci_dev *hdev) |
975 | { | 1057 | { |
@@ -1029,6 +1111,8 @@ int hci_register_dev(struct hci_dev *hdev) | |||
1029 | 1111 | ||
1030 | INIT_LIST_HEAD(&hdev->uuids); | 1112 | INIT_LIST_HEAD(&hdev->uuids); |
1031 | 1113 | ||
1114 | INIT_LIST_HEAD(&hdev->link_keys); | ||
1115 | |||
1032 | INIT_WORK(&hdev->power_on, hci_power_on); | 1116 | INIT_WORK(&hdev->power_on, hci_power_on); |
1033 | INIT_WORK(&hdev->power_off, hci_power_off); | 1117 | INIT_WORK(&hdev->power_off, hci_power_off); |
1034 | setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev); | 1118 | setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev); |
@@ -1105,6 +1189,7 @@ int hci_unregister_dev(struct hci_dev *hdev) | |||
1105 | hci_dev_lock_bh(hdev); | 1189 | hci_dev_lock_bh(hdev); |
1106 | hci_blacklist_clear(hdev); | 1190 | hci_blacklist_clear(hdev); |
1107 | hci_uuids_clear(hdev); | 1191 | hci_uuids_clear(hdev); |
1192 | hci_link_keys_clear(hdev); | ||
1108 | hci_dev_unlock_bh(hdev); | 1193 | hci_dev_unlock_bh(hdev); |
1109 | 1194 | ||
1110 | __hci_dev_put(hdev); | 1195 | __hci_dev_put(hdev); |