summaryrefslogtreecommitdiffstats
path: root/net/bluetooth/hci_sock.c
diff options
context:
space:
mode:
authorMarcel Holtmann2013-08-26 08:25:15 +0200
committerGustavo Padovan2013-09-16 19:35:54 +0200
commitf81fe64f3d3bc76c1a8d3edb80b54219a60ff291 (patch)
tree34423d1f59dbe20d27706799ba9ab38fc943d155 /net/bluetooth/hci_sock.c
parentnet: ipv6: mld: document force_mld_version in ip-sysctl.txt (diff)
downloadkernel-qcow2-linux-f81fe64f3d3bc76c1a8d3edb80b54219a60ff291.tar.gz
kernel-qcow2-linux-f81fe64f3d3bc76c1a8d3edb80b54219a60ff291.tar.xz
kernel-qcow2-linux-f81fe64f3d3bc76c1a8d3edb80b54219a60ff291.zip
Bluetooth: Refactor raw socket filter into more readable code
The handling of the raw socket filter is rather obscure code and it gets in the way of future extensions. Instead of inline filtering in the raw socket packet routine, refactor it into its own function. Signed-off-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Diffstat (limited to 'net/bluetooth/hci_sock.c')
-rw-r--r--net/bluetooth/hci_sock.c64
1 files changed, 41 insertions, 23 deletions
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 9bd7d959e384..c45ec25aefb9 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -66,6 +66,46 @@ static struct bt_sock_list hci_sk_list = {
.lock = __RW_LOCK_UNLOCKED(hci_sk_list.lock)
};
+static bool is_filtered_packet(struct sock *sk, struct sk_buff *skb)
+{
+ struct hci_filter *flt;
+ int flt_type, flt_event;
+
+ /* Apply filter */
+ flt = &hci_pi(sk)->filter;
+
+ if (bt_cb(skb)->pkt_type == HCI_VENDOR_PKT)
+ flt_type = 0;
+ else
+ flt_type = bt_cb(skb)->pkt_type & HCI_FLT_TYPE_BITS;
+
+ if (!test_bit(flt_type, &flt->type_mask))
+ return true;
+
+ /* Extra filter for event packets only */
+ if (bt_cb(skb)->pkt_type != HCI_EVENT_PKT)
+ return false;
+
+ flt_event = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS);
+
+ if (!hci_test_bit(flt_event, &flt->event_mask))
+ return true;
+
+ /* Check filter only when opcode is set */
+ if (!flt->opcode)
+ return false;
+
+ if (flt_event == HCI_EV_CMD_COMPLETE &&
+ flt->opcode != get_unaligned((__le16 *)(skb->data + 3)))
+ return true;
+
+ if (flt_event == HCI_EV_CMD_STATUS &&
+ flt->opcode != get_unaligned((__le16 *)(skb->data + 4)))
+ return true;
+
+ return false;
+}
+
/* Send frame to RAW socket */
void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
{
@@ -77,7 +117,6 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
read_lock(&hci_sk_list.lock);
sk_for_each(sk, &hci_sk_list.head) {
- struct hci_filter *flt;
struct sk_buff *nskb;
if (sk->sk_state != BT_BOUND || hci_pi(sk)->hdev != hdev)
@@ -90,30 +129,9 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
if (hci_pi(sk)->channel != HCI_CHANNEL_RAW)
continue;
- /* Apply filter */
- flt = &hci_pi(sk)->filter;
-
- if (!test_bit((bt_cb(skb)->pkt_type == HCI_VENDOR_PKT) ?
- 0 : (bt_cb(skb)->pkt_type & HCI_FLT_TYPE_BITS),
- &flt->type_mask))
+ if (is_filtered_packet(sk, skb))
continue;
- if (bt_cb(skb)->pkt_type == HCI_EVENT_PKT) {
- int evt = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS);
-
- if (!hci_test_bit(evt, &flt->event_mask))
- continue;
-
- if (flt->opcode &&
- ((evt == HCI_EV_CMD_COMPLETE &&
- flt->opcode !=
- get_unaligned((__le16 *)(skb->data + 3))) ||
- (evt == HCI_EV_CMD_STATUS &&
- flt->opcode !=
- get_unaligned((__le16 *)(skb->data + 4)))))
- continue;
- }
-
if (!skb_copy) {
/* Create a private copy with headroom */
skb_copy = __pskb_copy(skb, 1, GFP_ATOMIC);