Commit 161510cc authored by Luiz Augusto von Dentz's avatar Luiz Augusto von Dentz Committed by Marcel Holtmann

Bluetooth: hci_sync: Make use of hci_cmd_sync_queue set 1

This make use of hci_cmd_sync_queue for the following MGMT commands:

Set Device Class
Set Device ID
Add UUID
Remove UUID

tools/mgmt-tester -s "Set Device Class"

Test Summary
------------
Set Device Class - Success 1                         Passed
Set Device Class - Success 2                         Passed
Set Device Class - Invalid parameters 1              Passed
Total: 3, Passed: 3 (100.0%), Failed: 0, Not Run: 0
Overall execution time: 0.0599 seconds

tools/mgmt-tester -s "Set Device ID"

Test Summary
------------
Set Device ID - Success 1                            Passed
Set Device ID - Success 2                            Passed
Set Device ID - Disable                              Passed
Set Device ID - Power off and Power on               Passed
Set Device ID - SSP off and Power on                 Passed
Set Device ID - Invalid Parameter                    Passed
Total: 6, Passed: 6 (100.0%), Failed: 0, Not Run: 0
Overall execution time: 0.107 seconds

tools/mgmt-tester -s "Add UUID"

Test Summary
------------
Add UUID - UUID-16 1                                 Passed
Add UUID - UUID-16 multiple 1                        Passed
Add UUID - UUID-16 partial 1                         Passed
Add UUID - UUID-32 1                                 Passed
Add UUID - UUID-32 multiple 1                        Passed
Add UUID - UUID-32 partial 1                         Passed
Add UUID - UUID-128 1                                Passed
Add UUID - UUID-128 multiple 1                       Passed
Add UUID - UUID-128 partial 1                        Passed
Add UUID - UUID mix                                  Passed
Total: 10, Passed: 10 (100.0%), Failed: 0, Not Run: 0
Overall execution time: 0.198 seconds

tools/mgmt-tester -s "Remove UUID"

Test Summary
------------
Remove UUID - Success 1                              Passed
Remove UUID - All UUID - Success 2                   Passed
Remove UUID - Power Off - Success 3                  Passed
Remove UUID - Power Off and On - Success 4           Passed
Remove UUID - Not Exist - Invalid Params 1           Passed
Total: 5, Passed: 5 (100.0%), Failed: 0, Not Run: 0
Overall execution time: 0.0908 seconds
Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 6a98e383
......@@ -40,3 +40,6 @@ void hci_cmd_sync_clear(struct hci_dev *hdev);
int hci_cmd_sync_queue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
void *data, hci_cmd_sync_work_destroy_t destroy);
int hci_update_eir_sync(struct hci_dev *hdev);
int hci_update_class_sync(struct hci_dev *hdev);
......@@ -97,8 +97,8 @@ int hci_req_run_skb(struct hci_request *req, hci_req_complete_skb_t complete)
return req_run(req, NULL, complete);
}
static void hci_req_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode,
struct sk_buff *skb)
void hci_req_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode,
struct sk_buff *skb)
{
bt_dev_dbg(hdev, "result 0x%2.2x", result);
......
......@@ -22,6 +22,10 @@
#include <asm/unaligned.h>
#define HCI_REQ_DONE 0
#define HCI_REQ_PEND 1
#define HCI_REQ_CANCELED 2
#define hci_req_sync_lock(hdev) mutex_lock(&hdev->req_lock)
#define hci_req_sync_unlock(hdev) mutex_unlock(&hdev->req_lock)
......@@ -44,6 +48,8 @@ void hci_req_purge(struct hci_request *req);
bool hci_req_status_pend(struct hci_dev *hdev);
int hci_req_run(struct hci_request *req, hci_req_complete_t complete);
int hci_req_run_skb(struct hci_request *req, hci_req_complete_skb_t complete);
void hci_req_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode,
struct sk_buff *skb);
void hci_req_add(struct hci_request *req, u16 opcode, u32 plen,
const void *param);
void hci_req_add_ev(struct hci_request *req, u16 opcode, u32 plen,
......
......@@ -11,6 +11,7 @@
#include "hci_request.h"
#include "smp.h"
#include "eir.h"
static void hci_cmd_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode,
struct sk_buff *skb)
......@@ -328,3 +329,74 @@ int hci_cmd_sync_queue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
return 0;
}
EXPORT_SYMBOL(hci_cmd_sync_queue);
int hci_update_eir_sync(struct hci_dev *hdev)
{
struct hci_cp_write_eir cp;
bt_dev_dbg(hdev, "");
if (!hdev_is_powered(hdev))
return 0;
if (!lmp_ext_inq_capable(hdev))
return 0;
if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
return 0;
if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE))
return 0;
memset(&cp, 0, sizeof(cp));
eir_create(hdev, cp.data);
if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
return 0;
memcpy(hdev->eir, cp.data, sizeof(cp.data));
return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp,
HCI_CMD_TIMEOUT);
}
static u8 get_service_classes(struct hci_dev *hdev)
{
struct bt_uuid *uuid;
u8 val = 0;
list_for_each_entry(uuid, &hdev->uuids, list)
val |= uuid->svc_hint;
return val;
}
int hci_update_class_sync(struct hci_dev *hdev)
{
u8 cod[3];
bt_dev_dbg(hdev, "");
if (!hdev_is_powered(hdev))
return 0;
if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
return 0;
if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE))
return 0;
cod[0] = hdev->minor_class;
cod[1] = hdev->major_class;
cod[2] = get_service_classes(hdev);
if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
cod[1] |= 0x20;
if (memcmp(cod, hdev->dev_class, 3) == 0)
return 0;
return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_CLASS_OF_DEV,
sizeof(cod), cod, HCI_CMD_TIMEOUT);
}
......@@ -276,10 +276,39 @@ static const u8 mgmt_status_table[] = {
MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
};
static u8 mgmt_status(u8 hci_status)
static u8 mgmt_errno_status(int err)
{
if (hci_status < ARRAY_SIZE(mgmt_status_table))
return mgmt_status_table[hci_status];
switch (err) {
case 0:
return MGMT_STATUS_SUCCESS;
case -EPERM:
return MGMT_STATUS_REJECTED;
case -EINVAL:
return MGMT_STATUS_INVALID_PARAMS;
case -EOPNOTSUPP:
return MGMT_STATUS_NOT_SUPPORTED;
case -EBUSY:
return MGMT_STATUS_BUSY;
case -ETIMEDOUT:
return MGMT_STATUS_AUTH_FAILED;
case -ENOMEM:
return MGMT_STATUS_NO_RESOURCES;
case -EISCONN:
return MGMT_STATUS_ALREADY_CONNECTED;
case -ENOTCONN:
return MGMT_STATUS_DISCONNECTED;
}
return MGMT_STATUS_FAILED;
}
static u8 mgmt_status(int err)
{
if (err < 0)
return mgmt_errno_status(err);
if (err < ARRAY_SIZE(mgmt_status_table))
return mgmt_status_table[err];
return MGMT_STATUS_FAILED;
}
......@@ -951,25 +980,23 @@ bool mgmt_get_connectable(struct hci_dev *hdev)
return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
}
static int service_cache_sync(struct hci_dev *hdev, void *data)
{
hci_update_eir_sync(hdev);
hci_update_class_sync(hdev);
return 0;
}
static void service_cache_off(struct work_struct *work)
{
struct hci_dev *hdev = container_of(work, struct hci_dev,
service_cache.work);
struct hci_request req;
if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
return;
hci_req_init(&req, hdev);
hci_dev_lock(hdev);
__hci_req_update_eir(&req);
__hci_req_update_class(&req);
hci_dev_unlock(hdev);
hci_req_run(&req, NULL);
hci_cmd_sync_queue(hdev, service_cache_sync, NULL, NULL);
}
static void rpa_expired(struct work_struct *work)
......@@ -2075,37 +2102,33 @@ static u8 get_uuid_size(const u8 *uuid)
return 16;
}
static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
static void mgmt_class_complete(struct hci_dev *hdev, void *data, int err)
{
struct mgmt_pending_cmd *cmd;
hci_dev_lock(hdev);
struct mgmt_pending_cmd *cmd = data;
cmd = pending_find(mgmt_op, hdev);
if (!cmd)
goto unlock;
bt_dev_dbg(hdev, "err %d", err);
mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
mgmt_status(status), hdev->dev_class, 3);
mgmt_status(err), hdev->dev_class, 3);
mgmt_pending_remove(cmd);
unlock:
hci_dev_unlock(hdev);
mgmt_pending_free(cmd);
}
static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
static int add_uuid_sync(struct hci_dev *hdev, void *data)
{
bt_dev_dbg(hdev, "status 0x%02x", status);
int err;
mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
err = hci_update_class_sync(hdev);
if (err)
return err;
return hci_update_eir_sync(hdev);
}
static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
{
struct mgmt_cp_add_uuid *cp = data;
struct mgmt_pending_cmd *cmd;
struct hci_request req;
struct bt_uuid *uuid;
int err;
......@@ -2131,28 +2154,17 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
list_add_tail(&uuid->list, &hdev->uuids);
hci_req_init(&req, hdev);
__hci_req_update_class(&req);
__hci_req_update_eir(&req);
err = hci_req_run(&req, add_uuid_complete);
if (err < 0) {
if (err != -ENODATA)
goto failed;
err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
hdev->dev_class, 3);
goto failed;
}
cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
cmd = mgmt_pending_new(sk, MGMT_OP_ADD_UUID, hdev, data, len);
if (!cmd) {
err = -ENOMEM;
goto failed;
}
err = 0;
err = hci_cmd_sync_queue(hdev, add_uuid_sync, cmd, mgmt_class_complete);
if (err < 0) {
mgmt_pending_free(cmd);
goto failed;
}
failed:
hci_dev_unlock(hdev);
......@@ -2173,11 +2185,15 @@ static bool enable_service_cache(struct hci_dev *hdev)
return false;
}
static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
static int remove_uuid_sync(struct hci_dev *hdev, void *data)
{
bt_dev_dbg(hdev, "status 0x%02x", status);
int err;
mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
err = hci_update_class_sync(hdev);
if (err)
return err;
return hci_update_eir_sync(hdev);
}
static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
......@@ -2187,7 +2203,6 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
struct mgmt_pending_cmd *cmd;
struct bt_uuid *match, *tmp;
u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
struct hci_request req;
int err, found;
bt_dev_dbg(hdev, "sock %p", sk);
......@@ -2231,39 +2246,35 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
}
update_class:
hci_req_init(&req, hdev);
__hci_req_update_class(&req);
__hci_req_update_eir(&req);
err = hci_req_run(&req, remove_uuid_complete);
if (err < 0) {
if (err != -ENODATA)
goto unlock;
err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
hdev->dev_class, 3);
goto unlock;
}
cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
cmd = mgmt_pending_new(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
if (!cmd) {
err = -ENOMEM;
goto unlock;
}
err = 0;
err = hci_cmd_sync_queue(hdev, remove_uuid_sync, cmd,
mgmt_class_complete);
if (err < 0)
mgmt_pending_free(cmd);
unlock:
hci_dev_unlock(hdev);
return err;
}
static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
static int set_class_sync(struct hci_dev *hdev, void *data)
{
bt_dev_dbg(hdev, "status 0x%02x", status);
int err = 0;
if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
cancel_delayed_work_sync(&hdev->service_cache);
err = hci_update_eir_sync(hdev);
}
if (err)
return err;
mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
return hci_update_class_sync(hdev);
}
static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
......@@ -2271,7 +2282,6 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
{
struct mgmt_cp_set_dev_class *cp = data;
struct mgmt_pending_cmd *cmd;
struct hci_request req;
int err;
bt_dev_dbg(hdev, "sock %p", sk);
......@@ -2303,34 +2313,16 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
goto unlock;
}
hci_req_init(&req, hdev);
if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
hci_dev_unlock(hdev);
cancel_delayed_work_sync(&hdev->service_cache);
hci_dev_lock(hdev);
__hci_req_update_eir(&req);
}
__hci_req_update_class(&req);
err = hci_req_run(&req, set_class_complete);
if (err < 0) {
if (err != -ENODATA)
goto unlock;
err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
hdev->dev_class, 3);
goto unlock;
}
cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
cmd = mgmt_pending_new(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
if (!cmd) {
err = -ENOMEM;
goto unlock;
}
err = 0;
err = hci_cmd_sync_queue(hdev, set_class_sync, cmd,
mgmt_class_complete);
if (err < 0)
mgmt_pending_free(cmd);
unlock:
hci_dev_unlock(hdev);
......@@ -5494,11 +5486,15 @@ static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
return err;
}
static int set_device_id_sync(struct hci_dev *hdev, void *data)
{
return hci_update_eir_sync(hdev);
}
static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
u16 len)
{
struct mgmt_cp_set_device_id *cp = data;
struct hci_request req;
int err;
__u16 source;
......@@ -5520,9 +5516,7 @@ static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
NULL, 0);
hci_req_init(&req, hdev);
__hci_req_update_eir(&req);
hci_req_run(&req, NULL);
hci_cmd_sync_queue(hdev, set_device_id_sync, NULL, NULL);
hci_dev_unlock(hdev);
......
......@@ -227,7 +227,7 @@ void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
}
}
struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode,
struct hci_dev *hdev,
void *data, u16 len)
{
......@@ -251,6 +251,19 @@ struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
cmd->sk = sk;
sock_hold(sk);
return cmd;
}
struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
struct hci_dev *hdev,
void *data, u16 len)
{
struct mgmt_pending_cmd *cmd;
cmd = mgmt_pending_new(sk, opcode, hdev, data, len);
if (!cmd)
return NULL;
list_add(&cmd->list, &hdev->mgmt_pending);
return cmd;
......
......@@ -49,5 +49,8 @@ void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
struct hci_dev *hdev,
void *data, u16 len);
struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode,
struct hci_dev *hdev,
void *data, u16 len);
void mgmt_pending_free(struct mgmt_pending_cmd *cmd);
void mgmt_pending_remove(struct mgmt_pending_cmd *cmd);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment