diff options
author | Vinicius Costa Gomes <vinicius.gomes@openbossa.org> | 2012-02-02 19:08:02 -0500 |
---|---|---|
committer | Johan Hedberg <johan.hedberg@intel.com> | 2012-02-13 10:01:33 -0500 |
commit | 346af67b8d116f01ef696fd47959a55deb2db8b6 (patch) | |
tree | ca22e1b5d479f35550893c530bab69446362ae66 /net/bluetooth/mgmt.c | |
parent | c9839a11c0e460a2457e7cac76650d07773e6c3b (diff) |
Bluetooth: Add MGMT handlers for dealing with SMP LTK's
This adds a method to notify that a new LTK is available and
a handler to store keys coming from userspace into the kernel LTK
list.
Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@openbossa.org>
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Diffstat (limited to 'net/bluetooth/mgmt.c')
-rw-r--r-- | net/bluetooth/mgmt.c | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ad8986276848..fd0b08115f2e 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -2191,6 +2191,60 @@ done: | |||
2191 | return err; | 2191 | return err; |
2192 | } | 2192 | } |
2193 | 2193 | ||
2194 | static int load_long_term_keys(struct sock *sk, u16 index, | ||
2195 | void *cp_data, u16 len) | ||
2196 | { | ||
2197 | struct hci_dev *hdev; | ||
2198 | struct mgmt_cp_load_long_term_keys *cp = cp_data; | ||
2199 | u16 key_count, expected_len; | ||
2200 | int i; | ||
2201 | |||
2202 | if (len < sizeof(*cp)) | ||
2203 | return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS, | ||
2204 | EINVAL); | ||
2205 | |||
2206 | key_count = get_unaligned_le16(&cp->key_count); | ||
2207 | |||
2208 | expected_len = sizeof(*cp) + key_count * | ||
2209 | sizeof(struct mgmt_ltk_info); | ||
2210 | if (expected_len != len) { | ||
2211 | BT_ERR("load_keys: expected %u bytes, got %u bytes", | ||
2212 | len, expected_len); | ||
2213 | return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS, | ||
2214 | EINVAL); | ||
2215 | } | ||
2216 | |||
2217 | hdev = hci_dev_get(index); | ||
2218 | if (!hdev) | ||
2219 | return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS, | ||
2220 | ENODEV); | ||
2221 | |||
2222 | BT_DBG("hci%u key_count %u", index, key_count); | ||
2223 | |||
2224 | hci_dev_lock(hdev); | ||
2225 | |||
2226 | hci_smp_ltks_clear(hdev); | ||
2227 | |||
2228 | for (i = 0; i < key_count; i++) { | ||
2229 | struct mgmt_ltk_info *key = &cp->keys[i]; | ||
2230 | u8 type; | ||
2231 | |||
2232 | if (key->master) | ||
2233 | type = HCI_SMP_LTK; | ||
2234 | else | ||
2235 | type = HCI_SMP_LTK_SLAVE; | ||
2236 | |||
2237 | hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type, | ||
2238 | type, 0, key->authenticated, key->val, | ||
2239 | key->enc_size, key->ediv, key->rand); | ||
2240 | } | ||
2241 | |||
2242 | hci_dev_unlock(hdev); | ||
2243 | hci_dev_put(hdev); | ||
2244 | |||
2245 | return 0; | ||
2246 | } | ||
2247 | |||
2194 | int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | 2248 | int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) |
2195 | { | 2249 | { |
2196 | void *buf; | 2250 | void *buf; |
@@ -2325,6 +2379,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | |||
2325 | case MGMT_OP_UNBLOCK_DEVICE: | 2379 | case MGMT_OP_UNBLOCK_DEVICE: |
2326 | err = unblock_device(sk, index, cp, len); | 2380 | err = unblock_device(sk, index, cp, len); |
2327 | break; | 2381 | break; |
2382 | case MGMT_OP_LOAD_LONG_TERM_KEYS: | ||
2383 | err = load_long_term_keys(sk, index, cp, len); | ||
2384 | break; | ||
2328 | default: | 2385 | default: |
2329 | BT_DBG("Unknown op %u", opcode); | 2386 | BT_DBG("Unknown op %u", opcode); |
2330 | err = cmd_status(sk, index, opcode, | 2387 | err = cmd_status(sk, index, opcode, |
@@ -2478,6 +2535,29 @@ int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, | |||
2478 | return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL); | 2535 | return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL); |
2479 | } | 2536 | } |
2480 | 2537 | ||
2538 | int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent) | ||
2539 | { | ||
2540 | struct mgmt_ev_new_long_term_key ev; | ||
2541 | |||
2542 | memset(&ev, 0, sizeof(ev)); | ||
2543 | |||
2544 | ev.store_hint = persistent; | ||
2545 | bacpy(&ev.key.addr.bdaddr, &key->bdaddr); | ||
2546 | ev.key.addr.type = key->bdaddr_type; | ||
2547 | ev.key.authenticated = key->authenticated; | ||
2548 | ev.key.enc_size = key->enc_size; | ||
2549 | ev.key.ediv = key->ediv; | ||
2550 | |||
2551 | if (key->type == HCI_SMP_LTK) | ||
2552 | ev.key.master = 1; | ||
2553 | |||
2554 | memcpy(ev.key.rand, key->rand, sizeof(key->rand)); | ||
2555 | memcpy(ev.key.val, key->val, sizeof(key->val)); | ||
2556 | |||
2557 | return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, | ||
2558 | &ev, sizeof(ev), NULL); | ||
2559 | } | ||
2560 | |||
2481 | int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, | 2561 | int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, |
2482 | u8 addr_type, u8 *name, u8 name_len, | 2562 | u8 addr_type, u8 *name, u8 name_len, |
2483 | u8 *dev_class) | 2563 | u8 *dev_class) |