diff options
Diffstat (limited to 'net/bluetooth/mgmt.c')
-rw-r--r-- | net/bluetooth/mgmt.c | 1730 |
1 files changed, 1079 insertions, 651 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 2c7634296866..2540944d871f 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | /* Bluetooth HCI Management interface */ | 23 | /* Bluetooth HCI Management interface */ |
24 | 24 | ||
25 | #include <linux/kernel.h> | ||
25 | #include <linux/uaccess.h> | 26 | #include <linux/uaccess.h> |
26 | #include <linux/module.h> | 27 | #include <linux/module.h> |
27 | #include <asm/unaligned.h> | 28 | #include <asm/unaligned.h> |
@@ -29,26 +30,103 @@ | |||
29 | #include <net/bluetooth/bluetooth.h> | 30 | #include <net/bluetooth/bluetooth.h> |
30 | #include <net/bluetooth/hci_core.h> | 31 | #include <net/bluetooth/hci_core.h> |
31 | #include <net/bluetooth/mgmt.h> | 32 | #include <net/bluetooth/mgmt.h> |
33 | #include <net/bluetooth/smp.h> | ||
32 | 34 | ||
33 | #define MGMT_VERSION 0 | 35 | #define MGMT_VERSION 0 |
34 | #define MGMT_REVISION 1 | 36 | #define MGMT_REVISION 1 |
35 | 37 | ||
38 | #define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */ | ||
39 | |||
40 | #define SERVICE_CACHE_TIMEOUT (5 * 1000) | ||
41 | |||
36 | struct pending_cmd { | 42 | struct pending_cmd { |
37 | struct list_head list; | 43 | struct list_head list; |
38 | __u16 opcode; | 44 | u16 opcode; |
39 | int index; | 45 | int index; |
40 | void *param; | 46 | void *param; |
41 | struct sock *sk; | 47 | struct sock *sk; |
42 | void *user_data; | 48 | void *user_data; |
43 | }; | 49 | }; |
44 | 50 | ||
45 | static LIST_HEAD(cmd_list); | 51 | /* HCI to MGMT error code conversion table */ |
52 | static u8 mgmt_status_table[] = { | ||
53 | MGMT_STATUS_SUCCESS, | ||
54 | MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */ | ||
55 | MGMT_STATUS_NOT_CONNECTED, /* No Connection */ | ||
56 | MGMT_STATUS_FAILED, /* Hardware Failure */ | ||
57 | MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */ | ||
58 | MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */ | ||
59 | MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */ | ||
60 | MGMT_STATUS_NO_RESOURCES, /* Memory Full */ | ||
61 | MGMT_STATUS_TIMEOUT, /* Connection Timeout */ | ||
62 | MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */ | ||
63 | MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */ | ||
64 | MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */ | ||
65 | MGMT_STATUS_BUSY, /* Command Disallowed */ | ||
66 | MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */ | ||
67 | MGMT_STATUS_REJECTED, /* Rejected Security */ | ||
68 | MGMT_STATUS_REJECTED, /* Rejected Personal */ | ||
69 | MGMT_STATUS_TIMEOUT, /* Host Timeout */ | ||
70 | MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */ | ||
71 | MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */ | ||
72 | MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */ | ||
73 | MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */ | ||
74 | MGMT_STATUS_DISCONNECTED, /* OE Power Off */ | ||
75 | MGMT_STATUS_DISCONNECTED, /* Connection Terminated */ | ||
76 | MGMT_STATUS_BUSY, /* Repeated Attempts */ | ||
77 | MGMT_STATUS_REJECTED, /* Pairing Not Allowed */ | ||
78 | MGMT_STATUS_FAILED, /* Unknown LMP PDU */ | ||
79 | MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */ | ||
80 | MGMT_STATUS_REJECTED, /* SCO Offset Rejected */ | ||
81 | MGMT_STATUS_REJECTED, /* SCO Interval Rejected */ | ||
82 | MGMT_STATUS_REJECTED, /* Air Mode Rejected */ | ||
83 | MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */ | ||
84 | MGMT_STATUS_FAILED, /* Unspecified Error */ | ||
85 | MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */ | ||
86 | MGMT_STATUS_FAILED, /* Role Change Not Allowed */ | ||
87 | MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */ | ||
88 | MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */ | ||
89 | MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */ | ||
90 | MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */ | ||
91 | MGMT_STATUS_FAILED, /* Unit Link Key Used */ | ||
92 | MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */ | ||
93 | MGMT_STATUS_TIMEOUT, /* Instant Passed */ | ||
94 | MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */ | ||
95 | MGMT_STATUS_FAILED, /* Transaction Collision */ | ||
96 | MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */ | ||
97 | MGMT_STATUS_REJECTED, /* QoS Rejected */ | ||
98 | MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */ | ||
99 | MGMT_STATUS_REJECTED, /* Insufficient Security */ | ||
100 | MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */ | ||
101 | MGMT_STATUS_BUSY, /* Role Switch Pending */ | ||
102 | MGMT_STATUS_FAILED, /* Slot Violation */ | ||
103 | MGMT_STATUS_FAILED, /* Role Switch Failed */ | ||
104 | MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */ | ||
105 | MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */ | ||
106 | MGMT_STATUS_BUSY, /* Host Busy Pairing */ | ||
107 | MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */ | ||
108 | MGMT_STATUS_BUSY, /* Controller Busy */ | ||
109 | MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */ | ||
110 | MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */ | ||
111 | MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */ | ||
112 | MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */ | ||
113 | MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */ | ||
114 | }; | ||
115 | |||
116 | static u8 mgmt_status(u8 hci_status) | ||
117 | { | ||
118 | if (hci_status < ARRAY_SIZE(mgmt_status_table)) | ||
119 | return mgmt_status_table[hci_status]; | ||
120 | |||
121 | return MGMT_STATUS_FAILED; | ||
122 | } | ||
46 | 123 | ||
47 | static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status) | 124 | static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status) |
48 | { | 125 | { |
49 | struct sk_buff *skb; | 126 | struct sk_buff *skb; |
50 | struct mgmt_hdr *hdr; | 127 | struct mgmt_hdr *hdr; |
51 | struct mgmt_ev_cmd_status *ev; | 128 | struct mgmt_ev_cmd_status *ev; |
129 | int err; | ||
52 | 130 | ||
53 | BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status); | 131 | BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status); |
54 | 132 | ||
@@ -66,10 +144,11 @@ static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status) | |||
66 | ev->status = status; | 144 | ev->status = status; |
67 | put_unaligned_le16(cmd, &ev->opcode); | 145 | put_unaligned_le16(cmd, &ev->opcode); |
68 | 146 | ||
69 | if (sock_queue_rcv_skb(sk, skb) < 0) | 147 | err = sock_queue_rcv_skb(sk, skb); |
148 | if (err < 0) | ||
70 | kfree_skb(skb); | 149 | kfree_skb(skb); |
71 | 150 | ||
72 | return 0; | 151 | return err; |
73 | } | 152 | } |
74 | 153 | ||
75 | static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp, | 154 | static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp, |
@@ -78,6 +157,7 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp, | |||
78 | struct sk_buff *skb; | 157 | struct sk_buff *skb; |
79 | struct mgmt_hdr *hdr; | 158 | struct mgmt_hdr *hdr; |
80 | struct mgmt_ev_cmd_complete *ev; | 159 | struct mgmt_ev_cmd_complete *ev; |
160 | int err; | ||
81 | 161 | ||
82 | BT_DBG("sock %p", sk); | 162 | BT_DBG("sock %p", sk); |
83 | 163 | ||
@@ -97,10 +177,11 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp, | |||
97 | if (rp) | 177 | if (rp) |
98 | memcpy(ev->data, rp, rp_len); | 178 | memcpy(ev->data, rp, rp_len); |
99 | 179 | ||
100 | if (sock_queue_rcv_skb(sk, skb) < 0) | 180 | err = sock_queue_rcv_skb(sk, skb); |
181 | if (err < 0) | ||
101 | kfree_skb(skb); | 182 | kfree_skb(skb); |
102 | 183 | ||
103 | return 0; | 184 | return err;; |
104 | } | 185 | } |
105 | 186 | ||
106 | static int read_version(struct sock *sk) | 187 | static int read_version(struct sock *sk) |
@@ -120,6 +201,7 @@ static int read_index_list(struct sock *sk) | |||
120 | { | 201 | { |
121 | struct mgmt_rp_read_index_list *rp; | 202 | struct mgmt_rp_read_index_list *rp; |
122 | struct list_head *p; | 203 | struct list_head *p; |
204 | struct hci_dev *d; | ||
123 | size_t rp_len; | 205 | size_t rp_len; |
124 | u16 count; | 206 | u16 count; |
125 | int i, err; | 207 | int i, err; |
@@ -143,10 +225,9 @@ static int read_index_list(struct sock *sk) | |||
143 | put_unaligned_le16(count, &rp->num_controllers); | 225 | put_unaligned_le16(count, &rp->num_controllers); |
144 | 226 | ||
145 | i = 0; | 227 | i = 0; |
146 | list_for_each(p, &hci_dev_list) { | 228 | list_for_each_entry(d, &hci_dev_list, list) { |
147 | struct hci_dev *d = list_entry(p, struct hci_dev, list); | 229 | if (test_and_clear_bit(HCI_AUTO_OFF, &d->flags)) |
148 | 230 | cancel_delayed_work(&d->power_off); | |
149 | hci_del_off_timer(d); | ||
150 | 231 | ||
151 | if (test_bit(HCI_SETUP, &d->flags)) | 232 | if (test_bit(HCI_SETUP, &d->flags)) |
152 | continue; | 233 | continue; |
@@ -165,6 +246,262 @@ static int read_index_list(struct sock *sk) | |||
165 | return err; | 246 | return err; |
166 | } | 247 | } |
167 | 248 | ||
249 | static u32 get_supported_settings(struct hci_dev *hdev) | ||
250 | { | ||
251 | u32 settings = 0; | ||
252 | |||
253 | settings |= MGMT_SETTING_POWERED; | ||
254 | settings |= MGMT_SETTING_CONNECTABLE; | ||
255 | settings |= MGMT_SETTING_FAST_CONNECTABLE; | ||
256 | settings |= MGMT_SETTING_DISCOVERABLE; | ||
257 | settings |= MGMT_SETTING_PAIRABLE; | ||
258 | |||
259 | if (hdev->features[6] & LMP_SIMPLE_PAIR) | ||
260 | settings |= MGMT_SETTING_SSP; | ||
261 | |||
262 | if (!(hdev->features[4] & LMP_NO_BREDR)) { | ||
263 | settings |= MGMT_SETTING_BREDR; | ||
264 | settings |= MGMT_SETTING_LINK_SECURITY; | ||
265 | } | ||
266 | |||
267 | if (hdev->features[4] & LMP_LE) | ||
268 | settings |= MGMT_SETTING_LE; | ||
269 | |||
270 | return settings; | ||
271 | } | ||
272 | |||
273 | static u32 get_current_settings(struct hci_dev *hdev) | ||
274 | { | ||
275 | u32 settings = 0; | ||
276 | |||
277 | if (test_bit(HCI_UP, &hdev->flags)) | ||
278 | settings |= MGMT_SETTING_POWERED; | ||
279 | else | ||
280 | return settings; | ||
281 | |||
282 | if (test_bit(HCI_PSCAN, &hdev->flags)) | ||
283 | settings |= MGMT_SETTING_CONNECTABLE; | ||
284 | |||
285 | if (test_bit(HCI_ISCAN, &hdev->flags)) | ||
286 | settings |= MGMT_SETTING_DISCOVERABLE; | ||
287 | |||
288 | if (test_bit(HCI_PAIRABLE, &hdev->flags)) | ||
289 | settings |= MGMT_SETTING_PAIRABLE; | ||
290 | |||
291 | if (!(hdev->features[4] & LMP_NO_BREDR)) | ||
292 | settings |= MGMT_SETTING_BREDR; | ||
293 | |||
294 | if (hdev->extfeatures[0] & LMP_HOST_LE) | ||
295 | settings |= MGMT_SETTING_LE; | ||
296 | |||
297 | if (test_bit(HCI_AUTH, &hdev->flags)) | ||
298 | settings |= MGMT_SETTING_LINK_SECURITY; | ||
299 | |||
300 | if (hdev->ssp_mode > 0) | ||
301 | settings |= MGMT_SETTING_SSP; | ||
302 | |||
303 | return settings; | ||
304 | } | ||
305 | |||
306 | #define EIR_FLAGS 0x01 /* flags */ | ||
307 | #define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */ | ||
308 | #define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */ | ||
309 | #define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */ | ||
310 | #define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */ | ||
311 | #define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */ | ||
312 | #define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */ | ||
313 | #define EIR_NAME_SHORT 0x08 /* shortened local name */ | ||
314 | #define EIR_NAME_COMPLETE 0x09 /* complete local name */ | ||
315 | #define EIR_TX_POWER 0x0A /* transmit power level */ | ||
316 | #define EIR_DEVICE_ID 0x10 /* device ID */ | ||
317 | |||
318 | #define PNP_INFO_SVCLASS_ID 0x1200 | ||
319 | |||
320 | static u8 bluetooth_base_uuid[] = { | ||
321 | 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, | ||
322 | 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
323 | }; | ||
324 | |||
325 | static u16 get_uuid16(u8 *uuid128) | ||
326 | { | ||
327 | u32 val; | ||
328 | int i; | ||
329 | |||
330 | for (i = 0; i < 12; i++) { | ||
331 | if (bluetooth_base_uuid[i] != uuid128[i]) | ||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | memcpy(&val, &uuid128[12], 4); | ||
336 | |||
337 | val = le32_to_cpu(val); | ||
338 | if (val > 0xffff) | ||
339 | return 0; | ||
340 | |||
341 | return (u16) val; | ||
342 | } | ||
343 | |||
344 | static void create_eir(struct hci_dev *hdev, u8 *data) | ||
345 | { | ||
346 | u8 *ptr = data; | ||
347 | u16 eir_len = 0; | ||
348 | u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)]; | ||
349 | int i, truncated = 0; | ||
350 | struct bt_uuid *uuid; | ||
351 | size_t name_len; | ||
352 | |||
353 | name_len = strlen(hdev->dev_name); | ||
354 | |||
355 | if (name_len > 0) { | ||
356 | /* EIR Data type */ | ||
357 | if (name_len > 48) { | ||
358 | name_len = 48; | ||
359 | ptr[1] = EIR_NAME_SHORT; | ||
360 | } else | ||
361 | ptr[1] = EIR_NAME_COMPLETE; | ||
362 | |||
363 | /* EIR Data length */ | ||
364 | ptr[0] = name_len + 1; | ||
365 | |||
366 | memcpy(ptr + 2, hdev->dev_name, name_len); | ||
367 | |||
368 | eir_len += (name_len + 2); | ||
369 | ptr += (name_len + 2); | ||
370 | } | ||
371 | |||
372 | memset(uuid16_list, 0, sizeof(uuid16_list)); | ||
373 | |||
374 | /* Group all UUID16 types */ | ||
375 | list_for_each_entry(uuid, &hdev->uuids, list) { | ||
376 | u16 uuid16; | ||
377 | |||
378 | uuid16 = get_uuid16(uuid->uuid); | ||
379 | if (uuid16 == 0) | ||
380 | return; | ||
381 | |||
382 | if (uuid16 < 0x1100) | ||
383 | continue; | ||
384 | |||
385 | if (uuid16 == PNP_INFO_SVCLASS_ID) | ||
386 | continue; | ||
387 | |||
388 | /* Stop if not enough space to put next UUID */ | ||
389 | if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) { | ||
390 | truncated = 1; | ||
391 | break; | ||
392 | } | ||
393 | |||
394 | /* Check for duplicates */ | ||
395 | for (i = 0; uuid16_list[i] != 0; i++) | ||
396 | if (uuid16_list[i] == uuid16) | ||
397 | break; | ||
398 | |||
399 | if (uuid16_list[i] == 0) { | ||
400 | uuid16_list[i] = uuid16; | ||
401 | eir_len += sizeof(u16); | ||
402 | } | ||
403 | } | ||
404 | |||
405 | if (uuid16_list[0] != 0) { | ||
406 | u8 *length = ptr; | ||
407 | |||
408 | /* EIR Data type */ | ||
409 | ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL; | ||
410 | |||
411 | ptr += 2; | ||
412 | eir_len += 2; | ||
413 | |||
414 | for (i = 0; uuid16_list[i] != 0; i++) { | ||
415 | *ptr++ = (uuid16_list[i] & 0x00ff); | ||
416 | *ptr++ = (uuid16_list[i] & 0xff00) >> 8; | ||
417 | } | ||
418 | |||
419 | /* EIR Data length */ | ||
420 | *length = (i * sizeof(u16)) + 1; | ||
421 | } | ||
422 | } | ||
423 | |||
424 | static int update_eir(struct hci_dev *hdev) | ||
425 | { | ||
426 | struct hci_cp_write_eir cp; | ||
427 | |||
428 | if (!(hdev->features[6] & LMP_EXT_INQ)) | ||
429 | return 0; | ||
430 | |||
431 | if (hdev->ssp_mode == 0) | ||
432 | return 0; | ||
433 | |||
434 | if (test_bit(HCI_SERVICE_CACHE, &hdev->flags)) | ||
435 | return 0; | ||
436 | |||
437 | memset(&cp, 0, sizeof(cp)); | ||
438 | |||
439 | create_eir(hdev, cp.data); | ||
440 | |||
441 | if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0) | ||
442 | return 0; | ||
443 | |||
444 | memcpy(hdev->eir, cp.data, sizeof(cp.data)); | ||
445 | |||
446 | return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp); | ||
447 | } | ||
448 | |||
449 | static u8 get_service_classes(struct hci_dev *hdev) | ||
450 | { | ||
451 | struct bt_uuid *uuid; | ||
452 | u8 val = 0; | ||
453 | |||
454 | list_for_each_entry(uuid, &hdev->uuids, list) | ||
455 | val |= uuid->svc_hint; | ||
456 | |||
457 | return val; | ||
458 | } | ||
459 | |||
460 | static int update_class(struct hci_dev *hdev) | ||
461 | { | ||
462 | u8 cod[3]; | ||
463 | |||
464 | BT_DBG("%s", hdev->name); | ||
465 | |||
466 | if (test_bit(HCI_SERVICE_CACHE, &hdev->flags)) | ||
467 | return 0; | ||
468 | |||
469 | cod[0] = hdev->minor_class; | ||
470 | cod[1] = hdev->major_class; | ||
471 | cod[2] = get_service_classes(hdev); | ||
472 | |||
473 | if (memcmp(cod, hdev->dev_class, 3) == 0) | ||
474 | return 0; | ||
475 | |||
476 | return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod); | ||
477 | } | ||
478 | |||
479 | static void service_cache_off(struct work_struct *work) | ||
480 | { | ||
481 | struct hci_dev *hdev = container_of(work, struct hci_dev, | ||
482 | service_cache.work); | ||
483 | |||
484 | if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags)) | ||
485 | return; | ||
486 | |||
487 | hci_dev_lock(hdev); | ||
488 | |||
489 | update_eir(hdev); | ||
490 | update_class(hdev); | ||
491 | |||
492 | hci_dev_unlock(hdev); | ||
493 | } | ||
494 | |||
495 | static void mgmt_init_hdev(struct hci_dev *hdev) | ||
496 | { | ||
497 | if (!test_and_set_bit(HCI_MGMT, &hdev->flags)) | ||
498 | INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off); | ||
499 | |||
500 | if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->flags)) | ||
501 | schedule_delayed_work(&hdev->service_cache, | ||
502 | msecs_to_jiffies(SERVICE_CACHE_TIMEOUT)); | ||
503 | } | ||
504 | |||
168 | static int read_controller_info(struct sock *sk, u16 index) | 505 | static int read_controller_info(struct sock *sk, u16 index) |
169 | { | 506 | { |
170 | struct mgmt_rp_read_info rp; | 507 | struct mgmt_rp_read_info rp; |
@@ -174,40 +511,33 @@ static int read_controller_info(struct sock *sk, u16 index) | |||
174 | 511 | ||
175 | hdev = hci_dev_get(index); | 512 | hdev = hci_dev_get(index); |
176 | if (!hdev) | 513 | if (!hdev) |
177 | return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV); | 514 | return cmd_status(sk, index, MGMT_OP_READ_INFO, |
515 | MGMT_STATUS_INVALID_PARAMS); | ||
178 | 516 | ||
179 | hci_del_off_timer(hdev); | 517 | if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags)) |
518 | cancel_delayed_work_sync(&hdev->power_off); | ||
180 | 519 | ||
181 | hci_dev_lock_bh(hdev); | 520 | hci_dev_lock(hdev); |
182 | 521 | ||
183 | set_bit(HCI_MGMT, &hdev->flags); | 522 | if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags)) |
523 | mgmt_init_hdev(hdev); | ||
184 | 524 | ||
185 | memset(&rp, 0, sizeof(rp)); | 525 | memset(&rp, 0, sizeof(rp)); |
186 | 526 | ||
187 | rp.type = hdev->dev_type; | 527 | bacpy(&rp.bdaddr, &hdev->bdaddr); |
188 | 528 | ||
189 | rp.powered = test_bit(HCI_UP, &hdev->flags); | 529 | rp.version = hdev->hci_ver; |
190 | rp.connectable = test_bit(HCI_PSCAN, &hdev->flags); | ||
191 | rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags); | ||
192 | rp.pairable = test_bit(HCI_PSCAN, &hdev->flags); | ||
193 | 530 | ||
194 | if (test_bit(HCI_AUTH, &hdev->flags)) | 531 | put_unaligned_le16(hdev->manufacturer, &rp.manufacturer); |
195 | rp.sec_mode = 3; | 532 | |
196 | else if (hdev->ssp_mode > 0) | 533 | rp.supported_settings = cpu_to_le32(get_supported_settings(hdev)); |
197 | rp.sec_mode = 4; | 534 | rp.current_settings = cpu_to_le32(get_current_settings(hdev)); |
198 | else | ||
199 | rp.sec_mode = 2; | ||
200 | 535 | ||
201 | bacpy(&rp.bdaddr, &hdev->bdaddr); | ||
202 | memcpy(rp.features, hdev->features, 8); | ||
203 | memcpy(rp.dev_class, hdev->dev_class, 3); | 536 | memcpy(rp.dev_class, hdev->dev_class, 3); |
204 | put_unaligned_le16(hdev->manufacturer, &rp.manufacturer); | ||
205 | rp.hci_ver = hdev->hci_ver; | ||
206 | put_unaligned_le16(hdev->hci_rev, &rp.hci_rev); | ||
207 | 537 | ||
208 | memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name)); | 538 | memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name)); |
209 | 539 | ||
210 | hci_dev_unlock_bh(hdev); | 540 | hci_dev_unlock(hdev); |
211 | hci_dev_put(hdev); | 541 | hci_dev_put(hdev); |
212 | 542 | ||
213 | return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp)); | 543 | return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp)); |
@@ -221,7 +551,8 @@ static void mgmt_pending_free(struct pending_cmd *cmd) | |||
221 | } | 551 | } |
222 | 552 | ||
223 | static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode, | 553 | static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode, |
224 | u16 index, void *data, u16 len) | 554 | struct hci_dev *hdev, |
555 | void *data, u16 len) | ||
225 | { | 556 | { |
226 | struct pending_cmd *cmd; | 557 | struct pending_cmd *cmd; |
227 | 558 | ||
@@ -230,7 +561,7 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode, | |||
230 | return NULL; | 561 | return NULL; |
231 | 562 | ||
232 | cmd->opcode = opcode; | 563 | cmd->opcode = opcode; |
233 | cmd->index = index; | 564 | cmd->index = hdev->id; |
234 | 565 | ||
235 | cmd->param = kmalloc(len, GFP_ATOMIC); | 566 | cmd->param = kmalloc(len, GFP_ATOMIC); |
236 | if (!cmd->param) { | 567 | if (!cmd->param) { |
@@ -244,48 +575,36 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode, | |||
244 | cmd->sk = sk; | 575 | cmd->sk = sk; |
245 | sock_hold(sk); | 576 | sock_hold(sk); |
246 | 577 | ||
247 | list_add(&cmd->list, &cmd_list); | 578 | list_add(&cmd->list, &hdev->mgmt_pending); |
248 | 579 | ||
249 | return cmd; | 580 | return cmd; |
250 | } | 581 | } |
251 | 582 | ||
252 | static void mgmt_pending_foreach(u16 opcode, int index, | 583 | static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, |
253 | void (*cb)(struct pending_cmd *cmd, void *data), | 584 | void (*cb)(struct pending_cmd *cmd, void *data), |
254 | void *data) | 585 | void *data) |
255 | { | 586 | { |
256 | struct list_head *p, *n; | 587 | struct list_head *p, *n; |
257 | 588 | ||
258 | list_for_each_safe(p, n, &cmd_list) { | 589 | list_for_each_safe(p, n, &hdev->mgmt_pending) { |
259 | struct pending_cmd *cmd; | 590 | struct pending_cmd *cmd; |
260 | 591 | ||
261 | cmd = list_entry(p, struct pending_cmd, list); | 592 | cmd = list_entry(p, struct pending_cmd, list); |
262 | 593 | ||
263 | if (cmd->opcode != opcode) | 594 | if (opcode > 0 && cmd->opcode != opcode) |
264 | continue; | ||
265 | |||
266 | if (index >= 0 && cmd->index != index) | ||
267 | continue; | 595 | continue; |
268 | 596 | ||
269 | cb(cmd, data); | 597 | cb(cmd, data); |
270 | } | 598 | } |
271 | } | 599 | } |
272 | 600 | ||
273 | static struct pending_cmd *mgmt_pending_find(u16 opcode, int index) | 601 | static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev) |
274 | { | 602 | { |
275 | struct list_head *p; | 603 | struct pending_cmd *cmd; |
276 | |||
277 | list_for_each(p, &cmd_list) { | ||
278 | struct pending_cmd *cmd; | ||
279 | |||
280 | cmd = list_entry(p, struct pending_cmd, list); | ||
281 | |||
282 | if (cmd->opcode != opcode) | ||
283 | continue; | ||
284 | |||
285 | if (index >= 0 && cmd->index != index) | ||
286 | continue; | ||
287 | 604 | ||
288 | return cmd; | 605 | list_for_each_entry(cmd, &hdev->mgmt_pending, list) { |
606 | if (cmd->opcode == opcode) | ||
607 | return cmd; | ||
289 | } | 608 | } |
290 | 609 | ||
291 | return NULL; | 610 | return NULL; |
@@ -297,6 +616,13 @@ static void mgmt_pending_remove(struct pending_cmd *cmd) | |||
297 | mgmt_pending_free(cmd); | 616 | mgmt_pending_free(cmd); |
298 | } | 617 | } |
299 | 618 | ||
619 | static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev) | ||
620 | { | ||
621 | __le32 settings = cpu_to_le32(get_current_settings(hdev)); | ||
622 | |||
623 | return cmd_complete(sk, hdev->id, opcode, &settings, sizeof(settings)); | ||
624 | } | ||
625 | |||
300 | static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) | 626 | static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) |
301 | { | 627 | { |
302 | struct mgmt_mode *cp; | 628 | struct mgmt_mode *cp; |
@@ -309,40 +635,43 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
309 | BT_DBG("request for hci%u", index); | 635 | BT_DBG("request for hci%u", index); |
310 | 636 | ||
311 | if (len != sizeof(*cp)) | 637 | if (len != sizeof(*cp)) |
312 | return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL); | 638 | return cmd_status(sk, index, MGMT_OP_SET_POWERED, |
639 | MGMT_STATUS_INVALID_PARAMS); | ||
313 | 640 | ||
314 | hdev = hci_dev_get(index); | 641 | hdev = hci_dev_get(index); |
315 | if (!hdev) | 642 | if (!hdev) |
316 | return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV); | 643 | return cmd_status(sk, index, MGMT_OP_SET_POWERED, |
644 | MGMT_STATUS_INVALID_PARAMS); | ||
317 | 645 | ||
318 | hci_dev_lock_bh(hdev); | 646 | hci_dev_lock(hdev); |
319 | 647 | ||
320 | up = test_bit(HCI_UP, &hdev->flags); | 648 | up = test_bit(HCI_UP, &hdev->flags); |
321 | if ((cp->val && up) || (!cp->val && !up)) { | 649 | if ((cp->val && up) || (!cp->val && !up)) { |
322 | err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY); | 650 | err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev); |
323 | goto failed; | 651 | goto failed; |
324 | } | 652 | } |
325 | 653 | ||
326 | if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) { | 654 | if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) { |
327 | err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY); | 655 | err = cmd_status(sk, index, MGMT_OP_SET_POWERED, |
656 | MGMT_STATUS_BUSY); | ||
328 | goto failed; | 657 | goto failed; |
329 | } | 658 | } |
330 | 659 | ||
331 | cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len); | 660 | cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len); |
332 | if (!cmd) { | 661 | if (!cmd) { |
333 | err = -ENOMEM; | 662 | err = -ENOMEM; |
334 | goto failed; | 663 | goto failed; |
335 | } | 664 | } |
336 | 665 | ||
337 | if (cp->val) | 666 | if (cp->val) |
338 | queue_work(hdev->workqueue, &hdev->power_on); | 667 | schedule_work(&hdev->power_on); |
339 | else | 668 | else |
340 | queue_work(hdev->workqueue, &hdev->power_off); | 669 | schedule_work(&hdev->power_off.work); |
341 | 670 | ||
342 | err = 0; | 671 | err = 0; |
343 | 672 | ||
344 | failed: | 673 | failed: |
345 | hci_dev_unlock_bh(hdev); | 674 | hci_dev_unlock(hdev); |
346 | hci_dev_put(hdev); | 675 | hci_dev_put(hdev); |
347 | return err; | 676 | return err; |
348 | } | 677 | } |
@@ -350,7 +679,7 @@ failed: | |||
350 | static int set_discoverable(struct sock *sk, u16 index, unsigned char *data, | 679 | static int set_discoverable(struct sock *sk, u16 index, unsigned char *data, |
351 | u16 len) | 680 | u16 len) |
352 | { | 681 | { |
353 | struct mgmt_mode *cp; | 682 | struct mgmt_cp_set_discoverable *cp; |
354 | struct hci_dev *hdev; | 683 | struct hci_dev *hdev; |
355 | struct pending_cmd *cmd; | 684 | struct pending_cmd *cmd; |
356 | u8 scan; | 685 | u8 scan; |
@@ -361,32 +690,36 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data, | |||
361 | BT_DBG("request for hci%u", index); | 690 | BT_DBG("request for hci%u", index); |
362 | 691 | ||
363 | if (len != sizeof(*cp)) | 692 | if (len != sizeof(*cp)) |
364 | return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL); | 693 | return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, |
694 | MGMT_STATUS_INVALID_PARAMS); | ||
365 | 695 | ||
366 | hdev = hci_dev_get(index); | 696 | hdev = hci_dev_get(index); |
367 | if (!hdev) | 697 | if (!hdev) |
368 | return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV); | 698 | return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, |
699 | MGMT_STATUS_INVALID_PARAMS); | ||
369 | 700 | ||
370 | hci_dev_lock_bh(hdev); | 701 | hci_dev_lock(hdev); |
371 | 702 | ||
372 | if (!test_bit(HCI_UP, &hdev->flags)) { | 703 | if (!test_bit(HCI_UP, &hdev->flags)) { |
373 | err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN); | 704 | err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, |
705 | MGMT_STATUS_NOT_POWERED); | ||
374 | goto failed; | 706 | goto failed; |
375 | } | 707 | } |
376 | 708 | ||
377 | if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) || | 709 | if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) || |
378 | mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) { | 710 | mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) { |
379 | err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY); | 711 | err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, |
712 | MGMT_STATUS_BUSY); | ||
380 | goto failed; | 713 | goto failed; |
381 | } | 714 | } |
382 | 715 | ||
383 | if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) && | 716 | if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) && |
384 | test_bit(HCI_PSCAN, &hdev->flags)) { | 717 | test_bit(HCI_PSCAN, &hdev->flags)) { |
385 | err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY); | 718 | err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev); |
386 | goto failed; | 719 | goto failed; |
387 | } | 720 | } |
388 | 721 | ||
389 | cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len); | 722 | cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len); |
390 | if (!cmd) { | 723 | if (!cmd) { |
391 | err = -ENOMEM; | 724 | err = -ENOMEM; |
392 | goto failed; | 725 | goto failed; |
@@ -396,13 +729,18 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data, | |||
396 | 729 | ||
397 | if (cp->val) | 730 | if (cp->val) |
398 | scan |= SCAN_INQUIRY; | 731 | scan |= SCAN_INQUIRY; |
732 | else | ||
733 | cancel_delayed_work(&hdev->discov_off); | ||
399 | 734 | ||
400 | err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); | 735 | err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); |
401 | if (err < 0) | 736 | if (err < 0) |
402 | mgmt_pending_remove(cmd); | 737 | mgmt_pending_remove(cmd); |
403 | 738 | ||
739 | if (cp->val) | ||
740 | hdev->discov_timeout = get_unaligned_le16(&cp->timeout); | ||
741 | |||
404 | failed: | 742 | failed: |
405 | hci_dev_unlock_bh(hdev); | 743 | hci_dev_unlock(hdev); |
406 | hci_dev_put(hdev); | 744 | hci_dev_put(hdev); |
407 | 745 | ||
408 | return err; | 746 | return err; |
@@ -422,31 +760,35 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data, | |||
422 | BT_DBG("request for hci%u", index); | 760 | BT_DBG("request for hci%u", index); |
423 | 761 | ||
424 | if (len != sizeof(*cp)) | 762 | if (len != sizeof(*cp)) |
425 | return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL); | 763 | return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, |
764 | MGMT_STATUS_INVALID_PARAMS); | ||
426 | 765 | ||
427 | hdev = hci_dev_get(index); | 766 | hdev = hci_dev_get(index); |
428 | if (!hdev) | 767 | if (!hdev) |
429 | return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV); | 768 | return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, |
769 | MGMT_STATUS_INVALID_PARAMS); | ||
430 | 770 | ||
431 | hci_dev_lock_bh(hdev); | 771 | hci_dev_lock(hdev); |
432 | 772 | ||
433 | if (!test_bit(HCI_UP, &hdev->flags)) { | 773 | if (!test_bit(HCI_UP, &hdev->flags)) { |
434 | err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN); | 774 | err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, |
775 | MGMT_STATUS_NOT_POWERED); | ||
435 | goto failed; | 776 | goto failed; |
436 | } | 777 | } |
437 | 778 | ||
438 | if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) || | 779 | if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) || |
439 | mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) { | 780 | mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) { |
440 | err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY); | 781 | err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, |
782 | MGMT_STATUS_BUSY); | ||
441 | goto failed; | 783 | goto failed; |
442 | } | 784 | } |
443 | 785 | ||
444 | if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) { | 786 | if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) { |
445 | err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY); | 787 | err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev); |
446 | goto failed; | 788 | goto failed; |
447 | } | 789 | } |
448 | 790 | ||
449 | cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len); | 791 | cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len); |
450 | if (!cmd) { | 792 | if (!cmd) { |
451 | err = -ENOMEM; | 793 | err = -ENOMEM; |
452 | goto failed; | 794 | goto failed; |
@@ -462,14 +804,14 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data, | |||
462 | mgmt_pending_remove(cmd); | 804 | mgmt_pending_remove(cmd); |
463 | 805 | ||
464 | failed: | 806 | failed: |
465 | hci_dev_unlock_bh(hdev); | 807 | hci_dev_unlock(hdev); |
466 | hci_dev_put(hdev); | 808 | hci_dev_put(hdev); |
467 | 809 | ||
468 | return err; | 810 | return err; |
469 | } | 811 | } |
470 | 812 | ||
471 | static int mgmt_event(u16 event, u16 index, void *data, u16 data_len, | 813 | static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, |
472 | struct sock *skip_sk) | 814 | u16 data_len, struct sock *skip_sk) |
473 | { | 815 | { |
474 | struct sk_buff *skb; | 816 | struct sk_buff *skb; |
475 | struct mgmt_hdr *hdr; | 817 | struct mgmt_hdr *hdr; |
@@ -482,7 +824,10 @@ static int mgmt_event(u16 event, u16 index, void *data, u16 data_len, | |||
482 | 824 | ||
483 | hdr = (void *) skb_put(skb, sizeof(*hdr)); | 825 | hdr = (void *) skb_put(skb, sizeof(*hdr)); |
484 | hdr->opcode = cpu_to_le16(event); | 826 | hdr->opcode = cpu_to_le16(event); |
485 | hdr->index = cpu_to_le16(index); | 827 | if (hdev) |
828 | hdr->index = cpu_to_le16(hdev->id); | ||
829 | else | ||
830 | hdr->index = cpu_to_le16(MGMT_INDEX_NONE); | ||
486 | hdr->len = cpu_to_le16(data_len); | 831 | hdr->len = cpu_to_le16(data_len); |
487 | 832 | ||
488 | if (data) | 833 | if (data) |
@@ -494,20 +839,12 @@ static int mgmt_event(u16 event, u16 index, void *data, u16 data_len, | |||
494 | return 0; | 839 | return 0; |
495 | } | 840 | } |
496 | 841 | ||
497 | static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val) | ||
498 | { | ||
499 | struct mgmt_mode rp; | ||
500 | |||
501 | rp.val = val; | ||
502 | |||
503 | return cmd_complete(sk, index, opcode, &rp, sizeof(rp)); | ||
504 | } | ||
505 | |||
506 | static int set_pairable(struct sock *sk, u16 index, unsigned char *data, | 842 | static int set_pairable(struct sock *sk, u16 index, unsigned char *data, |
507 | u16 len) | 843 | u16 len) |
508 | { | 844 | { |
509 | struct mgmt_mode *cp, ev; | 845 | struct mgmt_mode *cp; |
510 | struct hci_dev *hdev; | 846 | struct hci_dev *hdev; |
847 | __le32 ev; | ||
511 | int err; | 848 | int err; |
512 | 849 | ||
513 | cp = (void *) data; | 850 | cp = (void *) data; |
@@ -515,211 +852,36 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data, | |||
515 | BT_DBG("request for hci%u", index); | 852 | BT_DBG("request for hci%u", index); |
516 | 853 | ||
517 | if (len != sizeof(*cp)) | 854 | if (len != sizeof(*cp)) |
518 | return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL); | 855 | return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, |
856 | MGMT_STATUS_INVALID_PARAMS); | ||
519 | 857 | ||
520 | hdev = hci_dev_get(index); | 858 | hdev = hci_dev_get(index); |
521 | if (!hdev) | 859 | if (!hdev) |
522 | return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV); | 860 | return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, |
861 | MGMT_STATUS_INVALID_PARAMS); | ||
523 | 862 | ||
524 | hci_dev_lock_bh(hdev); | 863 | hci_dev_lock(hdev); |
525 | 864 | ||
526 | if (cp->val) | 865 | if (cp->val) |
527 | set_bit(HCI_PAIRABLE, &hdev->flags); | 866 | set_bit(HCI_PAIRABLE, &hdev->flags); |
528 | else | 867 | else |
529 | clear_bit(HCI_PAIRABLE, &hdev->flags); | 868 | clear_bit(HCI_PAIRABLE, &hdev->flags); |
530 | 869 | ||
531 | err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val); | 870 | err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev); |
532 | if (err < 0) | 871 | if (err < 0) |
533 | goto failed; | 872 | goto failed; |
534 | 873 | ||
535 | ev.val = cp->val; | 874 | ev = cpu_to_le32(get_current_settings(hdev)); |
536 | 875 | ||
537 | err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk); | 876 | err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk); |
538 | 877 | ||
539 | failed: | 878 | failed: |
540 | hci_dev_unlock_bh(hdev); | 879 | hci_dev_unlock(hdev); |
541 | hci_dev_put(hdev); | 880 | hci_dev_put(hdev); |
542 | 881 | ||
543 | return err; | 882 | return err; |
544 | } | 883 | } |
545 | 884 | ||
546 | #define EIR_FLAGS 0x01 /* flags */ | ||
547 | #define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */ | ||
548 | #define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */ | ||
549 | #define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */ | ||
550 | #define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */ | ||
551 | #define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */ | ||
552 | #define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */ | ||
553 | #define EIR_NAME_SHORT 0x08 /* shortened local name */ | ||
554 | #define EIR_NAME_COMPLETE 0x09 /* complete local name */ | ||
555 | #define EIR_TX_POWER 0x0A /* transmit power level */ | ||
556 | #define EIR_DEVICE_ID 0x10 /* device ID */ | ||
557 | |||
558 | #define PNP_INFO_SVCLASS_ID 0x1200 | ||
559 | |||
560 | static u8 bluetooth_base_uuid[] = { | ||
561 | 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, | ||
562 | 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
563 | }; | ||
564 | |||
565 | static u16 get_uuid16(u8 *uuid128) | ||
566 | { | ||
567 | u32 val; | ||
568 | int i; | ||
569 | |||
570 | for (i = 0; i < 12; i++) { | ||
571 | if (bluetooth_base_uuid[i] != uuid128[i]) | ||
572 | return 0; | ||
573 | } | ||
574 | |||
575 | memcpy(&val, &uuid128[12], 4); | ||
576 | |||
577 | val = le32_to_cpu(val); | ||
578 | if (val > 0xffff) | ||
579 | return 0; | ||
580 | |||
581 | return (u16) val; | ||
582 | } | ||
583 | |||
584 | static void create_eir(struct hci_dev *hdev, u8 *data) | ||
585 | { | ||
586 | u8 *ptr = data; | ||
587 | u16 eir_len = 0; | ||
588 | u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)]; | ||
589 | int i, truncated = 0; | ||
590 | struct list_head *p; | ||
591 | size_t name_len; | ||
592 | |||
593 | name_len = strlen(hdev->dev_name); | ||
594 | |||
595 | if (name_len > 0) { | ||
596 | /* EIR Data type */ | ||
597 | if (name_len > 48) { | ||
598 | name_len = 48; | ||
599 | ptr[1] = EIR_NAME_SHORT; | ||
600 | } else | ||
601 | ptr[1] = EIR_NAME_COMPLETE; | ||
602 | |||
603 | /* EIR Data length */ | ||
604 | ptr[0] = name_len + 1; | ||
605 | |||
606 | memcpy(ptr + 2, hdev->dev_name, name_len); | ||
607 | |||
608 | eir_len += (name_len + 2); | ||
609 | ptr += (name_len + 2); | ||
610 | } | ||
611 | |||
612 | memset(uuid16_list, 0, sizeof(uuid16_list)); | ||
613 | |||
614 | /* Group all UUID16 types */ | ||
615 | list_for_each(p, &hdev->uuids) { | ||
616 | struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list); | ||
617 | u16 uuid16; | ||
618 | |||
619 | uuid16 = get_uuid16(uuid->uuid); | ||
620 | if (uuid16 == 0) | ||
621 | return; | ||
622 | |||
623 | if (uuid16 < 0x1100) | ||
624 | continue; | ||
625 | |||
626 | if (uuid16 == PNP_INFO_SVCLASS_ID) | ||
627 | continue; | ||
628 | |||
629 | /* Stop if not enough space to put next UUID */ | ||
630 | if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) { | ||
631 | truncated = 1; | ||
632 | break; | ||
633 | } | ||
634 | |||
635 | /* Check for duplicates */ | ||
636 | for (i = 0; uuid16_list[i] != 0; i++) | ||
637 | if (uuid16_list[i] == uuid16) | ||
638 | break; | ||
639 | |||
640 | if (uuid16_list[i] == 0) { | ||
641 | uuid16_list[i] = uuid16; | ||
642 | eir_len += sizeof(u16); | ||
643 | } | ||
644 | } | ||
645 | |||
646 | if (uuid16_list[0] != 0) { | ||
647 | u8 *length = ptr; | ||
648 | |||
649 | /* EIR Data type */ | ||
650 | ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL; | ||
651 | |||
652 | ptr += 2; | ||
653 | eir_len += 2; | ||
654 | |||
655 | for (i = 0; uuid16_list[i] != 0; i++) { | ||
656 | *ptr++ = (uuid16_list[i] & 0x00ff); | ||
657 | *ptr++ = (uuid16_list[i] & 0xff00) >> 8; | ||
658 | } | ||
659 | |||
660 | /* EIR Data length */ | ||
661 | *length = (i * sizeof(u16)) + 1; | ||
662 | } | ||
663 | } | ||
664 | |||
665 | static int update_eir(struct hci_dev *hdev) | ||
666 | { | ||
667 | struct hci_cp_write_eir cp; | ||
668 | |||
669 | if (!(hdev->features[6] & LMP_EXT_INQ)) | ||
670 | return 0; | ||
671 | |||
672 | if (hdev->ssp_mode == 0) | ||
673 | return 0; | ||
674 | |||
675 | if (test_bit(HCI_SERVICE_CACHE, &hdev->flags)) | ||
676 | return 0; | ||
677 | |||
678 | memset(&cp, 0, sizeof(cp)); | ||
679 | |||
680 | create_eir(hdev, cp.data); | ||
681 | |||
682 | if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0) | ||
683 | return 0; | ||
684 | |||
685 | memcpy(hdev->eir, cp.data, sizeof(cp.data)); | ||
686 | |||
687 | return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp); | ||
688 | } | ||
689 | |||
690 | static u8 get_service_classes(struct hci_dev *hdev) | ||
691 | { | ||
692 | struct list_head *p; | ||
693 | u8 val = 0; | ||
694 | |||
695 | list_for_each(p, &hdev->uuids) { | ||
696 | struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list); | ||
697 | |||
698 | val |= uuid->svc_hint; | ||
699 | } | ||
700 | |||
701 | return val; | ||
702 | } | ||
703 | |||
704 | static int update_class(struct hci_dev *hdev) | ||
705 | { | ||
706 | u8 cod[3]; | ||
707 | |||
708 | BT_DBG("%s", hdev->name); | ||
709 | |||
710 | if (test_bit(HCI_SERVICE_CACHE, &hdev->flags)) | ||
711 | return 0; | ||
712 | |||
713 | cod[0] = hdev->minor_class; | ||
714 | cod[1] = hdev->major_class; | ||
715 | cod[2] = get_service_classes(hdev); | ||
716 | |||
717 | if (memcmp(cod, hdev->dev_class, 3) == 0) | ||
718 | return 0; | ||
719 | |||
720 | return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod); | ||
721 | } | ||
722 | |||
723 | static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) | 885 | static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) |
724 | { | 886 | { |
725 | struct mgmt_cp_add_uuid *cp; | 887 | struct mgmt_cp_add_uuid *cp; |
@@ -732,13 +894,15 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
732 | BT_DBG("request for hci%u", index); | 894 | BT_DBG("request for hci%u", index); |
733 | 895 | ||
734 | if (len != sizeof(*cp)) | 896 | if (len != sizeof(*cp)) |
735 | return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL); | 897 | return cmd_status(sk, index, MGMT_OP_ADD_UUID, |
898 | MGMT_STATUS_INVALID_PARAMS); | ||
736 | 899 | ||
737 | hdev = hci_dev_get(index); | 900 | hdev = hci_dev_get(index); |
738 | if (!hdev) | 901 | if (!hdev) |
739 | return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV); | 902 | return cmd_status(sk, index, MGMT_OP_ADD_UUID, |
903 | MGMT_STATUS_INVALID_PARAMS); | ||
740 | 904 | ||
741 | hci_dev_lock_bh(hdev); | 905 | hci_dev_lock(hdev); |
742 | 906 | ||
743 | uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC); | 907 | uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC); |
744 | if (!uuid) { | 908 | if (!uuid) { |
@@ -762,7 +926,7 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
762 | err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0); | 926 | err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0); |
763 | 927 | ||
764 | failed: | 928 | failed: |
765 | hci_dev_unlock_bh(hdev); | 929 | hci_dev_unlock(hdev); |
766 | hci_dev_put(hdev); | 930 | hci_dev_put(hdev); |
767 | 931 | ||
768 | return err; | 932 | return err; |
@@ -781,13 +945,15 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
781 | BT_DBG("request for hci%u", index); | 945 | BT_DBG("request for hci%u", index); |
782 | 946 | ||
783 | if (len != sizeof(*cp)) | 947 | if (len != sizeof(*cp)) |
784 | return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL); | 948 | return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, |
949 | MGMT_STATUS_INVALID_PARAMS); | ||
785 | 950 | ||
786 | hdev = hci_dev_get(index); | 951 | hdev = hci_dev_get(index); |
787 | if (!hdev) | 952 | if (!hdev) |
788 | return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV); | 953 | return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, |
954 | MGMT_STATUS_INVALID_PARAMS); | ||
789 | 955 | ||
790 | hci_dev_lock_bh(hdev); | 956 | hci_dev_lock(hdev); |
791 | 957 | ||
792 | if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) { | 958 | if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) { |
793 | err = hci_uuids_clear(hdev); | 959 | err = hci_uuids_clear(hdev); |
@@ -807,7 +973,8 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
807 | } | 973 | } |
808 | 974 | ||
809 | if (found == 0) { | 975 | if (found == 0) { |
810 | err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT); | 976 | err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, |
977 | MGMT_STATUS_INVALID_PARAMS); | ||
811 | goto unlock; | 978 | goto unlock; |
812 | } | 979 | } |
813 | 980 | ||
@@ -822,7 +989,7 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
822 | err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0); | 989 | err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0); |
823 | 990 | ||
824 | unlock: | 991 | unlock: |
825 | hci_dev_unlock_bh(hdev); | 992 | hci_dev_unlock(hdev); |
826 | hci_dev_put(hdev); | 993 | hci_dev_put(hdev); |
827 | 994 | ||
828 | return err; | 995 | return err; |
@@ -840,97 +1007,71 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data, | |||
840 | BT_DBG("request for hci%u", index); | 1007 | BT_DBG("request for hci%u", index); |
841 | 1008 | ||
842 | if (len != sizeof(*cp)) | 1009 | if (len != sizeof(*cp)) |
843 | return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL); | 1010 | return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, |
1011 | MGMT_STATUS_INVALID_PARAMS); | ||
844 | 1012 | ||
845 | hdev = hci_dev_get(index); | 1013 | hdev = hci_dev_get(index); |
846 | if (!hdev) | 1014 | if (!hdev) |
847 | return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV); | 1015 | return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, |
1016 | MGMT_STATUS_INVALID_PARAMS); | ||
848 | 1017 | ||
849 | hci_dev_lock_bh(hdev); | 1018 | hci_dev_lock(hdev); |
850 | 1019 | ||
851 | hdev->major_class = cp->major; | 1020 | hdev->major_class = cp->major; |
852 | hdev->minor_class = cp->minor; | 1021 | hdev->minor_class = cp->minor; |
853 | 1022 | ||
1023 | if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags)) { | ||
1024 | hci_dev_unlock(hdev); | ||
1025 | cancel_delayed_work_sync(&hdev->service_cache); | ||
1026 | hci_dev_lock(hdev); | ||
1027 | update_eir(hdev); | ||
1028 | } | ||
1029 | |||
854 | err = update_class(hdev); | 1030 | err = update_class(hdev); |
855 | 1031 | ||
856 | if (err == 0) | 1032 | if (err == 0) |
857 | err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0); | 1033 | err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0); |
858 | 1034 | ||
859 | hci_dev_unlock_bh(hdev); | 1035 | hci_dev_unlock(hdev); |
860 | hci_dev_put(hdev); | ||
861 | |||
862 | return err; | ||
863 | } | ||
864 | |||
865 | static int set_service_cache(struct sock *sk, u16 index, unsigned char *data, | ||
866 | u16 len) | ||
867 | { | ||
868 | struct hci_dev *hdev; | ||
869 | struct mgmt_cp_set_service_cache *cp; | ||
870 | int err; | ||
871 | |||
872 | cp = (void *) data; | ||
873 | |||
874 | if (len != sizeof(*cp)) | ||
875 | return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL); | ||
876 | |||
877 | hdev = hci_dev_get(index); | ||
878 | if (!hdev) | ||
879 | return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV); | ||
880 | |||
881 | hci_dev_lock_bh(hdev); | ||
882 | |||
883 | BT_DBG("hci%u enable %d", index, cp->enable); | ||
884 | |||
885 | if (cp->enable) { | ||
886 | set_bit(HCI_SERVICE_CACHE, &hdev->flags); | ||
887 | err = 0; | ||
888 | } else { | ||
889 | clear_bit(HCI_SERVICE_CACHE, &hdev->flags); | ||
890 | err = update_class(hdev); | ||
891 | if (err == 0) | ||
892 | err = update_eir(hdev); | ||
893 | } | ||
894 | |||
895 | if (err == 0) | ||
896 | err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL, | ||
897 | 0); | ||
898 | |||
899 | hci_dev_unlock_bh(hdev); | ||
900 | hci_dev_put(hdev); | 1036 | hci_dev_put(hdev); |
901 | 1037 | ||
902 | return err; | 1038 | return err; |
903 | } | 1039 | } |
904 | 1040 | ||
905 | static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len) | 1041 | static int load_link_keys(struct sock *sk, u16 index, unsigned char *data, |
1042 | u16 len) | ||
906 | { | 1043 | { |
907 | struct hci_dev *hdev; | 1044 | struct hci_dev *hdev; |
908 | struct mgmt_cp_load_keys *cp; | 1045 | struct mgmt_cp_load_link_keys *cp; |
909 | u16 key_count, expected_len; | 1046 | u16 key_count, expected_len; |
910 | int i; | 1047 | int i; |
911 | 1048 | ||
912 | cp = (void *) data; | 1049 | cp = (void *) data; |
913 | 1050 | ||
914 | if (len < sizeof(*cp)) | 1051 | if (len < sizeof(*cp)) |
915 | return -EINVAL; | 1052 | return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, |
1053 | MGMT_STATUS_INVALID_PARAMS); | ||
916 | 1054 | ||
917 | key_count = get_unaligned_le16(&cp->key_count); | 1055 | key_count = get_unaligned_le16(&cp->key_count); |
918 | 1056 | ||
919 | expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info); | 1057 | expected_len = sizeof(*cp) + key_count * |
1058 | sizeof(struct mgmt_link_key_info); | ||
920 | if (expected_len != len) { | 1059 | if (expected_len != len) { |
921 | BT_ERR("load_keys: expected %u bytes, got %u bytes", | 1060 | BT_ERR("load_link_keys: expected %u bytes, got %u bytes", |
922 | len, expected_len); | 1061 | len, expected_len); |
923 | return -EINVAL; | 1062 | return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, |
1063 | MGMT_STATUS_INVALID_PARAMS); | ||
924 | } | 1064 | } |
925 | 1065 | ||
926 | hdev = hci_dev_get(index); | 1066 | hdev = hci_dev_get(index); |
927 | if (!hdev) | 1067 | if (!hdev) |
928 | return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV); | 1068 | return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, |
1069 | MGMT_STATUS_INVALID_PARAMS); | ||
929 | 1070 | ||
930 | BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys, | 1071 | BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys, |
931 | key_count); | 1072 | key_count); |
932 | 1073 | ||
933 | hci_dev_lock_bh(hdev); | 1074 | hci_dev_lock(hdev); |
934 | 1075 | ||
935 | hci_link_keys_clear(hdev); | 1076 | hci_link_keys_clear(hdev); |
936 | 1077 | ||
@@ -942,58 +1083,84 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
942 | clear_bit(HCI_DEBUG_KEYS, &hdev->flags); | 1083 | clear_bit(HCI_DEBUG_KEYS, &hdev->flags); |
943 | 1084 | ||
944 | for (i = 0; i < key_count; i++) { | 1085 | for (i = 0; i < key_count; i++) { |
945 | struct mgmt_key_info *key = &cp->keys[i]; | 1086 | struct mgmt_link_key_info *key = &cp->keys[i]; |
946 | 1087 | ||
947 | hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type, | 1088 | hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type, |
948 | key->pin_len); | 1089 | key->pin_len); |
949 | } | 1090 | } |
950 | 1091 | ||
951 | hci_dev_unlock_bh(hdev); | 1092 | cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, NULL, 0); |
1093 | |||
1094 | hci_dev_unlock(hdev); | ||
952 | hci_dev_put(hdev); | 1095 | hci_dev_put(hdev); |
953 | 1096 | ||
954 | return 0; | 1097 | return 0; |
955 | } | 1098 | } |
956 | 1099 | ||
957 | static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len) | 1100 | static int remove_keys(struct sock *sk, u16 index, unsigned char *data, |
1101 | u16 len) | ||
958 | { | 1102 | { |
959 | struct hci_dev *hdev; | 1103 | struct hci_dev *hdev; |
960 | struct mgmt_cp_remove_key *cp; | 1104 | struct mgmt_cp_remove_keys *cp; |
1105 | struct mgmt_rp_remove_keys rp; | ||
1106 | struct hci_cp_disconnect dc; | ||
1107 | struct pending_cmd *cmd; | ||
961 | struct hci_conn *conn; | 1108 | struct hci_conn *conn; |
962 | int err; | 1109 | int err; |
963 | 1110 | ||
964 | cp = (void *) data; | 1111 | cp = (void *) data; |
965 | 1112 | ||
966 | if (len != sizeof(*cp)) | 1113 | if (len != sizeof(*cp)) |
967 | return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL); | 1114 | return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, |
1115 | MGMT_STATUS_INVALID_PARAMS); | ||
968 | 1116 | ||
969 | hdev = hci_dev_get(index); | 1117 | hdev = hci_dev_get(index); |
970 | if (!hdev) | 1118 | if (!hdev) |
971 | return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV); | 1119 | return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, |
1120 | MGMT_STATUS_INVALID_PARAMS); | ||
972 | 1121 | ||
973 | hci_dev_lock_bh(hdev); | 1122 | hci_dev_lock(hdev); |
1123 | |||
1124 | memset(&rp, 0, sizeof(rp)); | ||
1125 | bacpy(&rp.bdaddr, &cp->bdaddr); | ||
1126 | rp.status = MGMT_STATUS_FAILED; | ||
974 | 1127 | ||
975 | err = hci_remove_link_key(hdev, &cp->bdaddr); | 1128 | err = hci_remove_link_key(hdev, &cp->bdaddr); |
976 | if (err < 0) { | 1129 | if (err < 0) { |
977 | err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err); | 1130 | rp.status = MGMT_STATUS_NOT_PAIRED; |
978 | goto unlock; | 1131 | goto unlock; |
979 | } | 1132 | } |
980 | 1133 | ||
981 | err = 0; | 1134 | if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) { |
982 | 1135 | err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp, | |
983 | if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) | 1136 | sizeof(rp)); |
984 | goto unlock; | 1137 | goto unlock; |
1138 | } | ||
985 | 1139 | ||
986 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); | 1140 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); |
987 | if (conn) { | 1141 | if (!conn) { |
988 | struct hci_cp_disconnect dc; | 1142 | err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp, |
1143 | sizeof(rp)); | ||
1144 | goto unlock; | ||
1145 | } | ||
989 | 1146 | ||
990 | put_unaligned_le16(conn->handle, &dc.handle); | 1147 | cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_KEYS, hdev, cp, sizeof(*cp)); |
991 | dc.reason = 0x13; /* Remote User Terminated Connection */ | 1148 | if (!cmd) { |
992 | err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc); | 1149 | err = -ENOMEM; |
1150 | goto unlock; | ||
993 | } | 1151 | } |
994 | 1152 | ||
1153 | put_unaligned_le16(conn->handle, &dc.handle); | ||
1154 | dc.reason = 0x13; /* Remote User Terminated Connection */ | ||
1155 | err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc); | ||
1156 | if (err < 0) | ||
1157 | mgmt_pending_remove(cmd); | ||
1158 | |||
995 | unlock: | 1159 | unlock: |
996 | hci_dev_unlock_bh(hdev); | 1160 | if (err < 0) |
1161 | err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp, | ||
1162 | sizeof(rp)); | ||
1163 | hci_dev_unlock(hdev); | ||
997 | hci_dev_put(hdev); | 1164 | hci_dev_put(hdev); |
998 | 1165 | ||
999 | return err; | 1166 | return err; |
@@ -1013,21 +1180,25 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
1013 | cp = (void *) data; | 1180 | cp = (void *) data; |
1014 | 1181 | ||
1015 | if (len != sizeof(*cp)) | 1182 | if (len != sizeof(*cp)) |
1016 | return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL); | 1183 | return cmd_status(sk, index, MGMT_OP_DISCONNECT, |
1184 | MGMT_STATUS_INVALID_PARAMS); | ||
1017 | 1185 | ||
1018 | hdev = hci_dev_get(index); | 1186 | hdev = hci_dev_get(index); |
1019 | if (!hdev) | 1187 | if (!hdev) |
1020 | return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV); | 1188 | return cmd_status(sk, index, MGMT_OP_DISCONNECT, |
1189 | MGMT_STATUS_INVALID_PARAMS); | ||
1021 | 1190 | ||
1022 | hci_dev_lock_bh(hdev); | 1191 | hci_dev_lock(hdev); |
1023 | 1192 | ||
1024 | if (!test_bit(HCI_UP, &hdev->flags)) { | 1193 | if (!test_bit(HCI_UP, &hdev->flags)) { |
1025 | err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN); | 1194 | err = cmd_status(sk, index, MGMT_OP_DISCONNECT, |
1195 | MGMT_STATUS_NOT_POWERED); | ||
1026 | goto failed; | 1196 | goto failed; |
1027 | } | 1197 | } |
1028 | 1198 | ||
1029 | if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) { | 1199 | if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) { |
1030 | err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY); | 1200 | err = cmd_status(sk, index, MGMT_OP_DISCONNECT, |
1201 | MGMT_STATUS_BUSY); | ||
1031 | goto failed; | 1202 | goto failed; |
1032 | } | 1203 | } |
1033 | 1204 | ||
@@ -1036,11 +1207,12 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
1036 | conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr); | 1207 | conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr); |
1037 | 1208 | ||
1038 | if (!conn) { | 1209 | if (!conn) { |
1039 | err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN); | 1210 | err = cmd_status(sk, index, MGMT_OP_DISCONNECT, |
1211 | MGMT_STATUS_NOT_CONNECTED); | ||
1040 | goto failed; | 1212 | goto failed; |
1041 | } | 1213 | } |
1042 | 1214 | ||
1043 | cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len); | 1215 | cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len); |
1044 | if (!cmd) { | 1216 | if (!cmd) { |
1045 | err = -ENOMEM; | 1217 | err = -ENOMEM; |
1046 | goto failed; | 1218 | goto failed; |
@@ -1054,16 +1226,36 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
1054 | mgmt_pending_remove(cmd); | 1226 | mgmt_pending_remove(cmd); |
1055 | 1227 | ||
1056 | failed: | 1228 | failed: |
1057 | hci_dev_unlock_bh(hdev); | 1229 | hci_dev_unlock(hdev); |
1058 | hci_dev_put(hdev); | 1230 | hci_dev_put(hdev); |
1059 | 1231 | ||
1060 | return err; | 1232 | return err; |
1061 | } | 1233 | } |
1062 | 1234 | ||
1235 | static u8 link_to_mgmt(u8 link_type, u8 addr_type) | ||
1236 | { | ||
1237 | switch (link_type) { | ||
1238 | case LE_LINK: | ||
1239 | switch (addr_type) { | ||
1240 | case ADDR_LE_DEV_PUBLIC: | ||
1241 | return MGMT_ADDR_LE_PUBLIC; | ||
1242 | case ADDR_LE_DEV_RANDOM: | ||
1243 | return MGMT_ADDR_LE_RANDOM; | ||
1244 | default: | ||
1245 | return MGMT_ADDR_INVALID; | ||
1246 | } | ||
1247 | case ACL_LINK: | ||
1248 | return MGMT_ADDR_BREDR; | ||
1249 | default: | ||
1250 | return MGMT_ADDR_INVALID; | ||
1251 | } | ||
1252 | } | ||
1253 | |||
1063 | static int get_connections(struct sock *sk, u16 index) | 1254 | static int get_connections(struct sock *sk, u16 index) |
1064 | { | 1255 | { |
1065 | struct mgmt_rp_get_connections *rp; | 1256 | struct mgmt_rp_get_connections *rp; |
1066 | struct hci_dev *hdev; | 1257 | struct hci_dev *hdev; |
1258 | struct hci_conn *c; | ||
1067 | struct list_head *p; | 1259 | struct list_head *p; |
1068 | size_t rp_len; | 1260 | size_t rp_len; |
1069 | u16 count; | 1261 | u16 count; |
@@ -1073,16 +1265,17 @@ static int get_connections(struct sock *sk, u16 index) | |||
1073 | 1265 | ||
1074 | hdev = hci_dev_get(index); | 1266 | hdev = hci_dev_get(index); |
1075 | if (!hdev) | 1267 | if (!hdev) |
1076 | return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV); | 1268 | return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, |
1269 | MGMT_STATUS_INVALID_PARAMS); | ||
1077 | 1270 | ||
1078 | hci_dev_lock_bh(hdev); | 1271 | hci_dev_lock(hdev); |
1079 | 1272 | ||
1080 | count = 0; | 1273 | count = 0; |
1081 | list_for_each(p, &hdev->conn_hash.list) { | 1274 | list_for_each(p, &hdev->conn_hash.list) { |
1082 | count++; | 1275 | count++; |
1083 | } | 1276 | } |
1084 | 1277 | ||
1085 | rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t)); | 1278 | rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info)); |
1086 | rp = kmalloc(rp_len, GFP_ATOMIC); | 1279 | rp = kmalloc(rp_len, GFP_ATOMIC); |
1087 | if (!rp) { | 1280 | if (!rp) { |
1088 | err = -ENOMEM; | 1281 | err = -ENOMEM; |
@@ -1092,17 +1285,22 @@ static int get_connections(struct sock *sk, u16 index) | |||
1092 | put_unaligned_le16(count, &rp->conn_count); | 1285 | put_unaligned_le16(count, &rp->conn_count); |
1093 | 1286 | ||
1094 | i = 0; | 1287 | i = 0; |
1095 | list_for_each(p, &hdev->conn_hash.list) { | 1288 | list_for_each_entry(c, &hdev->conn_hash.list, list) { |
1096 | struct hci_conn *c = list_entry(p, struct hci_conn, list); | 1289 | bacpy(&rp->addr[i].bdaddr, &c->dst); |
1097 | 1290 | rp->addr[i].type = link_to_mgmt(c->type, c->dst_type); | |
1098 | bacpy(&rp->conn[i++], &c->dst); | 1291 | if (rp->addr[i].type == MGMT_ADDR_INVALID) |
1292 | continue; | ||
1293 | i++; | ||
1099 | } | 1294 | } |
1100 | 1295 | ||
1296 | /* Recalculate length in case of filtered SCO connections, etc */ | ||
1297 | rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info)); | ||
1298 | |||
1101 | err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len); | 1299 | err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len); |
1102 | 1300 | ||
1103 | unlock: | 1301 | unlock: |
1104 | kfree(rp); | 1302 | kfree(rp); |
1105 | hci_dev_unlock_bh(hdev); | 1303 | hci_dev_unlock(hdev); |
1106 | hci_dev_put(hdev); | 1304 | hci_dev_put(hdev); |
1107 | return err; | 1305 | return err; |
1108 | } | 1306 | } |
@@ -1113,7 +1311,7 @@ static int send_pin_code_neg_reply(struct sock *sk, u16 index, | |||
1113 | struct pending_cmd *cmd; | 1311 | struct pending_cmd *cmd; |
1114 | int err; | 1312 | int err; |
1115 | 1313 | ||
1116 | cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index, cp, | 1314 | cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp, |
1117 | sizeof(*cp)); | 1315 | sizeof(*cp)); |
1118 | if (!cmd) | 1316 | if (!cmd) |
1119 | return -ENOMEM; | 1317 | return -ENOMEM; |
@@ -1142,22 +1340,26 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data, | |||
1142 | cp = (void *) data; | 1340 | cp = (void *) data; |
1143 | 1341 | ||
1144 | if (len != sizeof(*cp)) | 1342 | if (len != sizeof(*cp)) |
1145 | return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL); | 1343 | return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, |
1344 | MGMT_STATUS_INVALID_PARAMS); | ||
1146 | 1345 | ||
1147 | hdev = hci_dev_get(index); | 1346 | hdev = hci_dev_get(index); |
1148 | if (!hdev) | 1347 | if (!hdev) |
1149 | return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV); | 1348 | return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, |
1349 | MGMT_STATUS_INVALID_PARAMS); | ||
1150 | 1350 | ||
1151 | hci_dev_lock_bh(hdev); | 1351 | hci_dev_lock(hdev); |
1152 | 1352 | ||
1153 | if (!test_bit(HCI_UP, &hdev->flags)) { | 1353 | if (!test_bit(HCI_UP, &hdev->flags)) { |
1154 | err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN); | 1354 | err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, |
1355 | MGMT_STATUS_NOT_POWERED); | ||
1155 | goto failed; | 1356 | goto failed; |
1156 | } | 1357 | } |
1157 | 1358 | ||
1158 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); | 1359 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); |
1159 | if (!conn) { | 1360 | if (!conn) { |
1160 | err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENOTCONN); | 1361 | err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, |
1362 | MGMT_STATUS_NOT_CONNECTED); | ||
1161 | goto failed; | 1363 | goto failed; |
1162 | } | 1364 | } |
1163 | 1365 | ||
@@ -1169,12 +1371,12 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data, | |||
1169 | err = send_pin_code_neg_reply(sk, index, hdev, &ncp); | 1371 | err = send_pin_code_neg_reply(sk, index, hdev, &ncp); |
1170 | if (err >= 0) | 1372 | if (err >= 0) |
1171 | err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, | 1373 | err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, |
1172 | EINVAL); | 1374 | MGMT_STATUS_INVALID_PARAMS); |
1173 | 1375 | ||
1174 | goto failed; | 1376 | goto failed; |
1175 | } | 1377 | } |
1176 | 1378 | ||
1177 | cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len); | 1379 | cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len); |
1178 | if (!cmd) { | 1380 | if (!cmd) { |
1179 | err = -ENOMEM; | 1381 | err = -ENOMEM; |
1180 | goto failed; | 1382 | goto failed; |
@@ -1189,7 +1391,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data, | |||
1189 | mgmt_pending_remove(cmd); | 1391 | mgmt_pending_remove(cmd); |
1190 | 1392 | ||
1191 | failed: | 1393 | failed: |
1192 | hci_dev_unlock_bh(hdev); | 1394 | hci_dev_unlock(hdev); |
1193 | hci_dev_put(hdev); | 1395 | hci_dev_put(hdev); |
1194 | 1396 | ||
1195 | return err; | 1397 | return err; |
@@ -1208,25 +1410,25 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data, | |||
1208 | 1410 | ||
1209 | if (len != sizeof(*cp)) | 1411 | if (len != sizeof(*cp)) |
1210 | return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, | 1412 | return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, |
1211 | EINVAL); | 1413 | MGMT_STATUS_INVALID_PARAMS); |
1212 | 1414 | ||
1213 | hdev = hci_dev_get(index); | 1415 | hdev = hci_dev_get(index); |
1214 | if (!hdev) | 1416 | if (!hdev) |
1215 | return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, | 1417 | return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, |
1216 | ENODEV); | 1418 | MGMT_STATUS_INVALID_PARAMS); |
1217 | 1419 | ||
1218 | hci_dev_lock_bh(hdev); | 1420 | hci_dev_lock(hdev); |
1219 | 1421 | ||
1220 | if (!test_bit(HCI_UP, &hdev->flags)) { | 1422 | if (!test_bit(HCI_UP, &hdev->flags)) { |
1221 | err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, | 1423 | err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, |
1222 | ENETDOWN); | 1424 | MGMT_STATUS_NOT_POWERED); |
1223 | goto failed; | 1425 | goto failed; |
1224 | } | 1426 | } |
1225 | 1427 | ||
1226 | err = send_pin_code_neg_reply(sk, index, hdev, cp); | 1428 | err = send_pin_code_neg_reply(sk, index, hdev, cp); |
1227 | 1429 | ||
1228 | failed: | 1430 | failed: |
1229 | hci_dev_unlock_bh(hdev); | 1431 | hci_dev_unlock(hdev); |
1230 | hci_dev_put(hdev); | 1432 | hci_dev_put(hdev); |
1231 | 1433 | ||
1232 | return err; | 1434 | return err; |
@@ -1243,20 +1445,22 @@ static int set_io_capability(struct sock *sk, u16 index, unsigned char *data, | |||
1243 | cp = (void *) data; | 1445 | cp = (void *) data; |
1244 | 1446 | ||
1245 | if (len != sizeof(*cp)) | 1447 | if (len != sizeof(*cp)) |
1246 | return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL); | 1448 | return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, |
1449 | MGMT_STATUS_INVALID_PARAMS); | ||
1247 | 1450 | ||
1248 | hdev = hci_dev_get(index); | 1451 | hdev = hci_dev_get(index); |
1249 | if (!hdev) | 1452 | if (!hdev) |
1250 | return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV); | 1453 | return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, |
1454 | MGMT_STATUS_INVALID_PARAMS); | ||
1251 | 1455 | ||
1252 | hci_dev_lock_bh(hdev); | 1456 | hci_dev_lock(hdev); |
1253 | 1457 | ||
1254 | hdev->io_capability = cp->io_capability; | 1458 | hdev->io_capability = cp->io_capability; |
1255 | 1459 | ||
1256 | BT_DBG("%s IO capability set to 0x%02x", hdev->name, | 1460 | BT_DBG("%s IO capability set to 0x%02x", hdev->name, |
1257 | hdev->io_capability); | 1461 | hdev->io_capability); |
1258 | 1462 | ||
1259 | hci_dev_unlock_bh(hdev); | 1463 | hci_dev_unlock(hdev); |
1260 | hci_dev_put(hdev); | 1464 | hci_dev_put(hdev); |
1261 | 1465 | ||
1262 | return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0); | 1466 | return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0); |
@@ -1265,19 +1469,12 @@ static int set_io_capability(struct sock *sk, u16 index, unsigned char *data, | |||
1265 | static inline struct pending_cmd *find_pairing(struct hci_conn *conn) | 1469 | static inline struct pending_cmd *find_pairing(struct hci_conn *conn) |
1266 | { | 1470 | { |
1267 | struct hci_dev *hdev = conn->hdev; | 1471 | struct hci_dev *hdev = conn->hdev; |
1268 | struct list_head *p; | 1472 | struct pending_cmd *cmd; |
1269 | |||
1270 | list_for_each(p, &cmd_list) { | ||
1271 | struct pending_cmd *cmd; | ||
1272 | |||
1273 | cmd = list_entry(p, struct pending_cmd, list); | ||
1274 | 1473 | ||
1474 | list_for_each_entry(cmd, &hdev->mgmt_pending, list) { | ||
1275 | if (cmd->opcode != MGMT_OP_PAIR_DEVICE) | 1475 | if (cmd->opcode != MGMT_OP_PAIR_DEVICE) |
1276 | continue; | 1476 | continue; |
1277 | 1477 | ||
1278 | if (cmd->index != hdev->id) | ||
1279 | continue; | ||
1280 | |||
1281 | if (cmd->user_data != conn) | 1478 | if (cmd->user_data != conn) |
1282 | continue; | 1479 | continue; |
1283 | 1480 | ||
@@ -1292,7 +1489,8 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status) | |||
1292 | struct mgmt_rp_pair_device rp; | 1489 | struct mgmt_rp_pair_device rp; |
1293 | struct hci_conn *conn = cmd->user_data; | 1490 | struct hci_conn *conn = cmd->user_data; |
1294 | 1491 | ||
1295 | bacpy(&rp.bdaddr, &conn->dst); | 1492 | bacpy(&rp.addr.bdaddr, &conn->dst); |
1493 | rp.addr.type = link_to_mgmt(conn->type, conn->dst_type); | ||
1296 | rp.status = status; | 1494 | rp.status = status; |
1297 | 1495 | ||
1298 | cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp)); | 1496 | cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp)); |
@@ -1314,20 +1512,18 @@ static void pairing_complete_cb(struct hci_conn *conn, u8 status) | |||
1314 | BT_DBG("status %u", status); | 1512 | BT_DBG("status %u", status); |
1315 | 1513 | ||
1316 | cmd = find_pairing(conn); | 1514 | cmd = find_pairing(conn); |
1317 | if (!cmd) { | 1515 | if (!cmd) |
1318 | BT_DBG("Unable to find a pending command"); | 1516 | BT_DBG("Unable to find a pending command"); |
1319 | return; | 1517 | else |
1320 | } | 1518 | pairing_complete(cmd, status); |
1321 | |||
1322 | pairing_complete(cmd, status); | ||
1323 | } | 1519 | } |
1324 | 1520 | ||
1325 | static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) | 1521 | static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) |
1326 | { | 1522 | { |
1327 | struct hci_dev *hdev; | 1523 | struct hci_dev *hdev; |
1328 | struct mgmt_cp_pair_device *cp; | 1524 | struct mgmt_cp_pair_device *cp; |
1525 | struct mgmt_rp_pair_device rp; | ||
1329 | struct pending_cmd *cmd; | 1526 | struct pending_cmd *cmd; |
1330 | struct adv_entry *entry; | ||
1331 | u8 sec_level, auth_type; | 1527 | u8 sec_level, auth_type; |
1332 | struct hci_conn *conn; | 1528 | struct hci_conn *conn; |
1333 | int err; | 1529 | int err; |
@@ -1337,13 +1533,15 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
1337 | cp = (void *) data; | 1533 | cp = (void *) data; |
1338 | 1534 | ||
1339 | if (len != sizeof(*cp)) | 1535 | if (len != sizeof(*cp)) |
1340 | return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL); | 1536 | return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, |
1537 | MGMT_STATUS_INVALID_PARAMS); | ||
1341 | 1538 | ||
1342 | hdev = hci_dev_get(index); | 1539 | hdev = hci_dev_get(index); |
1343 | if (!hdev) | 1540 | if (!hdev) |
1344 | return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV); | 1541 | return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, |
1542 | MGMT_STATUS_INVALID_PARAMS); | ||
1345 | 1543 | ||
1346 | hci_dev_lock_bh(hdev); | 1544 | hci_dev_lock(hdev); |
1347 | 1545 | ||
1348 | sec_level = BT_SECURITY_MEDIUM; | 1546 | sec_level = BT_SECURITY_MEDIUM; |
1349 | if (cp->io_cap == 0x03) | 1547 | if (cp->io_cap == 0x03) |
@@ -1351,26 +1549,33 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
1351 | else | 1549 | else |
1352 | auth_type = HCI_AT_DEDICATED_BONDING_MITM; | 1550 | auth_type = HCI_AT_DEDICATED_BONDING_MITM; |
1353 | 1551 | ||
1354 | entry = hci_find_adv_entry(hdev, &cp->bdaddr); | 1552 | if (cp->addr.type == MGMT_ADDR_BREDR) |
1355 | if (entry) | 1553 | conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level, |
1356 | conn = hci_connect(hdev, LE_LINK, &cp->bdaddr, sec_level, | ||
1357 | auth_type); | 1554 | auth_type); |
1358 | else | 1555 | else |
1359 | conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level, | 1556 | conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level, |
1360 | auth_type); | 1557 | auth_type); |
1361 | 1558 | ||
1559 | memset(&rp, 0, sizeof(rp)); | ||
1560 | bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); | ||
1561 | rp.addr.type = cp->addr.type; | ||
1562 | |||
1362 | if (IS_ERR(conn)) { | 1563 | if (IS_ERR(conn)) { |
1363 | err = PTR_ERR(conn); | 1564 | rp.status = -PTR_ERR(conn); |
1565 | err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE, | ||
1566 | &rp, sizeof(rp)); | ||
1364 | goto unlock; | 1567 | goto unlock; |
1365 | } | 1568 | } |
1366 | 1569 | ||
1367 | if (conn->connect_cfm_cb) { | 1570 | if (conn->connect_cfm_cb) { |
1368 | hci_conn_put(conn); | 1571 | hci_conn_put(conn); |
1369 | err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY); | 1572 | rp.status = EBUSY; |
1573 | err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE, | ||
1574 | &rp, sizeof(rp)); | ||
1370 | goto unlock; | 1575 | goto unlock; |
1371 | } | 1576 | } |
1372 | 1577 | ||
1373 | cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len); | 1578 | cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len); |
1374 | if (!cmd) { | 1579 | if (!cmd) { |
1375 | err = -ENOMEM; | 1580 | err = -ENOMEM; |
1376 | hci_conn_put(conn); | 1581 | hci_conn_put(conn); |
@@ -1378,7 +1583,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
1378 | } | 1583 | } |
1379 | 1584 | ||
1380 | /* For LE, just connecting isn't a proof that the pairing finished */ | 1585 | /* For LE, just connecting isn't a proof that the pairing finished */ |
1381 | if (!entry) | 1586 | if (cp->addr.type == MGMT_ADDR_BREDR) |
1382 | conn->connect_cfm_cb = pairing_complete_cb; | 1587 | conn->connect_cfm_cb = pairing_complete_cb; |
1383 | 1588 | ||
1384 | conn->security_cfm_cb = pairing_complete_cb; | 1589 | conn->security_cfm_cb = pairing_complete_cb; |
@@ -1393,62 +1598,151 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
1393 | err = 0; | 1598 | err = 0; |
1394 | 1599 | ||
1395 | unlock: | 1600 | unlock: |
1396 | hci_dev_unlock_bh(hdev); | 1601 | hci_dev_unlock(hdev); |
1397 | hci_dev_put(hdev); | 1602 | hci_dev_put(hdev); |
1398 | 1603 | ||
1399 | return err; | 1604 | return err; |
1400 | } | 1605 | } |
1401 | 1606 | ||
1402 | static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data, | 1607 | static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr, |
1403 | u16 len, int success) | 1608 | u16 mgmt_op, u16 hci_op, __le32 passkey) |
1404 | { | 1609 | { |
1405 | struct mgmt_cp_user_confirm_reply *cp = (void *) data; | ||
1406 | u16 mgmt_op, hci_op; | ||
1407 | struct pending_cmd *cmd; | 1610 | struct pending_cmd *cmd; |
1408 | struct hci_dev *hdev; | 1611 | struct hci_dev *hdev; |
1612 | struct hci_conn *conn; | ||
1409 | int err; | 1613 | int err; |
1410 | 1614 | ||
1411 | BT_DBG(""); | 1615 | hdev = hci_dev_get(index); |
1616 | if (!hdev) | ||
1617 | return cmd_status(sk, index, mgmt_op, | ||
1618 | MGMT_STATUS_INVALID_PARAMS); | ||
1412 | 1619 | ||
1413 | if (success) { | 1620 | hci_dev_lock(hdev); |
1414 | mgmt_op = MGMT_OP_USER_CONFIRM_REPLY; | 1621 | |
1415 | hci_op = HCI_OP_USER_CONFIRM_REPLY; | 1622 | if (!test_bit(HCI_UP, &hdev->flags)) { |
1416 | } else { | 1623 | err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED); |
1417 | mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY; | 1624 | goto done; |
1418 | hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY; | ||
1419 | } | 1625 | } |
1420 | 1626 | ||
1421 | if (len != sizeof(*cp)) | 1627 | /* |
1422 | return cmd_status(sk, index, mgmt_op, EINVAL); | 1628 | * Check for an existing ACL link, if present pair via |
1629 | * HCI commands. | ||
1630 | * | ||
1631 | * If no ACL link is present, check for an LE link and if | ||
1632 | * present, pair via the SMP engine. | ||
1633 | * | ||
1634 | * If neither ACL nor LE links are present, fail with error. | ||
1635 | */ | ||
1636 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr); | ||
1637 | if (!conn) { | ||
1638 | conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr); | ||
1639 | if (!conn) { | ||
1640 | err = cmd_status(sk, index, mgmt_op, | ||
1641 | MGMT_STATUS_NOT_CONNECTED); | ||
1642 | goto done; | ||
1643 | } | ||
1423 | 1644 | ||
1424 | hdev = hci_dev_get(index); | 1645 | /* Continue with pairing via SMP */ |
1425 | if (!hdev) | 1646 | err = smp_user_confirm_reply(conn, mgmt_op, passkey); |
1426 | return cmd_status(sk, index, mgmt_op, ENODEV); | ||
1427 | 1647 | ||
1428 | hci_dev_lock_bh(hdev); | 1648 | if (!err) |
1649 | err = cmd_status(sk, index, mgmt_op, | ||
1650 | MGMT_STATUS_SUCCESS); | ||
1651 | else | ||
1652 | err = cmd_status(sk, index, mgmt_op, | ||
1653 | MGMT_STATUS_FAILED); | ||
1429 | 1654 | ||
1430 | if (!test_bit(HCI_UP, &hdev->flags)) { | 1655 | goto done; |
1431 | err = cmd_status(sk, index, mgmt_op, ENETDOWN); | ||
1432 | goto failed; | ||
1433 | } | 1656 | } |
1434 | 1657 | ||
1435 | cmd = mgmt_pending_add(sk, mgmt_op, index, data, len); | 1658 | cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr)); |
1436 | if (!cmd) { | 1659 | if (!cmd) { |
1437 | err = -ENOMEM; | 1660 | err = -ENOMEM; |
1438 | goto failed; | 1661 | goto done; |
1439 | } | 1662 | } |
1440 | 1663 | ||
1441 | err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr); | 1664 | /* Continue with pairing via HCI */ |
1665 | if (hci_op == HCI_OP_USER_PASSKEY_REPLY) { | ||
1666 | struct hci_cp_user_passkey_reply cp; | ||
1667 | |||
1668 | bacpy(&cp.bdaddr, bdaddr); | ||
1669 | cp.passkey = passkey; | ||
1670 | err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp); | ||
1671 | } else | ||
1672 | err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr); | ||
1673 | |||
1442 | if (err < 0) | 1674 | if (err < 0) |
1443 | mgmt_pending_remove(cmd); | 1675 | mgmt_pending_remove(cmd); |
1444 | 1676 | ||
1445 | failed: | 1677 | done: |
1446 | hci_dev_unlock_bh(hdev); | 1678 | hci_dev_unlock(hdev); |
1447 | hci_dev_put(hdev); | 1679 | hci_dev_put(hdev); |
1448 | 1680 | ||
1449 | return err; | 1681 | return err; |
1450 | } | 1682 | } |
1451 | 1683 | ||
1684 | static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len) | ||
1685 | { | ||
1686 | struct mgmt_cp_user_confirm_reply *cp = (void *) data; | ||
1687 | |||
1688 | BT_DBG(""); | ||
1689 | |||
1690 | if (len != sizeof(*cp)) | ||
1691 | return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY, | ||
1692 | MGMT_STATUS_INVALID_PARAMS); | ||
1693 | |||
1694 | return user_pairing_resp(sk, index, &cp->bdaddr, | ||
1695 | MGMT_OP_USER_CONFIRM_REPLY, | ||
1696 | HCI_OP_USER_CONFIRM_REPLY, 0); | ||
1697 | } | ||
1698 | |||
1699 | static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data, | ||
1700 | u16 len) | ||
1701 | { | ||
1702 | struct mgmt_cp_user_confirm_neg_reply *cp = data; | ||
1703 | |||
1704 | BT_DBG(""); | ||
1705 | |||
1706 | if (len != sizeof(*cp)) | ||
1707 | return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY, | ||
1708 | MGMT_STATUS_INVALID_PARAMS); | ||
1709 | |||
1710 | return user_pairing_resp(sk, index, &cp->bdaddr, | ||
1711 | MGMT_OP_USER_CONFIRM_NEG_REPLY, | ||
1712 | HCI_OP_USER_CONFIRM_NEG_REPLY, 0); | ||
1713 | } | ||
1714 | |||
1715 | static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len) | ||
1716 | { | ||
1717 | struct mgmt_cp_user_passkey_reply *cp = (void *) data; | ||
1718 | |||
1719 | BT_DBG(""); | ||
1720 | |||
1721 | if (len != sizeof(*cp)) | ||
1722 | return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY, | ||
1723 | EINVAL); | ||
1724 | |||
1725 | return user_pairing_resp(sk, index, &cp->bdaddr, | ||
1726 | MGMT_OP_USER_PASSKEY_REPLY, | ||
1727 | HCI_OP_USER_PASSKEY_REPLY, cp->passkey); | ||
1728 | } | ||
1729 | |||
1730 | static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data, | ||
1731 | u16 len) | ||
1732 | { | ||
1733 | struct mgmt_cp_user_passkey_neg_reply *cp = (void *) data; | ||
1734 | |||
1735 | BT_DBG(""); | ||
1736 | |||
1737 | if (len != sizeof(*cp)) | ||
1738 | return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY, | ||
1739 | EINVAL); | ||
1740 | |||
1741 | return user_pairing_resp(sk, index, &cp->bdaddr, | ||
1742 | MGMT_OP_USER_PASSKEY_NEG_REPLY, | ||
1743 | HCI_OP_USER_PASSKEY_NEG_REPLY, 0); | ||
1744 | } | ||
1745 | |||
1452 | static int set_local_name(struct sock *sk, u16 index, unsigned char *data, | 1746 | static int set_local_name(struct sock *sk, u16 index, unsigned char *data, |
1453 | u16 len) | 1747 | u16 len) |
1454 | { | 1748 | { |
@@ -1461,15 +1755,17 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data, | |||
1461 | BT_DBG(""); | 1755 | BT_DBG(""); |
1462 | 1756 | ||
1463 | if (len != sizeof(*mgmt_cp)) | 1757 | if (len != sizeof(*mgmt_cp)) |
1464 | return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL); | 1758 | return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, |
1759 | MGMT_STATUS_INVALID_PARAMS); | ||
1465 | 1760 | ||
1466 | hdev = hci_dev_get(index); | 1761 | hdev = hci_dev_get(index); |
1467 | if (!hdev) | 1762 | if (!hdev) |
1468 | return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV); | 1763 | return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, |
1764 | MGMT_STATUS_INVALID_PARAMS); | ||
1469 | 1765 | ||
1470 | hci_dev_lock_bh(hdev); | 1766 | hci_dev_lock(hdev); |
1471 | 1767 | ||
1472 | cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len); | 1768 | cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len); |
1473 | if (!cmd) { | 1769 | if (!cmd) { |
1474 | err = -ENOMEM; | 1770 | err = -ENOMEM; |
1475 | goto failed; | 1771 | goto failed; |
@@ -1482,7 +1778,7 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data, | |||
1482 | mgmt_pending_remove(cmd); | 1778 | mgmt_pending_remove(cmd); |
1483 | 1779 | ||
1484 | failed: | 1780 | failed: |
1485 | hci_dev_unlock_bh(hdev); | 1781 | hci_dev_unlock(hdev); |
1486 | hci_dev_put(hdev); | 1782 | hci_dev_put(hdev); |
1487 | 1783 | ||
1488 | return err; | 1784 | return err; |
@@ -1499,28 +1795,29 @@ static int read_local_oob_data(struct sock *sk, u16 index) | |||
1499 | hdev = hci_dev_get(index); | 1795 | hdev = hci_dev_get(index); |
1500 | if (!hdev) | 1796 | if (!hdev) |
1501 | return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, | 1797 | return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, |
1502 | ENODEV); | 1798 | MGMT_STATUS_INVALID_PARAMS); |
1503 | 1799 | ||
1504 | hci_dev_lock_bh(hdev); | 1800 | hci_dev_lock(hdev); |
1505 | 1801 | ||
1506 | if (!test_bit(HCI_UP, &hdev->flags)) { | 1802 | if (!test_bit(HCI_UP, &hdev->flags)) { |
1507 | err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, | 1803 | err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, |
1508 | ENETDOWN); | 1804 | MGMT_STATUS_NOT_POWERED); |
1509 | goto unlock; | 1805 | goto unlock; |
1510 | } | 1806 | } |
1511 | 1807 | ||
1512 | if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) { | 1808 | if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) { |
1513 | err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, | 1809 | err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, |
1514 | EOPNOTSUPP); | 1810 | MGMT_STATUS_NOT_SUPPORTED); |
1515 | goto unlock; | 1811 | goto unlock; |
1516 | } | 1812 | } |
1517 | 1813 | ||
1518 | if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) { | 1814 | if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) { |
1519 | err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY); | 1815 | err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, |
1816 | MGMT_STATUS_BUSY); | ||
1520 | goto unlock; | 1817 | goto unlock; |
1521 | } | 1818 | } |
1522 | 1819 | ||
1523 | cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0); | 1820 | cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0); |
1524 | if (!cmd) { | 1821 | if (!cmd) { |
1525 | err = -ENOMEM; | 1822 | err = -ENOMEM; |
1526 | goto unlock; | 1823 | goto unlock; |
@@ -1531,7 +1828,7 @@ static int read_local_oob_data(struct sock *sk, u16 index) | |||
1531 | mgmt_pending_remove(cmd); | 1828 | mgmt_pending_remove(cmd); |
1532 | 1829 | ||
1533 | unlock: | 1830 | unlock: |
1534 | hci_dev_unlock_bh(hdev); | 1831 | hci_dev_unlock(hdev); |
1535 | hci_dev_put(hdev); | 1832 | hci_dev_put(hdev); |
1536 | 1833 | ||
1537 | return err; | 1834 | return err; |
@@ -1548,24 +1845,25 @@ static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data, | |||
1548 | 1845 | ||
1549 | if (len != sizeof(*cp)) | 1846 | if (len != sizeof(*cp)) |
1550 | return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, | 1847 | return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, |
1551 | EINVAL); | 1848 | MGMT_STATUS_INVALID_PARAMS); |
1552 | 1849 | ||
1553 | hdev = hci_dev_get(index); | 1850 | hdev = hci_dev_get(index); |
1554 | if (!hdev) | 1851 | if (!hdev) |
1555 | return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, | 1852 | return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, |
1556 | ENODEV); | 1853 | MGMT_STATUS_INVALID_PARAMS); |
1557 | 1854 | ||
1558 | hci_dev_lock_bh(hdev); | 1855 | hci_dev_lock(hdev); |
1559 | 1856 | ||
1560 | err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash, | 1857 | err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash, |
1561 | cp->randomizer); | 1858 | cp->randomizer); |
1562 | if (err < 0) | 1859 | if (err < 0) |
1563 | err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err); | 1860 | err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, |
1861 | MGMT_STATUS_FAILED); | ||
1564 | else | 1862 | else |
1565 | err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL, | 1863 | err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL, |
1566 | 0); | 1864 | 0); |
1567 | 1865 | ||
1568 | hci_dev_unlock_bh(hdev); | 1866 | hci_dev_unlock(hdev); |
1569 | hci_dev_put(hdev); | 1867 | hci_dev_put(hdev); |
1570 | 1868 | ||
1571 | return err; | 1869 | return err; |
@@ -1582,62 +1880,68 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, | |||
1582 | 1880 | ||
1583 | if (len != sizeof(*cp)) | 1881 | if (len != sizeof(*cp)) |
1584 | return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, | 1882 | return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, |
1585 | EINVAL); | 1883 | MGMT_STATUS_INVALID_PARAMS); |
1586 | 1884 | ||
1587 | hdev = hci_dev_get(index); | 1885 | hdev = hci_dev_get(index); |
1588 | if (!hdev) | 1886 | if (!hdev) |
1589 | return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, | 1887 | return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, |
1590 | ENODEV); | 1888 | MGMT_STATUS_INVALID_PARAMS); |
1591 | 1889 | ||
1592 | hci_dev_lock_bh(hdev); | 1890 | hci_dev_lock(hdev); |
1593 | 1891 | ||
1594 | err = hci_remove_remote_oob_data(hdev, &cp->bdaddr); | 1892 | err = hci_remove_remote_oob_data(hdev, &cp->bdaddr); |
1595 | if (err < 0) | 1893 | if (err < 0) |
1596 | err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, | 1894 | err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, |
1597 | -err); | 1895 | MGMT_STATUS_INVALID_PARAMS); |
1598 | else | 1896 | else |
1599 | err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, | 1897 | err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, |
1600 | NULL, 0); | 1898 | NULL, 0); |
1601 | 1899 | ||
1602 | hci_dev_unlock_bh(hdev); | 1900 | hci_dev_unlock(hdev); |
1603 | hci_dev_put(hdev); | 1901 | hci_dev_put(hdev); |
1604 | 1902 | ||
1605 | return err; | 1903 | return err; |
1606 | } | 1904 | } |
1607 | 1905 | ||
1608 | static int start_discovery(struct sock *sk, u16 index) | 1906 | static int start_discovery(struct sock *sk, u16 index, |
1907 | unsigned char *data, u16 len) | ||
1609 | { | 1908 | { |
1610 | u8 lap[3] = { 0x33, 0x8b, 0x9e }; | 1909 | struct mgmt_cp_start_discovery *cp = (void *) data; |
1611 | struct hci_cp_inquiry cp; | ||
1612 | struct pending_cmd *cmd; | 1910 | struct pending_cmd *cmd; |
1613 | struct hci_dev *hdev; | 1911 | struct hci_dev *hdev; |
1614 | int err; | 1912 | int err; |
1615 | 1913 | ||
1616 | BT_DBG("hci%u", index); | 1914 | BT_DBG("hci%u", index); |
1617 | 1915 | ||
1916 | if (len != sizeof(*cp)) | ||
1917 | return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, | ||
1918 | MGMT_STATUS_INVALID_PARAMS); | ||
1919 | |||
1618 | hdev = hci_dev_get(index); | 1920 | hdev = hci_dev_get(index); |
1619 | if (!hdev) | 1921 | if (!hdev) |
1620 | return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV); | 1922 | return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, |
1923 | MGMT_STATUS_INVALID_PARAMS); | ||
1621 | 1924 | ||
1622 | hci_dev_lock_bh(hdev); | 1925 | hci_dev_lock(hdev); |
1623 | 1926 | ||
1624 | cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0); | 1927 | if (!test_bit(HCI_UP, &hdev->flags)) { |
1928 | err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, | ||
1929 | MGMT_STATUS_NOT_POWERED); | ||
1930 | goto failed; | ||
1931 | } | ||
1932 | |||
1933 | cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0); | ||
1625 | if (!cmd) { | 1934 | if (!cmd) { |
1626 | err = -ENOMEM; | 1935 | err = -ENOMEM; |
1627 | goto failed; | 1936 | goto failed; |
1628 | } | 1937 | } |
1629 | 1938 | ||
1630 | memset(&cp, 0, sizeof(cp)); | 1939 | err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); |
1631 | memcpy(&cp.lap, lap, 3); | ||
1632 | cp.length = 0x08; | ||
1633 | cp.num_rsp = 0x00; | ||
1634 | |||
1635 | err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp); | ||
1636 | if (err < 0) | 1940 | if (err < 0) |
1637 | mgmt_pending_remove(cmd); | 1941 | mgmt_pending_remove(cmd); |
1638 | 1942 | ||
1639 | failed: | 1943 | failed: |
1640 | hci_dev_unlock_bh(hdev); | 1944 | hci_dev_unlock(hdev); |
1641 | hci_dev_put(hdev); | 1945 | hci_dev_put(hdev); |
1642 | 1946 | ||
1643 | return err; | 1947 | return err; |
@@ -1653,22 +1957,23 @@ static int stop_discovery(struct sock *sk, u16 index) | |||
1653 | 1957 | ||
1654 | hdev = hci_dev_get(index); | 1958 | hdev = hci_dev_get(index); |
1655 | if (!hdev) | 1959 | if (!hdev) |
1656 | return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV); | 1960 | return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, |
1961 | MGMT_STATUS_INVALID_PARAMS); | ||
1657 | 1962 | ||
1658 | hci_dev_lock_bh(hdev); | 1963 | hci_dev_lock(hdev); |
1659 | 1964 | ||
1660 | cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0); | 1965 | cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0); |
1661 | if (!cmd) { | 1966 | if (!cmd) { |
1662 | err = -ENOMEM; | 1967 | err = -ENOMEM; |
1663 | goto failed; | 1968 | goto failed; |
1664 | } | 1969 | } |
1665 | 1970 | ||
1666 | err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL); | 1971 | err = hci_cancel_inquiry(hdev); |
1667 | if (err < 0) | 1972 | if (err < 0) |
1668 | mgmt_pending_remove(cmd); | 1973 | mgmt_pending_remove(cmd); |
1669 | 1974 | ||
1670 | failed: | 1975 | failed: |
1671 | hci_dev_unlock_bh(hdev); | 1976 | hci_dev_unlock(hdev); |
1672 | hci_dev_put(hdev); | 1977 | hci_dev_put(hdev); |
1673 | 1978 | ||
1674 | return err; | 1979 | return err; |
@@ -1678,7 +1983,6 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data, | |||
1678 | u16 len) | 1983 | u16 len) |
1679 | { | 1984 | { |
1680 | struct hci_dev *hdev; | 1985 | struct hci_dev *hdev; |
1681 | struct pending_cmd *cmd; | ||
1682 | struct mgmt_cp_block_device *cp = (void *) data; | 1986 | struct mgmt_cp_block_device *cp = (void *) data; |
1683 | int err; | 1987 | int err; |
1684 | 1988 | ||
@@ -1686,33 +1990,24 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data, | |||
1686 | 1990 | ||
1687 | if (len != sizeof(*cp)) | 1991 | if (len != sizeof(*cp)) |
1688 | return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, | 1992 | return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, |
1689 | EINVAL); | 1993 | MGMT_STATUS_INVALID_PARAMS); |
1690 | 1994 | ||
1691 | hdev = hci_dev_get(index); | 1995 | hdev = hci_dev_get(index); |
1692 | if (!hdev) | 1996 | if (!hdev) |
1693 | return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, | 1997 | return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, |
1694 | ENODEV); | 1998 | MGMT_STATUS_INVALID_PARAMS); |
1695 | 1999 | ||
1696 | hci_dev_lock_bh(hdev); | 2000 | hci_dev_lock(hdev); |
1697 | |||
1698 | cmd = mgmt_pending_add(sk, MGMT_OP_BLOCK_DEVICE, index, NULL, 0); | ||
1699 | if (!cmd) { | ||
1700 | err = -ENOMEM; | ||
1701 | goto failed; | ||
1702 | } | ||
1703 | 2001 | ||
1704 | err = hci_blacklist_add(hdev, &cp->bdaddr); | 2002 | err = hci_blacklist_add(hdev, &cp->bdaddr); |
1705 | |||
1706 | if (err < 0) | 2003 | if (err < 0) |
1707 | err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err); | 2004 | err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, |
2005 | MGMT_STATUS_FAILED); | ||
1708 | else | 2006 | else |
1709 | err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, | 2007 | err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, |
1710 | NULL, 0); | 2008 | NULL, 0); |
1711 | 2009 | ||
1712 | mgmt_pending_remove(cmd); | 2010 | hci_dev_unlock(hdev); |
1713 | |||
1714 | failed: | ||
1715 | hci_dev_unlock_bh(hdev); | ||
1716 | hci_dev_put(hdev); | 2011 | hci_dev_put(hdev); |
1717 | 2012 | ||
1718 | return err; | 2013 | return err; |
@@ -1722,7 +2017,6 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data, | |||
1722 | u16 len) | 2017 | u16 len) |
1723 | { | 2018 | { |
1724 | struct hci_dev *hdev; | 2019 | struct hci_dev *hdev; |
1725 | struct pending_cmd *cmd; | ||
1726 | struct mgmt_cp_unblock_device *cp = (void *) data; | 2020 | struct mgmt_cp_unblock_device *cp = (void *) data; |
1727 | int err; | 2021 | int err; |
1728 | 2022 | ||
@@ -1730,33 +2024,25 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data, | |||
1730 | 2024 | ||
1731 | if (len != sizeof(*cp)) | 2025 | if (len != sizeof(*cp)) |
1732 | return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, | 2026 | return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, |
1733 | EINVAL); | 2027 | MGMT_STATUS_INVALID_PARAMS); |
1734 | 2028 | ||
1735 | hdev = hci_dev_get(index); | 2029 | hdev = hci_dev_get(index); |
1736 | if (!hdev) | 2030 | if (!hdev) |
1737 | return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, | 2031 | return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, |
1738 | ENODEV); | 2032 | MGMT_STATUS_INVALID_PARAMS); |
1739 | 2033 | ||
1740 | hci_dev_lock_bh(hdev); | 2034 | hci_dev_lock(hdev); |
1741 | |||
1742 | cmd = mgmt_pending_add(sk, MGMT_OP_UNBLOCK_DEVICE, index, NULL, 0); | ||
1743 | if (!cmd) { | ||
1744 | err = -ENOMEM; | ||
1745 | goto failed; | ||
1746 | } | ||
1747 | 2035 | ||
1748 | err = hci_blacklist_del(hdev, &cp->bdaddr); | 2036 | err = hci_blacklist_del(hdev, &cp->bdaddr); |
1749 | 2037 | ||
1750 | if (err < 0) | 2038 | if (err < 0) |
1751 | err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, -err); | 2039 | err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, |
2040 | MGMT_STATUS_INVALID_PARAMS); | ||
1752 | else | 2041 | else |
1753 | err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, | 2042 | err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, |
1754 | NULL, 0); | 2043 | NULL, 0); |
1755 | 2044 | ||
1756 | mgmt_pending_remove(cmd); | 2045 | hci_dev_unlock(hdev); |
1757 | |||
1758 | failed: | ||
1759 | hci_dev_unlock_bh(hdev); | ||
1760 | hci_dev_put(hdev); | 2046 | hci_dev_put(hdev); |
1761 | 2047 | ||
1762 | return err; | 2048 | return err; |
@@ -1766,7 +2052,7 @@ static int set_fast_connectable(struct sock *sk, u16 index, | |||
1766 | unsigned char *data, u16 len) | 2052 | unsigned char *data, u16 len) |
1767 | { | 2053 | { |
1768 | struct hci_dev *hdev; | 2054 | struct hci_dev *hdev; |
1769 | struct mgmt_cp_set_fast_connectable *cp = (void *) data; | 2055 | struct mgmt_mode *cp = (void *) data; |
1770 | struct hci_cp_write_page_scan_activity acp; | 2056 | struct hci_cp_write_page_scan_activity acp; |
1771 | u8 type; | 2057 | u8 type; |
1772 | int err; | 2058 | int err; |
@@ -1775,16 +2061,16 @@ static int set_fast_connectable(struct sock *sk, u16 index, | |||
1775 | 2061 | ||
1776 | if (len != sizeof(*cp)) | 2062 | if (len != sizeof(*cp)) |
1777 | return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, | 2063 | return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, |
1778 | EINVAL); | 2064 | MGMT_STATUS_INVALID_PARAMS); |
1779 | 2065 | ||
1780 | hdev = hci_dev_get(index); | 2066 | hdev = hci_dev_get(index); |
1781 | if (!hdev) | 2067 | if (!hdev) |
1782 | return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, | 2068 | return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, |
1783 | ENODEV); | 2069 | MGMT_STATUS_INVALID_PARAMS); |
1784 | 2070 | ||
1785 | hci_dev_lock(hdev); | 2071 | hci_dev_lock(hdev); |
1786 | 2072 | ||
1787 | if (cp->enable) { | 2073 | if (cp->val) { |
1788 | type = PAGE_SCAN_TYPE_INTERLACED; | 2074 | type = PAGE_SCAN_TYPE_INTERLACED; |
1789 | acp.interval = 0x0024; /* 22.5 msec page scan interval */ | 2075 | acp.interval = 0x0024; /* 22.5 msec page scan interval */ |
1790 | } else { | 2076 | } else { |
@@ -1798,14 +2084,14 @@ static int set_fast_connectable(struct sock *sk, u16 index, | |||
1798 | sizeof(acp), &acp); | 2084 | sizeof(acp), &acp); |
1799 | if (err < 0) { | 2085 | if (err < 0) { |
1800 | err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, | 2086 | err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, |
1801 | -err); | 2087 | MGMT_STATUS_FAILED); |
1802 | goto done; | 2088 | goto done; |
1803 | } | 2089 | } |
1804 | 2090 | ||
1805 | err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type); | 2091 | err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type); |
1806 | if (err < 0) { | 2092 | if (err < 0) { |
1807 | err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, | 2093 | err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, |
1808 | -err); | 2094 | MGMT_STATUS_FAILED); |
1809 | goto done; | 2095 | goto done; |
1810 | } | 2096 | } |
1811 | 2097 | ||
@@ -1868,6 +2154,10 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | |||
1868 | case MGMT_OP_SET_CONNECTABLE: | 2154 | case MGMT_OP_SET_CONNECTABLE: |
1869 | err = set_connectable(sk, index, buf + sizeof(*hdr), len); | 2155 | err = set_connectable(sk, index, buf + sizeof(*hdr), len); |
1870 | break; | 2156 | break; |
2157 | case MGMT_OP_SET_FAST_CONNECTABLE: | ||
2158 | err = set_fast_connectable(sk, index, buf + sizeof(*hdr), | ||
2159 | len); | ||
2160 | break; | ||
1871 | case MGMT_OP_SET_PAIRABLE: | 2161 | case MGMT_OP_SET_PAIRABLE: |
1872 | err = set_pairable(sk, index, buf + sizeof(*hdr), len); | 2162 | err = set_pairable(sk, index, buf + sizeof(*hdr), len); |
1873 | break; | 2163 | break; |
@@ -1880,14 +2170,11 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | |||
1880 | case MGMT_OP_SET_DEV_CLASS: | 2170 | case MGMT_OP_SET_DEV_CLASS: |
1881 | err = set_dev_class(sk, index, buf + sizeof(*hdr), len); | 2171 | err = set_dev_class(sk, index, buf + sizeof(*hdr), len); |
1882 | break; | 2172 | break; |
1883 | case MGMT_OP_SET_SERVICE_CACHE: | 2173 | case MGMT_OP_LOAD_LINK_KEYS: |
1884 | err = set_service_cache(sk, index, buf + sizeof(*hdr), len); | 2174 | err = load_link_keys(sk, index, buf + sizeof(*hdr), len); |
1885 | break; | ||
1886 | case MGMT_OP_LOAD_KEYS: | ||
1887 | err = load_keys(sk, index, buf + sizeof(*hdr), len); | ||
1888 | break; | 2175 | break; |
1889 | case MGMT_OP_REMOVE_KEY: | 2176 | case MGMT_OP_REMOVE_KEYS: |
1890 | err = remove_key(sk, index, buf + sizeof(*hdr), len); | 2177 | err = remove_keys(sk, index, buf + sizeof(*hdr), len); |
1891 | break; | 2178 | break; |
1892 | case MGMT_OP_DISCONNECT: | 2179 | case MGMT_OP_DISCONNECT: |
1893 | err = disconnect(sk, index, buf + sizeof(*hdr), len); | 2180 | err = disconnect(sk, index, buf + sizeof(*hdr), len); |
@@ -1908,10 +2195,18 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | |||
1908 | err = pair_device(sk, index, buf + sizeof(*hdr), len); | 2195 | err = pair_device(sk, index, buf + sizeof(*hdr), len); |
1909 | break; | 2196 | break; |
1910 | case MGMT_OP_USER_CONFIRM_REPLY: | 2197 | case MGMT_OP_USER_CONFIRM_REPLY: |
1911 | err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1); | 2198 | err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len); |
1912 | break; | 2199 | break; |
1913 | case MGMT_OP_USER_CONFIRM_NEG_REPLY: | 2200 | case MGMT_OP_USER_CONFIRM_NEG_REPLY: |
1914 | err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0); | 2201 | err = user_confirm_neg_reply(sk, index, buf + sizeof(*hdr), |
2202 | len); | ||
2203 | break; | ||
2204 | case MGMT_OP_USER_PASSKEY_REPLY: | ||
2205 | err = user_passkey_reply(sk, index, buf + sizeof(*hdr), len); | ||
2206 | break; | ||
2207 | case MGMT_OP_USER_PASSKEY_NEG_REPLY: | ||
2208 | err = user_passkey_neg_reply(sk, index, buf + sizeof(*hdr), | ||
2209 | len); | ||
1915 | break; | 2210 | break; |
1916 | case MGMT_OP_SET_LOCAL_NAME: | 2211 | case MGMT_OP_SET_LOCAL_NAME: |
1917 | err = set_local_name(sk, index, buf + sizeof(*hdr), len); | 2212 | err = set_local_name(sk, index, buf + sizeof(*hdr), len); |
@@ -1927,7 +2222,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | |||
1927 | len); | 2222 | len); |
1928 | break; | 2223 | break; |
1929 | case MGMT_OP_START_DISCOVERY: | 2224 | case MGMT_OP_START_DISCOVERY: |
1930 | err = start_discovery(sk, index); | 2225 | err = start_discovery(sk, index, buf + sizeof(*hdr), len); |
1931 | break; | 2226 | break; |
1932 | case MGMT_OP_STOP_DISCOVERY: | 2227 | case MGMT_OP_STOP_DISCOVERY: |
1933 | err = stop_discovery(sk, index); | 2228 | err = stop_discovery(sk, index); |
@@ -1938,13 +2233,10 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | |||
1938 | case MGMT_OP_UNBLOCK_DEVICE: | 2233 | case MGMT_OP_UNBLOCK_DEVICE: |
1939 | err = unblock_device(sk, index, buf + sizeof(*hdr), len); | 2234 | err = unblock_device(sk, index, buf + sizeof(*hdr), len); |
1940 | break; | 2235 | break; |
1941 | case MGMT_OP_SET_FAST_CONNECTABLE: | ||
1942 | err = set_fast_connectable(sk, index, buf + sizeof(*hdr), | ||
1943 | len); | ||
1944 | break; | ||
1945 | default: | 2236 | default: |
1946 | BT_DBG("Unknown op %u", opcode); | 2237 | BT_DBG("Unknown op %u", opcode); |
1947 | err = cmd_status(sk, index, opcode, 0x01); | 2238 | err = cmd_status(sk, index, opcode, |
2239 | MGMT_STATUS_UNKNOWN_COMMAND); | ||
1948 | break; | 2240 | break; |
1949 | } | 2241 | } |
1950 | 2242 | ||
@@ -1958,30 +2250,39 @@ done: | |||
1958 | return err; | 2250 | return err; |
1959 | } | 2251 | } |
1960 | 2252 | ||
1961 | int mgmt_index_added(u16 index) | 2253 | static void cmd_status_rsp(struct pending_cmd *cmd, void *data) |
1962 | { | 2254 | { |
1963 | return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL); | 2255 | u8 *status = data; |
2256 | |||
2257 | cmd_status(cmd->sk, cmd->index, cmd->opcode, *status); | ||
2258 | mgmt_pending_remove(cmd); | ||
1964 | } | 2259 | } |
1965 | 2260 | ||
1966 | int mgmt_index_removed(u16 index) | 2261 | int mgmt_index_added(struct hci_dev *hdev) |
1967 | { | 2262 | { |
1968 | return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL); | 2263 | return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL); |
2264 | } | ||
2265 | |||
2266 | int mgmt_index_removed(struct hci_dev *hdev) | ||
2267 | { | ||
2268 | u8 status = ENODEV; | ||
2269 | |||
2270 | mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); | ||
2271 | |||
2272 | return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL); | ||
1969 | } | 2273 | } |
1970 | 2274 | ||
1971 | struct cmd_lookup { | 2275 | struct cmd_lookup { |
1972 | u8 val; | 2276 | u8 val; |
1973 | struct sock *sk; | 2277 | struct sock *sk; |
2278 | struct hci_dev *hdev; | ||
1974 | }; | 2279 | }; |
1975 | 2280 | ||
1976 | static void mode_rsp(struct pending_cmd *cmd, void *data) | 2281 | static void settings_rsp(struct pending_cmd *cmd, void *data) |
1977 | { | 2282 | { |
1978 | struct mgmt_mode *cp = cmd->param; | ||
1979 | struct cmd_lookup *match = data; | 2283 | struct cmd_lookup *match = data; |
1980 | 2284 | ||
1981 | if (cp->val != match->val) | 2285 | send_settings_rsp(cmd->sk, cmd->opcode, match->hdev); |
1982 | return; | ||
1983 | |||
1984 | send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val); | ||
1985 | 2286 | ||
1986 | list_del(&cmd->list); | 2287 | list_del(&cmd->list); |
1987 | 2288 | ||
@@ -1993,17 +2294,23 @@ static void mode_rsp(struct pending_cmd *cmd, void *data) | |||
1993 | mgmt_pending_free(cmd); | 2294 | mgmt_pending_free(cmd); |
1994 | } | 2295 | } |
1995 | 2296 | ||
1996 | int mgmt_powered(u16 index, u8 powered) | 2297 | int mgmt_powered(struct hci_dev *hdev, u8 powered) |
1997 | { | 2298 | { |
1998 | struct mgmt_mode ev; | 2299 | struct cmd_lookup match = { powered, NULL, hdev }; |
1999 | struct cmd_lookup match = { powered, NULL }; | 2300 | __le32 ev; |
2000 | int ret; | 2301 | int ret; |
2001 | 2302 | ||
2002 | mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match); | 2303 | mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); |
2003 | 2304 | ||
2004 | ev.val = powered; | 2305 | if (!powered) { |
2306 | u8 status = ENETDOWN; | ||
2307 | mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); | ||
2308 | } | ||
2309 | |||
2310 | ev = cpu_to_le32(get_current_settings(hdev)); | ||
2005 | 2311 | ||
2006 | ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk); | 2312 | ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), |
2313 | match.sk); | ||
2007 | 2314 | ||
2008 | if (match.sk) | 2315 | if (match.sk) |
2009 | sock_put(match.sk); | 2316 | sock_put(match.sk); |
@@ -2011,36 +2318,36 @@ int mgmt_powered(u16 index, u8 powered) | |||
2011 | return ret; | 2318 | return ret; |
2012 | } | 2319 | } |
2013 | 2320 | ||
2014 | int mgmt_discoverable(u16 index, u8 discoverable) | 2321 | int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) |
2015 | { | 2322 | { |
2016 | struct mgmt_mode ev; | 2323 | struct cmd_lookup match = { discoverable, NULL, hdev }; |
2017 | struct cmd_lookup match = { discoverable, NULL }; | 2324 | __le32 ev; |
2018 | int ret; | 2325 | int ret; |
2019 | 2326 | ||
2020 | mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match); | 2327 | mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match); |
2021 | 2328 | ||
2022 | ev.val = discoverable; | 2329 | ev = cpu_to_le32(get_current_settings(hdev)); |
2023 | 2330 | ||
2024 | ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev), | 2331 | ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), |
2025 | match.sk); | 2332 | match.sk); |
2026 | |||
2027 | if (match.sk) | 2333 | if (match.sk) |
2028 | sock_put(match.sk); | 2334 | sock_put(match.sk); |
2029 | 2335 | ||
2030 | return ret; | 2336 | return ret; |
2031 | } | 2337 | } |
2032 | 2338 | ||
2033 | int mgmt_connectable(u16 index, u8 connectable) | 2339 | int mgmt_connectable(struct hci_dev *hdev, u8 connectable) |
2034 | { | 2340 | { |
2035 | struct mgmt_mode ev; | 2341 | __le32 ev; |
2036 | struct cmd_lookup match = { connectable, NULL }; | 2342 | struct cmd_lookup match = { connectable, NULL, hdev }; |
2037 | int ret; | 2343 | int ret; |
2038 | 2344 | ||
2039 | mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match); | 2345 | mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp, |
2346 | &match); | ||
2040 | 2347 | ||
2041 | ev.val = connectable; | 2348 | ev = cpu_to_le32(get_current_settings(hdev)); |
2042 | 2349 | ||
2043 | ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk); | 2350 | ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk); |
2044 | 2351 | ||
2045 | if (match.sk) | 2352 | if (match.sk) |
2046 | sock_put(match.sk); | 2353 | sock_put(match.sk); |
@@ -2048,9 +2355,25 @@ int mgmt_connectable(u16 index, u8 connectable) | |||
2048 | return ret; | 2355 | return ret; |
2049 | } | 2356 | } |
2050 | 2357 | ||
2051 | int mgmt_new_key(u16 index, struct link_key *key, u8 persistent) | 2358 | int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status) |
2359 | { | ||
2360 | u8 mgmt_err = mgmt_status(status); | ||
2361 | |||
2362 | if (scan & SCAN_PAGE) | ||
2363 | mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, | ||
2364 | cmd_status_rsp, &mgmt_err); | ||
2365 | |||
2366 | if (scan & SCAN_INQUIRY) | ||
2367 | mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, | ||
2368 | cmd_status_rsp, &mgmt_err); | ||
2369 | |||
2370 | return 0; | ||
2371 | } | ||
2372 | |||
2373 | int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, | ||
2374 | u8 persistent) | ||
2052 | { | 2375 | { |
2053 | struct mgmt_ev_new_key ev; | 2376 | struct mgmt_ev_new_link_key ev; |
2054 | 2377 | ||
2055 | memset(&ev, 0, sizeof(ev)); | 2378 | memset(&ev, 0, sizeof(ev)); |
2056 | 2379 | ||
@@ -2060,17 +2383,18 @@ int mgmt_new_key(u16 index, struct link_key *key, u8 persistent) | |||
2060 | memcpy(ev.key.val, key->val, 16); | 2383 | memcpy(ev.key.val, key->val, 16); |
2061 | ev.key.pin_len = key->pin_len; | 2384 | ev.key.pin_len = key->pin_len; |
2062 | 2385 | ||
2063 | return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL); | 2386 | return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL); |
2064 | } | 2387 | } |
2065 | 2388 | ||
2066 | int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type) | 2389 | int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, |
2390 | u8 addr_type) | ||
2067 | { | 2391 | { |
2068 | struct mgmt_ev_connected ev; | 2392 | struct mgmt_addr_info ev; |
2069 | 2393 | ||
2070 | bacpy(&ev.bdaddr, bdaddr); | 2394 | bacpy(&ev.bdaddr, bdaddr); |
2071 | ev.link_type = link_type; | 2395 | ev.type = link_to_mgmt(link_type, addr_type); |
2072 | 2396 | ||
2073 | return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL); | 2397 | return mgmt_event(MGMT_EV_CONNECTED, hdev, &ev, sizeof(ev), NULL); |
2074 | } | 2398 | } |
2075 | 2399 | ||
2076 | static void disconnect_rsp(struct pending_cmd *cmd, void *data) | 2400 | static void disconnect_rsp(struct pending_cmd *cmd, void *data) |
@@ -2080,6 +2404,7 @@ static void disconnect_rsp(struct pending_cmd *cmd, void *data) | |||
2080 | struct mgmt_rp_disconnect rp; | 2404 | struct mgmt_rp_disconnect rp; |
2081 | 2405 | ||
2082 | bacpy(&rp.bdaddr, &cp->bdaddr); | 2406 | bacpy(&rp.bdaddr, &cp->bdaddr); |
2407 | rp.status = 0; | ||
2083 | 2408 | ||
2084 | cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp)); | 2409 | cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp)); |
2085 | 2410 | ||
@@ -2089,75 +2414,110 @@ static void disconnect_rsp(struct pending_cmd *cmd, void *data) | |||
2089 | mgmt_pending_remove(cmd); | 2414 | mgmt_pending_remove(cmd); |
2090 | } | 2415 | } |
2091 | 2416 | ||
2092 | int mgmt_disconnected(u16 index, bdaddr_t *bdaddr) | 2417 | static void remove_keys_rsp(struct pending_cmd *cmd, void *data) |
2418 | { | ||
2419 | u8 *status = data; | ||
2420 | struct mgmt_cp_remove_keys *cp = cmd->param; | ||
2421 | struct mgmt_rp_remove_keys rp; | ||
2422 | |||
2423 | memset(&rp, 0, sizeof(rp)); | ||
2424 | bacpy(&rp.bdaddr, &cp->bdaddr); | ||
2425 | if (status != NULL) | ||
2426 | rp.status = *status; | ||
2427 | |||
2428 | cmd_complete(cmd->sk, cmd->index, MGMT_OP_REMOVE_KEYS, &rp, | ||
2429 | sizeof(rp)); | ||
2430 | |||
2431 | mgmt_pending_remove(cmd); | ||
2432 | } | ||
2433 | |||
2434 | int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, | ||
2435 | u8 addr_type) | ||
2093 | { | 2436 | { |
2094 | struct mgmt_ev_disconnected ev; | 2437 | struct mgmt_addr_info ev; |
2095 | struct sock *sk = NULL; | 2438 | struct sock *sk = NULL; |
2096 | int err; | 2439 | int err; |
2097 | 2440 | ||
2098 | mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk); | 2441 | mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk); |
2099 | 2442 | ||
2100 | bacpy(&ev.bdaddr, bdaddr); | 2443 | bacpy(&ev.bdaddr, bdaddr); |
2444 | ev.type = link_to_mgmt(link_type, addr_type); | ||
2101 | 2445 | ||
2102 | err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk); | 2446 | err = mgmt_event(MGMT_EV_DISCONNECTED, hdev, &ev, sizeof(ev), sk); |
2103 | 2447 | ||
2104 | if (sk) | 2448 | if (sk) |
2105 | sock_put(sk); | 2449 | sock_put(sk); |
2106 | 2450 | ||
2451 | mgmt_pending_foreach(MGMT_OP_REMOVE_KEYS, hdev, remove_keys_rsp, NULL); | ||
2452 | |||
2107 | return err; | 2453 | return err; |
2108 | } | 2454 | } |
2109 | 2455 | ||
2110 | int mgmt_disconnect_failed(u16 index) | 2456 | int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status) |
2111 | { | 2457 | { |
2112 | struct pending_cmd *cmd; | 2458 | struct pending_cmd *cmd; |
2459 | u8 mgmt_err = mgmt_status(status); | ||
2113 | int err; | 2460 | int err; |
2114 | 2461 | ||
2115 | cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index); | 2462 | cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev); |
2116 | if (!cmd) | 2463 | if (!cmd) |
2117 | return -ENOENT; | 2464 | return -ENOENT; |
2118 | 2465 | ||
2119 | err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO); | 2466 | if (bdaddr) { |
2467 | struct mgmt_rp_disconnect rp; | ||
2468 | |||
2469 | bacpy(&rp.bdaddr, bdaddr); | ||
2470 | rp.status = status; | ||
2471 | |||
2472 | err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, | ||
2473 | &rp, sizeof(rp)); | ||
2474 | } else | ||
2475 | err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT, | ||
2476 | mgmt_err); | ||
2120 | 2477 | ||
2121 | mgmt_pending_remove(cmd); | 2478 | mgmt_pending_remove(cmd); |
2122 | 2479 | ||
2123 | return err; | 2480 | return err; |
2124 | } | 2481 | } |
2125 | 2482 | ||
2126 | int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status) | 2483 | int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, |
2484 | u8 addr_type, u8 status) | ||
2127 | { | 2485 | { |
2128 | struct mgmt_ev_connect_failed ev; | 2486 | struct mgmt_ev_connect_failed ev; |
2129 | 2487 | ||
2130 | bacpy(&ev.bdaddr, bdaddr); | 2488 | bacpy(&ev.addr.bdaddr, bdaddr); |
2131 | ev.status = status; | 2489 | ev.addr.type = link_to_mgmt(link_type, addr_type); |
2490 | ev.status = mgmt_status(status); | ||
2132 | 2491 | ||
2133 | return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL); | 2492 | return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL); |
2134 | } | 2493 | } |
2135 | 2494 | ||
2136 | int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure) | 2495 | int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure) |
2137 | { | 2496 | { |
2138 | struct mgmt_ev_pin_code_request ev; | 2497 | struct mgmt_ev_pin_code_request ev; |
2139 | 2498 | ||
2140 | bacpy(&ev.bdaddr, bdaddr); | 2499 | bacpy(&ev.bdaddr, bdaddr); |
2141 | ev.secure = secure; | 2500 | ev.secure = secure; |
2142 | 2501 | ||
2143 | return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev), | 2502 | return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), |
2144 | NULL); | 2503 | NULL); |
2145 | } | 2504 | } |
2146 | 2505 | ||
2147 | int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status) | 2506 | int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, |
2507 | u8 status) | ||
2148 | { | 2508 | { |
2149 | struct pending_cmd *cmd; | 2509 | struct pending_cmd *cmd; |
2150 | struct mgmt_rp_pin_code_reply rp; | 2510 | struct mgmt_rp_pin_code_reply rp; |
2151 | int err; | 2511 | int err; |
2152 | 2512 | ||
2153 | cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index); | 2513 | cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev); |
2154 | if (!cmd) | 2514 | if (!cmd) |
2155 | return -ENOENT; | 2515 | return -ENOENT; |
2156 | 2516 | ||
2157 | bacpy(&rp.bdaddr, bdaddr); | 2517 | bacpy(&rp.bdaddr, bdaddr); |
2158 | rp.status = status; | 2518 | rp.status = mgmt_status(status); |
2159 | 2519 | ||
2160 | err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp, | 2520 | err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp, |
2161 | sizeof(rp)); | 2521 | sizeof(rp)); |
2162 | 2522 | ||
2163 | mgmt_pending_remove(cmd); | 2523 | mgmt_pending_remove(cmd); |
@@ -2165,20 +2525,21 @@ int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status) | |||
2165 | return err; | 2525 | return err; |
2166 | } | 2526 | } |
2167 | 2527 | ||
2168 | int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status) | 2528 | int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, |
2529 | u8 status) | ||
2169 | { | 2530 | { |
2170 | struct pending_cmd *cmd; | 2531 | struct pending_cmd *cmd; |
2171 | struct mgmt_rp_pin_code_reply rp; | 2532 | struct mgmt_rp_pin_code_reply rp; |
2172 | int err; | 2533 | int err; |
2173 | 2534 | ||
2174 | cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index); | 2535 | cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev); |
2175 | if (!cmd) | 2536 | if (!cmd) |
2176 | return -ENOENT; | 2537 | return -ENOENT; |
2177 | 2538 | ||
2178 | bacpy(&rp.bdaddr, bdaddr); | 2539 | bacpy(&rp.bdaddr, bdaddr); |
2179 | rp.status = status; | 2540 | rp.status = mgmt_status(status); |
2180 | 2541 | ||
2181 | err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp, | 2542 | err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp, |
2182 | sizeof(rp)); | 2543 | sizeof(rp)); |
2183 | 2544 | ||
2184 | mgmt_pending_remove(cmd); | 2545 | mgmt_pending_remove(cmd); |
@@ -2186,97 +2547,119 @@ int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status) | |||
2186 | return err; | 2547 | return err; |
2187 | } | 2548 | } |
2188 | 2549 | ||
2189 | int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value, | 2550 | int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr, |
2190 | u8 confirm_hint) | 2551 | __le32 value, u8 confirm_hint) |
2191 | { | 2552 | { |
2192 | struct mgmt_ev_user_confirm_request ev; | 2553 | struct mgmt_ev_user_confirm_request ev; |
2193 | 2554 | ||
2194 | BT_DBG("hci%u", index); | 2555 | BT_DBG("%s", hdev->name); |
2195 | 2556 | ||
2196 | bacpy(&ev.bdaddr, bdaddr); | 2557 | bacpy(&ev.bdaddr, bdaddr); |
2197 | ev.confirm_hint = confirm_hint; | 2558 | ev.confirm_hint = confirm_hint; |
2198 | put_unaligned_le32(value, &ev.value); | 2559 | put_unaligned_le32(value, &ev.value); |
2199 | 2560 | ||
2200 | return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev), | 2561 | return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev), |
2562 | NULL); | ||
2563 | } | ||
2564 | |||
2565 | int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr) | ||
2566 | { | ||
2567 | struct mgmt_ev_user_passkey_request ev; | ||
2568 | |||
2569 | BT_DBG("%s", hdev->name); | ||
2570 | |||
2571 | bacpy(&ev.bdaddr, bdaddr); | ||
2572 | |||
2573 | return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev), | ||
2201 | NULL); | 2574 | NULL); |
2202 | } | 2575 | } |
2203 | 2576 | ||
2204 | static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status, | 2577 | static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, |
2205 | u8 opcode) | 2578 | u8 status, u8 opcode) |
2206 | { | 2579 | { |
2207 | struct pending_cmd *cmd; | 2580 | struct pending_cmd *cmd; |
2208 | struct mgmt_rp_user_confirm_reply rp; | 2581 | struct mgmt_rp_user_confirm_reply rp; |
2209 | int err; | 2582 | int err; |
2210 | 2583 | ||
2211 | cmd = mgmt_pending_find(opcode, index); | 2584 | cmd = mgmt_pending_find(opcode, hdev); |
2212 | if (!cmd) | 2585 | if (!cmd) |
2213 | return -ENOENT; | 2586 | return -ENOENT; |
2214 | 2587 | ||
2215 | bacpy(&rp.bdaddr, bdaddr); | 2588 | bacpy(&rp.bdaddr, bdaddr); |
2216 | rp.status = status; | 2589 | rp.status = mgmt_status(status); |
2217 | err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp)); | 2590 | err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp)); |
2218 | 2591 | ||
2219 | mgmt_pending_remove(cmd); | 2592 | mgmt_pending_remove(cmd); |
2220 | 2593 | ||
2221 | return err; | 2594 | return err; |
2222 | } | 2595 | } |
2223 | 2596 | ||
2224 | int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status) | 2597 | int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, |
2598 | u8 status) | ||
2225 | { | 2599 | { |
2226 | return confirm_reply_complete(index, bdaddr, status, | 2600 | return user_pairing_resp_complete(hdev, bdaddr, status, |
2227 | MGMT_OP_USER_CONFIRM_REPLY); | 2601 | MGMT_OP_USER_CONFIRM_REPLY); |
2228 | } | 2602 | } |
2229 | 2603 | ||
2230 | int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status) | 2604 | int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, |
2605 | bdaddr_t *bdaddr, u8 status) | ||
2231 | { | 2606 | { |
2232 | return confirm_reply_complete(index, bdaddr, status, | 2607 | return user_pairing_resp_complete(hdev, bdaddr, status, |
2233 | MGMT_OP_USER_CONFIRM_NEG_REPLY); | 2608 | MGMT_OP_USER_CONFIRM_NEG_REPLY); |
2234 | } | 2609 | } |
2235 | 2610 | ||
2236 | int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status) | 2611 | int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, |
2612 | u8 status) | ||
2613 | { | ||
2614 | return user_pairing_resp_complete(hdev, bdaddr, status, | ||
2615 | MGMT_OP_USER_PASSKEY_REPLY); | ||
2616 | } | ||
2617 | |||
2618 | int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, | ||
2619 | bdaddr_t *bdaddr, u8 status) | ||
2620 | { | ||
2621 | return user_pairing_resp_complete(hdev, bdaddr, status, | ||
2622 | MGMT_OP_USER_PASSKEY_NEG_REPLY); | ||
2623 | } | ||
2624 | |||
2625 | int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status) | ||
2237 | { | 2626 | { |
2238 | struct mgmt_ev_auth_failed ev; | 2627 | struct mgmt_ev_auth_failed ev; |
2239 | 2628 | ||
2240 | bacpy(&ev.bdaddr, bdaddr); | 2629 | bacpy(&ev.bdaddr, bdaddr); |
2241 | ev.status = status; | 2630 | ev.status = mgmt_status(status); |
2242 | 2631 | ||
2243 | return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL); | 2632 | return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL); |
2244 | } | 2633 | } |
2245 | 2634 | ||
2246 | int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status) | 2635 | int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status) |
2247 | { | 2636 | { |
2248 | struct pending_cmd *cmd; | 2637 | struct pending_cmd *cmd; |
2249 | struct hci_dev *hdev; | ||
2250 | struct mgmt_cp_set_local_name ev; | 2638 | struct mgmt_cp_set_local_name ev; |
2251 | int err; | 2639 | int err; |
2252 | 2640 | ||
2253 | memset(&ev, 0, sizeof(ev)); | 2641 | memset(&ev, 0, sizeof(ev)); |
2254 | memcpy(ev.name, name, HCI_MAX_NAME_LENGTH); | 2642 | memcpy(ev.name, name, HCI_MAX_NAME_LENGTH); |
2255 | 2643 | ||
2256 | cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index); | 2644 | cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev); |
2257 | if (!cmd) | 2645 | if (!cmd) |
2258 | goto send_event; | 2646 | goto send_event; |
2259 | 2647 | ||
2260 | if (status) { | 2648 | if (status) { |
2261 | err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO); | 2649 | err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, |
2650 | mgmt_status(status)); | ||
2262 | goto failed; | 2651 | goto failed; |
2263 | } | 2652 | } |
2264 | 2653 | ||
2265 | hdev = hci_dev_get(index); | 2654 | update_eir(hdev); |
2266 | if (hdev) { | ||
2267 | hci_dev_lock_bh(hdev); | ||
2268 | update_eir(hdev); | ||
2269 | hci_dev_unlock_bh(hdev); | ||
2270 | hci_dev_put(hdev); | ||
2271 | } | ||
2272 | 2655 | ||
2273 | err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev, | 2656 | err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev, |
2274 | sizeof(ev)); | 2657 | sizeof(ev)); |
2275 | if (err < 0) | 2658 | if (err < 0) |
2276 | goto failed; | 2659 | goto failed; |
2277 | 2660 | ||
2278 | send_event: | 2661 | send_event: |
2279 | err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev), | 2662 | err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev), |
2280 | cmd ? cmd->sk : NULL); | 2663 | cmd ? cmd->sk : NULL); |
2281 | 2664 | ||
2282 | failed: | 2665 | failed: |
@@ -2285,29 +2668,31 @@ failed: | |||
2285 | return err; | 2668 | return err; |
2286 | } | 2669 | } |
2287 | 2670 | ||
2288 | int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer, | 2671 | int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, |
2289 | u8 status) | 2672 | u8 *randomizer, u8 status) |
2290 | { | 2673 | { |
2291 | struct pending_cmd *cmd; | 2674 | struct pending_cmd *cmd; |
2292 | int err; | 2675 | int err; |
2293 | 2676 | ||
2294 | BT_DBG("hci%u status %u", index, status); | 2677 | BT_DBG("%s status %u", hdev->name, status); |
2295 | 2678 | ||
2296 | cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index); | 2679 | cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev); |
2297 | if (!cmd) | 2680 | if (!cmd) |
2298 | return -ENOENT; | 2681 | return -ENOENT; |
2299 | 2682 | ||
2300 | if (status) { | 2683 | if (status) { |
2301 | err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, | 2684 | err = cmd_status(cmd->sk, hdev->id, |
2302 | EIO); | 2685 | MGMT_OP_READ_LOCAL_OOB_DATA, |
2686 | mgmt_status(status)); | ||
2303 | } else { | 2687 | } else { |
2304 | struct mgmt_rp_read_local_oob_data rp; | 2688 | struct mgmt_rp_read_local_oob_data rp; |
2305 | 2689 | ||
2306 | memcpy(rp.hash, hash, sizeof(rp.hash)); | 2690 | memcpy(rp.hash, hash, sizeof(rp.hash)); |
2307 | memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer)); | 2691 | memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer)); |
2308 | 2692 | ||
2309 | err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, | 2693 | err = cmd_complete(cmd->sk, hdev->id, |
2310 | &rp, sizeof(rp)); | 2694 | MGMT_OP_READ_LOCAL_OOB_DATA, |
2695 | &rp, sizeof(rp)); | ||
2311 | } | 2696 | } |
2312 | 2697 | ||
2313 | mgmt_pending_remove(cmd); | 2698 | mgmt_pending_remove(cmd); |
@@ -2315,14 +2700,15 @@ int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer, | |||
2315 | return err; | 2700 | return err; |
2316 | } | 2701 | } |
2317 | 2702 | ||
2318 | int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi, | 2703 | int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, |
2319 | u8 *eir) | 2704 | u8 addr_type, u8 *dev_class, s8 rssi, u8 *eir) |
2320 | { | 2705 | { |
2321 | struct mgmt_ev_device_found ev; | 2706 | struct mgmt_ev_device_found ev; |
2322 | 2707 | ||
2323 | memset(&ev, 0, sizeof(ev)); | 2708 | memset(&ev, 0, sizeof(ev)); |
2324 | 2709 | ||
2325 | bacpy(&ev.bdaddr, bdaddr); | 2710 | bacpy(&ev.addr.bdaddr, bdaddr); |
2711 | ev.addr.type = link_to_mgmt(link_type, addr_type); | ||
2326 | ev.rssi = rssi; | 2712 | ev.rssi = rssi; |
2327 | 2713 | ||
2328 | if (eir) | 2714 | if (eir) |
@@ -2331,10 +2717,10 @@ int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi, | |||
2331 | if (dev_class) | 2717 | if (dev_class) |
2332 | memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class)); | 2718 | memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class)); |
2333 | 2719 | ||
2334 | return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL); | 2720 | return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL); |
2335 | } | 2721 | } |
2336 | 2722 | ||
2337 | int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name) | 2723 | int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name) |
2338 | { | 2724 | { |
2339 | struct mgmt_ev_remote_name ev; | 2725 | struct mgmt_ev_remote_name ev; |
2340 | 2726 | ||
@@ -2343,37 +2729,79 @@ int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name) | |||
2343 | bacpy(&ev.bdaddr, bdaddr); | 2729 | bacpy(&ev.bdaddr, bdaddr); |
2344 | memcpy(ev.name, name, HCI_MAX_NAME_LENGTH); | 2730 | memcpy(ev.name, name, HCI_MAX_NAME_LENGTH); |
2345 | 2731 | ||
2346 | return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL); | 2732 | return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL); |
2733 | } | ||
2734 | |||
2735 | int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status) | ||
2736 | { | ||
2737 | struct pending_cmd *cmd; | ||
2738 | int err; | ||
2739 | |||
2740 | cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev); | ||
2741 | if (!cmd) | ||
2742 | return -ENOENT; | ||
2743 | |||
2744 | err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status)); | ||
2745 | mgmt_pending_remove(cmd); | ||
2746 | |||
2747 | return err; | ||
2748 | } | ||
2749 | |||
2750 | int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status) | ||
2751 | { | ||
2752 | struct pending_cmd *cmd; | ||
2753 | int err; | ||
2754 | |||
2755 | cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev); | ||
2756 | if (!cmd) | ||
2757 | return -ENOENT; | ||
2758 | |||
2759 | err = cmd_status(cmd->sk, hdev->id, cmd->opcode, status); | ||
2760 | mgmt_pending_remove(cmd); | ||
2761 | |||
2762 | return err; | ||
2347 | } | 2763 | } |
2348 | 2764 | ||
2349 | int mgmt_discovering(u16 index, u8 discovering) | 2765 | int mgmt_discovering(struct hci_dev *hdev, u8 discovering) |
2350 | { | 2766 | { |
2351 | return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering, | 2767 | struct pending_cmd *cmd; |
2768 | |||
2769 | if (discovering) | ||
2770 | cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev); | ||
2771 | else | ||
2772 | cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev); | ||
2773 | |||
2774 | if (cmd != NULL) { | ||
2775 | cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0); | ||
2776 | mgmt_pending_remove(cmd); | ||
2777 | } | ||
2778 | |||
2779 | return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering, | ||
2352 | sizeof(discovering), NULL); | 2780 | sizeof(discovering), NULL); |
2353 | } | 2781 | } |
2354 | 2782 | ||
2355 | int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr) | 2783 | int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr) |
2356 | { | 2784 | { |
2357 | struct pending_cmd *cmd; | 2785 | struct pending_cmd *cmd; |
2358 | struct mgmt_ev_device_blocked ev; | 2786 | struct mgmt_ev_device_blocked ev; |
2359 | 2787 | ||
2360 | cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, index); | 2788 | cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev); |
2361 | 2789 | ||
2362 | bacpy(&ev.bdaddr, bdaddr); | 2790 | bacpy(&ev.bdaddr, bdaddr); |
2363 | 2791 | ||
2364 | return mgmt_event(MGMT_EV_DEVICE_BLOCKED, index, &ev, sizeof(ev), | 2792 | return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev), |
2365 | cmd ? cmd->sk : NULL); | 2793 | cmd ? cmd->sk : NULL); |
2366 | } | 2794 | } |
2367 | 2795 | ||
2368 | int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr) | 2796 | int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr) |
2369 | { | 2797 | { |
2370 | struct pending_cmd *cmd; | 2798 | struct pending_cmd *cmd; |
2371 | struct mgmt_ev_device_unblocked ev; | 2799 | struct mgmt_ev_device_unblocked ev; |
2372 | 2800 | ||
2373 | cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, index); | 2801 | cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev); |
2374 | 2802 | ||
2375 | bacpy(&ev.bdaddr, bdaddr); | 2803 | bacpy(&ev.bdaddr, bdaddr); |
2376 | 2804 | ||
2377 | return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, index, &ev, sizeof(ev), | 2805 | return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev), |
2378 | cmd ? cmd->sk : NULL); | 2806 | cmd ? cmd->sk : NULL); |
2379 | } | 2807 | } |