Skip to content

Commit 55ed8ca

Browse files
Johan HedbergGustavo F. Padovan
authored andcommitted
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 <[email protected]> Signed-off-by: Gustavo F. Padovan <[email protected]>
1 parent 1aff6f0 commit 55ed8ca

File tree

6 files changed

+300
-0
lines changed

6 files changed

+300
-0
lines changed

include/net/bluetooth/hci.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ enum {
8282
HCI_MGMT,
8383
HCI_PAIRABLE,
8484
HCI_SERVICE_CACHE,
85+
HCI_LINK_KEYS,
86+
HCI_DEBUG_KEYS,
8587
};
8688

8789
/* HCI ioctl defines */

include/net/bluetooth/hci_core.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,14 @@ struct bt_uuid {
7373
u8 svc_hint;
7474
};
7575

76+
struct link_key {
77+
struct list_head list;
78+
bdaddr_t bdaddr;
79+
u8 type;
80+
u8 val[16];
81+
u8 pin_len;
82+
};
83+
7684
#define NUM_REASSEMBLY 4
7785
struct hci_dev {
7886
struct list_head list;
@@ -153,6 +161,8 @@ struct hci_dev {
153161

154162
struct list_head uuids;
155163

164+
struct list_head link_keys;
165+
156166
struct hci_dev_stats stat;
157167

158168
struct sk_buff_head driver_init;
@@ -461,6 +471,12 @@ int hci_blacklist_clear(struct hci_dev *hdev);
461471

462472
int hci_uuids_clear(struct hci_dev *hdev);
463473

474+
int hci_link_keys_clear(struct hci_dev *hdev);
475+
struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
476+
int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
477+
u8 *key, u8 type, u8 pin_len);
478+
int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
479+
464480
void hci_del_off_timer(struct hci_dev *hdev);
465481

466482
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
@@ -697,6 +713,7 @@ int mgmt_index_removed(u16 index);
697713
int mgmt_powered(u16 index, u8 powered);
698714
int mgmt_discoverable(u16 index, u8 discoverable);
699715
int mgmt_connectable(u16 index, u8 connectable);
716+
int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type);
700717

701718
/* HCI info for socket */
702719
#define hci_pi(sk) ((struct hci_pinfo *) sk)

include/net/bluetooth/mgmt.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,28 @@ struct mgmt_cp_set_service_cache {
9898
__u8 enable;
9999
} __packed;
100100

101+
struct mgmt_key_info {
102+
bdaddr_t bdaddr;
103+
u8 type;
104+
u8 val[16];
105+
u8 pin_len;
106+
} __packed;
107+
108+
#define MGMT_OP_LOAD_KEYS 0x000D
109+
struct mgmt_cp_load_keys {
110+
__le16 index;
111+
__u8 debug_keys;
112+
__le16 key_count;
113+
struct mgmt_key_info keys[0];
114+
} __packed;
115+
116+
#define MGMT_OP_REMOVE_KEY 0x000E
117+
struct mgmt_cp_remove_key {
118+
__le16 index;
119+
bdaddr_t bdaddr;
120+
__u8 disconnect;
121+
} __packed;
122+
101123
#define MGMT_EV_CMD_COMPLETE 0x0001
102124
struct mgmt_ev_cmd_complete {
103125
__le16 opcode;
@@ -133,3 +155,10 @@ struct mgmt_ev_index_removed {
133155
#define MGMT_EV_CONNECTABLE 0x0008
134156

135157
#define MGMT_EV_PAIRABLE 0x0009
158+
159+
#define MGMT_EV_NEW_KEY 0x000A
160+
struct mgmt_ev_new_key {
161+
__le16 index;
162+
struct mgmt_key_info key;
163+
__u8 old_key_type;
164+
} __packed;

net/bluetooth/hci_core.c

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -970,6 +970,88 @@ int hci_uuids_clear(struct hci_dev *hdev)
970970
return 0;
971971
}
972972

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+
9731055
/* Register HCI device */
9741056
int hci_register_dev(struct hci_dev *hdev)
9751057
{
@@ -1029,6 +1111,8 @@ int hci_register_dev(struct hci_dev *hdev)
10291111

10301112
INIT_LIST_HEAD(&hdev->uuids);
10311113

1114+
INIT_LIST_HEAD(&hdev->link_keys);
1115+
10321116
INIT_WORK(&hdev->power_on, hci_power_on);
10331117
INIT_WORK(&hdev->power_off, hci_power_off);
10341118
setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev);
@@ -1105,6 +1189,7 @@ int hci_unregister_dev(struct hci_dev *hdev)
11051189
hci_dev_lock_bh(hdev);
11061190
hci_blacklist_clear(hdev);
11071191
hci_uuids_clear(hdev);
1192+
hci_link_keys_clear(hdev);
11081193
hci_dev_unlock_bh(hdev);
11091194

11101195
__hci_dev_put(hdev);

net/bluetooth/hci_event.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1810,13 +1810,60 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff
18101810

18111811
static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
18121812
{
1813+
struct hci_ev_link_key_req *ev = (void *) skb->data;
1814+
struct hci_cp_link_key_reply cp;
1815+
struct hci_conn *conn;
1816+
struct link_key *key;
1817+
18131818
BT_DBG("%s", hdev->name);
1819+
1820+
if (!test_bit(HCI_LINK_KEYS, &hdev->flags))
1821+
return;
1822+
1823+
hci_dev_lock(hdev);
1824+
1825+
key = hci_find_link_key(hdev, &ev->bdaddr);
1826+
if (!key) {
1827+
BT_DBG("%s link key not found for %s", hdev->name,
1828+
batostr(&ev->bdaddr));
1829+
goto not_found;
1830+
}
1831+
1832+
BT_DBG("%s found key type %u for %s", hdev->name, key->type,
1833+
batostr(&ev->bdaddr));
1834+
1835+
if (!test_bit(HCI_DEBUG_KEYS, &hdev->flags) && key->type == 0x03) {
1836+
BT_DBG("%s ignoring debug key", hdev->name);
1837+
goto not_found;
1838+
}
1839+
1840+
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
1841+
1842+
if (key->type == 0x04 && conn && conn->auth_type != 0xff &&
1843+
(conn->auth_type & 0x01)) {
1844+
BT_DBG("%s ignoring unauthenticated key", hdev->name);
1845+
goto not_found;
1846+
}
1847+
1848+
bacpy(&cp.bdaddr, &ev->bdaddr);
1849+
memcpy(cp.link_key, key->val, 16);
1850+
1851+
hci_send_cmd(hdev, HCI_OP_LINK_KEY_REPLY, sizeof(cp), &cp);
1852+
1853+
hci_dev_unlock(hdev);
1854+
1855+
return;
1856+
1857+
not_found:
1858+
hci_send_cmd(hdev, HCI_OP_LINK_KEY_NEG_REPLY, 6, &ev->bdaddr);
1859+
hci_dev_unlock(hdev);
18141860
}
18151861

18161862
static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
18171863
{
18181864
struct hci_ev_link_key_notify *ev = (void *) skb->data;
18191865
struct hci_conn *conn;
1866+
u8 pin_len = 0;
18201867

18211868
BT_DBG("%s", hdev->name);
18221869

@@ -1829,6 +1876,10 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff
18291876
hci_conn_put(conn);
18301877
}
18311878

1879+
if (test_bit(HCI_LINK_KEYS, &hdev->flags))
1880+
hci_add_link_key(hdev, 1, &ev->bdaddr, ev->link_key,
1881+
ev->key_type, pin_len);
1882+
18321883
hci_dev_unlock(hdev);
18331884
}
18341885

0 commit comments

Comments
 (0)