mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-27 14:04:47 -04:00
Bluetooth: hci_event: Introduce handle_ev_vendor() for HCI_EV_VENDOR
Introduce the hook to solve issues below:
msft_vendor_evt(), the current handler for all VSEs, is unsuitable
since:
- many VSEs are not MSFT ones;
- it always corrupts the non-MSFT VSEs by calling skb_pull_data()
once the MSFT extension is enabled.
Several issues are caused by many transport drivers pre-processing
VSEs in their RX path, often an IRQ-disabled atomic context. Take
the two typical cases below as examples:
Case 1:
// no btmon log, no way to reach userspace
Step 1: handle and free @original_skb directly
Case 2:
// hurts performance and consumes GFP_ATOMIC memory
Step 1: cloned_skb = skb_clone(original_skb, GFP_ATOMIC);
// the VSE is handled here
Step 2: handle and free @cloned_skb
Step 3: hci_recv_frame(hdev, original_skb);
// already handled, but re-enters the stack's event-handling path
Step 4: hci_event_packet(hdev, original_skb);
Fix by introducing the hook with usage:
1) the transport driver registers the hook for VSEs of interest;
2) the stack calls it in process context, handling the VSE like any
other event:
- if interested, handle the VSE - no need to free it - and
return true;
- otherwise return false.
Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
committed by
Luiz Augusto von Dentz
parent
73c4c035ae
commit
0bd606b31d
@@ -646,6 +646,8 @@ struct hci_dev {
|
||||
int (*setup)(struct hci_dev *hdev);
|
||||
int (*shutdown)(struct hci_dev *hdev);
|
||||
int (*send)(struct hci_dev *hdev, struct sk_buff *skb);
|
||||
/* Handle HCI_EV_VENDOR; return true if handled, false otherwise */
|
||||
bool (*handle_ev_vendor)(struct hci_dev *hdev, struct sk_buff *skb);
|
||||
void (*notify)(struct hci_dev *hdev, unsigned int evt);
|
||||
void (*hw_error)(struct hci_dev *hdev, u8 code);
|
||||
int (*post_init)(struct hci_dev *hdev);
|
||||
|
||||
@@ -7604,6 +7604,14 @@ static void hci_le_meta_evt(struct hci_dev *hdev, void *data,
|
||||
subev->func(hdev, data, skb);
|
||||
}
|
||||
|
||||
static void hci_vendor_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb)
|
||||
{
|
||||
if (hdev->handle_ev_vendor && hdev->handle_ev_vendor(hdev, skb))
|
||||
return;
|
||||
|
||||
msft_vendor_evt(hdev, data, skb);
|
||||
}
|
||||
|
||||
static bool hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode,
|
||||
u8 event, struct sk_buff *skb)
|
||||
{
|
||||
@@ -7831,7 +7839,7 @@ static const struct hci_ev {
|
||||
HCI_EV_REQ_VL(HCI_EV_LE_META, hci_le_meta_evt,
|
||||
sizeof(struct hci_ev_le_meta), HCI_MAX_EVENT_SIZE),
|
||||
/* [0xff = HCI_EV_VENDOR] */
|
||||
HCI_EV_VL(HCI_EV_VENDOR, msft_vendor_evt, 0, HCI_MAX_EVENT_SIZE),
|
||||
HCI_EV_VL(HCI_EV_VENDOR, hci_vendor_evt, 0, HCI_MAX_EVENT_SIZE),
|
||||
};
|
||||
|
||||
static void hci_event_func(struct hci_dev *hdev, u8 event, struct sk_buff *skb,
|
||||
|
||||
Reference in New Issue
Block a user