|
@@ -4006,6 +4006,79 @@ unlock:
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
|
|
|
+ void *data, u16 len)
|
|
|
+{
|
|
|
+ struct mgmt_mode *cp = data;
|
|
|
+ struct pending_cmd *cmd;
|
|
|
+ u8 status;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ BT_DBG("request for %s", hdev->name);
|
|
|
+
|
|
|
+ status = mgmt_bredr_support(hdev);
|
|
|
+ if (status)
|
|
|
+ return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
|
|
|
+ status);
|
|
|
+
|
|
|
+ if (!lmp_sc_capable(hdev))
|
|
|
+ return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
|
|
|
+ MGMT_STATUS_NOT_SUPPORTED);
|
|
|
+
|
|
|
+ if (cp->val != 0x00 && cp->val != 0x01)
|
|
|
+ return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
|
|
|
+ MGMT_STATUS_INVALID_PARAMS);
|
|
|
+
|
|
|
+ hci_dev_lock(hdev);
|
|
|
+
|
|
|
+ if (!hdev_is_powered(hdev)) {
|
|
|
+ bool changed;
|
|
|
+
|
|
|
+ if (cp->val)
|
|
|
+ changed = !test_and_set_bit(HCI_SC_ENABLED,
|
|
|
+ &hdev->dev_flags);
|
|
|
+ else
|
|
|
+ changed = test_and_clear_bit(HCI_SC_ENABLED,
|
|
|
+ &hdev->dev_flags);
|
|
|
+
|
|
|
+ err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
|
|
|
+ if (err < 0)
|
|
|
+ goto failed;
|
|
|
+
|
|
|
+ if (changed)
|
|
|
+ err = new_settings(hdev, sk);
|
|
|
+
|
|
|
+ goto failed;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mgmt_pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
|
|
|
+ err = cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
|
|
|
+ MGMT_STATUS_BUSY);
|
|
|
+ goto failed;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!!cp->val == test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) {
|
|
|
+ err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
|
|
|
+ goto failed;
|
|
|
+ }
|
|
|
+
|
|
|
+ cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
|
|
|
+ if (!cmd) {
|
|
|
+ err = -ENOMEM;
|
|
|
+ goto failed;
|
|
|
+ }
|
|
|
+
|
|
|
+ err = hci_send_cmd(hdev, HCI_OP_WRITE_SC_SUPPORT, 1, &cp->val);
|
|
|
+ if (err < 0) {
|
|
|
+ mgmt_pending_remove(cmd);
|
|
|
+ goto failed;
|
|
|
+ }
|
|
|
+
|
|
|
+failed:
|
|
|
+ hci_dev_unlock(hdev);
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
static bool ltk_is_valid(struct mgmt_ltk_info *key)
|
|
|
{
|
|
|
if (key->authenticated != 0x00 && key->authenticated != 0x01)
|
|
@@ -4134,6 +4207,7 @@ static const struct mgmt_handler {
|
|
|
{ set_bredr, false, MGMT_SETTING_SIZE },
|
|
|
{ set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
|
|
|
{ set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
|
|
|
+ { set_secure_conn, false, MGMT_SETTING_SIZE },
|
|
|
};
|
|
|
|
|
|
|
|
@@ -4917,6 +4991,38 @@ void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
|
|
|
hci_req_run(&req, NULL);
|
|
|
}
|
|
|
|
|
|
+void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
|
|
|
+{
|
|
|
+ struct cmd_lookup match = { NULL, hdev };
|
|
|
+ bool changed = false;
|
|
|
+
|
|
|
+ if (status) {
|
|
|
+ u8 mgmt_err = mgmt_status(status);
|
|
|
+
|
|
|
+ if (enable && test_and_clear_bit(HCI_SC_ENABLED,
|
|
|
+ &hdev->dev_flags))
|
|
|
+ new_settings(hdev, NULL);
|
|
|
+
|
|
|
+ mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
|
|
|
+ cmd_status_rsp, &mgmt_err);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (enable)
|
|
|
+ changed = !test_and_set_bit(HCI_SC_ENABLED, &hdev->dev_flags);
|
|
|
+ else
|
|
|
+ changed = test_and_clear_bit(HCI_SC_ENABLED, &hdev->dev_flags);
|
|
|
+
|
|
|
+ mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
|
|
|
+ settings_rsp, &match);
|
|
|
+
|
|
|
+ if (changed)
|
|
|
+ new_settings(hdev, match.sk);
|
|
|
+
|
|
|
+ if (match.sk)
|
|
|
+ sock_put(match.sk);
|
|
|
+}
|
|
|
+
|
|
|
static void sk_lookup(struct pending_cmd *cmd, void *data)
|
|
|
{
|
|
|
struct cmd_lookup *match = data;
|