From 88c1fe4ba55c7245ad2f3c81689f854287875121 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 9 Feb 2012 15:56:11 +0200 Subject: Bluetooth: Add address type to mgmt blacklist messages This patch updates the implmentation for mgmt_block_device and mgmt_unblock_device and their corresponding events to match the latest API specification. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- net/bluetooth/hci_sock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/bluetooth/hci_sock.c') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 0dcc96266779..9e854d9fb460 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -190,7 +190,7 @@ static int hci_sock_blacklist_add(struct hci_dev *hdev, void __user *arg) hci_dev_lock(hdev); - err = hci_blacklist_add(hdev, &bdaddr); + err = hci_blacklist_add(hdev, &bdaddr, 0); hci_dev_unlock(hdev); @@ -207,7 +207,7 @@ static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg) hci_dev_lock(hdev); - err = hci_blacklist_del(hdev, &bdaddr); + err = hci_blacklist_del(hdev, &bdaddr, 0); hci_dev_unlock(hdev); -- cgit v1.2.3 From 470fe1b540fb50ba8ce01e0ac985602e8fbb108c Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 14:50:30 +0100 Subject: Bluetooth: Split sending for HCI raw and control sockets The sending functions for HCI raw and control sockets have nothing in common except that they iterate over the socket list. Split them into two so they can do their job more efficient. In addition the code becomes more readable. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 4 ++-- net/bluetooth/hci_core.c | 4 ++-- net/bluetooth/hci_event.c | 2 +- net/bluetooth/hci_sock.c | 51 ++++++++++++++++++++++++++++++---------- net/bluetooth/mgmt.c | 2 +- 5 files changed, 45 insertions(+), 18 deletions(-) (limited to 'net/bluetooth/hci_sock.c') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 2aafeb3a8793..9209e4c8a211 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -953,8 +953,8 @@ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode); void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data); /* ----- HCI Sockets ----- */ -void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb, - struct sock *skip_sk); +void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb); +void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk); /* Management interface */ #define MGMT_ADDR_BREDR 0x00 diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index fabca080ae70..638fa8c393d8 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2131,7 +2131,7 @@ static int hci_send_frame(struct sk_buff *skb) /* Time stamp */ __net_timestamp(skb); - hci_send_to_sock(hdev, skb, NULL); + hci_send_to_sock(hdev, skb); } /* Get rid of skb owner, prior to sending to the driver. */ @@ -2818,7 +2818,7 @@ static void hci_rx_work(struct work_struct *work) while ((skb = skb_dequeue(&hdev->rx_q))) { if (atomic_read(&hdev->promisc)) { /* Send copy to the sockets */ - hci_send_to_sock(hdev, skb, NULL); + hci_send_to_sock(hdev, skb); } if (test_bit(HCI_RAW, &hdev->flags)) { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 04fb1f02dfcc..e69db4a7b3ef 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3571,7 +3571,7 @@ void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data) bt_cb(skb)->pkt_type = HCI_EVENT_PKT; skb->dev = (void *) hdev; - hci_send_to_sock(hdev, skb, NULL); + hci_send_to_sock(hdev, skb); kfree_skb(skb); } diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 9e854d9fb460..b5b3bc8d2848 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -85,8 +85,7 @@ static struct bt_sock_list hci_sk_list = { }; /* Send frame to RAW socket */ -void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb, - struct sock *skip_sk) +void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) { struct sock *sk; struct hlist_node *node; @@ -94,13 +93,11 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb, BT_DBG("hdev %p len %d", hdev, skb->len); read_lock(&hci_sk_list.lock); + sk_for_each(sk, node, &hci_sk_list.head) { struct hci_filter *flt; struct sk_buff *nskb; - if (sk == skip_sk) - continue; - if (sk->sk_state != BT_BOUND || hci_pi(sk)->hdev != hdev) continue; @@ -108,12 +105,9 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb, if (skb->sk == sk) continue; - if (bt_cb(skb)->channel != hci_pi(sk)->channel) + if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) continue; - if (bt_cb(skb)->channel == HCI_CHANNEL_CONTROL) - goto clone; - /* Apply filter */ flt = &hci_pi(sk)->filter; @@ -137,18 +131,51 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb, continue; } -clone: nskb = skb_clone(skb, GFP_ATOMIC); if (!nskb) continue; /* Put type byte before the data */ - if (bt_cb(skb)->channel == HCI_CHANNEL_RAW) - memcpy(skb_push(nskb, 1), &bt_cb(nskb)->pkt_type, 1); + memcpy(skb_push(nskb, 1), &bt_cb(nskb)->pkt_type, 1); + + if (sock_queue_rcv_skb(sk, nskb)) + kfree_skb(nskb); + } + + read_unlock(&hci_sk_list.lock); +} + +/* Send frame to control socket */ +void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk) +{ + struct sock *sk; + struct hlist_node *node; + + BT_DBG("len %d", skb->len); + + read_lock(&hci_sk_list.lock); + + sk_for_each(sk, node, &hci_sk_list.head) { + struct sk_buff *nskb; + + /* Skip the original socket */ + if (sk == skip_sk) + continue; + + if (sk->sk_state != BT_BOUND) + continue; + + if (hci_pi(sk)->channel != HCI_CHANNEL_CONTROL) + continue; + + nskb = skb_clone(skb, GFP_ATOMIC); + if (!nskb) + continue; if (sock_queue_rcv_skb(sk, nskb)) kfree_skb(nskb); } + read_unlock(&hci_sk_list.lock); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 18d593f23934..1695d04d927d 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -924,7 +924,7 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, if (data) memcpy(skb_put(skb, data_len), data, data_len); - hci_send_to_sock(NULL, skb, skip_sk); + hci_send_to_control(skb, skip_sk); kfree_skb(skb); return 0; -- cgit v1.2.3 From 2f39cdb7a270da24532734dfdfd10c490be981c4 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 14:50:32 +0100 Subject: Bluetooth: Limit HCI raw socket options to actual raw sockets Currently the socket options of HCI sockets can be set on raw and control sockets, but on control sockets they make no sense. So just return EINVAL in that case. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'net/bluetooth/hci_sock.c') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index b5b3bc8d2848..612bc2af05a9 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -601,6 +601,11 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char lock_sock(sk); + if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) { + err = -EINVAL; + goto done; + } + switch (optname) { case HCI_DATA_DIR: if (get_user(opt, (int __user *)optval)) { @@ -663,6 +668,7 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char break; } +done: release_sock(sk); return err; } -- cgit v1.2.3 From cedc5469778846ee18c653aaa6d70681961eed93 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 14:50:33 +0100 Subject: Bluetooth: Lock socket when reading HCI socket options When reading the HCI raw socket option, the socket was never locked. So lock the socket and in addition return EINVAL on non raw sockets. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'net/bluetooth/hci_sock.c') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 612bc2af05a9..27ec9088508f 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -677,11 +677,20 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char { struct hci_ufilter uf; struct sock *sk = sock->sk; - int len, opt; + int len, opt, err = 0; + + BT_DBG("sk %p, opt %d", sk, optname); if (get_user(len, optlen)) return -EFAULT; + lock_sock(sk); + + if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) { + err = -EINVAL; + goto done; + } + switch (optname) { case HCI_DATA_DIR: if (hci_pi(sk)->cmsg_mask & HCI_CMSG_DIR) @@ -690,7 +699,7 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char opt = 0; if (put_user(opt, optval)) - return -EFAULT; + err = -EFAULT; break; case HCI_TIME_STAMP: @@ -700,7 +709,7 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char opt = 0; if (put_user(opt, optval)) - return -EFAULT; + err = -EFAULT; break; case HCI_FILTER: @@ -715,15 +724,17 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char len = min_t(unsigned int, len, sizeof(uf)); if (copy_to_user(optval, &uf, len)) - return -EFAULT; + err = -EFAULT; break; default: - return -ENOPROTOOPT; + err = -ENOPROTOOPT; break; } - return 0; +done: + release_sock(sk); + return err; } static const struct proto_ops hci_sock_ops = { -- cgit v1.2.3 From 3a208627f3ac83d3b749608770f7eb631db31a77 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 14:50:34 +0100 Subject: Bluetooth: Add HCI CMSG details only to raw sockets The HCI CMSG specific data is for raw sockets only. So only add them to actual raw sockets. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'net/bluetooth/hci_sock.c') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 27ec9088508f..71a02adbaa77 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -488,7 +488,11 @@ static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock, skb_reset_transport_header(skb); err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); - hci_sock_cmsg(sk, msg, skb); + switch (hci_pi(sk)->channel) { + case HCI_CHANNEL_RAW: + hci_sock_cmsg(sk, msg, skb); + break; + } skb_free_datagram(sk, skb); -- cgit v1.2.3 From 7cc2ade2cbc6f71090f0f8d0e11cb68886ddc65e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 14:50:35 +0100 Subject: Bluetooth: Simplify HCI socket bind handling The HCI socket bind handling checks a few too many times the channel we are binding. So centralize this and make the function easier to read. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 47 +++++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 16 deletions(-) (limited to 'net/bluetooth/hci_sock.c') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 71a02adbaa77..4dda4574db3e 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -367,34 +367,49 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le if (haddr.hci_family != AF_BLUETOOTH) return -EINVAL; - if (haddr.hci_channel > HCI_CHANNEL_CONTROL) - return -EINVAL; - - if (haddr.hci_channel == HCI_CHANNEL_CONTROL) { - if (!enable_mgmt) - return -EINVAL; - set_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags); - } - lock_sock(sk); - if (sk->sk_state == BT_BOUND || hci_pi(sk)->hdev) { + if (sk->sk_state == BT_BOUND) { err = -EALREADY; goto done; } - if (haddr.hci_dev != HCI_DEV_NONE) { - hdev = hci_dev_get(haddr.hci_dev); - if (!hdev) { - err = -ENODEV; + switch (haddr.hci_channel) { + case HCI_CHANNEL_RAW: + if (hci_pi(sk)->hdev) { + err = -EALREADY; goto done; } - atomic_inc(&hdev->promisc); + if (haddr.hci_dev != HCI_DEV_NONE) { + hdev = hci_dev_get(haddr.hci_dev); + if (!hdev) { + err = -ENODEV; + goto done; + } + + atomic_inc(&hdev->promisc); + } + + hci_pi(sk)->hdev = hdev; + break; + + case HCI_CHANNEL_CONTROL: + if (haddr.hci_dev != HCI_DEV_NONE || !enable_mgmt) { + err = -EINVAL; + goto done; + } + + set_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags); + break; + + default: + err = -EINVAL; + goto done; } + hci_pi(sk)->channel = haddr.hci_channel; - hci_pi(sk)->hdev = hdev; sk->sk_state = BT_BOUND; done: -- cgit v1.2.3 From e0edf3733fb62f91bbb8ec3fab4a90b0ac2dd037 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 14:50:36 +0100 Subject: Bluetooth: Fix issue with shared SKB between HCI raw socket and driver Any HCI raw socket gets a copy of each SKB that is either received or send via the Bluetooth subsystem. The raw socket uses SKB clones to send out data, but the problem is that it needs to add an extra packet type byte in front of it. And some drivers need to also add an extra header before submitting the packet. So far this all worked magically fine since all of the drivers and the raw sockets are adding the same byte at the same location. But that is by pure coincidence. Since the data of cloned SKBs is shared, this means that the raw socket and driver kept writing into the shared data area. To fix this the only safe way is if the HCI raw socket creates a copy of the SKB before sending it out. To not always copy all SKBs around, the copy is only created once and only after any of the HCI filter checks succeeded. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'net/bluetooth/hci_sock.c') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 4dda4574db3e..cf940bd7a2b0 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -89,6 +89,7 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) { struct sock *sk; struct hlist_node *node; + struct sk_buff *skb_copy = NULL; BT_DBG("hdev %p len %d", hdev, skb->len); @@ -131,18 +132,27 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) continue; } - nskb = skb_clone(skb, GFP_ATOMIC); + if (!skb_copy) { + /* Create a private copy with headroom */ + skb_copy = __pskb_copy(skb, 1, GFP_ATOMIC); + if (!skb_copy) + continue; + + /* Put type byte before the data */ + memcpy(skb_push(skb_copy, 1), &bt_cb(skb)->pkt_type, 1); + } + + nskb = skb_clone(skb_copy, GFP_ATOMIC); if (!nskb) continue; - /* Put type byte before the data */ - memcpy(skb_push(nskb, 1), &bt_cb(nskb)->pkt_type, 1); - if (sock_queue_rcv_skb(sk, nskb)) kfree_skb(nskb); } read_unlock(&hci_sk_list.lock); + + kfree_skb(skb_copy); } /* Send frame to control socket */ -- cgit v1.2.3 From 040030ef7d907107e6489b39da518bdf94136d68 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 14:50:37 +0100 Subject: Bluetooth: Remove HCI notifier handling The HCI notifier handling was never used outside of Bluetooth core layer and thus remove it and replace it with direct function calls. Also move the stack internal event generation into the HCI socket layer. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 7 +-- net/bluetooth/hci_conn.c | 1 - net/bluetooth/hci_core.c | 16 +----- net/bluetooth/hci_event.c | 29 ----------- net/bluetooth/hci_sock.c | 105 +++++++++++++++++++++++---------------- 5 files changed, 64 insertions(+), 94 deletions(-) (limited to 'net/bluetooth/hci_sock.c') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 9209e4c8a211..41adae509e9c 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -941,21 +941,18 @@ static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data, int hci_register_cb(struct hci_cb *hcb); int hci_unregister_cb(struct hci_cb *hcb); -int hci_register_notifier(struct notifier_block *nb); -int hci_unregister_notifier(struct notifier_block *nb); - int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param); void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags); void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb); void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode); -void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data); - /* ----- HCI Sockets ----- */ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb); void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk); +void hci_sock_dev_event(struct hci_dev *hdev, int event); + /* Management interface */ #define MGMT_ADDR_BREDR 0x00 #define MGMT_ADDR_LE_PUBLIC 0x01 diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 8549d04e3313..3c68e606d5e5 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 638fa8c393d8..47217281d9ac 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -69,24 +68,11 @@ DEFINE_RWLOCK(hci_dev_list_lock); LIST_HEAD(hci_cb_list); DEFINE_RWLOCK(hci_cb_list_lock); -/* HCI notifiers list */ -static ATOMIC_NOTIFIER_HEAD(hci_notifier); - /* ---- HCI notifications ---- */ -int hci_register_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(&hci_notifier, nb); -} - -int hci_unregister_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&hci_notifier, nb); -} - static void hci_notify(struct hci_dev *hdev, int event) { - atomic_notifier_call_chain(&hci_notifier, event, hdev); + hci_sock_dev_event(hdev, event); } /* ---- HCI requests ---- */ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e69db4a7b3ef..f00faf0ac32f 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include @@ -3547,33 +3546,5 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) hdev->stat.evt_rx++; } -/* Generate internal stack event */ -void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data) -{ - struct hci_event_hdr *hdr; - struct hci_ev_stack_internal *ev; - struct sk_buff *skb; - - skb = bt_skb_alloc(HCI_EVENT_HDR_SIZE + sizeof(*ev) + dlen, GFP_ATOMIC); - if (!skb) - return; - - hdr = (void *) skb_put(skb, HCI_EVENT_HDR_SIZE); - hdr->evt = HCI_EV_STACK_INTERNAL; - hdr->plen = sizeof(*ev) + dlen; - - ev = (void *) skb_put(skb, sizeof(*ev) + dlen); - ev->type = type; - memcpy(ev->data, data, dlen); - - bt_cb(skb)->incoming = 1; - __net_timestamp(skb); - - bt_cb(skb)->pkt_type = HCI_EVENT_PKT; - skb->dev = (void *) hdev; - hci_send_to_sock(hdev, skb); - kfree_skb(skb); -} - module_param(enable_le, bool, 0644); MODULE_PARM_DESC(enable_le, "Enable LE support"); diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index cf940bd7a2b0..14727cb43f63 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -189,6 +189,67 @@ void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk) read_unlock(&hci_sk_list.lock); } +/* Generate internal stack event */ +static void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data) +{ + struct hci_event_hdr *hdr; + struct hci_ev_stack_internal *ev; + struct sk_buff *skb; + + skb = bt_skb_alloc(HCI_EVENT_HDR_SIZE + sizeof(*ev) + dlen, GFP_ATOMIC); + if (!skb) + return; + + hdr = (void *) skb_put(skb, HCI_EVENT_HDR_SIZE); + hdr->evt = HCI_EV_STACK_INTERNAL; + hdr->plen = sizeof(*ev) + dlen; + + ev = (void *) skb_put(skb, sizeof(*ev) + dlen); + ev->type = type; + memcpy(ev->data, data, dlen); + + bt_cb(skb)->incoming = 1; + __net_timestamp(skb); + + bt_cb(skb)->pkt_type = HCI_EVENT_PKT; + skb->dev = (void *) hdev; + hci_send_to_sock(hdev, skb); + kfree_skb(skb); +} + +void hci_sock_dev_event(struct hci_dev *hdev, int event) +{ + struct hci_ev_si_device ev; + + BT_DBG("hdev %s event %d", hdev->name, event); + + /* Send event to sockets */ + ev.event = event; + ev.dev_id = hdev->id; + hci_si_event(NULL, HCI_EV_SI_DEVICE, sizeof(ev), &ev); + + if (event == HCI_DEV_UNREG) { + struct sock *sk; + struct hlist_node *node; + + /* Detach sockets from device */ + read_lock(&hci_sk_list.lock); + sk_for_each(sk, node, &hci_sk_list.head) { + bh_lock_sock_nested(sk); + if (hci_pi(sk)->hdev == hdev) { + hci_pi(sk)->hdev = NULL; + sk->sk_err = EPIPE; + sk->sk_state = BT_OPEN; + sk->sk_state_change(sk); + + hci_dev_put(hdev); + } + bh_unlock_sock(sk); + } + read_unlock(&hci_sk_list.lock); + } +} + static int hci_sock_release(struct socket *sock) { struct sock *sk = sock->sk; @@ -821,52 +882,12 @@ static int hci_sock_create(struct net *net, struct socket *sock, int protocol, return 0; } -static int hci_sock_dev_event(struct notifier_block *this, unsigned long event, void *ptr) -{ - struct hci_dev *hdev = (struct hci_dev *) ptr; - struct hci_ev_si_device ev; - - BT_DBG("hdev %s event %ld", hdev->name, event); - - /* Send event to sockets */ - ev.event = event; - ev.dev_id = hdev->id; - hci_si_event(NULL, HCI_EV_SI_DEVICE, sizeof(ev), &ev); - - if (event == HCI_DEV_UNREG) { - struct sock *sk; - struct hlist_node *node; - - /* Detach sockets from device */ - read_lock(&hci_sk_list.lock); - sk_for_each(sk, node, &hci_sk_list.head) { - bh_lock_sock_nested(sk); - if (hci_pi(sk)->hdev == hdev) { - hci_pi(sk)->hdev = NULL; - sk->sk_err = EPIPE; - sk->sk_state = BT_OPEN; - sk->sk_state_change(sk); - - hci_dev_put(hdev); - } - bh_unlock_sock(sk); - } - read_unlock(&hci_sk_list.lock); - } - - return NOTIFY_DONE; -} - static const struct net_proto_family hci_sock_family_ops = { .family = PF_BLUETOOTH, .owner = THIS_MODULE, .create = hci_sock_create, }; -static struct notifier_block hci_sock_nblock = { - .notifier_call = hci_sock_dev_event -}; - int __init hci_sock_init(void) { int err; @@ -879,8 +900,6 @@ int __init hci_sock_init(void) if (err < 0) goto error; - hci_register_notifier(&hci_sock_nblock); - BT_INFO("HCI socket layer initialized"); return 0; @@ -896,8 +915,6 @@ void hci_sock_cleanup(void) if (bt_sock_unregister(BTPROTO_HCI) < 0) BT_ERR("HCI socket unregistration failed"); - hci_unregister_notifier(&hci_sock_nblock); - proto_unregister(&hci_sk_proto); } -- cgit v1.2.3 From cd82e61c110a36e398323e422896fcfe05879fed Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 20:34:38 +0100 Subject: Bluetooth: Add support for HCI monitor channel The HCI monitor channel can be used to monitor all packets and events from the Bluetooth subsystem. The monitor is not bound to any specific HCI device and allows even capturing multiple devices at the same time. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 1 + include/net/bluetooth/hci_core.h | 1 + include/net/bluetooth/hci_mon.h | 51 ++++++++++ net/bluetooth/hci_core.c | 13 ++- net/bluetooth/hci_sock.c | 207 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 270 insertions(+), 3 deletions(-) create mode 100644 include/net/bluetooth/hci_mon.h (limited to 'net/bluetooth/hci_sock.c') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 1b634e126878..60a4727be935 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1320,6 +1320,7 @@ struct sockaddr_hci { #define HCI_CHANNEL_RAW 0 #define HCI_CHANNEL_CONTROL 1 +#define HCI_CHANNEL_MONITOR 2 struct hci_filter { unsigned long type_mask; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 41adae509e9c..094b5dbdb130 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -950,6 +950,7 @@ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode); /* ----- HCI Sockets ----- */ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb); void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk); +void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb); void hci_sock_dev_event(struct hci_dev *hdev, int event); diff --git a/include/net/bluetooth/hci_mon.h b/include/net/bluetooth/hci_mon.h new file mode 100644 index 000000000000..07a25c92502c --- /dev/null +++ b/include/net/bluetooth/hci_mon.h @@ -0,0 +1,51 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + + Copyright (C) 2011-2012 Intel Corporation + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +#ifndef __HCI_MON_H +#define __HCI_MON_H + +struct hci_mon_hdr { + __le16 opcode; + __le16 index; + __le16 len; +} __packed; +#define HCI_MON_HDR_SIZE 6 + +#define HCI_MON_NEW_INDEX 0 +#define HCI_MON_DEL_INDEX 1 +#define HCI_MON_COMMAND_PKT 2 +#define HCI_MON_EVENT_PKT 3 +#define HCI_MON_ACL_TX_PKT 4 +#define HCI_MON_ACL_RX_PKT 5 +#define HCI_MON_SCO_TX_PKT 6 +#define HCI_MON_SCO_RX_PKT 7 + +struct hci_mon_new_index { + __u8 type; + __u8 bus; + bdaddr_t bdaddr; + char name[8]; +} __packed; +#define HCI_MON_NEW_INDEX_SIZE 16 + +#endif /* __HCI_MON_H */ diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 47217281d9ac..87ff7ffdb367 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2113,10 +2113,14 @@ static int hci_send_frame(struct sk_buff *skb) BT_DBG("%s type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len); - if (atomic_read(&hdev->promisc)) { - /* Time stamp */ - __net_timestamp(skb); + /* Time stamp */ + __net_timestamp(skb); + /* Send copy to monitor */ + hci_send_to_monitor(hdev, skb); + + if (atomic_read(&hdev->promisc)) { + /* Send copy to the sockets */ hci_send_to_sock(hdev, skb); } @@ -2802,6 +2806,9 @@ static void hci_rx_work(struct work_struct *work) BT_DBG("%s", hdev->name); while ((skb = skb_dequeue(&hdev->rx_q))) { + /* Send copy to monitor */ + hci_send_to_monitor(hdev, skb); + if (atomic_read(&hdev->promisc)) { /* Send copy to the sockets */ hci_send_to_sock(hdev, skb); diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 14727cb43f63..213697d23771 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -48,9 +48,12 @@ #include #include +#include static bool enable_mgmt; +static atomic_t monitor_promisc = ATOMIC_INIT(0); + /* ----- HCI socket interface ----- */ static inline int hci_test_bit(int nr, void *addr) @@ -189,6 +192,174 @@ void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk) read_unlock(&hci_sk_list.lock); } +/* Send frame to monitor socket */ +void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct sock *sk; + struct hlist_node *node; + struct sk_buff *skb_copy = NULL; + __le16 opcode; + + if (!atomic_read(&monitor_promisc)) + return; + + BT_DBG("hdev %p len %d", hdev, skb->len); + + switch (bt_cb(skb)->pkt_type) { + case HCI_COMMAND_PKT: + opcode = __constant_cpu_to_le16(HCI_MON_COMMAND_PKT); + break; + case HCI_EVENT_PKT: + opcode = __constant_cpu_to_le16(HCI_MON_EVENT_PKT); + break; + case HCI_ACLDATA_PKT: + if (bt_cb(skb)->incoming) + opcode = __constant_cpu_to_le16(HCI_MON_ACL_RX_PKT); + else + opcode = __constant_cpu_to_le16(HCI_MON_ACL_TX_PKT); + break; + case HCI_SCODATA_PKT: + if (bt_cb(skb)->incoming) + opcode = __constant_cpu_to_le16(HCI_MON_SCO_RX_PKT); + else + opcode = __constant_cpu_to_le16(HCI_MON_SCO_TX_PKT); + break; + default: + return; + } + + read_lock(&hci_sk_list.lock); + + sk_for_each(sk, node, &hci_sk_list.head) { + struct sk_buff *nskb; + + if (sk->sk_state != BT_BOUND) + continue; + + if (hci_pi(sk)->channel != HCI_CHANNEL_MONITOR) + continue; + + if (!skb_copy) { + struct hci_mon_hdr *hdr; + + /* Create a private copy with headroom */ + skb_copy = __pskb_copy(skb, HCI_MON_HDR_SIZE, GFP_ATOMIC); + if (!skb_copy) + continue; + + /* Put header before the data */ + hdr = (void *) skb_push(skb_copy, HCI_MON_HDR_SIZE); + hdr->opcode = opcode; + hdr->index = cpu_to_le16(hdev->id); + hdr->len = cpu_to_le16(skb->len); + } + + nskb = skb_clone(skb_copy, GFP_ATOMIC); + if (!nskb) + continue; + + if (sock_queue_rcv_skb(sk, nskb)) + kfree_skb(nskb); + } + + read_unlock(&hci_sk_list.lock); + + kfree_skb(skb_copy); +} + +static void send_monitor_event(struct sk_buff *skb) +{ + struct sock *sk; + struct hlist_node *node; + + BT_DBG("len %d", skb->len); + + read_lock(&hci_sk_list.lock); + + sk_for_each(sk, node, &hci_sk_list.head) { + struct sk_buff *nskb; + + if (sk->sk_state != BT_BOUND) + continue; + + if (hci_pi(sk)->channel != HCI_CHANNEL_MONITOR) + continue; + + nskb = skb_clone(skb, GFP_ATOMIC); + if (!nskb) + continue; + + if (sock_queue_rcv_skb(sk, nskb)) + kfree_skb(nskb); + } + + read_unlock(&hci_sk_list.lock); +} + +static struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event) +{ + struct hci_mon_hdr *hdr; + struct hci_mon_new_index *ni; + struct sk_buff *skb; + __le16 opcode; + + switch (event) { + case HCI_DEV_REG: + skb = bt_skb_alloc(HCI_MON_NEW_INDEX_SIZE, GFP_ATOMIC); + if (!skb) + return NULL; + + ni = (void *) skb_put(skb, HCI_MON_NEW_INDEX_SIZE); + ni->type = hdev->dev_type; + ni->bus = hdev->bus; + bacpy(&ni->bdaddr, &hdev->bdaddr); + memcpy(ni->name, hdev->name, 8); + + opcode = __constant_cpu_to_le16(HCI_MON_NEW_INDEX); + break; + + case HCI_DEV_UNREG: + skb = bt_skb_alloc(0, GFP_ATOMIC); + if (!skb) + return NULL; + + opcode = __constant_cpu_to_le16(HCI_MON_DEL_INDEX); + break; + + default: + return NULL; + } + + __net_timestamp(skb); + + hdr = (void *) skb_push(skb, HCI_MON_HDR_SIZE); + hdr->opcode = opcode; + hdr->index = cpu_to_le16(hdev->id); + hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE); + + return skb; +} + +static void send_monitor_replay(struct sock *sk) +{ + struct hci_dev *hdev; + + read_lock(&hci_dev_list_lock); + + list_for_each_entry(hdev, &hci_dev_list, list) { + struct sk_buff *skb; + + skb = create_monitor_event(hdev, HCI_DEV_REG); + if (!skb) + continue; + + if (sock_queue_rcv_skb(sk, skb)) + kfree_skb(skb); + } + + read_unlock(&hci_dev_list_lock); +} + /* Generate internal stack event */ static void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data) { @@ -223,6 +394,17 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event) BT_DBG("hdev %s event %d", hdev->name, event); + /* Send event to monitor */ + if (atomic_read(&monitor_promisc)) { + struct sk_buff *skb; + + skb = create_monitor_event(hdev, event); + if (skb) { + send_monitor_event(skb); + kfree_skb(skb); + } + } + /* Send event to sockets */ ev.event = event; ev.dev_id = hdev->id; @@ -262,6 +444,9 @@ static int hci_sock_release(struct socket *sock) hdev = hci_pi(sk)->hdev; + if (hci_pi(sk)->channel == HCI_CHANNEL_MONITOR) + atomic_dec(&monitor_promisc); + bt_sock_unlink(&hci_sk_list, sk); if (hdev) { @@ -474,6 +659,22 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le set_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags); break; + case HCI_CHANNEL_MONITOR: + if (haddr.hci_dev != HCI_DEV_NONE) { + err = -EINVAL; + goto done; + } + + if (!capable(CAP_NET_RAW)) { + err = -EPERM; + goto done; + } + + send_monitor_replay(sk); + + atomic_inc(&monitor_promisc); + break; + default: err = -EINVAL; goto done; @@ -578,6 +779,9 @@ static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock, case HCI_CHANNEL_RAW: hci_sock_cmsg(sk, msg, skb); break; + case HCI_CHANNEL_MONITOR: + sock_recv_timestamp(msg, sk, skb); + break; } skb_free_datagram(sk, skb); @@ -612,6 +816,9 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, case HCI_CHANNEL_CONTROL: err = mgmt_control(sk, msg, len); goto done; + case HCI_CHANNEL_MONITOR: + err = -EOPNOTSUPP; + goto done; default: err = -EINVAL; goto done; -- cgit v1.2.3 From 801f13bd8ecc58f2cf42ec602a2b5db10fc5a132 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 20:54:10 +0100 Subject: Bluetooth: Restrict access to management interface The management interface on the HCI control channel should be restricted to applications with CAP_NET_ADMIN permission. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'net/bluetooth/hci_sock.c') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 213697d23771..8c429a179aa4 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -656,6 +656,11 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le goto done; } + if (!capable(CAP_NET_ADMIN)) { + err = -EPERM; + goto done; + } + set_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags); break; -- cgit v1.2.3 From 4b95a24ce12c4545fd7d2e3075841dc3119d1d71 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 20 Feb 2012 21:24:37 +0100 Subject: Bluetooth: Always enable management interface The management interface API has reached stable version 1.0 and thus it can now be always enabled. All future changes will be made backwards compatible. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'net/bluetooth/hci_sock.c') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 8c429a179aa4..dd5635064145 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -50,8 +50,6 @@ #include #include -static bool enable_mgmt; - static atomic_t monitor_promisc = ATOMIC_INIT(0); /* ----- HCI socket interface ----- */ @@ -651,7 +649,7 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le break; case HCI_CHANNEL_CONTROL: - if (haddr.hci_dev != HCI_DEV_NONE || !enable_mgmt) { + if (haddr.hci_dev != HCI_DEV_NONE) { err = -EINVAL; goto done; } @@ -1129,6 +1127,3 @@ void hci_sock_cleanup(void) proto_unregister(&hci_sk_proto); } - -module_param(enable_mgmt, bool, 0644); -MODULE_PARM_DESC(enable_mgmt, "Enable Management interface"); -- cgit v1.2.3 From 97e0bdeb93cc9bd014c21d5400af4fa7f2fe2f91 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 22 Feb 2012 13:49:28 +0100 Subject: Bluetooth: Enable timestamps for control channel The control channel can be also monitored, so include timestamps here as well. And make sure management events get their timestamp when they are created. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 1 + net/bluetooth/mgmt.c | 3 +++ 2 files changed, 4 insertions(+) (limited to 'net/bluetooth/hci_sock.c') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index dd5635064145..8a814bca00d7 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -782,6 +782,7 @@ static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock, case HCI_CHANNEL_RAW: hci_sock_cmsg(sk, msg, skb); break; + case HCI_CHANNEL_CONTROL: case HCI_CHANNEL_MONITOR: sock_recv_timestamp(msg, sk, skb); break; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 08c657df7f8c..8b4df0473ec3 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -817,6 +817,9 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, if (data) memcpy(skb_put(skb, data_len), data, data_len); + /* Time stamp */ + __net_timestamp(skb); + hci_send_to_control(skb, skip_sk); kfree_skb(skb); -- cgit v1.2.3 From 4f87da80a5210e66fb47b0e839f4d05016986f78 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 2 Mar 2012 19:55:56 +0200 Subject: Bluetooth: Remove HCI_PI_MGMT_INIT flag for sockets This flag is of no use right now and is in fact harmful in that it prevents the HCI_MGMT flag to be set for any controllers that may need it after the first one that bluetoothd takes into use (the flag is cleared for the first controller so any subsequent ones through the same bluetoothd mgmt socket never get the HCI_MGMT flag set). Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 4 ---- net/bluetooth/hci_sock.c | 1 - net/bluetooth/mgmt.c | 18 ++++++++---------- 3 files changed, 8 insertions(+), 15 deletions(-) (limited to 'net/bluetooth/hci_sock.c') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index facd7ed32b74..25cb0a15b579 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1034,16 +1034,12 @@ int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent); /* HCI info for socket */ #define hci_pi(sk) ((struct hci_pinfo *) sk) -/* HCI socket flags */ -#define HCI_PI_MGMT_INIT 0 - struct hci_pinfo { struct bt_sock bt; struct hci_dev *hdev; struct hci_filter filter; __u32 cmsg_mask; unsigned short channel; - unsigned long flags; }; /* HCI security filter */ diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 8a814bca00d7..63afd234283e 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -659,7 +659,6 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le goto done; } - set_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags); break; case HCI_CHANNEL_MONITOR: diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index fa9a58964278..4b1efedc18c5 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -615,19 +615,17 @@ static void service_cache_off(struct work_struct *work) static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev) { - if (!test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags)) + if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) return; - if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) { - INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off); + INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off); - /* Non-mgmt controlled devices get this bit set - * implicitly so that pairing works for them, however - * for mgmt we require user-space to explicitly enable - * it - */ - clear_bit(HCI_PAIRABLE, &hdev->dev_flags); - } + /* Non-mgmt controlled devices get this bit set + * implicitly so that pairing works for them, however + * for mgmt we require user-space to explicitly enable + * it + */ + clear_bit(HCI_PAIRABLE, &hdev->dev_flags); } static int read_controller_info(struct sock *sk, struct hci_dev *hdev, -- cgit v1.2.3