diff options
Diffstat (limited to 'net/bluetooth/mgmt.c')
-rw-r--r-- | net/bluetooth/mgmt.c | 281 |
1 files changed, 203 insertions, 78 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index dae382ce7020..53e109eb043e 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -41,7 +41,7 @@ struct pending_cmd { | |||
41 | void *user_data; | 41 | void *user_data; |
42 | }; | 42 | }; |
43 | 43 | ||
44 | LIST_HEAD(cmd_list); | 44 | static LIST_HEAD(cmd_list); |
45 | 45 | ||
46 | static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status) | 46 | static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status) |
47 | { | 47 | { |
@@ -179,7 +179,7 @@ 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(hdev); | 182 | hci_dev_lock_bh(hdev); |
183 | 183 | ||
184 | set_bit(HCI_MGMT, &hdev->flags); | 184 | set_bit(HCI_MGMT, &hdev->flags); |
185 | 185 | ||
@@ -208,7 +208,7 @@ static int read_controller_info(struct sock *sk, u16 index) | |||
208 | 208 | ||
209 | memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name)); | 209 | memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name)); |
210 | 210 | ||
211 | hci_dev_unlock(hdev); | 211 | hci_dev_unlock_bh(hdev); |
212 | hci_dev_put(hdev); | 212 | hci_dev_put(hdev); |
213 | 213 | ||
214 | 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)); |
@@ -316,7 +316,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
316 | if (!hdev) | 316 | if (!hdev) |
317 | return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV); | 317 | return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV); |
318 | 318 | ||
319 | hci_dev_lock(hdev); | 319 | hci_dev_lock_bh(hdev); |
320 | 320 | ||
321 | up = test_bit(HCI_UP, &hdev->flags); | 321 | up = test_bit(HCI_UP, &hdev->flags); |
322 | if ((cp->val && up) || (!cp->val && !up)) { | 322 | if ((cp->val && up) || (!cp->val && !up)) { |
@@ -343,7 +343,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
343 | err = 0; | 343 | err = 0; |
344 | 344 | ||
345 | failed: | 345 | failed: |
346 | hci_dev_unlock(hdev); | 346 | hci_dev_unlock_bh(hdev); |
347 | hci_dev_put(hdev); | 347 | hci_dev_put(hdev); |
348 | return err; | 348 | return err; |
349 | } | 349 | } |
@@ -368,7 +368,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data, | |||
368 | if (!hdev) | 368 | if (!hdev) |
369 | return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV); | 369 | return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV); |
370 | 370 | ||
371 | hci_dev_lock(hdev); | 371 | hci_dev_lock_bh(hdev); |
372 | 372 | ||
373 | if (!test_bit(HCI_UP, &hdev->flags)) { | 373 | if (!test_bit(HCI_UP, &hdev->flags)) { |
374 | err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN); | 374 | err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN); |
@@ -403,7 +403,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data, | |||
403 | mgmt_pending_remove(cmd); | 403 | mgmt_pending_remove(cmd); |
404 | 404 | ||
405 | failed: | 405 | failed: |
406 | hci_dev_unlock(hdev); | 406 | hci_dev_unlock_bh(hdev); |
407 | hci_dev_put(hdev); | 407 | hci_dev_put(hdev); |
408 | 408 | ||
409 | return err; | 409 | return err; |
@@ -429,7 +429,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data, | |||
429 | if (!hdev) | 429 | if (!hdev) |
430 | return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV); | 430 | return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV); |
431 | 431 | ||
432 | hci_dev_lock(hdev); | 432 | hci_dev_lock_bh(hdev); |
433 | 433 | ||
434 | if (!test_bit(HCI_UP, &hdev->flags)) { | 434 | if (!test_bit(HCI_UP, &hdev->flags)) { |
435 | err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN); | 435 | err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN); |
@@ -463,7 +463,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data, | |||
463 | mgmt_pending_remove(cmd); | 463 | mgmt_pending_remove(cmd); |
464 | 464 | ||
465 | failed: | 465 | failed: |
466 | hci_dev_unlock(hdev); | 466 | hci_dev_unlock_bh(hdev); |
467 | hci_dev_put(hdev); | 467 | hci_dev_put(hdev); |
468 | 468 | ||
469 | return err; | 469 | return err; |
@@ -522,7 +522,7 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data, | |||
522 | if (!hdev) | 522 | if (!hdev) |
523 | return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV); | 523 | return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV); |
524 | 524 | ||
525 | hci_dev_lock(hdev); | 525 | hci_dev_lock_bh(hdev); |
526 | 526 | ||
527 | if (cp->val) | 527 | if (cp->val) |
528 | set_bit(HCI_PAIRABLE, &hdev->flags); | 528 | set_bit(HCI_PAIRABLE, &hdev->flags); |
@@ -538,7 +538,7 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data, | |||
538 | err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk); | 538 | err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk); |
539 | 539 | ||
540 | failed: | 540 | failed: |
541 | hci_dev_unlock(hdev); | 541 | hci_dev_unlock_bh(hdev); |
542 | hci_dev_put(hdev); | 542 | hci_dev_put(hdev); |
543 | 543 | ||
544 | return err; | 544 | return err; |
@@ -739,7 +739,7 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
739 | if (!hdev) | 739 | if (!hdev) |
740 | return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV); | 740 | return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV); |
741 | 741 | ||
742 | hci_dev_lock(hdev); | 742 | hci_dev_lock_bh(hdev); |
743 | 743 | ||
744 | uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC); | 744 | uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC); |
745 | if (!uuid) { | 745 | if (!uuid) { |
@@ -763,7 +763,7 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
763 | err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0); | 763 | err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0); |
764 | 764 | ||
765 | failed: | 765 | failed: |
766 | hci_dev_unlock(hdev); | 766 | hci_dev_unlock_bh(hdev); |
767 | hci_dev_put(hdev); | 767 | hci_dev_put(hdev); |
768 | 768 | ||
769 | return err; | 769 | return err; |
@@ -788,7 +788,7 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
788 | if (!hdev) | 788 | if (!hdev) |
789 | return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV); | 789 | return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV); |
790 | 790 | ||
791 | hci_dev_lock(hdev); | 791 | hci_dev_lock_bh(hdev); |
792 | 792 | ||
793 | if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) { | 793 | if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) { |
794 | err = hci_uuids_clear(hdev); | 794 | err = hci_uuids_clear(hdev); |
@@ -823,7 +823,7 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
823 | err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0); | 823 | err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0); |
824 | 824 | ||
825 | unlock: | 825 | unlock: |
826 | hci_dev_unlock(hdev); | 826 | hci_dev_unlock_bh(hdev); |
827 | hci_dev_put(hdev); | 827 | hci_dev_put(hdev); |
828 | 828 | ||
829 | return err; | 829 | return err; |
@@ -847,7 +847,7 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data, | |||
847 | if (!hdev) | 847 | if (!hdev) |
848 | return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV); | 848 | return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV); |
849 | 849 | ||
850 | hci_dev_lock(hdev); | 850 | hci_dev_lock_bh(hdev); |
851 | 851 | ||
852 | hdev->major_class = cp->major; | 852 | hdev->major_class = cp->major; |
853 | hdev->minor_class = cp->minor; | 853 | hdev->minor_class = cp->minor; |
@@ -857,7 +857,7 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data, | |||
857 | if (err == 0) | 857 | if (err == 0) |
858 | 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); |
859 | 859 | ||
860 | hci_dev_unlock(hdev); | 860 | hci_dev_unlock_bh(hdev); |
861 | hci_dev_put(hdev); | 861 | hci_dev_put(hdev); |
862 | 862 | ||
863 | return err; | 863 | return err; |
@@ -879,7 +879,7 @@ static int set_service_cache(struct sock *sk, u16 index, unsigned char *data, | |||
879 | if (!hdev) | 879 | if (!hdev) |
880 | return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV); | 880 | return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV); |
881 | 881 | ||
882 | hci_dev_lock(hdev); | 882 | hci_dev_lock_bh(hdev); |
883 | 883 | ||
884 | BT_DBG("hci%u enable %d", index, cp->enable); | 884 | BT_DBG("hci%u enable %d", index, cp->enable); |
885 | 885 | ||
@@ -897,7 +897,7 @@ static int set_service_cache(struct sock *sk, u16 index, unsigned char *data, | |||
897 | err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL, | 897 | err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL, |
898 | 0); | 898 | 0); |
899 | 899 | ||
900 | hci_dev_unlock(hdev); | 900 | hci_dev_unlock_bh(hdev); |
901 | hci_dev_put(hdev); | 901 | hci_dev_put(hdev); |
902 | 902 | ||
903 | return err; | 903 | return err; |
@@ -908,7 +908,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
908 | struct hci_dev *hdev; | 908 | struct hci_dev *hdev; |
909 | struct mgmt_cp_load_keys *cp; | 909 | struct mgmt_cp_load_keys *cp; |
910 | u16 key_count, expected_len; | 910 | u16 key_count, expected_len; |
911 | int i; | 911 | int i, err; |
912 | 912 | ||
913 | cp = (void *) data; | 913 | cp = (void *) data; |
914 | 914 | ||
@@ -918,9 +918,9 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
918 | key_count = get_unaligned_le16(&cp->key_count); | 918 | key_count = get_unaligned_le16(&cp->key_count); |
919 | 919 | ||
920 | expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info); | 920 | expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info); |
921 | if (expected_len != len) { | 921 | if (expected_len > len) { |
922 | BT_ERR("load_keys: expected %u bytes, got %u bytes", | 922 | BT_ERR("load_keys: expected at least %u bytes, got %u bytes", |
923 | len, expected_len); | 923 | expected_len, len); |
924 | return -EINVAL; | 924 | return -EINVAL; |
925 | } | 925 | } |
926 | 926 | ||
@@ -931,7 +931,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
931 | 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, |
932 | key_count); | 932 | key_count); |
933 | 933 | ||
934 | hci_dev_lock(hdev); | 934 | hci_dev_lock_bh(hdev); |
935 | 935 | ||
936 | hci_link_keys_clear(hdev); | 936 | hci_link_keys_clear(hdev); |
937 | 937 | ||
@@ -942,17 +942,36 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
942 | else | 942 | else |
943 | clear_bit(HCI_DEBUG_KEYS, &hdev->flags); | 943 | clear_bit(HCI_DEBUG_KEYS, &hdev->flags); |
944 | 944 | ||
945 | for (i = 0; i < key_count; i++) { | 945 | len -= sizeof(*cp); |
946 | struct mgmt_key_info *key = &cp->keys[i]; | 946 | i = 0; |
947 | |||
948 | while (i < len) { | ||
949 | struct mgmt_key_info *key = (void *) cp->keys + i; | ||
950 | |||
951 | i += sizeof(*key) + key->dlen; | ||
952 | |||
953 | if (key->type == HCI_LK_SMP_LTK) { | ||
954 | struct key_master_id *id = (void *) key->data; | ||
955 | |||
956 | if (key->dlen != sizeof(struct key_master_id)) | ||
957 | continue; | ||
958 | |||
959 | hci_add_ltk(hdev, 0, &key->bdaddr, key->pin_len, | ||
960 | id->ediv, id->rand, key->val); | ||
961 | |||
962 | continue; | ||
963 | } | ||
947 | 964 | ||
948 | hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type, | 965 | hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type, |
949 | key->pin_len); | 966 | key->pin_len); |
950 | } | 967 | } |
951 | 968 | ||
952 | hci_dev_unlock(hdev); | 969 | err = cmd_complete(sk, index, MGMT_OP_LOAD_KEYS, NULL, 0); |
970 | |||
971 | hci_dev_unlock_bh(hdev); | ||
953 | hci_dev_put(hdev); | 972 | hci_dev_put(hdev); |
954 | 973 | ||
955 | return 0; | 974 | return err; |
956 | } | 975 | } |
957 | 976 | ||
958 | static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len) | 977 | static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len) |
@@ -971,7 +990,7 @@ static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
971 | if (!hdev) | 990 | if (!hdev) |
972 | return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV); | 991 | return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV); |
973 | 992 | ||
974 | hci_dev_lock(hdev); | 993 | hci_dev_lock_bh(hdev); |
975 | 994 | ||
976 | err = hci_remove_link_key(hdev, &cp->bdaddr); | 995 | err = hci_remove_link_key(hdev, &cp->bdaddr); |
977 | if (err < 0) { | 996 | if (err < 0) { |
@@ -990,11 +1009,11 @@ static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
990 | 1009 | ||
991 | put_unaligned_le16(conn->handle, &dc.handle); | 1010 | put_unaligned_le16(conn->handle, &dc.handle); |
992 | dc.reason = 0x13; /* Remote User Terminated Connection */ | 1011 | dc.reason = 0x13; /* Remote User Terminated Connection */ |
993 | err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL); | 1012 | err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc); |
994 | } | 1013 | } |
995 | 1014 | ||
996 | unlock: | 1015 | unlock: |
997 | hci_dev_unlock(hdev); | 1016 | hci_dev_unlock_bh(hdev); |
998 | hci_dev_put(hdev); | 1017 | hci_dev_put(hdev); |
999 | 1018 | ||
1000 | return err; | 1019 | return err; |
@@ -1020,7 +1039,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
1020 | if (!hdev) | 1039 | if (!hdev) |
1021 | return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV); | 1040 | return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV); |
1022 | 1041 | ||
1023 | hci_dev_lock(hdev); | 1042 | hci_dev_lock_bh(hdev); |
1024 | 1043 | ||
1025 | if (!test_bit(HCI_UP, &hdev->flags)) { | 1044 | if (!test_bit(HCI_UP, &hdev->flags)) { |
1026 | err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN); | 1045 | err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN); |
@@ -1055,7 +1074,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
1055 | mgmt_pending_remove(cmd); | 1074 | mgmt_pending_remove(cmd); |
1056 | 1075 | ||
1057 | failed: | 1076 | failed: |
1058 | hci_dev_unlock(hdev); | 1077 | hci_dev_unlock_bh(hdev); |
1059 | hci_dev_put(hdev); | 1078 | hci_dev_put(hdev); |
1060 | 1079 | ||
1061 | return err; | 1080 | return err; |
@@ -1076,7 +1095,7 @@ static int get_connections(struct sock *sk, u16 index) | |||
1076 | if (!hdev) | 1095 | if (!hdev) |
1077 | return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV); | 1096 | return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV); |
1078 | 1097 | ||
1079 | hci_dev_lock(hdev); | 1098 | hci_dev_lock_bh(hdev); |
1080 | 1099 | ||
1081 | count = 0; | 1100 | count = 0; |
1082 | list_for_each(p, &hdev->conn_hash.list) { | 1101 | list_for_each(p, &hdev->conn_hash.list) { |
@@ -1092,8 +1111,6 @@ static int get_connections(struct sock *sk, u16 index) | |||
1092 | 1111 | ||
1093 | put_unaligned_le16(count, &rp->conn_count); | 1112 | put_unaligned_le16(count, &rp->conn_count); |
1094 | 1113 | ||
1095 | read_lock(&hci_dev_list_lock); | ||
1096 | |||
1097 | i = 0; | 1114 | i = 0; |
1098 | list_for_each(p, &hdev->conn_hash.list) { | 1115 | list_for_each(p, &hdev->conn_hash.list) { |
1099 | struct hci_conn *c = list_entry(p, struct hci_conn, list); | 1116 | struct hci_conn *c = list_entry(p, struct hci_conn, list); |
@@ -1101,22 +1118,41 @@ static int get_connections(struct sock *sk, u16 index) | |||
1101 | bacpy(&rp->conn[i++], &c->dst); | 1118 | bacpy(&rp->conn[i++], &c->dst); |
1102 | } | 1119 | } |
1103 | 1120 | ||
1104 | read_unlock(&hci_dev_list_lock); | ||
1105 | |||
1106 | err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len); | 1121 | err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len); |
1107 | 1122 | ||
1108 | unlock: | 1123 | unlock: |
1109 | kfree(rp); | 1124 | kfree(rp); |
1110 | hci_dev_unlock(hdev); | 1125 | hci_dev_unlock_bh(hdev); |
1111 | hci_dev_put(hdev); | 1126 | hci_dev_put(hdev); |
1112 | return err; | 1127 | return err; |
1113 | } | 1128 | } |
1114 | 1129 | ||
1130 | static int send_pin_code_neg_reply(struct sock *sk, u16 index, | ||
1131 | struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp) | ||
1132 | { | ||
1133 | struct pending_cmd *cmd; | ||
1134 | int err; | ||
1135 | |||
1136 | cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index, cp, | ||
1137 | sizeof(*cp)); | ||
1138 | if (!cmd) | ||
1139 | return -ENOMEM; | ||
1140 | |||
1141 | err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr), | ||
1142 | &cp->bdaddr); | ||
1143 | if (err < 0) | ||
1144 | mgmt_pending_remove(cmd); | ||
1145 | |||
1146 | return err; | ||
1147 | } | ||
1148 | |||
1115 | static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data, | 1149 | static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data, |
1116 | u16 len) | 1150 | u16 len) |
1117 | { | 1151 | { |
1118 | struct hci_dev *hdev; | 1152 | struct hci_dev *hdev; |
1153 | struct hci_conn *conn; | ||
1119 | struct mgmt_cp_pin_code_reply *cp; | 1154 | struct mgmt_cp_pin_code_reply *cp; |
1155 | struct mgmt_cp_pin_code_neg_reply ncp; | ||
1120 | struct hci_cp_pin_code_reply reply; | 1156 | struct hci_cp_pin_code_reply reply; |
1121 | struct pending_cmd *cmd; | 1157 | struct pending_cmd *cmd; |
1122 | int err; | 1158 | int err; |
@@ -1132,13 +1168,32 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data, | |||
1132 | if (!hdev) | 1168 | if (!hdev) |
1133 | return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV); | 1169 | return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV); |
1134 | 1170 | ||
1135 | hci_dev_lock(hdev); | 1171 | hci_dev_lock_bh(hdev); |
1136 | 1172 | ||
1137 | if (!test_bit(HCI_UP, &hdev->flags)) { | 1173 | if (!test_bit(HCI_UP, &hdev->flags)) { |
1138 | err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN); | 1174 | err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN); |
1139 | goto failed; | 1175 | goto failed; |
1140 | } | 1176 | } |
1141 | 1177 | ||
1178 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); | ||
1179 | if (!conn) { | ||
1180 | err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENOTCONN); | ||
1181 | goto failed; | ||
1182 | } | ||
1183 | |||
1184 | if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) { | ||
1185 | bacpy(&ncp.bdaddr, &cp->bdaddr); | ||
1186 | |||
1187 | BT_ERR("PIN code is not 16 bytes long"); | ||
1188 | |||
1189 | err = send_pin_code_neg_reply(sk, index, hdev, &ncp); | ||
1190 | if (err >= 0) | ||
1191 | err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, | ||
1192 | EINVAL); | ||
1193 | |||
1194 | goto failed; | ||
1195 | } | ||
1196 | |||
1142 | cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len); | 1197 | cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len); |
1143 | if (!cmd) { | 1198 | if (!cmd) { |
1144 | err = -ENOMEM; | 1199 | err = -ENOMEM; |
@@ -1147,14 +1202,14 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data, | |||
1147 | 1202 | ||
1148 | bacpy(&reply.bdaddr, &cp->bdaddr); | 1203 | bacpy(&reply.bdaddr, &cp->bdaddr); |
1149 | reply.pin_len = cp->pin_len; | 1204 | reply.pin_len = cp->pin_len; |
1150 | memcpy(reply.pin_code, cp->pin_code, 16); | 1205 | memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code)); |
1151 | 1206 | ||
1152 | err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply); | 1207 | err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply); |
1153 | if (err < 0) | 1208 | if (err < 0) |
1154 | mgmt_pending_remove(cmd); | 1209 | mgmt_pending_remove(cmd); |
1155 | 1210 | ||
1156 | failed: | 1211 | failed: |
1157 | hci_dev_unlock(hdev); | 1212 | hci_dev_unlock_bh(hdev); |
1158 | hci_dev_put(hdev); | 1213 | hci_dev_put(hdev); |
1159 | 1214 | ||
1160 | return err; | 1215 | return err; |
@@ -1165,7 +1220,6 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data, | |||
1165 | { | 1220 | { |
1166 | struct hci_dev *hdev; | 1221 | struct hci_dev *hdev; |
1167 | struct mgmt_cp_pin_code_neg_reply *cp; | 1222 | struct mgmt_cp_pin_code_neg_reply *cp; |
1168 | struct pending_cmd *cmd; | ||
1169 | int err; | 1223 | int err; |
1170 | 1224 | ||
1171 | BT_DBG(""); | 1225 | BT_DBG(""); |
@@ -1181,7 +1235,7 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data, | |||
1181 | return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, | 1235 | return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, |
1182 | ENODEV); | 1236 | ENODEV); |
1183 | 1237 | ||
1184 | hci_dev_lock(hdev); | 1238 | hci_dev_lock_bh(hdev); |
1185 | 1239 | ||
1186 | if (!test_bit(HCI_UP, &hdev->flags)) { | 1240 | if (!test_bit(HCI_UP, &hdev->flags)) { |
1187 | err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, | 1241 | err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, |
@@ -1189,20 +1243,10 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data, | |||
1189 | goto failed; | 1243 | goto failed; |
1190 | } | 1244 | } |
1191 | 1245 | ||
1192 | cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index, | 1246 | err = send_pin_code_neg_reply(sk, index, hdev, cp); |
1193 | data, len); | ||
1194 | if (!cmd) { | ||
1195 | err = -ENOMEM; | ||
1196 | goto failed; | ||
1197 | } | ||
1198 | |||
1199 | err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr), | ||
1200 | &cp->bdaddr); | ||
1201 | if (err < 0) | ||
1202 | mgmt_pending_remove(cmd); | ||
1203 | 1247 | ||
1204 | failed: | 1248 | failed: |
1205 | hci_dev_unlock(hdev); | 1249 | hci_dev_unlock_bh(hdev); |
1206 | hci_dev_put(hdev); | 1250 | hci_dev_put(hdev); |
1207 | 1251 | ||
1208 | return err; | 1252 | return err; |
@@ -1225,14 +1269,14 @@ static int set_io_capability(struct sock *sk, u16 index, unsigned char *data, | |||
1225 | if (!hdev) | 1269 | if (!hdev) |
1226 | return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV); | 1270 | return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV); |
1227 | 1271 | ||
1228 | hci_dev_lock(hdev); | 1272 | hci_dev_lock_bh(hdev); |
1229 | 1273 | ||
1230 | hdev->io_capability = cp->io_capability; | 1274 | hdev->io_capability = cp->io_capability; |
1231 | 1275 | ||
1232 | BT_DBG("%s IO capability set to 0x%02x", hdev->name, | 1276 | BT_DBG("%s IO capability set to 0x%02x", hdev->name, |
1233 | hdev->io_capability); | 1277 | hdev->io_capability); |
1234 | 1278 | ||
1235 | hci_dev_unlock(hdev); | 1279 | hci_dev_unlock_bh(hdev); |
1236 | hci_dev_put(hdev); | 1280 | hci_dev_put(hdev); |
1237 | 1281 | ||
1238 | return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0); | 1282 | return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0); |
@@ -1318,7 +1362,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
1318 | if (!hdev) | 1362 | if (!hdev) |
1319 | return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV); | 1363 | return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV); |
1320 | 1364 | ||
1321 | hci_dev_lock(hdev); | 1365 | hci_dev_lock_bh(hdev); |
1322 | 1366 | ||
1323 | if (cp->io_cap == 0x03) { | 1367 | if (cp->io_cap == 0x03) { |
1324 | sec_level = BT_SECURITY_MEDIUM; | 1368 | sec_level = BT_SECURITY_MEDIUM; |
@@ -1360,7 +1404,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
1360 | err = 0; | 1404 | err = 0; |
1361 | 1405 | ||
1362 | unlock: | 1406 | unlock: |
1363 | hci_dev_unlock(hdev); | 1407 | hci_dev_unlock_bh(hdev); |
1364 | hci_dev_put(hdev); | 1408 | hci_dev_put(hdev); |
1365 | 1409 | ||
1366 | return err; | 1410 | return err; |
@@ -1392,7 +1436,7 @@ static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data, | |||
1392 | if (!hdev) | 1436 | if (!hdev) |
1393 | return cmd_status(sk, index, mgmt_op, ENODEV); | 1437 | return cmd_status(sk, index, mgmt_op, ENODEV); |
1394 | 1438 | ||
1395 | hci_dev_lock(hdev); | 1439 | hci_dev_lock_bh(hdev); |
1396 | 1440 | ||
1397 | if (!test_bit(HCI_UP, &hdev->flags)) { | 1441 | if (!test_bit(HCI_UP, &hdev->flags)) { |
1398 | err = cmd_status(sk, index, mgmt_op, ENETDOWN); | 1442 | err = cmd_status(sk, index, mgmt_op, ENETDOWN); |
@@ -1410,7 +1454,7 @@ static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data, | |||
1410 | mgmt_pending_remove(cmd); | 1454 | mgmt_pending_remove(cmd); |
1411 | 1455 | ||
1412 | failed: | 1456 | failed: |
1413 | hci_dev_unlock(hdev); | 1457 | hci_dev_unlock_bh(hdev); |
1414 | hci_dev_put(hdev); | 1458 | hci_dev_put(hdev); |
1415 | 1459 | ||
1416 | return err; | 1460 | return err; |
@@ -1434,7 +1478,7 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data, | |||
1434 | if (!hdev) | 1478 | if (!hdev) |
1435 | return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV); | 1479 | return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV); |
1436 | 1480 | ||
1437 | hci_dev_lock(hdev); | 1481 | hci_dev_lock_bh(hdev); |
1438 | 1482 | ||
1439 | cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len); | 1483 | cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len); |
1440 | if (!cmd) { | 1484 | if (!cmd) { |
@@ -1449,7 +1493,7 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data, | |||
1449 | mgmt_pending_remove(cmd); | 1493 | mgmt_pending_remove(cmd); |
1450 | 1494 | ||
1451 | failed: | 1495 | failed: |
1452 | hci_dev_unlock(hdev); | 1496 | hci_dev_unlock_bh(hdev); |
1453 | hci_dev_put(hdev); | 1497 | hci_dev_put(hdev); |
1454 | 1498 | ||
1455 | return err; | 1499 | return err; |
@@ -1468,7 +1512,7 @@ static int read_local_oob_data(struct sock *sk, u16 index) | |||
1468 | return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, | 1512 | return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, |
1469 | ENODEV); | 1513 | ENODEV); |
1470 | 1514 | ||
1471 | hci_dev_lock(hdev); | 1515 | hci_dev_lock_bh(hdev); |
1472 | 1516 | ||
1473 | if (!test_bit(HCI_UP, &hdev->flags)) { | 1517 | if (!test_bit(HCI_UP, &hdev->flags)) { |
1474 | err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, | 1518 | err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, |
@@ -1498,7 +1542,7 @@ static int read_local_oob_data(struct sock *sk, u16 index) | |||
1498 | mgmt_pending_remove(cmd); | 1542 | mgmt_pending_remove(cmd); |
1499 | 1543 | ||
1500 | unlock: | 1544 | unlock: |
1501 | hci_dev_unlock(hdev); | 1545 | hci_dev_unlock_bh(hdev); |
1502 | hci_dev_put(hdev); | 1546 | hci_dev_put(hdev); |
1503 | 1547 | ||
1504 | return err; | 1548 | return err; |
@@ -1522,7 +1566,7 @@ static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data, | |||
1522 | return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, | 1566 | return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, |
1523 | ENODEV); | 1567 | ENODEV); |
1524 | 1568 | ||
1525 | hci_dev_lock(hdev); | 1569 | hci_dev_lock_bh(hdev); |
1526 | 1570 | ||
1527 | err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash, | 1571 | err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash, |
1528 | cp->randomizer); | 1572 | cp->randomizer); |
@@ -1532,7 +1576,7 @@ static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data, | |||
1532 | err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL, | 1576 | err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL, |
1533 | 0); | 1577 | 0); |
1534 | 1578 | ||
1535 | hci_dev_unlock(hdev); | 1579 | hci_dev_unlock_bh(hdev); |
1536 | hci_dev_put(hdev); | 1580 | hci_dev_put(hdev); |
1537 | 1581 | ||
1538 | return err; | 1582 | return err; |
@@ -1556,7 +1600,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, | |||
1556 | return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, | 1600 | return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, |
1557 | ENODEV); | 1601 | ENODEV); |
1558 | 1602 | ||
1559 | hci_dev_lock(hdev); | 1603 | hci_dev_lock_bh(hdev); |
1560 | 1604 | ||
1561 | err = hci_remove_remote_oob_data(hdev, &cp->bdaddr); | 1605 | err = hci_remove_remote_oob_data(hdev, &cp->bdaddr); |
1562 | if (err < 0) | 1606 | if (err < 0) |
@@ -1566,7 +1610,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, | |||
1566 | err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, | 1610 | err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, |
1567 | NULL, 0); | 1611 | NULL, 0); |
1568 | 1612 | ||
1569 | hci_dev_unlock(hdev); | 1613 | hci_dev_unlock_bh(hdev); |
1570 | hci_dev_put(hdev); | 1614 | hci_dev_put(hdev); |
1571 | 1615 | ||
1572 | return err; | 1616 | return err; |
@@ -1641,6 +1685,70 @@ failed: | |||
1641 | return err; | 1685 | return err; |
1642 | } | 1686 | } |
1643 | 1687 | ||
1688 | static int block_device(struct sock *sk, u16 index, unsigned char *data, | ||
1689 | u16 len) | ||
1690 | { | ||
1691 | struct hci_dev *hdev; | ||
1692 | struct mgmt_cp_block_device *cp; | ||
1693 | int err; | ||
1694 | |||
1695 | BT_DBG("hci%u", index); | ||
1696 | |||
1697 | cp = (void *) data; | ||
1698 | |||
1699 | if (len != sizeof(*cp)) | ||
1700 | return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, | ||
1701 | EINVAL); | ||
1702 | |||
1703 | hdev = hci_dev_get(index); | ||
1704 | if (!hdev) | ||
1705 | return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, | ||
1706 | ENODEV); | ||
1707 | |||
1708 | err = hci_blacklist_add(hdev, &cp->bdaddr); | ||
1709 | |||
1710 | if (err < 0) | ||
1711 | err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err); | ||
1712 | else | ||
1713 | err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, | ||
1714 | NULL, 0); | ||
1715 | hci_dev_put(hdev); | ||
1716 | |||
1717 | return err; | ||
1718 | } | ||
1719 | |||
1720 | static int unblock_device(struct sock *sk, u16 index, unsigned char *data, | ||
1721 | u16 len) | ||
1722 | { | ||
1723 | struct hci_dev *hdev; | ||
1724 | struct mgmt_cp_unblock_device *cp; | ||
1725 | int err; | ||
1726 | |||
1727 | BT_DBG("hci%u", index); | ||
1728 | |||
1729 | cp = (void *) data; | ||
1730 | |||
1731 | if (len != sizeof(*cp)) | ||
1732 | return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, | ||
1733 | EINVAL); | ||
1734 | |||
1735 | hdev = hci_dev_get(index); | ||
1736 | if (!hdev) | ||
1737 | return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, | ||
1738 | ENODEV); | ||
1739 | |||
1740 | err = hci_blacklist_del(hdev, &cp->bdaddr); | ||
1741 | |||
1742 | if (err < 0) | ||
1743 | err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, -err); | ||
1744 | else | ||
1745 | err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, | ||
1746 | NULL, 0); | ||
1747 | hci_dev_put(hdev); | ||
1748 | |||
1749 | return err; | ||
1750 | } | ||
1751 | |||
1644 | int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | 1752 | int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) |
1645 | { | 1753 | { |
1646 | unsigned char *buf; | 1754 | unsigned char *buf; |
@@ -1755,6 +1863,12 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | |||
1755 | case MGMT_OP_STOP_DISCOVERY: | 1863 | case MGMT_OP_STOP_DISCOVERY: |
1756 | err = stop_discovery(sk, index); | 1864 | err = stop_discovery(sk, index); |
1757 | break; | 1865 | break; |
1866 | case MGMT_OP_BLOCK_DEVICE: | ||
1867 | err = block_device(sk, index, buf + sizeof(*hdr), len); | ||
1868 | break; | ||
1869 | case MGMT_OP_UNBLOCK_DEVICE: | ||
1870 | err = unblock_device(sk, index, buf + sizeof(*hdr), len); | ||
1871 | break; | ||
1758 | default: | 1872 | default: |
1759 | BT_DBG("Unknown op %u", opcode); | 1873 | BT_DBG("Unknown op %u", opcode); |
1760 | err = cmd_status(sk, index, opcode, 0x01); | 1874 | err = cmd_status(sk, index, opcode, 0x01); |
@@ -1863,17 +1977,28 @@ int mgmt_connectable(u16 index, u8 connectable) | |||
1863 | 1977 | ||
1864 | int mgmt_new_key(u16 index, struct link_key *key, u8 persistent) | 1978 | int mgmt_new_key(u16 index, struct link_key *key, u8 persistent) |
1865 | { | 1979 | { |
1866 | struct mgmt_ev_new_key ev; | 1980 | struct mgmt_ev_new_key *ev; |
1981 | int err, total; | ||
1867 | 1982 | ||
1868 | memset(&ev, 0, sizeof(ev)); | 1983 | total = sizeof(struct mgmt_ev_new_key) + key->dlen; |
1984 | ev = kzalloc(total, GFP_ATOMIC); | ||
1985 | if (!ev) | ||
1986 | return -ENOMEM; | ||
1869 | 1987 | ||
1870 | ev.store_hint = persistent; | 1988 | bacpy(&ev->key.bdaddr, &key->bdaddr); |
1871 | bacpy(&ev.key.bdaddr, &key->bdaddr); | 1989 | ev->key.type = key->type; |
1872 | ev.key.type = key->type; | 1990 | memcpy(ev->key.val, key->val, 16); |
1873 | memcpy(ev.key.val, key->val, 16); | 1991 | ev->key.pin_len = key->pin_len; |
1874 | ev.key.pin_len = key->pin_len; | 1992 | ev->key.dlen = key->dlen; |
1993 | ev->store_hint = persistent; | ||
1875 | 1994 | ||
1876 | return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL); | 1995 | memcpy(ev->key.data, key->data, key->dlen); |
1996 | |||
1997 | err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL); | ||
1998 | |||
1999 | kfree(ev); | ||
2000 | |||
2001 | return err; | ||
1877 | } | 2002 | } |
1878 | 2003 | ||
1879 | int mgmt_connected(u16 index, bdaddr_t *bdaddr) | 2004 | int mgmt_connected(u16 index, bdaddr_t *bdaddr) |