aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/mgmt.c
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2012-03-01 15:24:41 -0500
committerJohan Hedberg <johan.hedberg@intel.com>2012-03-01 16:55:58 -0500
commitbe22b54e8711734f4cb93ac31723b955fe9dbbe0 (patch)
treebd767d8adc1d3ab28700335c99d9e55572d0b82c /net/bluetooth/mgmt.c
parent9d1acbfb774fa5e043a44adedfcc36c9837a5e61 (diff)
Bluetooth: mgmt: Centralize message length checks
This patch moves the command length information into the command handler table allowing the removal of length checks from the handler functions and doing the check in a single place before calling the handler function. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Acked-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/mgmt.c')
-rw-r--r--net/bluetooth/mgmt.c220
1 files changed, 52 insertions, 168 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 88a342a1259..7bd7d57a877 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -751,10 +751,6 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
751 751
752 BT_DBG("request for %s", hdev->name); 752 BT_DBG("request for %s", hdev->name);
753 753
754 if (len != sizeof(*cp))
755 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
756 MGMT_STATUS_INVALID_PARAMS);
757
758 hci_dev_lock(hdev); 754 hci_dev_lock(hdev);
759 755
760 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) { 756 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
@@ -846,10 +842,6 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
846 842
847 BT_DBG("request for %s", hdev->name); 843 BT_DBG("request for %s", hdev->name);
848 844
849 if (len != sizeof(*cp))
850 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
851 MGMT_STATUS_INVALID_PARAMS);
852
853 timeout = get_unaligned_le16(&cp->timeout); 845 timeout = get_unaligned_le16(&cp->timeout);
854 if (!cp->val && timeout > 0) 846 if (!cp->val && timeout > 0)
855 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, 847 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
@@ -945,10 +937,6 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
945 937
946 BT_DBG("request for %s", hdev->name); 938 BT_DBG("request for %s", hdev->name);
947 939
948 if (len != sizeof(*cp))
949 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
950 MGMT_STATUS_INVALID_PARAMS);
951
952 hci_dev_lock(hdev); 940 hci_dev_lock(hdev);
953 941
954 if (!hdev_is_powered(hdev)) { 942 if (!hdev_is_powered(hdev)) {
@@ -1019,10 +1007,6 @@ static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
1019 1007
1020 BT_DBG("request for %s", hdev->name); 1008 BT_DBG("request for %s", hdev->name);
1021 1009
1022 if (len != sizeof(*cp))
1023 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1024 MGMT_STATUS_INVALID_PARAMS);
1025
1026 hci_dev_lock(hdev); 1010 hci_dev_lock(hdev);
1027 1011
1028 if (cp->val) 1012 if (cp->val)
@@ -1051,10 +1035,6 @@ static int set_link_security(struct sock *sk, struct hci_dev *hdev,
1051 1035
1052 BT_DBG("request for %s", hdev->name); 1036 BT_DBG("request for %s", hdev->name);
1053 1037
1054 if (len != sizeof(*cp))
1055 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1056 MGMT_STATUS_INVALID_PARAMS);
1057
1058 hci_dev_lock(hdev); 1038 hci_dev_lock(hdev);
1059 1039
1060 if (!hdev_is_powered(hdev)) { 1040 if (!hdev_is_powered(hdev)) {
@@ -1115,10 +1095,6 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
1115 1095
1116 BT_DBG("request for %s", hdev->name); 1096 BT_DBG("request for %s", hdev->name);
1117 1097
1118 if (len != sizeof(*cp))
1119 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1120 MGMT_STATUS_INVALID_PARAMS);
1121
1122 hci_dev_lock(hdev); 1098 hci_dev_lock(hdev);
1123 1099
1124 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) { 1100 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
@@ -1181,10 +1157,6 @@ static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
1181 1157
1182 BT_DBG("request for %s", hdev->name); 1158 BT_DBG("request for %s", hdev->name);
1183 1159
1184 if (len != sizeof(*cp))
1185 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1186 MGMT_STATUS_INVALID_PARAMS);
1187
1188 if (!enable_hs) 1160 if (!enable_hs)
1189 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, 1161 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1190 MGMT_STATUS_NOT_SUPPORTED); 1162 MGMT_STATUS_NOT_SUPPORTED);
@@ -1207,10 +1179,6 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
1207 1179
1208 BT_DBG("request for %s", hdev->name); 1180 BT_DBG("request for %s", hdev->name);
1209 1181
1210 if (len != sizeof(*cp))
1211 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1212 MGMT_STATUS_INVALID_PARAMS);
1213
1214 hci_dev_lock(hdev); 1182 hci_dev_lock(hdev);
1215 1183
1216 if (!enable_le || !(hdev->features[4] & LMP_LE)) { 1184 if (!enable_le || !(hdev->features[4] & LMP_LE)) {
@@ -1280,10 +1248,6 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
1280 1248
1281 BT_DBG("request for %s", hdev->name); 1249 BT_DBG("request for %s", hdev->name);
1282 1250
1283 if (len != sizeof(*cp))
1284 return cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
1285 MGMT_STATUS_INVALID_PARAMS);
1286
1287 hci_dev_lock(hdev); 1251 hci_dev_lock(hdev);
1288 1252
1289 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { 1253 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
@@ -1353,10 +1317,6 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
1353 1317
1354 BT_DBG("request for %s", hdev->name); 1318 BT_DBG("request for %s", hdev->name);
1355 1319
1356 if (len != sizeof(*cp))
1357 return cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
1358 MGMT_STATUS_INVALID_PARAMS);
1359
1360 hci_dev_lock(hdev); 1320 hci_dev_lock(hdev);
1361 1321
1362 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { 1322 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
@@ -1430,10 +1390,6 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
1430 1390
1431 BT_DBG("request for %s", hdev->name); 1391 BT_DBG("request for %s", hdev->name);
1432 1392
1433 if (len != sizeof(*cp))
1434 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1435 MGMT_STATUS_INVALID_PARAMS);
1436
1437 hci_dev_lock(hdev); 1393 hci_dev_lock(hdev);
1438 1394
1439 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { 1395 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
@@ -1486,10 +1442,6 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
1486 u16 key_count, expected_len; 1442 u16 key_count, expected_len;
1487 int i; 1443 int i;
1488 1444
1489 if (len < sizeof(*cp))
1490 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1491 MGMT_STATUS_INVALID_PARAMS);
1492
1493 key_count = get_unaligned_le16(&cp->key_count); 1445 key_count = get_unaligned_le16(&cp->key_count);
1494 1446
1495 expected_len = sizeof(*cp) + key_count * 1447 expected_len = sizeof(*cp) + key_count *
@@ -1551,10 +1503,6 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1551 struct hci_conn *conn; 1503 struct hci_conn *conn;
1552 int err; 1504 int err;
1553 1505
1554 if (len != sizeof(*cp))
1555 return cmd_status(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1556 MGMT_STATUS_INVALID_PARAMS);
1557
1558 hci_dev_lock(hdev); 1506 hci_dev_lock(hdev);
1559 1507
1560 memset(&rp, 0, sizeof(rp)); 1508 memset(&rp, 0, sizeof(rp));
@@ -1627,10 +1575,6 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
1627 1575
1628 BT_DBG(""); 1576 BT_DBG("");
1629 1577
1630 if (len != sizeof(*cp))
1631 return cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
1632 MGMT_STATUS_INVALID_PARAMS);
1633
1634 hci_dev_lock(hdev); 1578 hci_dev_lock(hdev);
1635 1579
1636 if (!test_bit(HCI_UP, &hdev->flags)) { 1580 if (!test_bit(HCI_UP, &hdev->flags)) {
@@ -1781,10 +1725,6 @@ static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
1781 1725
1782 BT_DBG(""); 1726 BT_DBG("");
1783 1727
1784 if (len != sizeof(*cp))
1785 return cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
1786 MGMT_STATUS_INVALID_PARAMS);
1787
1788 hci_dev_lock(hdev); 1728 hci_dev_lock(hdev);
1789 1729
1790 if (!hdev_is_powered(hdev)) { 1730 if (!hdev_is_powered(hdev)) {
@@ -1842,10 +1782,6 @@ static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
1842 1782
1843 BT_DBG(""); 1783 BT_DBG("");
1844 1784
1845 if (len != sizeof(*cp))
1846 return cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
1847 MGMT_STATUS_INVALID_PARAMS);
1848
1849 hci_dev_lock(hdev); 1785 hci_dev_lock(hdev);
1850 1786
1851 if (!hdev_is_powered(hdev)) { 1787 if (!hdev_is_powered(hdev)) {
@@ -1868,10 +1804,6 @@ static int set_io_capability(struct sock *sk, struct hci_dev *hdev,
1868 1804
1869 BT_DBG(""); 1805 BT_DBG("");
1870 1806
1871 if (len != sizeof(*cp))
1872 return cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
1873 MGMT_STATUS_INVALID_PARAMS);
1874
1875 hci_dev_lock(hdev); 1807 hci_dev_lock(hdev);
1876 1808
1877 hdev->io_capability = cp->io_capability; 1809 hdev->io_capability = cp->io_capability;
@@ -1949,10 +1881,6 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1949 1881
1950 BT_DBG(""); 1882 BT_DBG("");
1951 1883
1952 if (len != sizeof(*cp))
1953 return cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
1954 MGMT_STATUS_INVALID_PARAMS);
1955
1956 hci_dev_lock(hdev); 1884 hci_dev_lock(hdev);
1957 1885
1958 if (!hdev_is_powered(hdev)) { 1886 if (!hdev_is_powered(hdev)) {
@@ -2029,10 +1957,6 @@ static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev,
2029 1957
2030 BT_DBG(""); 1958 BT_DBG("");
2031 1959
2032 if (len != sizeof(*addr))
2033 return cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
2034 MGMT_STATUS_INVALID_PARAMS);
2035
2036 hci_dev_lock(hdev); 1960 hci_dev_lock(hdev);
2037 1961
2038 if (!hdev_is_powered(hdev)) { 1962 if (!hdev_is_powered(hdev)) {
@@ -2153,10 +2077,6 @@ static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
2153 2077
2154 BT_DBG(""); 2078 BT_DBG("");
2155 2079
2156 if (len != sizeof(*cp))
2157 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2158 MGMT_STATUS_INVALID_PARAMS);
2159
2160 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, 2080 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
2161 MGMT_OP_USER_CONFIRM_NEG_REPLY, 2081 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2162 HCI_OP_USER_CONFIRM_NEG_REPLY, 0); 2082 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
@@ -2169,10 +2089,6 @@ static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev,
2169 2089
2170 BT_DBG(""); 2090 BT_DBG("");
2171 2091
2172 if (len != sizeof(*cp))
2173 return cmd_status(sk, hdev->id, MGMT_OP_USER_PASSKEY_REPLY,
2174 EINVAL);
2175
2176 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, 2092 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
2177 MGMT_OP_USER_PASSKEY_REPLY, 2093 MGMT_OP_USER_PASSKEY_REPLY,
2178 HCI_OP_USER_PASSKEY_REPLY, 2094 HCI_OP_USER_PASSKEY_REPLY,
@@ -2186,10 +2102,6 @@ static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
2186 2102
2187 BT_DBG(""); 2103 BT_DBG("");
2188 2104
2189 if (len != sizeof(*cp))
2190 return cmd_status(sk, hdev->id, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2191 EINVAL);
2192
2193 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, 2105 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
2194 MGMT_OP_USER_PASSKEY_NEG_REPLY, 2106 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2195 HCI_OP_USER_PASSKEY_NEG_REPLY, 0); 2107 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
@@ -2205,10 +2117,6 @@ static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
2205 2117
2206 BT_DBG(""); 2118 BT_DBG("");
2207 2119
2208 if (len != sizeof(*mgmt_cp))
2209 return cmd_status(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2210 MGMT_STATUS_INVALID_PARAMS);
2211
2212 hci_dev_lock(hdev); 2120 hci_dev_lock(hdev);
2213 2121
2214 memcpy(hdev->short_name, mgmt_cp->short_name, 2122 memcpy(hdev->short_name, mgmt_cp->short_name,
@@ -2297,10 +2205,6 @@ static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
2297 2205
2298 BT_DBG("%s ", hdev->name); 2206 BT_DBG("%s ", hdev->name);
2299 2207
2300 if (len != sizeof(*cp))
2301 return cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
2302 MGMT_STATUS_INVALID_PARAMS);
2303
2304 hci_dev_lock(hdev); 2208 hci_dev_lock(hdev);
2305 2209
2306 if (!hdev_is_powered(hdev)) { 2210 if (!hdev_is_powered(hdev)) {
@@ -2334,10 +2238,6 @@ static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
2334 2238
2335 BT_DBG("%s", hdev->name); 2239 BT_DBG("%s", hdev->name);
2336 2240
2337 if (len != sizeof(*cp))
2338 return cmd_status(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2339 MGMT_STATUS_INVALID_PARAMS);
2340
2341 hci_dev_lock(hdev); 2241 hci_dev_lock(hdev);
2342 2242
2343 if (!hdev_is_powered(hdev)) { 2243 if (!hdev_is_powered(hdev)) {
@@ -2388,10 +2288,6 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
2388 2288
2389 BT_DBG("%s", hdev->name); 2289 BT_DBG("%s", hdev->name);
2390 2290
2391 if (len != sizeof(*cp))
2392 return cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2393 MGMT_STATUS_INVALID_PARAMS);
2394
2395 hci_dev_lock(hdev); 2291 hci_dev_lock(hdev);
2396 2292
2397 if (!hdev_is_powered(hdev)) { 2293 if (!hdev_is_powered(hdev)) {
@@ -2463,10 +2359,6 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
2463 2359
2464 BT_DBG("%s", hdev->name); 2360 BT_DBG("%s", hdev->name);
2465 2361
2466 if (len != sizeof(*mgmt_cp))
2467 return cmd_status(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
2468 MGMT_STATUS_INVALID_PARAMS);
2469
2470 hci_dev_lock(hdev); 2362 hci_dev_lock(hdev);
2471 2363
2472 if (!hci_discovery_active(hdev)) { 2364 if (!hci_discovery_active(hdev)) {
@@ -2529,10 +2421,6 @@ static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
2529 2421
2530 BT_DBG("%s", hdev->name); 2422 BT_DBG("%s", hdev->name);
2531 2423
2532 if (len != sizeof(*cp))
2533 return cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
2534 MGMT_STATUS_INVALID_PARAMS);
2535
2536 hci_dev_lock(hdev); 2424 hci_dev_lock(hdev);
2537 2425
2538 if (!hci_discovery_active(hdev)) { 2426 if (!hci_discovery_active(hdev)) {
@@ -2572,10 +2460,6 @@ static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
2572 2460
2573 BT_DBG("%s", hdev->name); 2461 BT_DBG("%s", hdev->name);
2574 2462
2575 if (len != sizeof(*cp))
2576 return cmd_status(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
2577 MGMT_STATUS_INVALID_PARAMS);
2578
2579 hci_dev_lock(hdev); 2463 hci_dev_lock(hdev);
2580 2464
2581 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type); 2465 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
@@ -2601,10 +2485,6 @@ static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
2601 2485
2602 BT_DBG("%s", hdev->name); 2486 BT_DBG("%s", hdev->name);
2603 2487
2604 if (len != sizeof(*cp))
2605 return cmd_status(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
2606 MGMT_STATUS_INVALID_PARAMS);
2607
2608 hci_dev_lock(hdev); 2488 hci_dev_lock(hdev);
2609 2489
2610 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type); 2490 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
@@ -2631,10 +2511,6 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
2631 2511
2632 BT_DBG("%s", hdev->name); 2512 BT_DBG("%s", hdev->name);
2633 2513
2634 if (len != sizeof(*cp))
2635 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2636 MGMT_STATUS_INVALID_PARAMS);
2637
2638 if (!hdev_is_powered(hdev)) 2514 if (!hdev_is_powered(hdev))
2639 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 2515 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2640 MGMT_STATUS_NOT_POWERED); 2516 MGMT_STATUS_NOT_POWERED);
@@ -2684,10 +2560,6 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
2684 u16 key_count, expected_len; 2560 u16 key_count, expected_len;
2685 int i; 2561 int i;
2686 2562
2687 if (len < sizeof(*cp))
2688 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
2689 EINVAL);
2690
2691 key_count = get_unaligned_le16(&cp->key_count); 2563 key_count = get_unaligned_le16(&cp->key_count);
2692 2564
2693 expected_len = sizeof(*cp) + key_count * 2565 expected_len = sizeof(*cp) + key_count *
@@ -2727,47 +2599,49 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
2727struct mgmt_handler { 2599struct mgmt_handler {
2728 int (*func) (struct sock *sk, struct hci_dev *hdev, 2600 int (*func) (struct sock *sk, struct hci_dev *hdev,
2729 void *data, u16 data_len); 2601 void *data, u16 data_len);
2602 bool var_len;
2603 size_t data_len;
2730} mgmt_handlers[] = { 2604} mgmt_handlers[] = {
2731 { NULL }, /* 0x0000 (no command) */ 2605 { NULL }, /* 0x0000 (no command) */
2732 { read_version, }, 2606 { read_version, false, MGMT_READ_VERSION_SIZE },
2733 { read_commands, }, 2607 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
2734 { read_index_list, }, 2608 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
2735 { read_controller_info, }, 2609 { read_controller_info, false, MGMT_READ_INFO_SIZE },
2736 { set_powered, }, 2610 { set_powered, false, MGMT_SETTING_SIZE },
2737 { set_discoverable, }, 2611 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
2738 { set_connectable, }, 2612 { set_connectable, false, MGMT_SETTING_SIZE },
2739 { set_fast_connectable, }, 2613 { set_fast_connectable, false, MGMT_SETTING_SIZE },
2740 { set_pairable, }, 2614 { set_pairable, false, MGMT_SETTING_SIZE },
2741 { set_link_security, }, 2615 { set_link_security, false, MGMT_SETTING_SIZE },
2742 { set_ssp, }, 2616 { set_ssp, false, MGMT_SETTING_SIZE },
2743 { set_hs, }, 2617 { set_hs, false, MGMT_SETTING_SIZE },
2744 { set_le, }, 2618 { set_le, false, MGMT_SETTING_SIZE },
2745 { set_dev_class, }, 2619 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
2746 { set_local_name, }, 2620 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
2747 { add_uuid, }, 2621 { add_uuid, false, MGMT_ADD_UUID_SIZE },
2748 { remove_uuid, }, 2622 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
2749 { load_link_keys, }, 2623 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
2750 { load_long_term_keys, }, 2624 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
2751 { disconnect, }, 2625 { disconnect, false, MGMT_DISCONNECT_SIZE },
2752 { get_connections, }, 2626 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
2753 { pin_code_reply, }, 2627 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
2754 { pin_code_neg_reply, }, 2628 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
2755 { set_io_capability, }, 2629 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
2756 { pair_device, }, 2630 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
2757 { cancel_pair_device, }, 2631 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
2758 { unpair_device, }, 2632 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
2759 { user_confirm_reply, }, 2633 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
2760 { user_confirm_neg_reply, }, 2634 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
2761 { user_passkey_reply, }, 2635 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
2762 { user_passkey_neg_reply, }, 2636 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
2763 { read_local_oob_data, }, 2637 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
2764 { add_remote_oob_data, }, 2638 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
2765 { remove_remote_oob_data, }, 2639 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
2766 { start_discovery, }, 2640 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
2767 { stop_discovery, }, 2641 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
2768 { confirm_name, }, 2642 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
2769 { block_device, }, 2643 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
2770 { unblock_device, }, 2644 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
2771}; 2645};
2772 2646
2773 2647
@@ -2778,6 +2652,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2778 struct mgmt_hdr *hdr; 2652 struct mgmt_hdr *hdr;
2779 u16 opcode, index, len; 2653 u16 opcode, index, len;
2780 struct hci_dev *hdev = NULL; 2654 struct hci_dev *hdev = NULL;
2655 struct mgmt_handler *handler;
2781 int err; 2656 int err;
2782 2657
2783 BT_DBG("got %zu bytes", msglen); 2658 BT_DBG("got %zu bytes", msglen);
@@ -2828,12 +2703,21 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2828 goto done; 2703 goto done;
2829 } 2704 }
2830 2705
2706 handler = &mgmt_handlers[opcode];
2707
2708 if ((handler->var_len && len < handler->data_len) ||
2709 (!handler->var_len && len != handler->data_len)) {
2710 err = cmd_status(sk, index, opcode,
2711 MGMT_STATUS_INVALID_PARAMS);
2712 goto done;
2713 }
2714
2831 if (hdev) 2715 if (hdev)
2832 mgmt_init_hdev(sk, hdev); 2716 mgmt_init_hdev(sk, hdev);
2833 2717
2834 cp = buf + sizeof(*hdr); 2718 cp = buf + sizeof(*hdr);
2835 2719
2836 err = mgmt_handlers[opcode].func(sk, hdev, cp, len); 2720 err = handler->func(sk, hdev, cp, len);
2837 if (err < 0) 2721 if (err < 0)
2838 goto done; 2722 goto done;
2839 2723