Skip to content

Commit

Permalink
Bluetooth: MGMT: Add initial implementation of MGMT_OP_HCI_CMD_SYNC
Browse files Browse the repository at this point in the history
This adds the initial implementation of MGMT_OP_HCI_CMD_SYNC as
documented in mgmt-api (BlueZ tree):

Send HCI command and wait for event Command
===========================================

	Command Code:		0x005B
	Controller Index:	<controller id>
	Command Parameters:	Opcode (2 Octets)
				Event (1 Octet)
				Timeout (1 Octet)
				Parameter Length (2 Octets)
				Parameter (variable)
	Return Parameters:	Response (1-variable Octets)

	This command may be used to send a HCI command and wait for an
	(optional) event.

	The HCI command is specified by the Opcode, any arbitrary is supported
	including vendor commands, but contrary to the like of
	Raw/User channel it is run as an HCI command send by the kernel
	since it uses its command synchronization thus it is possible to wait
	for a specific event as a response.

	Setting event to 0x00 will cause the command to wait for either
	HCI Command Status or HCI Command Complete.

	Timeout is specified in seconds, setting it to 0 will cause the
	default timeout to be used.

	Possible errors:	Failed
				Invalid Parameters

Signed-off-by: Luiz Augusto von Dentz <[email protected]>
  • Loading branch information
Vudentz committed Nov 14, 2024
1 parent 27aabf2 commit 827af47
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 0 deletions.
10 changes: 10 additions & 0 deletions include/net/bluetooth/mgmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -878,6 +878,16 @@ struct mgmt_cp_mesh_send_cancel {
} __packed;
#define MGMT_MESH_SEND_CANCEL_SIZE 1

#define MGMT_OP_HCI_CMD_SYNC 0x005B
struct mgmt_cp_hci_cmd_sync {
__le16 opcode;
__u8 event;
__u8 timeout;
__le16 params_len;
__u8 params[];
} __packed;
#define MGMT_HCI_CMD_SYNC_SIZE 6

#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
__le16 opcode;
Expand Down
60 changes: 60 additions & 0 deletions net/bluetooth/mgmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ static const u16 mgmt_commands[] = {
MGMT_OP_MESH_READ_FEATURES,
MGMT_OP_MESH_SEND,
MGMT_OP_MESH_SEND_CANCEL,
MGMT_OP_HCI_CMD_SYNC,
};

static const u16 mgmt_events[] = {
Expand Down Expand Up @@ -2515,6 +2516,64 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
return err;
}

static int send_hci_cmd_sync(struct hci_dev *hdev, void *data)
{
struct mgmt_pending_cmd *cmd = data;
struct mgmt_cp_hci_cmd_sync *cp = cmd->param;
struct sk_buff *skb;

skb = __hci_cmd_sync_ev(hdev, le16_to_cpu(cp->opcode),
le16_to_cpu(cp->params_len), cp->params,
cp->event, cp->timeout ?
msecs_to_jiffies(cp->timeout * 1000) :
HCI_CMD_TIMEOUT);
if (IS_ERR(skb)) {
mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_HCI_CMD_SYNC,
mgmt_status(PTR_ERR(skb)));
goto done;
}

mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_HCI_CMD_SYNC, 0,
skb->data, skb->len);

kfree_skb(skb);

done:
mgmt_pending_free(cmd);

return 0;
}

static int mgmt_hci_cmd_sync(struct sock *sk, struct hci_dev *hdev,
void *data, u16 len)
{
struct mgmt_cp_hci_cmd_sync *cp = data;
struct mgmt_pending_cmd *cmd;
int err;

if (len < sizeof(*cp))
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_HCI_CMD_SYNC,
MGMT_STATUS_INVALID_PARAMS);

hci_dev_lock(hdev);
cmd = mgmt_pending_new(sk, MGMT_OP_HCI_CMD_SYNC, hdev, data, len);
if (!cmd)
err = -ENOMEM;
else
err = hci_cmd_sync_queue(hdev, send_hci_cmd_sync, cmd, NULL);

if (err < 0) {
err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_HCI_CMD_SYNC,
MGMT_STATUS_FAILED);

if (cmd)
mgmt_pending_free(cmd);
}

hci_dev_unlock(hdev);
return err;
}

/* This is a helper function to test for pending mgmt commands that can
* cause CoD or EIR HCI commands. We can only allow one such pending
* mgmt command at a time since otherwise we cannot easily track what
Expand Down Expand Up @@ -9371,6 +9430,7 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
{ mesh_send, MGMT_MESH_SEND_SIZE,
HCI_MGMT_VAR_LEN },
{ mesh_send_cancel, MGMT_MESH_SEND_CANCEL_SIZE },
{ mgmt_hci_cmd_sync, MGMT_HCI_CMD_SYNC_SIZE, HCI_MGMT_VAR_LEN },
};

void mgmt_index_added(struct hci_dev *hdev)
Expand Down

0 comments on commit 827af47

Please sign in to comment.