mgmt: add initial support for link key handling
diff --git a/doc/mgmt-api.txt b/doc/mgmt-api.txt
index d964a70..cb00bd2 100644
--- a/doc/mgmt-api.txt
+++ b/doc/mgmt-api.txt
@@ -154,6 +154,34 @@
Return Paramters: Controller_Index (2 Octets)
+Load Keys Command
+=================
+
+ Command Code: 0x000D
+ Command Parameters: Controller_Index (2 Octets)
+ Debug_Keys (1 Octet)
+ Key_Count (2 Octets)
+ Key1 {
+ Address (6 Octets)
+ Type (1 Octet)
+ Value (16 Octets)
+ PIN_Length (1 Octet)
+ }
+ Key2 { }
+ ...
+ Return Paramters: Controller_Index (2 Octets)
+
+
+Remove Key Command
+==================
+
+ Command Code: 0x000D
+ Command Parameters: Controller_Index (2 Octets)
+ Address (6 Octets)
+ Disconnect (1 Octet)
+ Return Paramters: Controller_Index (2 Octets)
+
+
Read Tracing Buffer Size Command
================================
@@ -269,3 +297,16 @@
Event Code 0x0009
Event Parameters Controller_Index (2 Octets)
Pairable (1 Octet)
+
+New Key Event
+=============
+
+Event Code 0x000A
+Event Parameters Controller_Index (2 Octets)
+ Key {
+ Address (6 Octets)
+ Type (1 Octet)
+ Value (16 Octets)
+ PIN_Length (1 Octet)
+ }
+ Old_Key_Type (1 Octet)
diff --git a/lib/mgmt.h b/lib/mgmt.h
index 6bdefab..bd4bd96 100644
--- a/lib/mgmt.h
+++ b/lib/mgmt.h
@@ -107,6 +107,28 @@
uint8_t enable;
} __packed;
+struct mgmt_key_info {
+ bdaddr_t bdaddr;
+ uint8_t type;
+ uint8_t val[16];
+ uint8_t pin_len;
+} __packed;
+
+#define MGMT_OP_LOAD_KEYS 0x000D
+struct mgmt_cp_load_keys {
+ uint16_t index;
+ uint8_t debug_keys;
+ uint16_t key_count;
+ struct mgmt_key_info keys[0];
+} __packed;
+
+#define MGMT_OP_REMOVE_KEY 0x000E
+struct mgmt_cp_remove_key {
+ uint16_t index;
+ bdaddr_t bdaddr;
+ uint8_t disconnect;
+} __packed;
+
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
uint16_t opcode;
@@ -142,3 +164,10 @@
#define MGMT_EV_CONNECTABLE 0x0008
#define MGMT_EV_PAIRABLE 0x0009
+
+#define MGMT_EV_NEW_KEY 0x000A
+struct mgmt_ev_new_key {
+ uint16_t index;
+ struct mgmt_key_info key;
+ uint8_t old_key_type;
+} __packed;
diff --git a/plugins/mgmtops.c b/plugins/mgmtops.c
index e33c049..c082586 100644
--- a/plugins/mgmtops.c
+++ b/plugins/mgmtops.c
@@ -400,6 +400,33 @@
btd_adapter_pairable_changed(adapter, info->pairable);
}
+static void mgmt_new_key(int sk, void *buf, size_t len)
+{
+ struct mgmt_ev_new_key *ev = buf;
+ struct controller_info *info;
+ uint16_t index;
+
+ if (len < sizeof(*ev)) {
+ error("Too small new_key event");
+ return;
+ }
+
+ index = btohs(bt_get_unaligned(&ev->index));
+
+ DBG("Controller %u new key of type %u", index, ev->key.type);
+
+ if (index > max_index) {
+ error("Unexpected index %u in new_key event", index);
+ return;
+ }
+
+ info = &controllers[index];
+
+ btd_event_link_key_notify(&info->bdaddr, &ev->key.bdaddr,
+ ev->key.val, ev->key.type,
+ ev->key.pin_len, ev->old_key_type);
+}
+
static void uuid_to_uuid128(uuid_t *uuid128, const uuid_t *uuid)
{
if (uuid->type == SDP_UUID16)
@@ -736,6 +763,12 @@
case MGMT_OP_SET_SERVICE_CACHE:
DBG("set_service_cache complete");
break;
+ case MGMT_OP_LOAD_KEYS:
+ DBG("load_keys complete");
+ break;
+ case MGMT_OP_REMOVE_KEY:
+ DBG("remove_key complete");
+ break;
default:
error("Unknown command complete for opcode %u", opcode);
break;
@@ -842,6 +875,9 @@
case MGMT_EV_PAIRABLE:
mgmt_pairable(sk, buf + MGMT_HDR_SIZE, len);
break;
+ case MGMT_EV_NEW_KEY:
+ mgmt_new_key(sk, buf + MGMT_HDR_SIZE, len);
+ break;
default:
error("Unknown Management opcode %u", opcode);
break;
@@ -1089,12 +1125,26 @@
static int mgmt_remove_bonding(int index, bdaddr_t *bdaddr)
{
+ char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_remove_key)];
+ struct mgmt_hdr *hdr = (void *) buf;
+ struct mgmt_cp_remove_key *cp = (void *) &buf[sizeof(*hdr)];
char addr[18];
ba2str(bdaddr, addr);
DBG("index %d addr %s", index, addr);
- return -ENOSYS;
+ memset(buf, 0, sizeof(buf));
+ hdr->opcode = htobs(MGMT_OP_REMOVE_KEY);
+ hdr->len = htobs(sizeof(*cp));
+
+ cp->index = htobs(index);
+ bacpy(&cp->bdaddr, bdaddr);
+ cp->disconnect = 1;
+
+ if (write(mgmt_sock, buf, sizeof(buf)) < 0)
+ return -errno;
+
+ return 0;
}
static int mgmt_request_authentication(int index, uint16_t handle)
@@ -1188,9 +1238,52 @@
static int mgmt_load_keys(int index, GSList *keys, gboolean debug_keys)
{
- DBG("index %d keys %d debug_keys %d", index, g_slist_length(keys),
- debug_keys);
- return -ENOSYS;
+ char *buf;
+ struct mgmt_hdr *hdr;
+ struct mgmt_cp_load_keys *cp;
+ struct mgmt_key_info *key;
+ size_t key_count, cp_size;
+ GSList *l;
+ int err;
+
+ key_count = g_slist_length(keys);
+
+ DBG("index %d keys %zu debug_keys %d", index, key_count, debug_keys);
+
+ cp_size = sizeof(*cp) + (key_count * sizeof(*key));
+
+ buf = g_try_malloc0(sizeof(*hdr) + cp_size);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ memset(buf, 0, sizeof(buf));
+
+ hdr = (void *) buf;
+ hdr->opcode = htobs(MGMT_OP_LOAD_KEYS);
+ hdr->len = htobs(cp_size);
+
+ cp = (void *) (buf + sizeof(*hdr));
+ cp->index = htobs(index);
+ cp->debug_keys = debug_keys;
+ cp->key_count = htobs(key_count);
+
+ for (l = keys, key = cp->keys; l != NULL; l = g_slist_next(l), key++) {
+ struct link_key_info *info = l->data;
+
+ bacpy(&key->bdaddr, &info->bdaddr);
+ key->type = info->type;
+ memcpy(key->val, info->key, 16);
+ key->pin_len = info->pin_len;
+ }
+
+ if (write(mgmt_sock, buf, sizeof(*hdr) + cp_size) < 0)
+ err = -errno;
+ else
+ err = 0;
+
+ g_free(buf);
+
+ return err;
}
static struct btd_adapter_ops mgmt_ops = {