diff options
author | Johan Hedberg <johan.hedberg@intel.com> | 2011-11-11 11:10:00 -0500 |
---|---|---|
committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-11-16 13:07:52 -0500 |
commit | ca69b7957bf2e3bc0acc882b837a42617498ece1 (patch) | |
tree | e00f2f36d661eb5cef306b940d99f33df5570363 /net/bluetooth | |
parent | 8680570b0cae8f66ad28c8de227aab1894428ee5 (diff) |
Bluetooth: Create a unique mgmt error code hierarchy
The management protocol uses a single byte for error codes (aka command
status). In some places this value is directly copied from HCI and in
other a POSIX error number is used. This makes it impossible for
user-space to uniquily decipher the meaning of an error.
To solve this issue a new mgmt-specific set of error codes is added
along with a conversion table for HCI status values.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Diffstat (limited to 'net/bluetooth')
-rw-r--r-- | net/bluetooth/mgmt.c | 315 |
1 files changed, 224 insertions, 91 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index d0b1a49a66fb..cb3af4e4f959 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 <asm/unaligned.h> | 27 | #include <asm/unaligned.h> |
27 | 28 | ||
@@ -43,6 +44,79 @@ struct pending_cmd { | |||
43 | void *user_data; | 44 | void *user_data; |
44 | }; | 45 | }; |
45 | 46 | ||
47 | /* HCI to MGMT error code conversion table */ | ||
48 | static u8 mgmt_status_table[] = { | ||
49 | MGMT_STATUS_SUCCESS, | ||
50 | MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */ | ||
51 | MGMT_STATUS_NOT_CONNECTED, /* No Connection */ | ||
52 | MGMT_STATUS_FAILED, /* Hardware Failure */ | ||
53 | MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */ | ||
54 | MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */ | ||
55 | MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */ | ||
56 | MGMT_STATUS_NO_RESOURCES, /* Memory Full */ | ||
57 | MGMT_STATUS_TIMEOUT, /* Connection Timeout */ | ||
58 | MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */ | ||
59 | MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */ | ||
60 | MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */ | ||
61 | MGMT_STATUS_BUSY, /* Command Disallowed */ | ||
62 | MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */ | ||
63 | MGMT_STATUS_REJECTED, /* Rejected Security */ | ||
64 | MGMT_STATUS_REJECTED, /* Rejected Personal */ | ||
65 | MGMT_STATUS_TIMEOUT, /* Host Timeout */ | ||
66 | MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */ | ||
67 | MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */ | ||
68 | MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */ | ||
69 | MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */ | ||
70 | MGMT_STATUS_DISCONNECTED, /* OE Power Off */ | ||
71 | MGMT_STATUS_DISCONNECTED, /* Connection Terminated */ | ||
72 | MGMT_STATUS_BUSY, /* Repeated Attempts */ | ||
73 | MGMT_STATUS_REJECTED, /* Pairing Not Allowed */ | ||
74 | MGMT_STATUS_FAILED, /* Unknown LMP PDU */ | ||
75 | MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */ | ||
76 | MGMT_STATUS_REJECTED, /* SCO Offset Rejected */ | ||
77 | MGMT_STATUS_REJECTED, /* SCO Interval Rejected */ | ||
78 | MGMT_STATUS_REJECTED, /* Air Mode Rejected */ | ||
79 | MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */ | ||
80 | MGMT_STATUS_FAILED, /* Unspecified Error */ | ||
81 | MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */ | ||
82 | MGMT_STATUS_FAILED, /* Role Change Not Allowed */ | ||
83 | MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */ | ||
84 | MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */ | ||
85 | MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */ | ||
86 | MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */ | ||
87 | MGMT_STATUS_FAILED, /* Unit Link Key Used */ | ||
88 | MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */ | ||
89 | MGMT_STATUS_TIMEOUT, /* Instant Passed */ | ||
90 | MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */ | ||
91 | MGMT_STATUS_FAILED, /* Transaction Collision */ | ||
92 | MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */ | ||
93 | MGMT_STATUS_REJECTED, /* QoS Rejected */ | ||
94 | MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */ | ||
95 | MGMT_STATUS_REJECTED, /* Insufficient Security */ | ||
96 | MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */ | ||
97 | MGMT_STATUS_BUSY, /* Role Switch Pending */ | ||
98 | MGMT_STATUS_FAILED, /* Slot Violation */ | ||
99 | MGMT_STATUS_FAILED, /* Role Switch Failed */ | ||
100 | MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */ | ||
101 | MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */ | ||
102 | MGMT_STATUS_BUSY, /* Host Busy Pairing */ | ||
103 | MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */ | ||
104 | MGMT_STATUS_BUSY, /* Controller Busy */ | ||
105 | MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */ | ||
106 | MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */ | ||
107 | MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */ | ||
108 | MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */ | ||
109 | MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */ | ||
110 | }; | ||
111 | |||
112 | static u8 mgmt_status(u8 hci_status) | ||
113 | { | ||
114 | if (hci_status < ARRAY_SIZE(mgmt_status_table)) | ||
115 | return mgmt_status_table[hci_status]; | ||
116 | |||
117 | return MGMT_STATUS_FAILED; | ||
118 | } | ||
119 | |||
46 | static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status) | 120 | static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status) |
47 | { | 121 | { |
48 | struct sk_buff *skb; | 122 | struct sk_buff *skb; |
@@ -177,7 +251,8 @@ static int read_controller_info(struct sock *sk, u16 index) | |||
177 | 251 | ||
178 | hdev = hci_dev_get(index); | 252 | hdev = hci_dev_get(index); |
179 | if (!hdev) | 253 | if (!hdev) |
180 | return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV); | 254 | return cmd_status(sk, index, MGMT_OP_READ_INFO, |
255 | MGMT_STATUS_INVALID_PARAMS); | ||
181 | 256 | ||
182 | if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags)) | 257 | if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags)) |
183 | cancel_delayed_work_sync(&hdev->power_off); | 258 | cancel_delayed_work_sync(&hdev->power_off); |
@@ -311,11 +386,13 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
311 | BT_DBG("request for hci%u", index); | 386 | BT_DBG("request for hci%u", index); |
312 | 387 | ||
313 | if (len != sizeof(*cp)) | 388 | if (len != sizeof(*cp)) |
314 | return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL); | 389 | return cmd_status(sk, index, MGMT_OP_SET_POWERED, |
390 | MGMT_STATUS_INVALID_PARAMS); | ||
315 | 391 | ||
316 | hdev = hci_dev_get(index); | 392 | hdev = hci_dev_get(index); |
317 | if (!hdev) | 393 | if (!hdev) |
318 | return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV); | 394 | return cmd_status(sk, index, MGMT_OP_SET_POWERED, |
395 | MGMT_STATUS_INVALID_PARAMS); | ||
319 | 396 | ||
320 | hci_dev_lock_bh(hdev); | 397 | hci_dev_lock_bh(hdev); |
321 | 398 | ||
@@ -326,7 +403,8 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
326 | } | 403 | } |
327 | 404 | ||
328 | if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) { | 405 | if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) { |
329 | err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY); | 406 | err = cmd_status(sk, index, MGMT_OP_SET_POWERED, |
407 | MGMT_STATUS_BUSY); | ||
330 | goto failed; | 408 | goto failed; |
331 | } | 409 | } |
332 | 410 | ||
@@ -363,22 +441,26 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data, | |||
363 | BT_DBG("request for hci%u", index); | 441 | BT_DBG("request for hci%u", index); |
364 | 442 | ||
365 | if (len != sizeof(*cp)) | 443 | if (len != sizeof(*cp)) |
366 | return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL); | 444 | return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, |
445 | MGMT_STATUS_INVALID_PARAMS); | ||
367 | 446 | ||
368 | hdev = hci_dev_get(index); | 447 | hdev = hci_dev_get(index); |
369 | if (!hdev) | 448 | if (!hdev) |
370 | return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV); | 449 | return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, |
450 | MGMT_STATUS_INVALID_PARAMS); | ||
371 | 451 | ||
372 | hci_dev_lock_bh(hdev); | 452 | hci_dev_lock_bh(hdev); |
373 | 453 | ||
374 | if (!test_bit(HCI_UP, &hdev->flags)) { | 454 | if (!test_bit(HCI_UP, &hdev->flags)) { |
375 | err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN); | 455 | err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, |
456 | MGMT_STATUS_NOT_POWERED); | ||
376 | goto failed; | 457 | goto failed; |
377 | } | 458 | } |
378 | 459 | ||
379 | if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) || | 460 | if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) || |
380 | mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) { | 461 | mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) { |
381 | err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY); | 462 | err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, |
463 | MGMT_STATUS_BUSY); | ||
382 | goto failed; | 464 | goto failed; |
383 | } | 465 | } |
384 | 466 | ||
@@ -430,22 +512,26 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data, | |||
430 | BT_DBG("request for hci%u", index); | 512 | BT_DBG("request for hci%u", index); |
431 | 513 | ||
432 | if (len != sizeof(*cp)) | 514 | if (len != sizeof(*cp)) |
433 | return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL); | 515 | return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, |
516 | MGMT_STATUS_INVALID_PARAMS); | ||
434 | 517 | ||
435 | hdev = hci_dev_get(index); | 518 | hdev = hci_dev_get(index); |
436 | if (!hdev) | 519 | if (!hdev) |
437 | return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV); | 520 | return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, |
521 | MGMT_STATUS_INVALID_PARAMS); | ||
438 | 522 | ||
439 | hci_dev_lock_bh(hdev); | 523 | hci_dev_lock_bh(hdev); |
440 | 524 | ||
441 | if (!test_bit(HCI_UP, &hdev->flags)) { | 525 | if (!test_bit(HCI_UP, &hdev->flags)) { |
442 | err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN); | 526 | err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, |
527 | MGMT_STATUS_NOT_POWERED); | ||
443 | goto failed; | 528 | goto failed; |
444 | } | 529 | } |
445 | 530 | ||
446 | if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) || | 531 | if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) || |
447 | mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) { | 532 | mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) { |
448 | err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY); | 533 | err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, |
534 | MGMT_STATUS_BUSY); | ||
449 | goto failed; | 535 | goto failed; |
450 | } | 536 | } |
451 | 537 | ||
@@ -518,11 +604,13 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data, | |||
518 | BT_DBG("request for hci%u", index); | 604 | BT_DBG("request for hci%u", index); |
519 | 605 | ||
520 | if (len != sizeof(*cp)) | 606 | if (len != sizeof(*cp)) |
521 | return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL); | 607 | return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, |
608 | MGMT_STATUS_INVALID_PARAMS); | ||
522 | 609 | ||
523 | hdev = hci_dev_get(index); | 610 | hdev = hci_dev_get(index); |
524 | if (!hdev) | 611 | if (!hdev) |
525 | return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV); | 612 | return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, |
613 | MGMT_STATUS_INVALID_PARAMS); | ||
526 | 614 | ||
527 | hci_dev_lock_bh(hdev); | 615 | hci_dev_lock_bh(hdev); |
528 | 616 | ||
@@ -731,11 +819,13 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
731 | BT_DBG("request for hci%u", index); | 819 | BT_DBG("request for hci%u", index); |
732 | 820 | ||
733 | if (len != sizeof(*cp)) | 821 | if (len != sizeof(*cp)) |
734 | return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL); | 822 | return cmd_status(sk, index, MGMT_OP_ADD_UUID, |
823 | MGMT_STATUS_INVALID_PARAMS); | ||
735 | 824 | ||
736 | hdev = hci_dev_get(index); | 825 | hdev = hci_dev_get(index); |
737 | if (!hdev) | 826 | if (!hdev) |
738 | return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV); | 827 | return cmd_status(sk, index, MGMT_OP_ADD_UUID, |
828 | MGMT_STATUS_INVALID_PARAMS); | ||
739 | 829 | ||
740 | hci_dev_lock_bh(hdev); | 830 | hci_dev_lock_bh(hdev); |
741 | 831 | ||
@@ -780,11 +870,13 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
780 | BT_DBG("request for hci%u", index); | 870 | BT_DBG("request for hci%u", index); |
781 | 871 | ||
782 | if (len != sizeof(*cp)) | 872 | if (len != sizeof(*cp)) |
783 | return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL); | 873 | return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, |
874 | MGMT_STATUS_INVALID_PARAMS); | ||
784 | 875 | ||
785 | hdev = hci_dev_get(index); | 876 | hdev = hci_dev_get(index); |
786 | if (!hdev) | 877 | if (!hdev) |
787 | return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV); | 878 | return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, |
879 | MGMT_STATUS_INVALID_PARAMS); | ||
788 | 880 | ||
789 | hci_dev_lock_bh(hdev); | 881 | hci_dev_lock_bh(hdev); |
790 | 882 | ||
@@ -806,7 +898,8 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
806 | } | 898 | } |
807 | 899 | ||
808 | if (found == 0) { | 900 | if (found == 0) { |
809 | err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT); | 901 | err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, |
902 | MGMT_STATUS_INVALID_PARAMS); | ||
810 | goto unlock; | 903 | goto unlock; |
811 | } | 904 | } |
812 | 905 | ||
@@ -839,11 +932,13 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data, | |||
839 | BT_DBG("request for hci%u", index); | 932 | BT_DBG("request for hci%u", index); |
840 | 933 | ||
841 | if (len != sizeof(*cp)) | 934 | if (len != sizeof(*cp)) |
842 | return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL); | 935 | return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, |
936 | MGMT_STATUS_INVALID_PARAMS); | ||
843 | 937 | ||
844 | hdev = hci_dev_get(index); | 938 | hdev = hci_dev_get(index); |
845 | if (!hdev) | 939 | if (!hdev) |
846 | return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV); | 940 | return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, |
941 | MGMT_STATUS_INVALID_PARAMS); | ||
847 | 942 | ||
848 | hci_dev_lock_bh(hdev); | 943 | hci_dev_lock_bh(hdev); |
849 | 944 | ||
@@ -871,11 +966,13 @@ static int set_service_cache(struct sock *sk, u16 index, unsigned char *data, | |||
871 | cp = (void *) data; | 966 | cp = (void *) data; |
872 | 967 | ||
873 | if (len != sizeof(*cp)) | 968 | if (len != sizeof(*cp)) |
874 | return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL); | 969 | return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, |
970 | MGMT_STATUS_INVALID_PARAMS); | ||
875 | 971 | ||
876 | hdev = hci_dev_get(index); | 972 | hdev = hci_dev_get(index); |
877 | if (!hdev) | 973 | if (!hdev) |
878 | return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV); | 974 | return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, |
975 | MGMT_STATUS_INVALID_PARAMS); | ||
879 | 976 | ||
880 | hci_dev_lock_bh(hdev); | 977 | hci_dev_lock_bh(hdev); |
881 | 978 | ||
@@ -915,7 +1012,8 @@ static int load_link_keys(struct sock *sk, u16 index, unsigned char *data, | |||
915 | cp = (void *) data; | 1012 | cp = (void *) data; |
916 | 1013 | ||
917 | if (len < sizeof(*cp)) | 1014 | if (len < sizeof(*cp)) |
918 | return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, EINVAL); | 1015 | return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, |
1016 | MGMT_STATUS_INVALID_PARAMS); | ||
919 | 1017 | ||
920 | key_count = get_unaligned_le16(&cp->key_count); | 1018 | key_count = get_unaligned_le16(&cp->key_count); |
921 | 1019 | ||
@@ -924,12 +1022,14 @@ static int load_link_keys(struct sock *sk, u16 index, unsigned char *data, | |||
924 | if (expected_len != len) { | 1022 | if (expected_len != len) { |
925 | BT_ERR("load_link_keys: expected %u bytes, got %u bytes", | 1023 | BT_ERR("load_link_keys: expected %u bytes, got %u bytes", |
926 | len, expected_len); | 1024 | len, expected_len); |
927 | return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, EINVAL); | 1025 | return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, |
1026 | MGMT_STATUS_INVALID_PARAMS); | ||
928 | } | 1027 | } |
929 | 1028 | ||
930 | hdev = hci_dev_get(index); | 1029 | hdev = hci_dev_get(index); |
931 | if (!hdev) | 1030 | if (!hdev) |
932 | return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, ENODEV); | 1031 | return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, |
1032 | MGMT_STATUS_INVALID_PARAMS); | ||
933 | 1033 | ||
934 | BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys, | 1034 | BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys, |
935 | key_count); | 1035 | key_count); |
@@ -972,20 +1072,25 @@ static int remove_keys(struct sock *sk, u16 index, unsigned char *data, | |||
972 | cp = (void *) data; | 1072 | cp = (void *) data; |
973 | 1073 | ||
974 | if (len != sizeof(*cp)) | 1074 | if (len != sizeof(*cp)) |
975 | return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, EINVAL); | 1075 | return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, |
1076 | MGMT_STATUS_INVALID_PARAMS); | ||
976 | 1077 | ||
977 | hdev = hci_dev_get(index); | 1078 | hdev = hci_dev_get(index); |
978 | if (!hdev) | 1079 | if (!hdev) |
979 | return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, ENODEV); | 1080 | return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, |
1081 | MGMT_STATUS_INVALID_PARAMS); | ||
980 | 1082 | ||
981 | hci_dev_lock_bh(hdev); | 1083 | hci_dev_lock_bh(hdev); |
982 | 1084 | ||
983 | memset(&rp, 0, sizeof(rp)); | 1085 | memset(&rp, 0, sizeof(rp)); |
984 | bacpy(&rp.bdaddr, &cp->bdaddr); | 1086 | bacpy(&rp.bdaddr, &cp->bdaddr); |
1087 | rp.status = MGMT_STATUS_FAILED; | ||
985 | 1088 | ||
986 | err = hci_remove_link_key(hdev, &cp->bdaddr); | 1089 | err = hci_remove_link_key(hdev, &cp->bdaddr); |
987 | if (err < 0) | 1090 | if (err < 0) { |
1091 | rp.status = MGMT_STATUS_NOT_PAIRED; | ||
988 | goto unlock; | 1092 | goto unlock; |
1093 | } | ||
989 | 1094 | ||
990 | if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) { | 1095 | if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) { |
991 | err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp, | 1096 | err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp, |
@@ -1013,11 +1118,9 @@ static int remove_keys(struct sock *sk, u16 index, unsigned char *data, | |||
1013 | mgmt_pending_remove(cmd); | 1118 | mgmt_pending_remove(cmd); |
1014 | 1119 | ||
1015 | unlock: | 1120 | unlock: |
1016 | if (err < 0) { | 1121 | if (err < 0) |
1017 | rp.status = -err; | ||
1018 | err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp, | 1122 | err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp, |
1019 | sizeof(rp)); | 1123 | sizeof(rp)); |
1020 | } | ||
1021 | hci_dev_unlock_bh(hdev); | 1124 | hci_dev_unlock_bh(hdev); |
1022 | hci_dev_put(hdev); | 1125 | hci_dev_put(hdev); |
1023 | 1126 | ||
@@ -1038,21 +1141,25 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
1038 | cp = (void *) data; | 1141 | cp = (void *) data; |
1039 | 1142 | ||
1040 | if (len != sizeof(*cp)) | 1143 | if (len != sizeof(*cp)) |
1041 | return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL); | 1144 | return cmd_status(sk, index, MGMT_OP_DISCONNECT, |
1145 | MGMT_STATUS_INVALID_PARAMS); | ||
1042 | 1146 | ||
1043 | hdev = hci_dev_get(index); | 1147 | hdev = hci_dev_get(index); |
1044 | if (!hdev) | 1148 | if (!hdev) |
1045 | return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV); | 1149 | return cmd_status(sk, index, MGMT_OP_DISCONNECT, |
1150 | MGMT_STATUS_INVALID_PARAMS); | ||
1046 | 1151 | ||
1047 | hci_dev_lock_bh(hdev); | 1152 | hci_dev_lock_bh(hdev); |
1048 | 1153 | ||
1049 | if (!test_bit(HCI_UP, &hdev->flags)) { | 1154 | if (!test_bit(HCI_UP, &hdev->flags)) { |
1050 | err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN); | 1155 | err = cmd_status(sk, index, MGMT_OP_DISCONNECT, |
1156 | MGMT_STATUS_NOT_POWERED); | ||
1051 | goto failed; | 1157 | goto failed; |
1052 | } | 1158 | } |
1053 | 1159 | ||
1054 | if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) { | 1160 | if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) { |
1055 | err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY); | 1161 | err = cmd_status(sk, index, MGMT_OP_DISCONNECT, |
1162 | MGMT_STATUS_BUSY); | ||
1056 | goto failed; | 1163 | goto failed; |
1057 | } | 1164 | } |
1058 | 1165 | ||
@@ -1061,7 +1168,8 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
1061 | conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr); | 1168 | conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr); |
1062 | 1169 | ||
1063 | if (!conn) { | 1170 | if (!conn) { |
1064 | err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN); | 1171 | err = cmd_status(sk, index, MGMT_OP_DISCONNECT, |
1172 | MGMT_STATUS_NOT_CONNECTED); | ||
1065 | goto failed; | 1173 | goto failed; |
1066 | } | 1174 | } |
1067 | 1175 | ||
@@ -1118,7 +1226,8 @@ static int get_connections(struct sock *sk, u16 index) | |||
1118 | 1226 | ||
1119 | hdev = hci_dev_get(index); | 1227 | hdev = hci_dev_get(index); |
1120 | if (!hdev) | 1228 | if (!hdev) |
1121 | return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV); | 1229 | return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, |
1230 | MGMT_STATUS_INVALID_PARAMS); | ||
1122 | 1231 | ||
1123 | hci_dev_lock_bh(hdev); | 1232 | hci_dev_lock_bh(hdev); |
1124 | 1233 | ||
@@ -1192,22 +1301,26 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data, | |||
1192 | cp = (void *) data; | 1301 | cp = (void *) data; |
1193 | 1302 | ||
1194 | if (len != sizeof(*cp)) | 1303 | if (len != sizeof(*cp)) |
1195 | return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL); | 1304 | return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, |
1305 | MGMT_STATUS_INVALID_PARAMS); | ||
1196 | 1306 | ||
1197 | hdev = hci_dev_get(index); | 1307 | hdev = hci_dev_get(index); |
1198 | if (!hdev) | 1308 | if (!hdev) |
1199 | return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV); | 1309 | return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, |
1310 | MGMT_STATUS_INVALID_PARAMS); | ||
1200 | 1311 | ||
1201 | hci_dev_lock_bh(hdev); | 1312 | hci_dev_lock_bh(hdev); |
1202 | 1313 | ||
1203 | if (!test_bit(HCI_UP, &hdev->flags)) { | 1314 | if (!test_bit(HCI_UP, &hdev->flags)) { |
1204 | err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN); | 1315 | err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, |
1316 | MGMT_STATUS_NOT_POWERED); | ||
1205 | goto failed; | 1317 | goto failed; |
1206 | } | 1318 | } |
1207 | 1319 | ||
1208 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); | 1320 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); |
1209 | if (!conn) { | 1321 | if (!conn) { |
1210 | err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENOTCONN); | 1322 | err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, |
1323 | MGMT_STATUS_NOT_CONNECTED); | ||
1211 | goto failed; | 1324 | goto failed; |
1212 | } | 1325 | } |
1213 | 1326 | ||
@@ -1219,7 +1332,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data, | |||
1219 | err = send_pin_code_neg_reply(sk, index, hdev, &ncp); | 1332 | err = send_pin_code_neg_reply(sk, index, hdev, &ncp); |
1220 | if (err >= 0) | 1333 | if (err >= 0) |
1221 | err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, | 1334 | err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, |
1222 | EINVAL); | 1335 | MGMT_STATUS_INVALID_PARAMS); |
1223 | 1336 | ||
1224 | goto failed; | 1337 | goto failed; |
1225 | } | 1338 | } |
@@ -1258,18 +1371,18 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data, | |||
1258 | 1371 | ||
1259 | if (len != sizeof(*cp)) | 1372 | if (len != sizeof(*cp)) |
1260 | return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, | 1373 | return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, |
1261 | EINVAL); | 1374 | MGMT_STATUS_INVALID_PARAMS); |
1262 | 1375 | ||
1263 | hdev = hci_dev_get(index); | 1376 | hdev = hci_dev_get(index); |
1264 | if (!hdev) | 1377 | if (!hdev) |
1265 | return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, | 1378 | return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, |
1266 | ENODEV); | 1379 | MGMT_STATUS_INVALID_PARAMS); |
1267 | 1380 | ||
1268 | hci_dev_lock_bh(hdev); | 1381 | hci_dev_lock_bh(hdev); |
1269 | 1382 | ||
1270 | if (!test_bit(HCI_UP, &hdev->flags)) { | 1383 | if (!test_bit(HCI_UP, &hdev->flags)) { |
1271 | err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, | 1384 | err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, |
1272 | ENETDOWN); | 1385 | MGMT_STATUS_NOT_POWERED); |
1273 | goto failed; | 1386 | goto failed; |
1274 | } | 1387 | } |
1275 | 1388 | ||
@@ -1293,11 +1406,13 @@ static int set_io_capability(struct sock *sk, u16 index, unsigned char *data, | |||
1293 | cp = (void *) data; | 1406 | cp = (void *) data; |
1294 | 1407 | ||
1295 | if (len != sizeof(*cp)) | 1408 | if (len != sizeof(*cp)) |
1296 | return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL); | 1409 | return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, |
1410 | MGMT_STATUS_INVALID_PARAMS); | ||
1297 | 1411 | ||
1298 | hdev = hci_dev_get(index); | 1412 | hdev = hci_dev_get(index); |
1299 | if (!hdev) | 1413 | if (!hdev) |
1300 | return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV); | 1414 | return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, |
1415 | MGMT_STATUS_INVALID_PARAMS); | ||
1301 | 1416 | ||
1302 | hci_dev_lock_bh(hdev); | 1417 | hci_dev_lock_bh(hdev); |
1303 | 1418 | ||
@@ -1379,11 +1494,13 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) | |||
1379 | cp = (void *) data; | 1494 | cp = (void *) data; |
1380 | 1495 | ||
1381 | if (len != sizeof(*cp)) | 1496 | if (len != sizeof(*cp)) |
1382 | return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL); | 1497 | return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, |
1498 | MGMT_STATUS_INVALID_PARAMS); | ||
1383 | 1499 | ||
1384 | hdev = hci_dev_get(index); | 1500 | hdev = hci_dev_get(index); |
1385 | if (!hdev) | 1501 | if (!hdev) |
1386 | return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV); | 1502 | return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, |
1503 | MGMT_STATUS_INVALID_PARAMS); | ||
1387 | 1504 | ||
1388 | hci_dev_lock_bh(hdev); | 1505 | hci_dev_lock_bh(hdev); |
1389 | 1506 | ||
@@ -1468,11 +1585,13 @@ static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data, | |||
1468 | } | 1585 | } |
1469 | 1586 | ||
1470 | if (len != sizeof(*cp)) | 1587 | if (len != sizeof(*cp)) |
1471 | return cmd_status(sk, index, mgmt_op, EINVAL); | 1588 | return cmd_status(sk, index, mgmt_op, |
1589 | MGMT_STATUS_INVALID_PARAMS); | ||
1472 | 1590 | ||
1473 | hdev = hci_dev_get(index); | 1591 | hdev = hci_dev_get(index); |
1474 | if (!hdev) | 1592 | if (!hdev) |
1475 | return cmd_status(sk, index, mgmt_op, ENODEV); | 1593 | return cmd_status(sk, index, mgmt_op, |
1594 | MGMT_STATUS_INVALID_PARAMS); | ||
1476 | 1595 | ||
1477 | hci_dev_lock_bh(hdev); | 1596 | hci_dev_lock_bh(hdev); |
1478 | 1597 | ||
@@ -1510,11 +1629,13 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data, | |||
1510 | BT_DBG(""); | 1629 | BT_DBG(""); |
1511 | 1630 | ||
1512 | if (len != sizeof(*mgmt_cp)) | 1631 | if (len != sizeof(*mgmt_cp)) |
1513 | return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL); | 1632 | return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, |
1633 | MGMT_STATUS_INVALID_PARAMS); | ||
1514 | 1634 | ||
1515 | hdev = hci_dev_get(index); | 1635 | hdev = hci_dev_get(index); |
1516 | if (!hdev) | 1636 | if (!hdev) |
1517 | return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV); | 1637 | return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, |
1638 | MGMT_STATUS_INVALID_PARAMS); | ||
1518 | 1639 | ||
1519 | hci_dev_lock_bh(hdev); | 1640 | hci_dev_lock_bh(hdev); |
1520 | 1641 | ||
@@ -1548,24 +1669,25 @@ static int read_local_oob_data(struct sock *sk, u16 index) | |||
1548 | hdev = hci_dev_get(index); | 1669 | hdev = hci_dev_get(index); |
1549 | if (!hdev) | 1670 | if (!hdev) |
1550 | return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, | 1671 | return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, |
1551 | ENODEV); | 1672 | MGMT_STATUS_INVALID_PARAMS); |
1552 | 1673 | ||
1553 | hci_dev_lock_bh(hdev); | 1674 | hci_dev_lock_bh(hdev); |
1554 | 1675 | ||
1555 | if (!test_bit(HCI_UP, &hdev->flags)) { | 1676 | if (!test_bit(HCI_UP, &hdev->flags)) { |
1556 | err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, | 1677 | err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, |
1557 | ENETDOWN); | 1678 | MGMT_STATUS_NOT_POWERED); |
1558 | goto unlock; | 1679 | goto unlock; |
1559 | } | 1680 | } |
1560 | 1681 | ||
1561 | if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) { | 1682 | if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) { |
1562 | err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, | 1683 | err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, |
1563 | EOPNOTSUPP); | 1684 | MGMT_STATUS_NOT_SUPPORTED); |
1564 | goto unlock; | 1685 | goto unlock; |
1565 | } | 1686 | } |
1566 | 1687 | ||
1567 | if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) { | 1688 | if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) { |
1568 | err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY); | 1689 | err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, |
1690 | MGMT_STATUS_BUSY); | ||
1569 | goto unlock; | 1691 | goto unlock; |
1570 | } | 1692 | } |
1571 | 1693 | ||
@@ -1597,19 +1719,20 @@ static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data, | |||
1597 | 1719 | ||
1598 | if (len != sizeof(*cp)) | 1720 | if (len != sizeof(*cp)) |
1599 | return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, | 1721 | return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, |
1600 | EINVAL); | 1722 | MGMT_STATUS_INVALID_PARAMS); |
1601 | 1723 | ||
1602 | hdev = hci_dev_get(index); | 1724 | hdev = hci_dev_get(index); |
1603 | if (!hdev) | 1725 | if (!hdev) |
1604 | return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, | 1726 | return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, |
1605 | ENODEV); | 1727 | MGMT_STATUS_INVALID_PARAMS); |
1606 | 1728 | ||
1607 | hci_dev_lock_bh(hdev); | 1729 | hci_dev_lock_bh(hdev); |
1608 | 1730 | ||
1609 | err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash, | 1731 | err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash, |
1610 | cp->randomizer); | 1732 | cp->randomizer); |
1611 | if (err < 0) | 1733 | if (err < 0) |
1612 | err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err); | 1734 | err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, |
1735 | MGMT_STATUS_FAILED); | ||
1613 | else | 1736 | else |
1614 | err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL, | 1737 | err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL, |
1615 | 0); | 1738 | 0); |
@@ -1631,19 +1754,19 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, | |||
1631 | 1754 | ||
1632 | if (len != sizeof(*cp)) | 1755 | if (len != sizeof(*cp)) |
1633 | return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, | 1756 | return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, |
1634 | EINVAL); | 1757 | MGMT_STATUS_INVALID_PARAMS); |
1635 | 1758 | ||
1636 | hdev = hci_dev_get(index); | 1759 | hdev = hci_dev_get(index); |
1637 | if (!hdev) | 1760 | if (!hdev) |
1638 | return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, | 1761 | return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, |
1639 | ENODEV); | 1762 | MGMT_STATUS_INVALID_PARAMS); |
1640 | 1763 | ||
1641 | hci_dev_lock_bh(hdev); | 1764 | hci_dev_lock_bh(hdev); |
1642 | 1765 | ||
1643 | err = hci_remove_remote_oob_data(hdev, &cp->bdaddr); | 1766 | err = hci_remove_remote_oob_data(hdev, &cp->bdaddr); |
1644 | if (err < 0) | 1767 | if (err < 0) |
1645 | err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, | 1768 | err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, |
1646 | -err); | 1769 | MGMT_STATUS_INVALID_PARAMS); |
1647 | else | 1770 | else |
1648 | err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, | 1771 | err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, |
1649 | NULL, 0); | 1772 | NULL, 0); |
@@ -1664,12 +1787,14 @@ static int start_discovery(struct sock *sk, u16 index) | |||
1664 | 1787 | ||
1665 | hdev = hci_dev_get(index); | 1788 | hdev = hci_dev_get(index); |
1666 | if (!hdev) | 1789 | if (!hdev) |
1667 | return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV); | 1790 | return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, |
1791 | MGMT_STATUS_INVALID_PARAMS); | ||
1668 | 1792 | ||
1669 | hci_dev_lock_bh(hdev); | 1793 | hci_dev_lock_bh(hdev); |
1670 | 1794 | ||
1671 | if (!test_bit(HCI_UP, &hdev->flags)) { | 1795 | if (!test_bit(HCI_UP, &hdev->flags)) { |
1672 | err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENETDOWN); | 1796 | err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, |
1797 | MGMT_STATUS_NOT_POWERED); | ||
1673 | goto failed; | 1798 | goto failed; |
1674 | } | 1799 | } |
1675 | 1800 | ||
@@ -1700,7 +1825,8 @@ static int stop_discovery(struct sock *sk, u16 index) | |||
1700 | 1825 | ||
1701 | hdev = hci_dev_get(index); | 1826 | hdev = hci_dev_get(index); |
1702 | if (!hdev) | 1827 | if (!hdev) |
1703 | return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV); | 1828 | return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, |
1829 | MGMT_STATUS_INVALID_PARAMS); | ||
1704 | 1830 | ||
1705 | hci_dev_lock_bh(hdev); | 1831 | hci_dev_lock_bh(hdev); |
1706 | 1832 | ||
@@ -1732,18 +1858,19 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data, | |||
1732 | 1858 | ||
1733 | if (len != sizeof(*cp)) | 1859 | if (len != sizeof(*cp)) |
1734 | return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, | 1860 | return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, |
1735 | EINVAL); | 1861 | MGMT_STATUS_INVALID_PARAMS); |
1736 | 1862 | ||
1737 | hdev = hci_dev_get(index); | 1863 | hdev = hci_dev_get(index); |
1738 | if (!hdev) | 1864 | if (!hdev) |
1739 | return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, | 1865 | return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, |
1740 | ENODEV); | 1866 | MGMT_STATUS_INVALID_PARAMS); |
1741 | 1867 | ||
1742 | hci_dev_lock_bh(hdev); | 1868 | hci_dev_lock_bh(hdev); |
1743 | 1869 | ||
1744 | err = hci_blacklist_add(hdev, &cp->bdaddr); | 1870 | err = hci_blacklist_add(hdev, &cp->bdaddr); |
1745 | if (err < 0) | 1871 | if (err < 0) |
1746 | err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err); | 1872 | err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, |
1873 | MGMT_STATUS_FAILED); | ||
1747 | else | 1874 | else |
1748 | err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, | 1875 | err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, |
1749 | NULL, 0); | 1876 | NULL, 0); |
@@ -1765,19 +1892,20 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data, | |||
1765 | 1892 | ||
1766 | if (len != sizeof(*cp)) | 1893 | if (len != sizeof(*cp)) |
1767 | return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, | 1894 | return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, |
1768 | EINVAL); | 1895 | MGMT_STATUS_INVALID_PARAMS); |
1769 | 1896 | ||
1770 | hdev = hci_dev_get(index); | 1897 | hdev = hci_dev_get(index); |
1771 | if (!hdev) | 1898 | if (!hdev) |
1772 | return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, | 1899 | return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, |
1773 | ENODEV); | 1900 | MGMT_STATUS_INVALID_PARAMS); |
1774 | 1901 | ||
1775 | hci_dev_lock_bh(hdev); | 1902 | hci_dev_lock_bh(hdev); |
1776 | 1903 | ||
1777 | err = hci_blacklist_del(hdev, &cp->bdaddr); | 1904 | err = hci_blacklist_del(hdev, &cp->bdaddr); |
1778 | 1905 | ||
1779 | if (err < 0) | 1906 | if (err < 0) |
1780 | err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, -err); | 1907 | err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, |
1908 | MGMT_STATUS_INVALID_PARAMS); | ||
1781 | else | 1909 | else |
1782 | err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, | 1910 | err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, |
1783 | NULL, 0); | 1911 | NULL, 0); |
@@ -1801,12 +1929,12 @@ static int set_fast_connectable(struct sock *sk, u16 index, | |||
1801 | 1929 | ||
1802 | if (len != sizeof(*cp)) | 1930 | if (len != sizeof(*cp)) |
1803 | return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, | 1931 | return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, |
1804 | EINVAL); | 1932 | MGMT_STATUS_INVALID_PARAMS); |
1805 | 1933 | ||
1806 | hdev = hci_dev_get(index); | 1934 | hdev = hci_dev_get(index); |
1807 | if (!hdev) | 1935 | if (!hdev) |
1808 | return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, | 1936 | return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, |
1809 | ENODEV); | 1937 | MGMT_STATUS_INVALID_PARAMS); |
1810 | 1938 | ||
1811 | hci_dev_lock(hdev); | 1939 | hci_dev_lock(hdev); |
1812 | 1940 | ||
@@ -1824,14 +1952,14 @@ static int set_fast_connectable(struct sock *sk, u16 index, | |||
1824 | sizeof(acp), &acp); | 1952 | sizeof(acp), &acp); |
1825 | if (err < 0) { | 1953 | if (err < 0) { |
1826 | err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, | 1954 | err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, |
1827 | -err); | 1955 | MGMT_STATUS_FAILED); |
1828 | goto done; | 1956 | goto done; |
1829 | } | 1957 | } |
1830 | 1958 | ||
1831 | err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type); | 1959 | err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type); |
1832 | if (err < 0) { | 1960 | if (err < 0) { |
1833 | err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, | 1961 | err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, |
1834 | -err); | 1962 | MGMT_STATUS_FAILED); |
1835 | goto done; | 1963 | goto done; |
1836 | } | 1964 | } |
1837 | 1965 | ||
@@ -1970,7 +2098,8 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) | |||
1970 | break; | 2098 | break; |
1971 | default: | 2099 | default: |
1972 | BT_DBG("Unknown op %u", opcode); | 2100 | BT_DBG("Unknown op %u", opcode); |
1973 | err = cmd_status(sk, index, opcode, 0x01); | 2101 | err = cmd_status(sk, index, opcode, |
2102 | MGMT_STATUS_UNKNOWN_COMMAND); | ||
1974 | break; | 2103 | break; |
1975 | } | 2104 | } |
1976 | 2105 | ||
@@ -2093,13 +2222,15 @@ int mgmt_connectable(struct hci_dev *hdev, u8 connectable) | |||
2093 | 2222 | ||
2094 | int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status) | 2223 | int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status) |
2095 | { | 2224 | { |
2225 | u8 mgmt_err = mgmt_status(status); | ||
2226 | |||
2096 | if (scan & SCAN_PAGE) | 2227 | if (scan & SCAN_PAGE) |
2097 | mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, | 2228 | mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, |
2098 | cmd_status_rsp, &status); | 2229 | cmd_status_rsp, &mgmt_err); |
2099 | 2230 | ||
2100 | if (scan & SCAN_INQUIRY) | 2231 | if (scan & SCAN_INQUIRY) |
2101 | mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, | 2232 | mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, |
2102 | cmd_status_rsp, &status); | 2233 | cmd_status_rsp, &mgmt_err); |
2103 | 2234 | ||
2104 | return 0; | 2235 | return 0; |
2105 | } | 2236 | } |
@@ -2190,6 +2321,7 @@ int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, | |||
2190 | int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status) | 2321 | int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status) |
2191 | { | 2322 | { |
2192 | struct pending_cmd *cmd; | 2323 | struct pending_cmd *cmd; |
2324 | u8 mgmt_err = mgmt_status(status); | ||
2193 | int err; | 2325 | int err; |
2194 | 2326 | ||
2195 | cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev); | 2327 | cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev); |
@@ -2206,7 +2338,7 @@ int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status) | |||
2206 | &rp, sizeof(rp)); | 2338 | &rp, sizeof(rp)); |
2207 | } else | 2339 | } else |
2208 | err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT, | 2340 | err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT, |
2209 | status); | 2341 | mgmt_err); |
2210 | 2342 | ||
2211 | mgmt_pending_remove(cmd); | 2343 | mgmt_pending_remove(cmd); |
2212 | 2344 | ||
@@ -2220,7 +2352,7 @@ int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, | |||
2220 | 2352 | ||
2221 | bacpy(&ev.addr.bdaddr, bdaddr); | 2353 | bacpy(&ev.addr.bdaddr, bdaddr); |
2222 | ev.addr.type = link_to_mgmt(link_type, addr_type); | 2354 | ev.addr.type = link_to_mgmt(link_type, addr_type); |
2223 | ev.status = status; | 2355 | ev.status = mgmt_status(status); |
2224 | 2356 | ||
2225 | return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL); | 2357 | return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL); |
2226 | } | 2358 | } |
@@ -2248,7 +2380,7 @@ int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, | |||
2248 | return -ENOENT; | 2380 | return -ENOENT; |
2249 | 2381 | ||
2250 | bacpy(&rp.bdaddr, bdaddr); | 2382 | bacpy(&rp.bdaddr, bdaddr); |
2251 | rp.status = status; | 2383 | rp.status = mgmt_status(status); |
2252 | 2384 | ||
2253 | err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp, | 2385 | err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp, |
2254 | sizeof(rp)); | 2386 | sizeof(rp)); |
@@ -2270,7 +2402,7 @@ int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, | |||
2270 | return -ENOENT; | 2402 | return -ENOENT; |
2271 | 2403 | ||
2272 | bacpy(&rp.bdaddr, bdaddr); | 2404 | bacpy(&rp.bdaddr, bdaddr); |
2273 | rp.status = status; | 2405 | rp.status = mgmt_status(status); |
2274 | 2406 | ||
2275 | err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp, | 2407 | err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp, |
2276 | sizeof(rp)); | 2408 | sizeof(rp)); |
@@ -2307,7 +2439,7 @@ static int confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, | |||
2307 | return -ENOENT; | 2439 | return -ENOENT; |
2308 | 2440 | ||
2309 | bacpy(&rp.bdaddr, bdaddr); | 2441 | bacpy(&rp.bdaddr, bdaddr); |
2310 | rp.status = status; | 2442 | rp.status = mgmt_status(status); |
2311 | err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp)); | 2443 | err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp)); |
2312 | 2444 | ||
2313 | mgmt_pending_remove(cmd); | 2445 | mgmt_pending_remove(cmd); |
@@ -2318,14 +2450,14 @@ static int confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, | |||
2318 | int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, | 2450 | int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, |
2319 | u8 status) | 2451 | u8 status) |
2320 | { | 2452 | { |
2321 | return confirm_reply_complete(hdev, bdaddr, status, | 2453 | return confirm_reply_complete(hdev, bdaddr, mgmt_status(status), |
2322 | MGMT_OP_USER_CONFIRM_REPLY); | 2454 | MGMT_OP_USER_CONFIRM_REPLY); |
2323 | } | 2455 | } |
2324 | 2456 | ||
2325 | int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, | 2457 | int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, |
2326 | bdaddr_t *bdaddr, u8 status) | 2458 | bdaddr_t *bdaddr, u8 status) |
2327 | { | 2459 | { |
2328 | return confirm_reply_complete(hdev, bdaddr, status, | 2460 | return confirm_reply_complete(hdev, bdaddr, mgmt_status(status), |
2329 | MGMT_OP_USER_CONFIRM_NEG_REPLY); | 2461 | MGMT_OP_USER_CONFIRM_NEG_REPLY); |
2330 | } | 2462 | } |
2331 | 2463 | ||
@@ -2334,7 +2466,7 @@ int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status) | |||
2334 | struct mgmt_ev_auth_failed ev; | 2466 | struct mgmt_ev_auth_failed ev; |
2335 | 2467 | ||
2336 | bacpy(&ev.bdaddr, bdaddr); | 2468 | bacpy(&ev.bdaddr, bdaddr); |
2337 | ev.status = status; | 2469 | ev.status = mgmt_status(status); |
2338 | 2470 | ||
2339 | return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL); | 2471 | return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL); |
2340 | } | 2472 | } |
@@ -2354,7 +2486,7 @@ int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status) | |||
2354 | 2486 | ||
2355 | if (status) { | 2487 | if (status) { |
2356 | err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, | 2488 | err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, |
2357 | EIO); | 2489 | mgmt_status(status)); |
2358 | goto failed; | 2490 | goto failed; |
2359 | } | 2491 | } |
2360 | 2492 | ||
@@ -2389,7 +2521,8 @@ int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, | |||
2389 | 2521 | ||
2390 | if (status) { | 2522 | if (status) { |
2391 | err = cmd_status(cmd->sk, hdev->id, | 2523 | err = cmd_status(cmd->sk, hdev->id, |
2392 | MGMT_OP_READ_LOCAL_OOB_DATA, EIO); | 2524 | MGMT_OP_READ_LOCAL_OOB_DATA, |
2525 | mgmt_status(status)); | ||
2393 | } else { | 2526 | } else { |
2394 | struct mgmt_rp_read_local_oob_data rp; | 2527 | struct mgmt_rp_read_local_oob_data rp; |
2395 | 2528 | ||
@@ -2447,7 +2580,7 @@ int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status) | |||
2447 | if (!cmd) | 2580 | if (!cmd) |
2448 | return -ENOENT; | 2581 | return -ENOENT; |
2449 | 2582 | ||
2450 | err = cmd_status(cmd->sk, hdev->id, cmd->opcode, status); | 2583 | err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status)); |
2451 | mgmt_pending_remove(cmd); | 2584 | mgmt_pending_remove(cmd); |
2452 | 2585 | ||
2453 | return err; | 2586 | return err; |