mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-04-06 22:44:40 +00:00
Bluetooth: Add support for sending MGMT commands and events to monitor
This adds support for tracing all management commands and events via the monitor interface. Signed-off-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
parent
249fa1699f
commit
38ceaa00d0
4 changed files with 162 additions and 3 deletions
|
@ -1406,6 +1406,9 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb);
|
||||||
void hci_send_to_channel(unsigned short channel, struct sk_buff *skb,
|
void hci_send_to_channel(unsigned short channel, struct sk_buff *skb,
|
||||||
int flag, struct sock *skip_sk);
|
int flag, struct sock *skip_sk);
|
||||||
void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb);
|
void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb);
|
||||||
|
void hci_send_monitor_ctrl_event(struct hci_dev *hdev, u16 event,
|
||||||
|
void *data, u16 data_len, ktime_t tstamp,
|
||||||
|
int flag, struct sock *skip_sk);
|
||||||
|
|
||||||
void hci_sock_dev_event(struct hci_dev *hdev, int event);
|
void hci_sock_dev_event(struct hci_dev *hdev, int event);
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,8 @@ struct hci_mon_hdr {
|
||||||
#define HCI_MON_USER_LOGGING 13
|
#define HCI_MON_USER_LOGGING 13
|
||||||
#define HCI_MON_CTRL_OPEN 14
|
#define HCI_MON_CTRL_OPEN 14
|
||||||
#define HCI_MON_CTRL_CLOSE 15
|
#define HCI_MON_CTRL_CLOSE 15
|
||||||
|
#define HCI_MON_CTRL_COMMAND 16
|
||||||
|
#define HCI_MON_CTRL_EVENT 17
|
||||||
|
|
||||||
struct hci_mon_new_index {
|
struct hci_mon_new_index {
|
||||||
__u8 type;
|
__u8 type;
|
||||||
|
|
|
@ -315,6 +315,60 @@ void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
kfree_skb(skb_copy);
|
kfree_skb(skb_copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hci_send_monitor_ctrl_event(struct hci_dev *hdev, u16 event,
|
||||||
|
void *data, u16 data_len, ktime_t tstamp,
|
||||||
|
int flag, struct sock *skip_sk)
|
||||||
|
{
|
||||||
|
struct sock *sk;
|
||||||
|
__le16 index;
|
||||||
|
|
||||||
|
if (hdev)
|
||||||
|
index = cpu_to_le16(hdev->id);
|
||||||
|
else
|
||||||
|
index = cpu_to_le16(MGMT_INDEX_NONE);
|
||||||
|
|
||||||
|
read_lock(&hci_sk_list.lock);
|
||||||
|
|
||||||
|
sk_for_each(sk, &hci_sk_list.head) {
|
||||||
|
struct hci_mon_hdr *hdr;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
|
||||||
|
if (hci_pi(sk)->channel != HCI_CHANNEL_CONTROL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Ignore socket without the flag set */
|
||||||
|
if (!hci_sock_test_flag(sk, flag))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Skip the original socket */
|
||||||
|
if (sk == skip_sk)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
skb = bt_skb_alloc(6 + data_len, GFP_ATOMIC);
|
||||||
|
if (!skb)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
put_unaligned_le32(hci_pi(sk)->cookie, skb_put(skb, 4));
|
||||||
|
put_unaligned_le16(event, skb_put(skb, 2));
|
||||||
|
|
||||||
|
if (data)
|
||||||
|
memcpy(skb_put(skb, data_len), data, data_len);
|
||||||
|
|
||||||
|
skb->tstamp = tstamp;
|
||||||
|
|
||||||
|
hdr = (void *)skb_push(skb, HCI_MON_HDR_SIZE);
|
||||||
|
hdr->opcode = cpu_to_le16(HCI_MON_CTRL_EVENT);
|
||||||
|
hdr->index = index;
|
||||||
|
hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE);
|
||||||
|
|
||||||
|
hci_send_to_channel(HCI_CHANNEL_MONITOR, skb,
|
||||||
|
HCI_SOCK_TRUSTED, NULL);
|
||||||
|
kfree_skb(skb);
|
||||||
|
}
|
||||||
|
|
||||||
|
read_unlock(&hci_sk_list.lock);
|
||||||
|
}
|
||||||
|
|
||||||
static struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event)
|
static struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event)
|
||||||
{
|
{
|
||||||
struct hci_mon_hdr *hdr;
|
struct hci_mon_hdr *hdr;
|
||||||
|
@ -447,6 +501,33 @@ static struct sk_buff *create_monitor_ctrl_close(struct sock *sk)
|
||||||
return skb;
|
return skb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct sk_buff *create_monitor_ctrl_command(struct sock *sk, u16 index,
|
||||||
|
u16 opcode, u16 len,
|
||||||
|
const void *buf)
|
||||||
|
{
|
||||||
|
struct hci_mon_hdr *hdr;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
|
||||||
|
skb = bt_skb_alloc(6 + len, GFP_ATOMIC);
|
||||||
|
if (!skb)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
put_unaligned_le32(hci_pi(sk)->cookie, skb_put(skb, 4));
|
||||||
|
put_unaligned_le16(opcode, skb_put(skb, 2));
|
||||||
|
|
||||||
|
if (buf)
|
||||||
|
memcpy(skb_put(skb, len), buf, len);
|
||||||
|
|
||||||
|
__net_timestamp(skb);
|
||||||
|
|
||||||
|
hdr = (void *)skb_push(skb, HCI_MON_HDR_SIZE);
|
||||||
|
hdr->opcode = cpu_to_le16(HCI_MON_CTRL_COMMAND);
|
||||||
|
hdr->index = cpu_to_le16(index);
|
||||||
|
hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE);
|
||||||
|
|
||||||
|
return skb;
|
||||||
|
}
|
||||||
|
|
||||||
static void __printf(2, 3)
|
static void __printf(2, 3)
|
||||||
send_monitor_note(struct sock *sk, const char *fmt, ...)
|
send_monitor_note(struct sock *sk, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
|
@ -1257,6 +1338,19 @@ static int hci_mgmt_cmd(struct hci_mgmt_chan *chan, struct sock *sk,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (chan->channel == HCI_CHANNEL_CONTROL) {
|
||||||
|
struct sk_buff *skb;
|
||||||
|
|
||||||
|
/* Send event to monitor */
|
||||||
|
skb = create_monitor_ctrl_command(sk, index, opcode, len,
|
||||||
|
buf + sizeof(*hdr));
|
||||||
|
if (skb) {
|
||||||
|
hci_send_to_channel(HCI_CHANNEL_MONITOR, skb,
|
||||||
|
HCI_SOCK_TRUSTED, NULL);
|
||||||
|
kfree_skb(skb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (opcode >= chan->handler_count ||
|
if (opcode >= chan->handler_count ||
|
||||||
chan->handlers[opcode].func == NULL) {
|
chan->handlers[opcode].func == NULL) {
|
||||||
BT_DBG("Unknown op %u", opcode);
|
BT_DBG("Unknown op %u", opcode);
|
||||||
|
|
|
@ -21,12 +21,41 @@
|
||||||
SOFTWARE IS DISCLAIMED.
|
SOFTWARE IS DISCLAIMED.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <asm/unaligned.h>
|
||||||
|
|
||||||
#include <net/bluetooth/bluetooth.h>
|
#include <net/bluetooth/bluetooth.h>
|
||||||
#include <net/bluetooth/hci_core.h>
|
#include <net/bluetooth/hci_core.h>
|
||||||
|
#include <net/bluetooth/hci_mon.h>
|
||||||
#include <net/bluetooth/mgmt.h>
|
#include <net/bluetooth/mgmt.h>
|
||||||
|
|
||||||
#include "mgmt_util.h"
|
#include "mgmt_util.h"
|
||||||
|
|
||||||
|
static struct sk_buff *create_monitor_ctrl_event(__le16 index, u32 cookie,
|
||||||
|
u16 opcode, u16 len, void *buf)
|
||||||
|
{
|
||||||
|
struct hci_mon_hdr *hdr;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
|
||||||
|
skb = bt_skb_alloc(6 + len, GFP_ATOMIC);
|
||||||
|
if (!skb)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
put_unaligned_le32(cookie, skb_put(skb, 4));
|
||||||
|
put_unaligned_le16(opcode, skb_put(skb, 2));
|
||||||
|
|
||||||
|
if (buf)
|
||||||
|
memcpy(skb_put(skb, len), buf, len);
|
||||||
|
|
||||||
|
__net_timestamp(skb);
|
||||||
|
|
||||||
|
hdr = (void *)skb_push(skb, HCI_MON_HDR_SIZE);
|
||||||
|
hdr->opcode = cpu_to_le16(HCI_MON_CTRL_EVENT);
|
||||||
|
hdr->index = index;
|
||||||
|
hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE);
|
||||||
|
|
||||||
|
return skb;
|
||||||
|
}
|
||||||
|
|
||||||
int mgmt_send_event(u16 event, struct hci_dev *hdev, unsigned short channel,
|
int mgmt_send_event(u16 event, struct hci_dev *hdev, unsigned short channel,
|
||||||
void *data, u16 data_len, int flag, struct sock *skip_sk)
|
void *data, u16 data_len, int flag, struct sock *skip_sk)
|
||||||
{
|
{
|
||||||
|
@ -52,14 +81,18 @@ int mgmt_send_event(u16 event, struct hci_dev *hdev, unsigned short channel,
|
||||||
__net_timestamp(skb);
|
__net_timestamp(skb);
|
||||||
|
|
||||||
hci_send_to_channel(channel, skb, flag, skip_sk);
|
hci_send_to_channel(channel, skb, flag, skip_sk);
|
||||||
kfree_skb(skb);
|
|
||||||
|
|
||||||
|
if (channel == HCI_CHANNEL_CONTROL)
|
||||||
|
hci_send_monitor_ctrl_event(hdev, event, data, data_len,
|
||||||
|
skb_get_ktime(skb), flag, skip_sk);
|
||||||
|
|
||||||
|
kfree_skb(skb);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mgmt_cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
|
int mgmt_cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
|
||||||
{
|
{
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb, *mskb;
|
||||||
struct mgmt_hdr *hdr;
|
struct mgmt_hdr *hdr;
|
||||||
struct mgmt_ev_cmd_status *ev;
|
struct mgmt_ev_cmd_status *ev;
|
||||||
int err;
|
int err;
|
||||||
|
@ -80,17 +113,30 @@ int mgmt_cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
|
||||||
ev->status = status;
|
ev->status = status;
|
||||||
ev->opcode = cpu_to_le16(cmd);
|
ev->opcode = cpu_to_le16(cmd);
|
||||||
|
|
||||||
|
mskb = create_monitor_ctrl_event(hdr->index, hci_sock_get_cookie(sk),
|
||||||
|
MGMT_EV_CMD_STATUS, sizeof(*ev), ev);
|
||||||
|
if (mskb)
|
||||||
|
skb->tstamp = mskb->tstamp;
|
||||||
|
else
|
||||||
|
__net_timestamp(skb);
|
||||||
|
|
||||||
err = sock_queue_rcv_skb(sk, skb);
|
err = sock_queue_rcv_skb(sk, skb);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
|
|
||||||
|
if (mskb) {
|
||||||
|
hci_send_to_channel(HCI_CHANNEL_MONITOR, mskb,
|
||||||
|
HCI_SOCK_TRUSTED, NULL);
|
||||||
|
kfree_skb(mskb);
|
||||||
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
|
int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
|
||||||
void *rp, size_t rp_len)
|
void *rp, size_t rp_len)
|
||||||
{
|
{
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb, *mskb;
|
||||||
struct mgmt_hdr *hdr;
|
struct mgmt_hdr *hdr;
|
||||||
struct mgmt_ev_cmd_complete *ev;
|
struct mgmt_ev_cmd_complete *ev;
|
||||||
int err;
|
int err;
|
||||||
|
@ -114,10 +160,24 @@ int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
|
||||||
if (rp)
|
if (rp)
|
||||||
memcpy(ev->data, rp, rp_len);
|
memcpy(ev->data, rp, rp_len);
|
||||||
|
|
||||||
|
mskb = create_monitor_ctrl_event(hdr->index, hci_sock_get_cookie(sk),
|
||||||
|
MGMT_EV_CMD_COMPLETE,
|
||||||
|
sizeof(*ev) + rp_len, ev);
|
||||||
|
if (mskb)
|
||||||
|
skb->tstamp = mskb->tstamp;
|
||||||
|
else
|
||||||
|
__net_timestamp(skb);
|
||||||
|
|
||||||
err = sock_queue_rcv_skb(sk, skb);
|
err = sock_queue_rcv_skb(sk, skb);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
|
|
||||||
|
if (mskb) {
|
||||||
|
hci_send_to_channel(HCI_CHANNEL_MONITOR, mskb,
|
||||||
|
HCI_SOCK_TRUSTED, NULL);
|
||||||
|
kfree_skb(mskb);
|
||||||
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue