3
* BlueZ - Bluetooth protocol stack for Linux
5
* Copyright (C) 2012-2014 Intel Corporation. All rights reserved.
8
* This library is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU Lesser General Public
10
* License as published by the Free Software Foundation; either
11
* version 2.1 of the License, or (at your option) any later version.
13
* This library is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* Lesser General Public License for more details.
18
* You should have received a copy of the GNU Lesser General Public
19
* License along with this library; if not, write to the Free Software
20
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
31
#include "lib/bluetooth.h"
34
#include "src/shared/util.h"
35
#include "src/shared/queue.h"
36
#include "src/shared/mgmt.h"
37
#include "src/shared/gap.h"
39
#define FLAG_MGMT_CONN_CONTROL (0 << 1)
47
uint16_t mgmt_revision;
52
bt_gap_ready_func_t ready_handler;
53
bt_gap_destroy_func_t ready_destroy;
56
uint8_t static_addr[6];
57
uint8_t local_irk[16];
58
struct queue *irk_list;
67
static void irk_entry_free(void *data)
69
struct irk_entry *irk = data;
74
static void ready_status(struct bt_gap *gap, bool status)
76
gap->mgmt_ready = status;
78
if (gap->ready_handler)
79
gap->ready_handler(status, gap->ready_data);
82
static void read_commands_complete(uint8_t status, uint16_t length,
83
const void *param, void *user_data)
85
struct bt_gap *gap = user_data;
86
const struct mgmt_rp_read_commands *rp = param;
87
uint16_t num_commands, num_events;
88
const uint16_t *opcode;
92
if (status != MGMT_STATUS_SUCCESS) {
93
ready_status(gap, false);
97
if (length < sizeof(*rp)) {
98
ready_status(gap, false);
102
num_commands = le16_to_cpu(rp->num_commands);
103
num_events = le16_to_cpu(rp->num_events);
105
expected_len = sizeof(*rp) + num_commands * sizeof(uint16_t) +
106
num_events * sizeof(uint16_t);
108
if (length < expected_len) {
109
ready_status(gap, false);
113
opcode = rp->opcodes;
115
for (i = 0; i < num_commands; i++) {
116
uint16_t op = get_le16(opcode++);
118
if (op == MGMT_OP_ADD_DEVICE)
119
gap->flags |= FLAG_MGMT_CONN_CONTROL;
122
ready_status(gap, true);
125
static void read_version_complete(uint8_t status, uint16_t length,
126
const void *param, void *user_data)
128
struct bt_gap *gap = user_data;
129
const struct mgmt_rp_read_version *rp = param;
131
if (status != MGMT_STATUS_SUCCESS) {
132
ready_status(gap, false);
136
if (length < sizeof(*rp)) {
137
ready_status(gap, false);
141
gap->mgmt_version = rp->version;
142
gap->mgmt_revision = le16_to_cpu(rp->revision);
144
if (!mgmt_send(gap->mgmt, MGMT_OP_READ_COMMANDS,
145
MGMT_INDEX_NONE, 0, NULL,
146
read_commands_complete, gap, NULL)) {
147
ready_status(gap, false);
152
struct bt_gap *bt_gap_new_default(void)
154
return bt_gap_new_index(0x0000);
157
struct bt_gap *bt_gap_new_index(uint16_t index)
161
if (index == MGMT_INDEX_NONE)
164
gap = new0(struct bt_gap, 1);
170
gap->mgmt = mgmt_new_default();
176
gap->irk_list = queue_new();
178
gap->mgmt_ready = false;
180
if (!mgmt_send(gap->mgmt, MGMT_OP_READ_VERSION,
181
MGMT_INDEX_NONE, 0, NULL,
182
read_version_complete, gap, NULL)) {
183
mgmt_unref(gap->mgmt);
187
return bt_gap_ref(gap);
190
struct bt_gap *bt_gap_ref(struct bt_gap *gap)
195
__sync_fetch_and_add(&gap->ref_count, 1);
200
void bt_gap_unref(struct bt_gap *gap)
205
if (__sync_sub_and_fetch(&gap->ref_count, 1))
208
gap->mgmt_ready = false;
210
mgmt_cancel_all(gap->mgmt);
211
mgmt_unregister_all(gap->mgmt);
213
if (gap->ready_destroy)
214
gap->ready_destroy(gap->ready_data);
216
queue_destroy(gap->irk_list, irk_entry_free);
218
mgmt_unref(gap->mgmt);
223
bool bt_gap_set_ready_handler(struct bt_gap *gap,
224
bt_gap_ready_func_t handler, void *user_data,
225
bt_gap_destroy_func_t destroy)
230
if (gap->ready_destroy)
231
gap->ready_destroy(gap->ready_data);
233
gap->ready_handler = handler;
234
gap->ready_destroy = destroy;
235
gap->ready_data = user_data;
240
bool bt_gap_set_static_addr(struct bt_gap *gap, uint8_t addr[6])
245
memcpy(gap->static_addr, addr, 6);
250
bool bt_gap_set_local_irk(struct bt_gap *gap, uint8_t key[16])
255
memcpy(gap->local_irk, key, 16);
260
bool bt_gap_add_peer_irk(struct bt_gap *gap, uint8_t addr_type,
261
uint8_t addr[6], uint8_t key[16])
263
struct irk_entry *irk;
268
if (addr_type > BT_GAP_ADDR_TYPE_LE_RANDOM)
271
irk = new0(struct irk_entry, 1);
275
irk->addr_type = addr_type;
276
memcpy(irk->addr, addr, 6);
277
memcpy(irk->key, key, 16);
279
if (!queue_push_tail(gap->irk_list, irk)) {