diff options
Diffstat (limited to 'net/bluetooth/mgmt.c')
-rw-r--r-- | net/bluetooth/mgmt.c | 612 |
1 files changed, 564 insertions, 48 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 4476d8e3c0f2..dae382ce7020 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -36,7 +36,7 @@ struct pending_cmd { | |||
36 | struct list_head list; | 36 | struct list_head list; |
37 | __u16 opcode; | 37 | __u16 opcode; |
38 | int index; | 38 | int index; |
39 | void *cmd; | 39 | void *param; |
40 | struct sock *sk; | 40 | struct sock *sk; |
41 | void *user_data; | 41 | void *user_data; |
42 | }; | 42 | }; |
@@ -179,10 +179,12 @@ static int read_controller_info(struct sock *sk, u16 index) | |||
179 | 179 | ||
180 | hci_del_off_timer(hdev); | 180 | hci_del_off_timer(hdev); |
181 | 181 | ||
182 | hci_dev_lock_bh(hdev); | 182 | hci_dev_lock(hdev); |
183 | 183 | ||
184 | set_bit(HCI_MGMT, &hdev->flags); | 184 | set_bit(HCI_MGMT, &hdev->flags); |
185 | 185 | ||
186 | memset(&rp, 0, sizeof(rp)); | ||
187 | |||
186 | rp.type = hdev->dev_type; | 188 | rp.type = hdev->dev_type; |
187 | 189 | ||
188 | rp.powered = test_bit(HCI_UP, &hdev->flags); | 190 | rp.powered = test_bit(HCI_UP, &hdev->flags); |
@@ -204,7 +206,9 @@ static int read_controller_info(struct sock *sk, u16 index) | |||
204 | rp.hci_ver = hdev->hci_ver; | 206 | rp.hci_ver = hdev->hci_ver; |
205 | put_unaligned_le16(hdev->hci_rev, &rp.hci_rev); | 207 | put_unaligned_le16(hdev->hci_rev, &rp.hci_rev); |
206 | 208 | ||
207 | hci_dev_unlock_bh(hdev); | 209 | memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name)); |
210 | |||
211 | hci_dev_unlock(hdev); | ||
208 | hci_dev_put(hdev); | 212 | hci_dev_put(hdev); |
209 | 213 | ||
210 | return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp)); | 214 | return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp)); |
@@ -213,7 +217,7 @@ static int read_controller_info(struct sock *sk, u16 index) | |||
213 | static void mgmt_pending_free(struct pending_cmd *cmd) | 217 | static void mgmt_pending_free(struct pending_cmd *cmd) |
214 | { | 218 | { |
215 | sock_put(cmd->sk); | 219 | sock_put(cmd->sk); |
216 | kfree(cmd->cmd); | 220 | kfree(cmd->param); |
217 | kfree(cmd); | 221 | kfree(cmd); |
218 | } | 222 | } |
219 | 223 | ||
@@ -229,13 +233,14 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode, | |||
229 | cmd->opcode = opcode; | 233 | cmd->opcode = opcode; |
230 | cmd->index = index; | 234 | cmd->index = index; |
231 | 235 | ||
232 | cmd->cmd = kmalloc(len, GFP_ATOMIC); | 236 | cmd->param = kmalloc(len, GFP_ATOMIC); |
233 | if (!cmd->cmd) { | 237 | if (!cmd->param) { |
234 | kfree(cmd); | 238 | kfree(cmd); |
235 | return NULL; | 239 | return NULL; |
236 | } | 240 | } |
237 | 241 | ||
238 | memcpy(cmd->cmd, data, len); | 242 | if (data) |
243 | memcpy(cmd->param, data, len); | ||
239 | 244 | ||
240 | cmd->sk = sk; | 245 | cmd->sk = sk; |
241 | sock_hold(sk); | 246 | sock_hold(sk); |
@@ -311,7 +316,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
311 | if (!hdev) | 316 | if (!hdev) |
312 | return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV); | 317 | return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV); |
313 | 318 | ||
314 | hci_dev_lock_bh(hdev); | 319 | hci_dev_lock(hdev); |
315 | 320 | ||
316 | up = test_bit(HCI_UP, &hdev->flags); | 321 | up = test_bit(HCI_UP, &hdev->flags); |
317 | if ((cp->val && up) || (!cp->val && !up)) { | 322 | if ((cp->val && up) || (!cp->val && !up)) { |
@@ -338,7 +343,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
338 | err = 0; | 343 | err = 0; |
339 | 344 | ||
340 | failed: | 345 | failed: |
341 | hci_dev_unlock_bh(hdev); | 346 | hci_dev_unlock(hdev); |
342 | hci_dev_put(hdev); | 347 | hci_dev_put(hdev); |
343 | return err; | 348 | return err; |
344 | } | 349 | } |
@@ -363,7 +368,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data, | |||
363 | if (!hdev) | 368 | if (!hdev) |
364 | return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV); | 369 | return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV); |
365 | 370 | ||
366 | hci_dev_lock_bh(hdev); | 371 | hci_dev_lock(hdev); |
367 | 372 | ||
368 | if (!test_bit(HCI_UP, &hdev->flags)) { | 373 | if (!test_bit(HCI_UP, &hdev->flags)) { |
369 | err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN); | 374 | err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN); |
@@ -398,7 +403,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data, | |||
398 | mgmt_pending_remove(cmd); | 403 | mgmt_pending_remove(cmd); |
399 | 404 | ||
400 | failed: | 405 | failed: |
401 | hci_dev_unlock_bh(hdev); | 406 | hci_dev_unlock(hdev); |
402 | hci_dev_put(hdev); | 407 | hci_dev_put(hdev); |
403 | 408 | ||
404 | return err; | 409 | return err; |
@@ -424,7 +429,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data, | |||
424 | if (!hdev) | 429 | if (!hdev) |
425 | return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV); | 430 | return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV); |
426 | 431 | ||
427 | hci_dev_lock_bh(hdev); | 432 | hci_dev_lock(hdev); |
428 | 433 | ||
429 | if (!test_bit(HCI_UP, &hdev->flags)) { | 434 | if (!test_bit(HCI_UP, &hdev->flags)) { |
430 | err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN); | 435 | err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN); |
@@ -458,7 +463,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data, | |||
458 | mgmt_pending_remove(cmd); | 463 | mgmt_pending_remove(cmd); |
459 | 464 | ||
460 | failed: | 465 | failed: |
461 | hci_dev_unlock_bh(hdev); | 466 | hci_dev_unlock(hdev); |
462 | hci_dev_put(hdev); | 467 | hci_dev_put(hdev); |
463 | 468 | ||
464 | return err; | 469 | return err; |
@@ -517,7 +522,7 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data, | |||
517 | if (!hdev) | 522 | if (!hdev) |
518 | return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV); | 523 | return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV); |
519 | 524 | ||
520 | hci_dev_lock_bh(hdev); | 525 | hci_dev_lock(hdev); |
521 | 526 | ||
522 | if (cp->val) | 527 | if (cp->val) |
523 | set_bit(HCI_PAIRABLE, &hdev->flags); | 528 | set_bit(HCI_PAIRABLE, &hdev->flags); |
@@ -533,12 +538,156 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data, | |||
533 | err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk); | 538 | err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk); |
534 | 539 | ||
535 | failed: | 540 | failed: |
536 | hci_dev_unlock_bh(hdev); | 541 | hci_dev_unlock(hdev); |
537 | hci_dev_put(hdev); | 542 | hci_dev_put(hdev); |
538 | 543 | ||
539 | return err; | 544 | return err; |
540 | } | 545 | } |
541 | 546 | ||
547 | #define EIR_FLAGS 0x01 /* flags */ | ||
548 | #define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */ | ||
549 | #define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */ | ||
550 | #define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */ | ||
551 | #define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */ | ||
552 | #define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */ | ||
553 | #define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */ | ||
554 | #define EIR_NAME_SHORT 0x08 /* shortened local name */ | ||
555 | #define EIR_NAME_COMPLETE 0x09 /* complete local name */ | ||
556 | #define EIR_TX_POWER 0x0A /* transmit power level */ | ||
557 | #define EIR_DEVICE_ID 0x10 /* device ID */ | ||
558 | |||
559 | #define PNP_INFO_SVCLASS_ID 0x1200 | ||
560 | |||
561 | static u8 bluetooth_base_uuid[] = { | ||
562 | 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, | ||
563 | 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
564 | }; | ||
565 | |||
566 | static u16 get_uuid16(u8 *uuid128) | ||
567 | { | ||
568 | u32 val; | ||
569 | int i; | ||
570 | |||
571 | for (i = 0; i < 12; i++) { | ||
572 | if (bluetooth_base_uuid[i] != uuid128[i]) | ||
573 | return 0; | ||
574 | } | ||
575 | |||
576 | memcpy(&val, &uuid128[12], 4); | ||
577 | |||
578 | val = le32_to_cpu(val); | ||
579 | if (val > 0xffff) | ||
580 | return 0; | ||
581 | |||
582 | return (u16) val; | ||
583 | } | ||
584 | |||
585 | static void create_eir(struct hci_dev *hdev, u8 *data) | ||
586 | { | ||
587 | u8 *ptr = data; | ||
588 | u16 eir_len = 0; | ||
589 | u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)]; | ||
590 | int i, truncated = 0; | ||
591 | struct list_head *p; | ||
592 | size_t name_len; | ||
593 | |||
594 | name_len = strlen(hdev->dev_name); | ||
595 | |||
596 | if (name_len > 0) { | ||
597 | /* EIR Data type */ | ||
598 | if (name_len > 48) { | ||
599 | name_len = 48; | ||
600 | ptr[1] = EIR_NAME_SHORT; | ||
601 | } else | ||
602 | ptr[1] = EIR_NAME_COMPLETE; | ||
603 | |||
604 | /* EIR Data length */ | ||
605 | ptr[0] = name_len + 1; | ||
606 | |||
607 | memcpy(ptr + 2, hdev->dev_name, name_len); | ||
608 | |||
609 | eir_len += (name_len + 2); | ||
610 | ptr += (name_len + 2); | ||
611 | } | ||
612 | |||
613 | memset(uuid16_list, 0, sizeof(uuid16_list)); | ||
614 | |||
615 | /* Group all UUID16 types */ | ||
616 | list_for_each(p, &hdev->uuids) { | ||
617 | struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list); | ||
618 | u16 uuid16; | ||
619 | |||
620 | uuid16 = get_uuid16(uuid->uuid); | ||
621 | if (uuid16 == 0) | ||
622 | return; | ||
623 | |||
624 | if (uuid16 < 0x1100) | ||
625 | continue; | ||
626 | |||
627 | if (uuid16 == PNP_INFO_SVCLASS_ID) | ||
628 | continue; | ||
629 | |||
630 | /* Stop if not enough space to put next UUID */ | ||
631 | if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) { | ||
632 | truncated = 1; | ||
633 | break; | ||
634 | } | ||
635 | |||
636 | /* Check for duplicates */ | ||
637 | for (i = 0; uuid16_list[i] != 0; i++) | ||
638 | if (uuid16_list[i] == uuid16) | ||
639 | break; | ||
640 | |||
641 | if (uuid16_list[i] == 0) { | ||
642 | uuid16_list[i] = uuid16; | ||
643 | eir_len += sizeof(u16); | ||
644 | } | ||
645 | } | ||
646 | |||
647 | if (uuid16_list[0] != 0) { | ||
648 | u8 *length = ptr; | ||
649 | |||
650 | /* EIR Data type */ | ||
651 | ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL; | ||
652 | |||
653 | ptr += 2; | ||
654 | eir_len += 2; | ||
655 | |||
656 | for (i = 0; uuid16_list[i] != 0; i++) { | ||
657 | *ptr++ = (uuid16_list[i] & 0x00ff); | ||
658 | *ptr++ = (uuid16_list[i] & 0xff00) >> 8; | ||
659 | } | ||
660 | |||
661 | /* EIR Data length */ | ||
662 | *length = (i * sizeof(u16)) + 1; | ||
663 | } | ||
664 | } | ||
665 | |||
666 | static int update_eir(struct hci_dev *hdev) | ||
667 | { | ||
668 | struct hci_cp_write_eir cp; | ||
669 | |||
670 | if (!(hdev->features[6] & LMP_EXT_INQ)) | ||
671 | return 0; | ||
672 | |||
673 | if (hdev->ssp_mode == 0) | ||
674 | return 0; | ||
675 | |||
676 | if (test_bit(HCI_SERVICE_CACHE, &hdev->flags)) | ||
677 | return 0; | ||
678 | |||
679 | memset(&cp, 0, sizeof(cp)); | ||
680 | |||
681 | create_eir(hdev, cp.data); | ||
682 | |||
683 | if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0) | ||
684 | return 0; | ||
685 | |||
686 | memcpy(hdev->eir, cp.data, sizeof(cp.data)); | ||
687 | |||
688 | return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp); | ||
689 | } | ||
690 | |||
542 | static u8 get_service_classes(struct hci_dev *hdev) | 691 | static u8 get_service_classes(struct hci_dev *hdev) |
543 | { | 692 | { |
544 | struct list_head *p; | 693 | struct list_head *p; |
@@ -590,7 +739,7 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
590 | if (!hdev) | 739 | if (!hdev) |
591 | return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV); | 740 | return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV); |
592 | 741 | ||
593 | hci_dev_lock_bh(hdev); | 742 | hci_dev_lock(hdev); |
594 | 743 | ||
595 | uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC); | 744 | uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC); |
596 | if (!uuid) { | 745 | if (!uuid) { |
@@ -607,10 +756,14 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
607 | if (err < 0) | 756 | if (err < 0) |
608 | goto failed; | 757 | goto failed; |
609 | 758 | ||
759 | err = update_eir(hdev); | ||
760 | if (err < 0) | ||
761 | goto failed; | ||
762 | |||
610 | err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0); | 763 | err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0); |
611 | 764 | ||
612 | failed: | 765 | failed: |
613 | hci_dev_unlock_bh(hdev); | 766 | hci_dev_unlock(hdev); |
614 | hci_dev_put(hdev); | 767 | hci_dev_put(hdev); |
615 | 768 | ||
616 | return err; | 769 | return err; |
@@ -635,7 +788,7 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
635 | if (!hdev) | 788 | if (!hdev) |
636 | return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV); | 789 | return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV); |
637 | 790 | ||
638 | hci_dev_lock_bh(hdev); | 791 | hci_dev_lock(hdev); |
639 | 792 | ||
640 | if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) { | 793 | if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) { |
641 | err = hci_uuids_clear(hdev); | 794 | err = hci_uuids_clear(hdev); |
@@ -663,10 +816,14 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
663 | if (err < 0) | 816 | if (err < 0) |
664 | goto unlock; | 817 | goto unlock; |
665 | 818 | ||
819 | err = update_eir(hdev); | ||
820 | if (err < 0) | ||
821 | goto unlock; | ||
822 | |||
666 | err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0); | 823 | err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0); |
667 | 824 | ||
668 | unlock: | 825 | unlock: |
669 | hci_dev_unlock_bh(hdev); | 826 | hci_dev_unlock(hdev); |
670 | hci_dev_put(hdev); | 827 | hci_dev_put(hdev); |
671 | 828 | ||
672 | return err; | 829 | return err; |
@@ -690,7 +847,7 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data, | |||
690 | if (!hdev) | 847 | if (!hdev) |
691 | return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV); | 848 | return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV); |
692 | 849 | ||
693 | hci_dev_lock_bh(hdev); | 850 | hci_dev_lock(hdev); |
694 | 851 | ||
695 | hdev->major_class = cp->major; | 852 | hdev->major_class = cp->major; |
696 | hdev->minor_class = cp->minor; | 853 | hdev->minor_class = cp->minor; |
@@ -700,7 +857,7 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data, | |||
700 | if (err == 0) | 857 | if (err == 0) |
701 | err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0); | 858 | err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0); |
702 | 859 | ||
703 | hci_dev_unlock_bh(hdev); | 860 | hci_dev_unlock(hdev); |
704 | hci_dev_put(hdev); | 861 | hci_dev_put(hdev); |
705 | 862 | ||
706 | return err; | 863 | return err; |
@@ -722,7 +879,7 @@ static int set_service_cache(struct sock *sk, u16 index, unsigned char *data, | |||
722 | if (!hdev) | 879 | if (!hdev) |
723 | return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV); | 880 | return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV); |
724 | 881 | ||
725 | hci_dev_lock_bh(hdev); | 882 | hci_dev_lock(hdev); |
726 | 883 | ||
727 | BT_DBG("hci%u enable %d", index, cp->enable); | 884 | BT_DBG("hci%u enable %d", index, cp->enable); |
728 | 885 | ||
@@ -732,13 +889,15 @@ static int set_service_cache(struct sock *sk, u16 index, unsigned char *data, | |||
732 | } else { | 889 | } else { |
733 | clear_bit(HCI_SERVICE_CACHE, &hdev->flags); | 890 | clear_bit(HCI_SERVICE_CACHE, &hdev->flags); |
734 | err = update_class(hdev); | 891 | err = update_class(hdev); |
892 | if (err == 0) | ||
893 | err = update_eir(hdev); | ||
735 | } | 894 | } |
736 | 895 | ||
737 | if (err == 0) | 896 | if (err == 0) |
738 | err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL, | 897 | err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL, |
739 | 0); | 898 | 0); |
740 | 899 | ||
741 | hci_dev_unlock_bh(hdev); | 900 | hci_dev_unlock(hdev); |
742 | hci_dev_put(hdev); | 901 | hci_dev_put(hdev); |
743 | 902 | ||
744 | return err; | 903 | return err; |
@@ -772,7 +931,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
772 | BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys, | 931 | BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys, |
773 | key_count); | 932 | key_count); |
774 | 933 | ||
775 | hci_dev_lock_bh(hdev); | 934 | hci_dev_lock(hdev); |
776 | 935 | ||
777 | hci_link_keys_clear(hdev); | 936 | hci_link_keys_clear(hdev); |
778 | 937 | ||
@@ -786,11 +945,11 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
786 | for (i = 0; i < key_count; i++) { | 945 | for (i = 0; i < key_count; i++) { |
787 | struct mgmt_key_info *key = &cp->keys[i]; | 946 | struct mgmt_key_info *key = &cp->keys[i]; |
788 | 947 | ||
789 | hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->type, | 948 | hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type, |
790 | key->pin_len); | 949 | key->pin_len); |
791 | } | 950 | } |
792 | 951 | ||
793 | hci_dev_unlock_bh(hdev); | 952 | hci_dev_unlock(hdev); |
794 | hci_dev_put(hdev); | 953 | hci_dev_put(hdev); |
795 | 954 | ||
796 | return 0; | 955 | return 0; |
@@ -812,7 +971,7 @@ static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
812 | if (!hdev) | 971 | if (!hdev) |
813 | return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV); | 972 | return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV); |
814 | 973 | ||
815 | hci_dev_lock_bh(hdev); | 974 | hci_dev_lock(hdev); |
816 | 975 | ||
817 | err = hci_remove_link_key(hdev, &cp->bdaddr); | 976 | err = hci_remove_link_key(hdev, &cp->bdaddr); |
818 | if (err < 0) { | 977 | if (err < 0) { |
@@ -835,7 +994,7 @@ static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
835 | } | 994 | } |
836 | 995 | ||
837 | unlock: | 996 | unlock: |
838 | hci_dev_unlock_bh(hdev); | 997 | hci_dev_unlock(hdev); |
839 | hci_dev_put(hdev); | 998 | hci_dev_put(hdev); |
840 | 999 | ||
841 | return err; | 1000 | return err; |
@@ -861,7 +1020,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
861 | if (!hdev) | 1020 | if (!hdev) |
862 | return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV); | 1021 | return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV); |
863 | 1022 | ||
864 | hci_dev_lock_bh(hdev); | 1023 | hci_dev_lock(hdev); |
865 | 1024 | ||
866 | if (!test_bit(HCI_UP, &hdev->flags)) { | 1025 | if (!test_bit(HCI_UP, &hdev->flags)) { |
867 | err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN); | 1026 | err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN); |
@@ -874,6 +1033,9 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
874 | } | 1033 | } |
875 | 1034 | ||
876 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); | 1035 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); |
1036 | if (!conn) | ||
1037 | conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr); | ||
1038 | |||
877 | if (!conn) { | 1039 | if (!conn) { |
878 | err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN); | 1040 | err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN); |
879 | goto failed; | 1041 | goto failed; |
@@ -893,7 +1055,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
893 | mgmt_pending_remove(cmd); | 1055 | mgmt_pending_remove(cmd); |
894 | 1056 | ||
895 | failed: | 1057 | failed: |
896 | hci_dev_unlock_bh(hdev); | 1058 | hci_dev_unlock(hdev); |
897 | hci_dev_put(hdev); | 1059 | hci_dev_put(hdev); |
898 | 1060 | ||
899 | return err; | 1061 | return err; |
@@ -914,7 +1076,7 @@ static int get_connections(struct sock *sk, u16 index) | |||
914 | if (!hdev) | 1076 | if (!hdev) |
915 | return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV); | 1077 | return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV); |
916 | 1078 | ||
917 | hci_dev_lock_bh(hdev); | 1079 | hci_dev_lock(hdev); |
918 | 1080 | ||
919 | count = 0; | 1081 | count = 0; |
920 | list_for_each(p, &hdev->conn_hash.list) { | 1082 | list_for_each(p, &hdev->conn_hash.list) { |
@@ -945,7 +1107,7 @@ static int get_connections(struct sock *sk, u16 index) | |||
945 | 1107 | ||
946 | unlock: | 1108 | unlock: |
947 | kfree(rp); | 1109 | kfree(rp); |
948 | hci_dev_unlock_bh(hdev); | 1110 | hci_dev_unlock(hdev); |
949 | hci_dev_put(hdev); | 1111 | hci_dev_put(hdev); |
950 | return err; | 1112 | return err; |
951 | } | 1113 | } |
@@ -970,7 +1132,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data, | |||
970 | if (!hdev) | 1132 | if (!hdev) |
971 | return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV); | 1133 | return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV); |
972 | 1134 | ||
973 | hci_dev_lock_bh(hdev); | 1135 | hci_dev_lock(hdev); |
974 | 1136 | ||
975 | if (!test_bit(HCI_UP, &hdev->flags)) { | 1137 | if (!test_bit(HCI_UP, &hdev->flags)) { |
976 | err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN); | 1138 | err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN); |
@@ -992,7 +1154,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data, | |||
992 | mgmt_pending_remove(cmd); | 1154 | mgmt_pending_remove(cmd); |
993 | 1155 | ||
994 | failed: | 1156 | failed: |
995 | hci_dev_unlock_bh(hdev); | 1157 | hci_dev_unlock(hdev); |
996 | hci_dev_put(hdev); | 1158 | hci_dev_put(hdev); |
997 | 1159 | ||
998 | return err; | 1160 | return err; |
@@ -1019,7 +1181,7 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data, | |||
1019 | return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, | 1181 | return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, |
1020 | ENODEV); | 1182 | ENODEV); |
1021 | 1183 | ||
1022 | hci_dev_lock_bh(hdev); | 1184 | hci_dev_lock(hdev); |
1023 | 1185 | ||
1024 | if (!test_bit(HCI_UP, &hdev->flags)) { | 1186 | if (!test_bit(HCI_UP, &hdev->flags)) { |
1025 | err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, | 1187 | err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, |
@@ -1040,7 +1202,7 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data, | |||
1040 | mgmt_pending_remove(cmd); | 1202 | mgmt_pending_remove(cmd); |
1041 | 1203 | ||
1042 | failed: | 1204 | failed: |
1043 | hci_dev_unlock_bh(hdev); | 1205 | hci_dev_unlock(hdev); |
1044 | hci_dev_put(hdev); | 1206 | hci_dev_put(hdev); |
1045 | 1207 | ||
1046 | return err; | 1208 | return err; |
@@ -1063,14 +1225,14 @@ static int set_io_capability(struct sock *sk, u16 index, unsigned char *data, | |||
1063 | if (!hdev) | 1225 | if (!hdev) |
1064 | return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV); | 1226 | return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV); |
1065 | 1227 | ||
1066 | hci_dev_lock_bh(hdev); | 1228 | hci_dev_lock(hdev); |
1067 | 1229 | ||
1068 | hdev->io_capability = cp->io_capability; | 1230 | hdev->io_capability = cp->io_capability; |
1069 | 1231 | ||
1070 | BT_DBG("%s IO capability set to 0x%02x", hdev->name, | 1232 | BT_DBG("%s IO capability set to 0x%02x", hdev->name, |
1071 | hdev->io_capability); | 1233 | hdev->io_capability); |
1072 | 1234 | ||
1073 | hci_dev_unlock_bh(hdev); | 1235 | hci_dev_unlock(hdev); |
1074 | hci_dev_put(hdev); | 1236 | hci_dev_put(hdev); |
1075 | 1237 | ||
1076 | return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0); | 1238 | return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0); |
@@ -1156,7 +1318,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
1156 | if (!hdev) | 1318 | if (!hdev) |
1157 | return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV); | 1319 | return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV); |
1158 | 1320 | ||
1159 | hci_dev_lock_bh(hdev); | 1321 | hci_dev_lock(hdev); |
1160 | 1322 | ||
1161 | if (cp->io_cap == 0x03) { | 1323 | if (cp->io_cap == 0x03) { |
1162 | sec_level = BT_SECURITY_MEDIUM; | 1324 | sec_level = BT_SECURITY_MEDIUM; |
@@ -1198,7 +1360,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
1198 | err = 0; | 1360 | err = 0; |
1199 | 1361 | ||
1200 | unlock: | 1362 | unlock: |
1201 | hci_dev_unlock_bh(hdev); | 1363 | hci_dev_unlock(hdev); |
1202 | hci_dev_put(hdev); | 1364 | hci_dev_put(hdev); |
1203 | 1365 | ||
1204 | return err; | 1366 | return err; |
@@ -1230,7 +1392,7 @@ static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data, | |||
1230 | if (!hdev) | 1392 | if (!hdev) |
1231 | return cmd_status(sk, index, mgmt_op, ENODEV); | 1393 | return cmd_status(sk, index, mgmt_op, ENODEV); |
1232 | 1394 | ||
1233 | hci_dev_lock_bh(hdev); | 1395 | hci_dev_lock(hdev); |
1234 | 1396 | ||
1235 | if (!test_bit(HCI_UP, &hdev->flags)) { | 1397 | if (!test_bit(HCI_UP, &hdev->flags)) { |
1236 | err = cmd_status(sk, index, mgmt_op, ENETDOWN); | 1398 | err = cmd_status(sk, index, mgmt_op, ENETDOWN); |
@@ -1248,6 +1410,231 @@ static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data, | |||
1248 | mgmt_pending_remove(cmd); | 1410 | mgmt_pending_remove(cmd); |
1249 | 1411 | ||
1250 | failed: | 1412 | failed: |
1413 | hci_dev_unlock(hdev); | ||
1414 | hci_dev_put(hdev); | ||
1415 | |||
1416 | return err; | ||
1417 | } | ||
1418 | |||
1419 | static int set_local_name(struct sock *sk, u16 index, unsigned char *data, | ||
1420 | u16 len) | ||
1421 | { | ||
1422 | struct mgmt_cp_set_local_name *mgmt_cp = (void *) data; | ||
1423 | struct hci_cp_write_local_name hci_cp; | ||
1424 | struct hci_dev *hdev; | ||
1425 | struct pending_cmd *cmd; | ||
1426 | int err; | ||
1427 | |||
1428 | BT_DBG(""); | ||
1429 | |||
1430 | if (len != sizeof(*mgmt_cp)) | ||
1431 | return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL); | ||
1432 | |||
1433 | hdev = hci_dev_get(index); | ||
1434 | if (!hdev) | ||
1435 | return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV); | ||
1436 | |||
1437 | hci_dev_lock(hdev); | ||
1438 | |||
1439 | cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len); | ||
1440 | if (!cmd) { | ||
1441 | err = -ENOMEM; | ||
1442 | goto failed; | ||
1443 | } | ||
1444 | |||
1445 | memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name)); | ||
1446 | err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp), | ||
1447 | &hci_cp); | ||
1448 | if (err < 0) | ||
1449 | mgmt_pending_remove(cmd); | ||
1450 | |||
1451 | failed: | ||
1452 | hci_dev_unlock(hdev); | ||
1453 | hci_dev_put(hdev); | ||
1454 | |||
1455 | return err; | ||
1456 | } | ||
1457 | |||
1458 | static int read_local_oob_data(struct sock *sk, u16 index) | ||
1459 | { | ||
1460 | struct hci_dev *hdev; | ||
1461 | struct pending_cmd *cmd; | ||
1462 | int err; | ||
1463 | |||
1464 | BT_DBG("hci%u", index); | ||
1465 | |||
1466 | hdev = hci_dev_get(index); | ||
1467 | if (!hdev) | ||
1468 | return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, | ||
1469 | ENODEV); | ||
1470 | |||
1471 | hci_dev_lock(hdev); | ||
1472 | |||
1473 | if (!test_bit(HCI_UP, &hdev->flags)) { | ||
1474 | err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, | ||
1475 | ENETDOWN); | ||
1476 | goto unlock; | ||
1477 | } | ||
1478 | |||
1479 | if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) { | ||
1480 | err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, | ||
1481 | EOPNOTSUPP); | ||
1482 | goto unlock; | ||
1483 | } | ||
1484 | |||
1485 | if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) { | ||
1486 | err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY); | ||
1487 | goto unlock; | ||
1488 | } | ||
1489 | |||
1490 | cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0); | ||
1491 | if (!cmd) { | ||
1492 | err = -ENOMEM; | ||
1493 | goto unlock; | ||
1494 | } | ||
1495 | |||
1496 | err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL); | ||
1497 | if (err < 0) | ||
1498 | mgmt_pending_remove(cmd); | ||
1499 | |||
1500 | unlock: | ||
1501 | hci_dev_unlock(hdev); | ||
1502 | hci_dev_put(hdev); | ||
1503 | |||
1504 | return err; | ||
1505 | } | ||
1506 | |||
1507 | static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data, | ||
1508 | u16 len) | ||
1509 | { | ||
1510 | struct hci_dev *hdev; | ||
1511 | struct mgmt_cp_add_remote_oob_data *cp = (void *) data; | ||
1512 | int err; | ||
1513 | |||
1514 | BT_DBG("hci%u ", index); | ||
1515 | |||
1516 | if (len != sizeof(*cp)) | ||
1517 | return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, | ||
1518 | EINVAL); | ||
1519 | |||
1520 | hdev = hci_dev_get(index); | ||
1521 | if (!hdev) | ||
1522 | return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, | ||
1523 | ENODEV); | ||
1524 | |||
1525 | hci_dev_lock(hdev); | ||
1526 | |||
1527 | err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash, | ||
1528 | cp->randomizer); | ||
1529 | if (err < 0) | ||
1530 | err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err); | ||
1531 | else | ||
1532 | err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL, | ||
1533 | 0); | ||
1534 | |||
1535 | hci_dev_unlock(hdev); | ||
1536 | hci_dev_put(hdev); | ||
1537 | |||
1538 | return err; | ||
1539 | } | ||
1540 | |||
1541 | static int remove_remote_oob_data(struct sock *sk, u16 index, | ||
1542 | unsigned char *data, u16 len) | ||
1543 | { | ||
1544 | struct hci_dev *hdev; | ||
1545 | struct mgmt_cp_remove_remote_oob_data *cp = (void *) data; | ||
1546 | int err; | ||
1547 | |||
1548 | BT_DBG("hci%u ", index); | ||
1549 | |||
1550 | if (len != sizeof(*cp)) | ||
1551 | return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, | ||
1552 | EINVAL); | ||
1553 | |||
1554 | hdev = hci_dev_get(index); | ||
1555 | if (!hdev) | ||
1556 | return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, | ||
1557 | ENODEV); | ||
1558 | |||
1559 | hci_dev_lock(hdev); | ||
1560 | |||
1561 | err = hci_remove_remote_oob_data(hdev, &cp->bdaddr); | ||
1562 | if (err < 0) | ||
1563 | err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, | ||
1564 | -err); | ||
1565 | else | ||
1566 | err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, | ||
1567 | NULL, 0); | ||
1568 | |||
1569 | hci_dev_unlock(hdev); | ||
1570 | hci_dev_put(hdev); | ||
1571 | |||
1572 | return err; | ||
1573 | } | ||
1574 | |||
1575 | static int start_discovery(struct sock *sk, u16 index) | ||
1576 | { | ||
1577 | u8 lap[3] = { 0x33, 0x8b, 0x9e }; | ||
1578 | struct hci_cp_inquiry cp; | ||
1579 | struct pending_cmd *cmd; | ||
1580 | struct hci_dev *hdev; | ||
1581 | int err; | ||
1582 | |||
1583 | BT_DBG("hci%u", index); | ||
1584 | |||
1585 | hdev = hci_dev_get(index); | ||
1586 | if (!hdev) | ||
1587 | return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV); | ||
1588 | |||
1589 | hci_dev_lock_bh(hdev); | ||
1590 | |||
1591 | cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0); | ||
1592 | if (!cmd) { | ||
1593 | err = -ENOMEM; | ||
1594 | goto failed; | ||
1595 | } | ||
1596 | |||
1597 | memset(&cp, 0, sizeof(cp)); | ||
1598 | memcpy(&cp.lap, lap, 3); | ||
1599 | cp.length = 0x08; | ||
1600 | cp.num_rsp = 0x00; | ||
1601 | |||
1602 | err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp); | ||
1603 | if (err < 0) | ||
1604 | mgmt_pending_remove(cmd); | ||
1605 | |||
1606 | failed: | ||
1607 | hci_dev_unlock_bh(hdev); | ||
1608 | hci_dev_put(hdev); | ||
1609 | |||
1610 | return err; | ||
1611 | } | ||
1612 | |||
1613 | static int stop_discovery(struct sock *sk, u16 index) | ||
1614 | { | ||
1615 | struct hci_dev *hdev; | ||
1616 | struct pending_cmd *cmd; | ||
1617 | int err; | ||
1618 | |||
1619 | BT_DBG("hci%u", index); | ||
1620 | |||
1621 | hdev = hci_dev_get(index); | ||
1622 | if (!hdev) | ||
1623 | return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV); | ||
1624 | |||
1625 | hci_dev_lock_bh(hdev); | ||
1626 | |||
1627 | cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0); | ||
1628 | if (!cmd) { | ||
1629 | err = -ENOMEM; | ||
1630 | goto failed; | ||
1631 | } | ||
1632 | |||
1633 | err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL); | ||
1634 | if (err < 0) | ||
1635 | mgmt_pending_remove(cmd); | ||
1636 | |||
1637 | failed: | ||
1251 | hci_dev_unlock_bh(hdev); | 1638 | hci_dev_unlock_bh(hdev); |
1252 | hci_dev_put(hdev); | 1639 | hci_dev_put(hdev); |
1253 | 1640 | ||
@@ -1266,7 +1653,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | |||
1266 | if (msglen < sizeof(*hdr)) | 1653 | if (msglen < sizeof(*hdr)) |
1267 | return -EINVAL; | 1654 | return -EINVAL; |
1268 | 1655 | ||
1269 | buf = kmalloc(msglen, GFP_ATOMIC); | 1656 | buf = kmalloc(msglen, GFP_KERNEL); |
1270 | if (!buf) | 1657 | if (!buf) |
1271 | return -ENOMEM; | 1658 | return -ENOMEM; |
1272 | 1659 | ||
@@ -1349,6 +1736,25 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | |||
1349 | case MGMT_OP_USER_CONFIRM_NEG_REPLY: | 1736 | case MGMT_OP_USER_CONFIRM_NEG_REPLY: |
1350 | err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0); | 1737 | err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0); |
1351 | break; | 1738 | break; |
1739 | case MGMT_OP_SET_LOCAL_NAME: | ||
1740 | err = set_local_name(sk, index, buf + sizeof(*hdr), len); | ||
1741 | break; | ||
1742 | case MGMT_OP_READ_LOCAL_OOB_DATA: | ||
1743 | err = read_local_oob_data(sk, index); | ||
1744 | break; | ||
1745 | case MGMT_OP_ADD_REMOTE_OOB_DATA: | ||
1746 | err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len); | ||
1747 | break; | ||
1748 | case MGMT_OP_REMOVE_REMOTE_OOB_DATA: | ||
1749 | err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr), | ||
1750 | len); | ||
1751 | break; | ||
1752 | case MGMT_OP_START_DISCOVERY: | ||
1753 | err = start_discovery(sk, index); | ||
1754 | break; | ||
1755 | case MGMT_OP_STOP_DISCOVERY: | ||
1756 | err = stop_discovery(sk, index); | ||
1757 | break; | ||
1352 | default: | 1758 | default: |
1353 | BT_DBG("Unknown op %u", opcode); | 1759 | BT_DBG("Unknown op %u", opcode); |
1354 | err = cmd_status(sk, index, opcode, 0x01); | 1760 | err = cmd_status(sk, index, opcode, 0x01); |
@@ -1382,7 +1788,7 @@ struct cmd_lookup { | |||
1382 | 1788 | ||
1383 | static void mode_rsp(struct pending_cmd *cmd, void *data) | 1789 | static void mode_rsp(struct pending_cmd *cmd, void *data) |
1384 | { | 1790 | { |
1385 | struct mgmt_mode *cp = cmd->cmd; | 1791 | struct mgmt_mode *cp = cmd->param; |
1386 | struct cmd_lookup *match = data; | 1792 | struct cmd_lookup *match = data; |
1387 | 1793 | ||
1388 | if (cp->val != match->val) | 1794 | if (cp->val != match->val) |
@@ -1455,17 +1861,17 @@ int mgmt_connectable(u16 index, u8 connectable) | |||
1455 | return ret; | 1861 | return ret; |
1456 | } | 1862 | } |
1457 | 1863 | ||
1458 | int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type) | 1864 | int mgmt_new_key(u16 index, struct link_key *key, u8 persistent) |
1459 | { | 1865 | { |
1460 | struct mgmt_ev_new_key ev; | 1866 | struct mgmt_ev_new_key ev; |
1461 | 1867 | ||
1462 | memset(&ev, 0, sizeof(ev)); | 1868 | memset(&ev, 0, sizeof(ev)); |
1463 | 1869 | ||
1870 | ev.store_hint = persistent; | ||
1464 | bacpy(&ev.key.bdaddr, &key->bdaddr); | 1871 | bacpy(&ev.key.bdaddr, &key->bdaddr); |
1465 | ev.key.type = key->type; | 1872 | ev.key.type = key->type; |
1466 | memcpy(ev.key.val, key->val, 16); | 1873 | memcpy(ev.key.val, key->val, 16); |
1467 | ev.key.pin_len = key->pin_len; | 1874 | ev.key.pin_len = key->pin_len; |
1468 | ev.old_key_type = old_key_type; | ||
1469 | 1875 | ||
1470 | return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL); | 1876 | return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL); |
1471 | } | 1877 | } |
@@ -1481,7 +1887,7 @@ int mgmt_connected(u16 index, bdaddr_t *bdaddr) | |||
1481 | 1887 | ||
1482 | static void disconnect_rsp(struct pending_cmd *cmd, void *data) | 1888 | static void disconnect_rsp(struct pending_cmd *cmd, void *data) |
1483 | { | 1889 | { |
1484 | struct mgmt_cp_disconnect *cp = cmd->cmd; | 1890 | struct mgmt_cp_disconnect *cp = cmd->param; |
1485 | struct sock **sk = data; | 1891 | struct sock **sk = data; |
1486 | struct mgmt_rp_disconnect rp; | 1892 | struct mgmt_rp_disconnect rp; |
1487 | 1893 | ||
@@ -1539,11 +1945,12 @@ int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status) | |||
1539 | return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL); | 1945 | return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL); |
1540 | } | 1946 | } |
1541 | 1947 | ||
1542 | int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr) | 1948 | int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure) |
1543 | { | 1949 | { |
1544 | struct mgmt_ev_pin_code_request ev; | 1950 | struct mgmt_ev_pin_code_request ev; |
1545 | 1951 | ||
1546 | bacpy(&ev.bdaddr, bdaddr); | 1952 | bacpy(&ev.bdaddr, bdaddr); |
1953 | ev.secure = secure; | ||
1547 | 1954 | ||
1548 | return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev), | 1955 | return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev), |
1549 | NULL); | 1956 | NULL); |
@@ -1591,13 +1998,15 @@ int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status) | |||
1591 | return err; | 1998 | return err; |
1592 | } | 1999 | } |
1593 | 2000 | ||
1594 | int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value) | 2001 | int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value, |
2002 | u8 confirm_hint) | ||
1595 | { | 2003 | { |
1596 | struct mgmt_ev_user_confirm_request ev; | 2004 | struct mgmt_ev_user_confirm_request ev; |
1597 | 2005 | ||
1598 | BT_DBG("hci%u", index); | 2006 | BT_DBG("hci%u", index); |
1599 | 2007 | ||
1600 | bacpy(&ev.bdaddr, bdaddr); | 2008 | bacpy(&ev.bdaddr, bdaddr); |
2009 | ev.confirm_hint = confirm_hint; | ||
1601 | put_unaligned_le32(value, &ev.value); | 2010 | put_unaligned_le32(value, &ev.value); |
1602 | 2011 | ||
1603 | return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev), | 2012 | return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev), |
@@ -1645,3 +2054,110 @@ int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status) | |||
1645 | 2054 | ||
1646 | return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL); | 2055 | return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL); |
1647 | } | 2056 | } |
2057 | |||
2058 | int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status) | ||
2059 | { | ||
2060 | struct pending_cmd *cmd; | ||
2061 | struct hci_dev *hdev; | ||
2062 | struct mgmt_cp_set_local_name ev; | ||
2063 | int err; | ||
2064 | |||
2065 | memset(&ev, 0, sizeof(ev)); | ||
2066 | memcpy(ev.name, name, HCI_MAX_NAME_LENGTH); | ||
2067 | |||
2068 | cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index); | ||
2069 | if (!cmd) | ||
2070 | goto send_event; | ||
2071 | |||
2072 | if (status) { | ||
2073 | err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO); | ||
2074 | goto failed; | ||
2075 | } | ||
2076 | |||
2077 | hdev = hci_dev_get(index); | ||
2078 | if (hdev) { | ||
2079 | hci_dev_lock_bh(hdev); | ||
2080 | update_eir(hdev); | ||
2081 | hci_dev_unlock_bh(hdev); | ||
2082 | hci_dev_put(hdev); | ||
2083 | } | ||
2084 | |||
2085 | err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev, | ||
2086 | sizeof(ev)); | ||
2087 | if (err < 0) | ||
2088 | goto failed; | ||
2089 | |||
2090 | send_event: | ||
2091 | err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev), | ||
2092 | cmd ? cmd->sk : NULL); | ||
2093 | |||
2094 | failed: | ||
2095 | if (cmd) | ||
2096 | mgmt_pending_remove(cmd); | ||
2097 | return err; | ||
2098 | } | ||
2099 | |||
2100 | int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer, | ||
2101 | u8 status) | ||
2102 | { | ||
2103 | struct pending_cmd *cmd; | ||
2104 | int err; | ||
2105 | |||
2106 | BT_DBG("hci%u status %u", index, status); | ||
2107 | |||
2108 | cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index); | ||
2109 | if (!cmd) | ||
2110 | return -ENOENT; | ||
2111 | |||
2112 | if (status) { | ||
2113 | err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, | ||
2114 | EIO); | ||
2115 | } else { | ||
2116 | struct mgmt_rp_read_local_oob_data rp; | ||
2117 | |||
2118 | memcpy(rp.hash, hash, sizeof(rp.hash)); | ||
2119 | memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer)); | ||
2120 | |||
2121 | err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, | ||
2122 | &rp, sizeof(rp)); | ||
2123 | } | ||
2124 | |||
2125 | mgmt_pending_remove(cmd); | ||
2126 | |||
2127 | return err; | ||
2128 | } | ||
2129 | |||
2130 | int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi, | ||
2131 | u8 *eir) | ||
2132 | { | ||
2133 | struct mgmt_ev_device_found ev; | ||
2134 | |||
2135 | memset(&ev, 0, sizeof(ev)); | ||
2136 | |||
2137 | bacpy(&ev.bdaddr, bdaddr); | ||
2138 | memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class)); | ||
2139 | ev.rssi = rssi; | ||
2140 | |||
2141 | if (eir) | ||
2142 | memcpy(ev.eir, eir, sizeof(ev.eir)); | ||
2143 | |||
2144 | return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL); | ||
2145 | } | ||
2146 | |||
2147 | int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name) | ||
2148 | { | ||
2149 | struct mgmt_ev_remote_name ev; | ||
2150 | |||
2151 | memset(&ev, 0, sizeof(ev)); | ||
2152 | |||
2153 | bacpy(&ev.bdaddr, bdaddr); | ||
2154 | memcpy(ev.name, name, HCI_MAX_NAME_LENGTH); | ||
2155 | |||
2156 | return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL); | ||
2157 | } | ||
2158 | |||
2159 | int mgmt_discovering(u16 index, u8 discovering) | ||
2160 | { | ||
2161 | return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering, | ||
2162 | sizeof(discovering), NULL); | ||
2163 | } | ||