diff options
author | Johannes Berg <johannes.berg@intel.com> | 2013-01-30 15:39:54 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-01-30 15:39:54 -0500 |
commit | de8d7a53807c8d2bb04b59ff3a0daa225e81a775 (patch) | |
tree | fcd911aff52d3192af95f1e2aee7ecfd4187d5ec /net/bluetooth/mgmt.c | |
parent | 97c7952792018589640ecb3e62e1ab8f06005546 (diff) | |
parent | c331997b6c9ad7f4b8075e6e60d3caa6e36f5938 (diff) |
Merge remote-tracking branch 'wireless-next/master' into iwlwifi-next
Diffstat (limited to 'net/bluetooth/mgmt.c')
-rw-r--r-- | net/bluetooth/mgmt.c | 270 |
1 files changed, 192 insertions, 78 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f559b966279c..e7f944f52ff2 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -777,14 +777,19 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, | |||
777 | 777 | ||
778 | BT_DBG("request for %s", hdev->name); | 778 | BT_DBG("request for %s", hdev->name); |
779 | 779 | ||
780 | if (cp->val != 0x00 && cp->val != 0x01) | ||
781 | return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED, | ||
782 | MGMT_STATUS_INVALID_PARAMS); | ||
783 | |||
780 | hci_dev_lock(hdev); | 784 | hci_dev_lock(hdev); |
781 | 785 | ||
782 | if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) { | 786 | if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) { |
783 | cancel_delayed_work(&hdev->power_off); | 787 | cancel_delayed_work(&hdev->power_off); |
784 | 788 | ||
785 | if (cp->val) { | 789 | if (cp->val) { |
786 | err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev); | 790 | mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, |
787 | mgmt_powered(hdev, 1); | 791 | data, len); |
792 | err = mgmt_powered(hdev, 1); | ||
788 | goto failed; | 793 | goto failed; |
789 | } | 794 | } |
790 | } | 795 | } |
@@ -807,9 +812,9 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, | |||
807 | } | 812 | } |
808 | 813 | ||
809 | if (cp->val) | 814 | if (cp->val) |
810 | schedule_work(&hdev->power_on); | 815 | queue_work(hdev->req_workqueue, &hdev->power_on); |
811 | else | 816 | else |
812 | schedule_work(&hdev->power_off.work); | 817 | queue_work(hdev->req_workqueue, &hdev->power_off.work); |
813 | 818 | ||
814 | err = 0; | 819 | err = 0; |
815 | 820 | ||
@@ -872,6 +877,10 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data, | |||
872 | return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, | 877 | return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, |
873 | MGMT_STATUS_NOT_SUPPORTED); | 878 | MGMT_STATUS_NOT_SUPPORTED); |
874 | 879 | ||
880 | if (cp->val != 0x00 && cp->val != 0x01) | ||
881 | return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, | ||
882 | MGMT_STATUS_INVALID_PARAMS); | ||
883 | |||
875 | timeout = __le16_to_cpu(cp->timeout); | 884 | timeout = __le16_to_cpu(cp->timeout); |
876 | if (!cp->val && timeout > 0) | 885 | if (!cp->val && timeout > 0) |
877 | return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, | 886 | return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, |
@@ -971,6 +980,10 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, | |||
971 | return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE, | 980 | return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE, |
972 | MGMT_STATUS_NOT_SUPPORTED); | 981 | MGMT_STATUS_NOT_SUPPORTED); |
973 | 982 | ||
983 | if (cp->val != 0x00 && cp->val != 0x01) | ||
984 | return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE, | ||
985 | MGMT_STATUS_INVALID_PARAMS); | ||
986 | |||
974 | hci_dev_lock(hdev); | 987 | hci_dev_lock(hdev); |
975 | 988 | ||
976 | if (!hdev_is_powered(hdev)) { | 989 | if (!hdev_is_powered(hdev)) { |
@@ -1041,6 +1054,10 @@ static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data, | |||
1041 | 1054 | ||
1042 | BT_DBG("request for %s", hdev->name); | 1055 | BT_DBG("request for %s", hdev->name); |
1043 | 1056 | ||
1057 | if (cp->val != 0x00 && cp->val != 0x01) | ||
1058 | return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE, | ||
1059 | MGMT_STATUS_INVALID_PARAMS); | ||
1060 | |||
1044 | hci_dev_lock(hdev); | 1061 | hci_dev_lock(hdev); |
1045 | 1062 | ||
1046 | if (cp->val) | 1063 | if (cp->val) |
@@ -1073,6 +1090,10 @@ static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data, | |||
1073 | return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY, | 1090 | return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY, |
1074 | MGMT_STATUS_NOT_SUPPORTED); | 1091 | MGMT_STATUS_NOT_SUPPORTED); |
1075 | 1092 | ||
1093 | if (cp->val != 0x00 && cp->val != 0x01) | ||
1094 | return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY, | ||
1095 | MGMT_STATUS_INVALID_PARAMS); | ||
1096 | |||
1076 | hci_dev_lock(hdev); | 1097 | hci_dev_lock(hdev); |
1077 | 1098 | ||
1078 | if (!hdev_is_powered(hdev)) { | 1099 | if (!hdev_is_powered(hdev)) { |
@@ -1133,13 +1154,15 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) | |||
1133 | 1154 | ||
1134 | BT_DBG("request for %s", hdev->name); | 1155 | BT_DBG("request for %s", hdev->name); |
1135 | 1156 | ||
1136 | hci_dev_lock(hdev); | 1157 | if (!lmp_ssp_capable(hdev)) |
1158 | return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, | ||
1159 | MGMT_STATUS_NOT_SUPPORTED); | ||
1137 | 1160 | ||
1138 | if (!lmp_ssp_capable(hdev)) { | 1161 | if (cp->val != 0x00 && cp->val != 0x01) |
1139 | err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, | 1162 | return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, |
1140 | MGMT_STATUS_NOT_SUPPORTED); | 1163 | MGMT_STATUS_INVALID_PARAMS); |
1141 | goto failed; | 1164 | |
1142 | } | 1165 | hci_dev_lock(hdev); |
1143 | 1166 | ||
1144 | val = !!cp->val; | 1167 | val = !!cp->val; |
1145 | 1168 | ||
@@ -1199,6 +1222,10 @@ static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) | |||
1199 | return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, | 1222 | return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, |
1200 | MGMT_STATUS_NOT_SUPPORTED); | 1223 | MGMT_STATUS_NOT_SUPPORTED); |
1201 | 1224 | ||
1225 | if (cp->val != 0x00 && cp->val != 0x01) | ||
1226 | return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, | ||
1227 | MGMT_STATUS_INVALID_PARAMS); | ||
1228 | |||
1202 | if (cp->val) | 1229 | if (cp->val) |
1203 | set_bit(HCI_HS_ENABLED, &hdev->dev_flags); | 1230 | set_bit(HCI_HS_ENABLED, &hdev->dev_flags); |
1204 | else | 1231 | else |
@@ -1217,13 +1244,15 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) | |||
1217 | 1244 | ||
1218 | BT_DBG("request for %s", hdev->name); | 1245 | BT_DBG("request for %s", hdev->name); |
1219 | 1246 | ||
1220 | hci_dev_lock(hdev); | 1247 | if (!lmp_le_capable(hdev)) |
1248 | return cmd_status(sk, hdev->id, MGMT_OP_SET_LE, | ||
1249 | MGMT_STATUS_NOT_SUPPORTED); | ||
1221 | 1250 | ||
1222 | if (!lmp_le_capable(hdev)) { | 1251 | if (cp->val != 0x00 && cp->val != 0x01) |
1223 | err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE, | 1252 | return cmd_status(sk, hdev->id, MGMT_OP_SET_LE, |
1224 | MGMT_STATUS_NOT_SUPPORTED); | 1253 | MGMT_STATUS_INVALID_PARAMS); |
1225 | goto unlock; | 1254 | |
1226 | } | 1255 | hci_dev_lock(hdev); |
1227 | 1256 | ||
1228 | val = !!cp->val; | 1257 | val = !!cp->val; |
1229 | enabled = lmp_host_le_capable(hdev); | 1258 | enabled = lmp_host_le_capable(hdev); |
@@ -1332,7 +1361,8 @@ static bool enable_service_cache(struct hci_dev *hdev) | |||
1332 | return false; | 1361 | return false; |
1333 | 1362 | ||
1334 | if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) { | 1363 | if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) { |
1335 | schedule_delayed_work(&hdev->service_cache, CACHE_TIMEOUT); | 1364 | queue_delayed_work(hdev->workqueue, &hdev->service_cache, |
1365 | CACHE_TIMEOUT); | ||
1336 | return true; | 1366 | return true; |
1337 | } | 1367 | } |
1338 | 1368 | ||
@@ -1422,13 +1452,19 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data, | |||
1422 | 1452 | ||
1423 | BT_DBG("request for %s", hdev->name); | 1453 | BT_DBG("request for %s", hdev->name); |
1424 | 1454 | ||
1425 | hci_dev_lock(hdev); | 1455 | if (!lmp_bredr_capable(hdev)) |
1456 | return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, | ||
1457 | MGMT_STATUS_NOT_SUPPORTED); | ||
1426 | 1458 | ||
1427 | if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { | 1459 | if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) |
1428 | err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, | 1460 | return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, |
1429 | MGMT_STATUS_BUSY); | 1461 | MGMT_STATUS_BUSY); |
1430 | goto unlock; | 1462 | |
1431 | } | 1463 | if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) |
1464 | return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, | ||
1465 | MGMT_STATUS_INVALID_PARAMS); | ||
1466 | |||
1467 | hci_dev_lock(hdev); | ||
1432 | 1468 | ||
1433 | hdev->major_class = cp->major; | 1469 | hdev->major_class = cp->major; |
1434 | hdev->minor_class = cp->minor; | 1470 | hdev->minor_class = cp->minor; |
@@ -1483,9 +1519,21 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, | |||
1483 | MGMT_STATUS_INVALID_PARAMS); | 1519 | MGMT_STATUS_INVALID_PARAMS); |
1484 | } | 1520 | } |
1485 | 1521 | ||
1522 | if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01) | ||
1523 | return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, | ||
1524 | MGMT_STATUS_INVALID_PARAMS); | ||
1525 | |||
1486 | BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys, | 1526 | BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys, |
1487 | key_count); | 1527 | key_count); |
1488 | 1528 | ||
1529 | for (i = 0; i < key_count; i++) { | ||
1530 | struct mgmt_link_key_info *key = &cp->keys[i]; | ||
1531 | |||
1532 | if (key->addr.type != BDADDR_BREDR) | ||
1533 | return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, | ||
1534 | MGMT_STATUS_INVALID_PARAMS); | ||
1535 | } | ||
1536 | |||
1489 | hci_dev_lock(hdev); | 1537 | hci_dev_lock(hdev); |
1490 | 1538 | ||
1491 | hci_link_keys_clear(hdev); | 1539 | hci_link_keys_clear(hdev); |
@@ -1533,12 +1581,22 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, | |||
1533 | struct hci_conn *conn; | 1581 | struct hci_conn *conn; |
1534 | int err; | 1582 | int err; |
1535 | 1583 | ||
1536 | hci_dev_lock(hdev); | ||
1537 | |||
1538 | memset(&rp, 0, sizeof(rp)); | 1584 | memset(&rp, 0, sizeof(rp)); |
1539 | bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); | 1585 | bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); |
1540 | rp.addr.type = cp->addr.type; | 1586 | rp.addr.type = cp->addr.type; |
1541 | 1587 | ||
1588 | if (!bdaddr_type_is_valid(cp->addr.type)) | ||
1589 | return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, | ||
1590 | MGMT_STATUS_INVALID_PARAMS, | ||
1591 | &rp, sizeof(rp)); | ||
1592 | |||
1593 | if (cp->disconnect != 0x00 && cp->disconnect != 0x01) | ||
1594 | return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, | ||
1595 | MGMT_STATUS_INVALID_PARAMS, | ||
1596 | &rp, sizeof(rp)); | ||
1597 | |||
1598 | hci_dev_lock(hdev); | ||
1599 | |||
1542 | if (!hdev_is_powered(hdev)) { | 1600 | if (!hdev_is_powered(hdev)) { |
1543 | err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, | 1601 | err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, |
1544 | MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp)); | 1602 | MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp)); |
@@ -1596,6 +1654,7 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, | |||
1596 | u16 len) | 1654 | u16 len) |
1597 | { | 1655 | { |
1598 | struct mgmt_cp_disconnect *cp = data; | 1656 | struct mgmt_cp_disconnect *cp = data; |
1657 | struct mgmt_rp_disconnect rp; | ||
1599 | struct hci_cp_disconnect dc; | 1658 | struct hci_cp_disconnect dc; |
1600 | struct pending_cmd *cmd; | 1659 | struct pending_cmd *cmd; |
1601 | struct hci_conn *conn; | 1660 | struct hci_conn *conn; |
@@ -1603,17 +1662,26 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, | |||
1603 | 1662 | ||
1604 | BT_DBG(""); | 1663 | BT_DBG(""); |
1605 | 1664 | ||
1665 | memset(&rp, 0, sizeof(rp)); | ||
1666 | bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); | ||
1667 | rp.addr.type = cp->addr.type; | ||
1668 | |||
1669 | if (!bdaddr_type_is_valid(cp->addr.type)) | ||
1670 | return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT, | ||
1671 | MGMT_STATUS_INVALID_PARAMS, | ||
1672 | &rp, sizeof(rp)); | ||
1673 | |||
1606 | hci_dev_lock(hdev); | 1674 | hci_dev_lock(hdev); |
1607 | 1675 | ||
1608 | if (!test_bit(HCI_UP, &hdev->flags)) { | 1676 | if (!test_bit(HCI_UP, &hdev->flags)) { |
1609 | err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT, | 1677 | err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT, |
1610 | MGMT_STATUS_NOT_POWERED); | 1678 | MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp)); |
1611 | goto failed; | 1679 | goto failed; |
1612 | } | 1680 | } |
1613 | 1681 | ||
1614 | if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) { | 1682 | if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) { |
1615 | err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT, | 1683 | err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT, |
1616 | MGMT_STATUS_BUSY); | 1684 | MGMT_STATUS_BUSY, &rp, sizeof(rp)); |
1617 | goto failed; | 1685 | goto failed; |
1618 | } | 1686 | } |
1619 | 1687 | ||
@@ -1624,8 +1692,8 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, | |||
1624 | conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr); | 1692 | conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr); |
1625 | 1693 | ||
1626 | if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) { | 1694 | if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) { |
1627 | err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT, | 1695 | err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT, |
1628 | MGMT_STATUS_NOT_CONNECTED); | 1696 | MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp)); |
1629 | goto failed; | 1697 | goto failed; |
1630 | } | 1698 | } |
1631 | 1699 | ||
@@ -1903,11 +1971,20 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, | |||
1903 | 1971 | ||
1904 | BT_DBG(""); | 1972 | BT_DBG(""); |
1905 | 1973 | ||
1974 | memset(&rp, 0, sizeof(rp)); | ||
1975 | bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); | ||
1976 | rp.addr.type = cp->addr.type; | ||
1977 | |||
1978 | if (!bdaddr_type_is_valid(cp->addr.type)) | ||
1979 | return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE, | ||
1980 | MGMT_STATUS_INVALID_PARAMS, | ||
1981 | &rp, sizeof(rp)); | ||
1982 | |||
1906 | hci_dev_lock(hdev); | 1983 | hci_dev_lock(hdev); |
1907 | 1984 | ||
1908 | if (!hdev_is_powered(hdev)) { | 1985 | if (!hdev_is_powered(hdev)) { |
1909 | err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE, | 1986 | err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE, |
1910 | MGMT_STATUS_NOT_POWERED); | 1987 | MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp)); |
1911 | goto unlock; | 1988 | goto unlock; |
1912 | } | 1989 | } |
1913 | 1990 | ||
@@ -1924,10 +2001,6 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, | |||
1924 | conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, | 2001 | conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, |
1925 | cp->addr.type, sec_level, auth_type); | 2002 | cp->addr.type, sec_level, auth_type); |
1926 | 2003 | ||
1927 | memset(&rp, 0, sizeof(rp)); | ||
1928 | bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); | ||
1929 | rp.addr.type = cp->addr.type; | ||
1930 | |||
1931 | if (IS_ERR(conn)) { | 2004 | if (IS_ERR(conn)) { |
1932 | int status; | 2005 | int status; |
1933 | 2006 | ||
@@ -2254,24 +2327,16 @@ static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev, | |||
2254 | 2327 | ||
2255 | hci_dev_lock(hdev); | 2328 | hci_dev_lock(hdev); |
2256 | 2329 | ||
2257 | if (!hdev_is_powered(hdev)) { | ||
2258 | err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, | ||
2259 | MGMT_STATUS_NOT_POWERED, &cp->addr, | ||
2260 | sizeof(cp->addr)); | ||
2261 | goto unlock; | ||
2262 | } | ||
2263 | |||
2264 | err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash, | 2330 | err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash, |
2265 | cp->randomizer); | 2331 | cp->randomizer); |
2266 | if (err < 0) | 2332 | if (err < 0) |
2267 | status = MGMT_STATUS_FAILED; | 2333 | status = MGMT_STATUS_FAILED; |
2268 | else | 2334 | else |
2269 | status = 0; | 2335 | status = MGMT_STATUS_SUCCESS; |
2270 | 2336 | ||
2271 | err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status, | 2337 | err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status, |
2272 | &cp->addr, sizeof(cp->addr)); | 2338 | &cp->addr, sizeof(cp->addr)); |
2273 | 2339 | ||
2274 | unlock: | ||
2275 | hci_dev_unlock(hdev); | 2340 | hci_dev_unlock(hdev); |
2276 | return err; | 2341 | return err; |
2277 | } | 2342 | } |
@@ -2287,24 +2352,15 @@ static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev, | |||
2287 | 2352 | ||
2288 | hci_dev_lock(hdev); | 2353 | hci_dev_lock(hdev); |
2289 | 2354 | ||
2290 | if (!hdev_is_powered(hdev)) { | ||
2291 | err = cmd_complete(sk, hdev->id, | ||
2292 | MGMT_OP_REMOVE_REMOTE_OOB_DATA, | ||
2293 | MGMT_STATUS_NOT_POWERED, &cp->addr, | ||
2294 | sizeof(cp->addr)); | ||
2295 | goto unlock; | ||
2296 | } | ||
2297 | |||
2298 | err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr); | 2355 | err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr); |
2299 | if (err < 0) | 2356 | if (err < 0) |
2300 | status = MGMT_STATUS_INVALID_PARAMS; | 2357 | status = MGMT_STATUS_INVALID_PARAMS; |
2301 | else | 2358 | else |
2302 | status = 0; | 2359 | status = MGMT_STATUS_SUCCESS; |
2303 | 2360 | ||
2304 | err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA, | 2361 | err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA, |
2305 | status, &cp->addr, sizeof(cp->addr)); | 2362 | status, &cp->addr, sizeof(cp->addr)); |
2306 | 2363 | ||
2307 | unlock: | ||
2308 | hci_dev_unlock(hdev); | 2364 | hci_dev_unlock(hdev); |
2309 | return err; | 2365 | return err; |
2310 | } | 2366 | } |
@@ -2365,31 +2421,45 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, | |||
2365 | 2421 | ||
2366 | switch (hdev->discovery.type) { | 2422 | switch (hdev->discovery.type) { |
2367 | case DISCOV_TYPE_BREDR: | 2423 | case DISCOV_TYPE_BREDR: |
2368 | if (lmp_bredr_capable(hdev)) | 2424 | if (!lmp_bredr_capable(hdev)) { |
2369 | err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); | 2425 | err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, |
2370 | else | 2426 | MGMT_STATUS_NOT_SUPPORTED); |
2371 | err = -ENOTSUPP; | 2427 | mgmt_pending_remove(cmd); |
2428 | goto failed; | ||
2429 | } | ||
2430 | |||
2431 | err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR); | ||
2372 | break; | 2432 | break; |
2373 | 2433 | ||
2374 | case DISCOV_TYPE_LE: | 2434 | case DISCOV_TYPE_LE: |
2375 | if (lmp_host_le_capable(hdev)) | 2435 | if (!lmp_host_le_capable(hdev)) { |
2376 | err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, | 2436 | err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, |
2377 | LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY); | 2437 | MGMT_STATUS_NOT_SUPPORTED); |
2378 | else | 2438 | mgmt_pending_remove(cmd); |
2379 | err = -ENOTSUPP; | 2439 | goto failed; |
2440 | } | ||
2441 | |||
2442 | err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, | ||
2443 | LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY); | ||
2380 | break; | 2444 | break; |
2381 | 2445 | ||
2382 | case DISCOV_TYPE_INTERLEAVED: | 2446 | case DISCOV_TYPE_INTERLEAVED: |
2383 | if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev)) | 2447 | if (!lmp_host_le_capable(hdev) || !lmp_bredr_capable(hdev)) { |
2384 | err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, | 2448 | err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, |
2385 | LE_SCAN_WIN, | 2449 | MGMT_STATUS_NOT_SUPPORTED); |
2386 | LE_SCAN_TIMEOUT_BREDR_LE); | 2450 | mgmt_pending_remove(cmd); |
2387 | else | 2451 | goto failed; |
2388 | err = -ENOTSUPP; | 2452 | } |
2453 | |||
2454 | err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, LE_SCAN_WIN, | ||
2455 | LE_SCAN_TIMEOUT_BREDR_LE); | ||
2389 | break; | 2456 | break; |
2390 | 2457 | ||
2391 | default: | 2458 | default: |
2392 | err = -EINVAL; | 2459 | err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, |
2460 | MGMT_STATUS_INVALID_PARAMS); | ||
2461 | mgmt_pending_remove(cmd); | ||
2462 | goto failed; | ||
2393 | } | 2463 | } |
2394 | 2464 | ||
2395 | if (err < 0) | 2465 | if (err < 0) |
@@ -2510,7 +2580,8 @@ static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data, | |||
2510 | hci_inquiry_cache_update_resolve(hdev, e); | 2580 | hci_inquiry_cache_update_resolve(hdev, e); |
2511 | } | 2581 | } |
2512 | 2582 | ||
2513 | err = 0; | 2583 | err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr, |
2584 | sizeof(cp->addr)); | ||
2514 | 2585 | ||
2515 | failed: | 2586 | failed: |
2516 | hci_dev_unlock(hdev); | 2587 | hci_dev_unlock(hdev); |
@@ -2526,13 +2597,18 @@ static int block_device(struct sock *sk, struct hci_dev *hdev, void *data, | |||
2526 | 2597 | ||
2527 | BT_DBG("%s", hdev->name); | 2598 | BT_DBG("%s", hdev->name); |
2528 | 2599 | ||
2600 | if (!bdaddr_type_is_valid(cp->addr.type)) | ||
2601 | return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, | ||
2602 | MGMT_STATUS_INVALID_PARAMS, | ||
2603 | &cp->addr, sizeof(cp->addr)); | ||
2604 | |||
2529 | hci_dev_lock(hdev); | 2605 | hci_dev_lock(hdev); |
2530 | 2606 | ||
2531 | err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type); | 2607 | err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type); |
2532 | if (err < 0) | 2608 | if (err < 0) |
2533 | status = MGMT_STATUS_FAILED; | 2609 | status = MGMT_STATUS_FAILED; |
2534 | else | 2610 | else |
2535 | status = 0; | 2611 | status = MGMT_STATUS_SUCCESS; |
2536 | 2612 | ||
2537 | err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status, | 2613 | err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status, |
2538 | &cp->addr, sizeof(cp->addr)); | 2614 | &cp->addr, sizeof(cp->addr)); |
@@ -2551,13 +2627,18 @@ static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data, | |||
2551 | 2627 | ||
2552 | BT_DBG("%s", hdev->name); | 2628 | BT_DBG("%s", hdev->name); |
2553 | 2629 | ||
2630 | if (!bdaddr_type_is_valid(cp->addr.type)) | ||
2631 | return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, | ||
2632 | MGMT_STATUS_INVALID_PARAMS, | ||
2633 | &cp->addr, sizeof(cp->addr)); | ||
2634 | |||
2554 | hci_dev_lock(hdev); | 2635 | hci_dev_lock(hdev); |
2555 | 2636 | ||
2556 | err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type); | 2637 | err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type); |
2557 | if (err < 0) | 2638 | if (err < 0) |
2558 | status = MGMT_STATUS_INVALID_PARAMS; | 2639 | status = MGMT_STATUS_INVALID_PARAMS; |
2559 | else | 2640 | else |
2560 | status = 0; | 2641 | status = MGMT_STATUS_SUCCESS; |
2561 | 2642 | ||
2562 | err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status, | 2643 | err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status, |
2563 | &cp->addr, sizeof(cp->addr)); | 2644 | &cp->addr, sizeof(cp->addr)); |
@@ -2612,6 +2693,10 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, | |||
2612 | return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, | 2693 | return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, |
2613 | MGMT_STATUS_NOT_SUPPORTED); | 2694 | MGMT_STATUS_NOT_SUPPORTED); |
2614 | 2695 | ||
2696 | if (cp->val != 0x00 && cp->val != 0x01) | ||
2697 | return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, | ||
2698 | MGMT_STATUS_INVALID_PARAMS); | ||
2699 | |||
2615 | if (!hdev_is_powered(hdev)) | 2700 | if (!hdev_is_powered(hdev)) |
2616 | return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, | 2701 | return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, |
2617 | MGMT_STATUS_NOT_POWERED); | 2702 | MGMT_STATUS_NOT_POWERED); |
@@ -2659,12 +2744,23 @@ done: | |||
2659 | return err; | 2744 | return err; |
2660 | } | 2745 | } |
2661 | 2746 | ||
2747 | static bool ltk_is_valid(struct mgmt_ltk_info *key) | ||
2748 | { | ||
2749 | if (key->authenticated != 0x00 && key->authenticated != 0x01) | ||
2750 | return false; | ||
2751 | if (key->master != 0x00 && key->master != 0x01) | ||
2752 | return false; | ||
2753 | if (!bdaddr_type_is_le(key->addr.type)) | ||
2754 | return false; | ||
2755 | return true; | ||
2756 | } | ||
2757 | |||
2662 | static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, | 2758 | static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, |
2663 | void *cp_data, u16 len) | 2759 | void *cp_data, u16 len) |
2664 | { | 2760 | { |
2665 | struct mgmt_cp_load_long_term_keys *cp = cp_data; | 2761 | struct mgmt_cp_load_long_term_keys *cp = cp_data; |
2666 | u16 key_count, expected_len; | 2762 | u16 key_count, expected_len; |
2667 | int i; | 2763 | int i, err; |
2668 | 2764 | ||
2669 | key_count = __le16_to_cpu(cp->key_count); | 2765 | key_count = __le16_to_cpu(cp->key_count); |
2670 | 2766 | ||
@@ -2674,11 +2770,20 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, | |||
2674 | BT_ERR("load_keys: expected %u bytes, got %u bytes", | 2770 | BT_ERR("load_keys: expected %u bytes, got %u bytes", |
2675 | len, expected_len); | 2771 | len, expected_len); |
2676 | return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, | 2772 | return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, |
2677 | EINVAL); | 2773 | MGMT_STATUS_INVALID_PARAMS); |
2678 | } | 2774 | } |
2679 | 2775 | ||
2680 | BT_DBG("%s key_count %u", hdev->name, key_count); | 2776 | BT_DBG("%s key_count %u", hdev->name, key_count); |
2681 | 2777 | ||
2778 | for (i = 0; i < key_count; i++) { | ||
2779 | struct mgmt_ltk_info *key = &cp->keys[i]; | ||
2780 | |||
2781 | if (!ltk_is_valid(key)) | ||
2782 | return cmd_status(sk, hdev->id, | ||
2783 | MGMT_OP_LOAD_LONG_TERM_KEYS, | ||
2784 | MGMT_STATUS_INVALID_PARAMS); | ||
2785 | } | ||
2786 | |||
2682 | hci_dev_lock(hdev); | 2787 | hci_dev_lock(hdev); |
2683 | 2788 | ||
2684 | hci_smp_ltks_clear(hdev); | 2789 | hci_smp_ltks_clear(hdev); |
@@ -2698,9 +2803,12 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, | |||
2698 | key->enc_size, key->ediv, key->rand); | 2803 | key->enc_size, key->ediv, key->rand); |
2699 | } | 2804 | } |
2700 | 2805 | ||
2806 | err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0, | ||
2807 | NULL, 0); | ||
2808 | |||
2701 | hci_dev_unlock(hdev); | 2809 | hci_dev_unlock(hdev); |
2702 | 2810 | ||
2703 | return 0; | 2811 | return err; |
2704 | } | 2812 | } |
2705 | 2813 | ||
2706 | static const struct mgmt_handler { | 2814 | static const struct mgmt_handler { |
@@ -2946,7 +3054,13 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) | |||
2946 | } | 3054 | } |
2947 | } else { | 3055 | } else { |
2948 | u8 status = MGMT_STATUS_NOT_POWERED; | 3056 | u8 status = MGMT_STATUS_NOT_POWERED; |
3057 | u8 zero_cod[] = { 0, 0, 0 }; | ||
3058 | |||
2949 | mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); | 3059 | mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); |
3060 | |||
3061 | if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) | ||
3062 | mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, | ||
3063 | zero_cod, sizeof(zero_cod), NULL); | ||
2950 | } | 3064 | } |
2951 | 3065 | ||
2952 | err = new_settings(hdev, match.sk); | 3066 | err = new_settings(hdev, match.sk); |