device: Set disconnect timer to zero for fast disconnection
[platform/upstream/bluez.git] / monitor / keys.c
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 /*
3  *
4  *  BlueZ - Bluetooth protocol stack for Linux
5  *
6  *  Copyright (C) 2011-2014  Intel Corporation
7  *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
8  *
9  *
10  */
11
12 #ifdef HAVE_CONFIG_H
13 #include <config.h>
14 #endif
15
16 #include <string.h>
17
18 #include "src/shared/util.h"
19 #include "src/shared/queue.h"
20 #include "src/shared/crypto.h"
21
22 #include "keys.h"
23
24 static const uint8_t empty_key[16] = { 0x00, };
25 static const uint8_t empty_addr[6] = { 0x00, };
26
27 static struct bt_crypto *crypto;
28
29 struct irk_data {
30         uint8_t key[16];
31         uint8_t addr[6];
32         uint8_t addr_type;
33 };
34
35 static struct queue *irk_list;
36
37 void keys_setup(void)
38 {
39         crypto = bt_crypto_new();
40
41         irk_list = queue_new();
42 }
43
44 void keys_cleanup(void)
45 {
46         bt_crypto_unref(crypto);
47
48         queue_destroy(irk_list, free);
49 }
50
51 void keys_update_identity_key(const uint8_t key[16])
52 {
53         struct irk_data *irk;
54
55         irk = queue_peek_tail(irk_list);
56         if (irk && !memcmp(irk->key, empty_key, 16)) {
57                 memcpy(irk->key, key, 16);
58                 return;
59         }
60
61         irk = new0(struct irk_data, 1);
62         if (irk) {
63                 memcpy(irk->key, key, 16);
64                 if (!queue_push_tail(irk_list, irk))
65                         free(irk);
66         }
67 }
68
69 void keys_update_identity_addr(const uint8_t addr[6], uint8_t addr_type)
70 {
71         struct irk_data *irk;
72
73         irk = queue_peek_tail(irk_list);
74         if (irk && !memcmp(irk->addr, empty_addr, 6)) {
75                 memcpy(irk->addr, addr, 6);
76                 irk->addr_type = addr_type;
77                 return;
78         }
79
80         irk = new0(struct irk_data, 1);
81         if (irk) {
82                 memcpy(irk->addr, addr, 6);
83                 irk->addr_type = addr_type;
84                 if (!queue_push_tail(irk_list, irk))
85                         free(irk);
86         }
87 }
88
89 static bool match_resolve_irk(const void *data, const void *match_data)
90 {
91         const struct irk_data *irk = data;
92         const uint8_t *addr = match_data;
93         uint8_t local_hash[3];
94
95         bt_crypto_ah(crypto, irk->key, addr + 3, local_hash);
96
97         return !memcmp(addr, local_hash, 3);
98 }
99
100 bool keys_resolve_identity(const uint8_t addr[6], uint8_t ident[6],
101                                                         uint8_t *ident_type)
102 {
103         struct irk_data *irk;
104
105         irk = queue_find(irk_list, match_resolve_irk, addr);
106
107         if (irk) {
108                 memcpy(ident, irk->addr, 6);
109                 *ident_type = irk->addr_type;
110                 return true;
111         }
112
113         return false;
114 }
115
116 static bool match_key(const void *data, const void *match_data)
117 {
118         const struct irk_data *irk = data;
119         const uint8_t *key = match_data;
120
121         return !memcmp(irk->key, key, 16);
122 }
123
124 bool keys_add_identity(const uint8_t addr[6], uint8_t addr_type,
125                                         const uint8_t key[16])
126 {
127         struct irk_data *irk;
128
129         irk = queue_find(irk_list, match_key, key);
130         if (!irk) {
131                 irk = new0(struct irk_data, 1);
132                 memcpy(irk->key, key, 16);
133                 queue_push_tail(irk_list, irk);
134         }
135
136         memcpy(irk->addr, addr, 6);
137         irk->addr_type = addr_type;
138
139         return true;
140 }