From 2c33c06a8fd2f784ca763ad150d5d63c3c49946e Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 14 Dec 2011 13:02:51 -0200 Subject: Bluetooth: remove struct hci_chan_hash Only the list member of the struct was used, so we now fold it into hci_conn. Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_conn.c | 13 ++++++------- net/bluetooth/hci_core.c | 9 ++------- 2 files changed, 8 insertions(+), 14 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index b328ac611cc..1a076941829 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -374,7 +374,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) skb_queue_head_init(&conn->data_q); - hci_chan_hash_init(conn); + INIT_LIST_HEAD(&conn->chan_list);; setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn); setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn); @@ -434,7 +434,7 @@ int hci_conn_del(struct hci_conn *conn) tasklet_disable(&hdev->tx_task); - hci_chan_hash_flush(conn); + hci_chan_list_flush(conn); hci_conn_hash_del(hdev, conn); if (hdev->notify) @@ -970,7 +970,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn) skb_queue_head_init(&chan->data_q); tasklet_disable(&hdev->tx_task); - hci_chan_hash_add(conn, chan); + list_add(&conn->chan_list, &chan->list); tasklet_enable(&hdev->tx_task); return chan; @@ -984,7 +984,7 @@ int hci_chan_del(struct hci_chan *chan) BT_DBG("%s conn %p chan %p", hdev->name, conn, chan); tasklet_disable(&hdev->tx_task); - hci_chan_hash_del(conn, chan); + list_del(&chan->list); tasklet_enable(&hdev->tx_task); skb_queue_purge(&chan->data_q); @@ -993,13 +993,12 @@ int hci_chan_del(struct hci_chan *chan) return 0; } -void hci_chan_hash_flush(struct hci_conn *conn) +void hci_chan_list_flush(struct hci_conn *conn) { - struct hci_chan_hash *h = &conn->chan_hash; struct hci_chan *chan, *tmp; BT_DBG("conn %p", conn); - list_for_each_entry_safe(chan, tmp, &h->list, list) + list_for_each_entry_safe(chan, tmp, &conn->chan_list, list) hci_chan_del(chan); } diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index ce3727ecc0c..700d0abdf2b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2125,7 +2125,6 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type, BT_DBG("%s", hdev->name); list_for_each_entry(conn, &h->list, list) { - struct hci_chan_hash *ch; struct hci_chan *tmp; if (conn->type != type) @@ -2136,9 +2135,7 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type, conn_num++; - ch = &conn->chan_hash; - - list_for_each_entry(tmp, &ch->list, list) { + list_for_each_entry(tmp, &conn->chan_list, list) { struct sk_buff *skb; if (skb_queue_empty(&tmp->data_q)) @@ -2200,7 +2197,6 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type) BT_DBG("%s", hdev->name); list_for_each_entry(conn, &h->list, list) { - struct hci_chan_hash *ch; struct hci_chan *chan; if (conn->type != type) @@ -2211,8 +2207,7 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type) num++; - ch = &conn->chan_hash; - list_for_each_entry(chan, &ch->list, list) { + list_for_each_entry(chan, &conn->chan_list, list) { struct sk_buff *skb; if (chan->sent) { -- cgit v1.2.3 From f9c3123b5a7c9585902927b14983e6635aca00c6 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 9 Dec 2011 04:40:10 -0200 Subject: Bluetooth: Use chan instead of l2cap_pi macro Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_sock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index b85e3906b3a..fbdc8b38d9e 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -176,7 +176,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al chan->psm = la.l2_psm; chan->dcid = la.l2_cid; - err = l2cap_chan_connect(l2cap_pi(sk)->chan); + err = l2cap_chan_connect(chan); if (err) goto done; -- cgit v1.2.3 From 3e9c40a6f72a4ee7a978204cac00f91ad08bbe9b Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 14 Dec 2011 22:52:31 -0200 Subject: Bluetooth: Use list_for_each_entry in hci_conn_hash_flush() Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_conn.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 1a076941829..dfe807fb7e7 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -807,17 +807,11 @@ void hci_conn_enter_sniff_mode(struct hci_conn *conn) void hci_conn_hash_flush(struct hci_dev *hdev) { struct hci_conn_hash *h = &hdev->conn_hash; - struct list_head *p; + struct hci_conn *c; BT_DBG("hdev %s", hdev->name); - p = h->list.next; - while (p != &h->list) { - struct hci_conn *c; - - c = list_entry(p, struct hci_conn, list); - p = p->next; - + list_for_each_entry(c, &h->list, list) { c->state = BT_CLOSED; hci_proto_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM); -- cgit v1.2.3 From 416dc94baa4a0de6904707d17522f7eae7778c8e Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 7 Dec 2011 13:24:33 -0200 Subject: Bluetooth: make hci_conn_enter_sniff_mode static It isn't used outside hci_conn.c Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 1 - net/bluetooth/hci_conn.c | 72 ++++++++++++++++++++-------------------- 2 files changed, 36 insertions(+), 37 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 8e33c66eac7..6a1ac2c2489 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -509,7 +509,6 @@ int hci_conn_change_link_key(struct hci_conn *conn); int hci_conn_switch_role(struct hci_conn *conn, __u8 role); void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active); -void hci_conn_enter_sniff_mode(struct hci_conn *conn); void hci_conn_hold_device(struct hci_conn *conn); void hci_conn_put_device(struct hci_conn *conn); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index dfe807fb7e7..3131a99dd5f 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -311,6 +311,42 @@ static void hci_conn_timeout(unsigned long arg) hci_dev_unlock(hdev); } +/* Enter sniff mode */ +static void hci_conn_enter_sniff_mode(struct hci_conn *conn) +{ + struct hci_dev *hdev = conn->hdev; + + BT_DBG("conn %p mode %d", conn, conn->mode); + + if (test_bit(HCI_RAW, &hdev->flags)) + return; + + if (!lmp_sniff_capable(hdev) || !lmp_sniff_capable(conn)) + return; + + if (conn->mode != HCI_CM_ACTIVE || !(conn->link_policy & HCI_LP_SNIFF)) + return; + + if (lmp_sniffsubr_capable(hdev) && lmp_sniffsubr_capable(conn)) { + struct hci_cp_sniff_subrate cp; + cp.handle = cpu_to_le16(conn->handle); + cp.max_latency = cpu_to_le16(0); + cp.min_remote_timeout = cpu_to_le16(0); + cp.min_local_timeout = cpu_to_le16(0); + hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp); + } + + if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { + struct hci_cp_sniff_mode cp; + cp.handle = cpu_to_le16(conn->handle); + cp.max_interval = cpu_to_le16(hdev->sniff_max_interval); + cp.min_interval = cpu_to_le16(hdev->sniff_min_interval); + cp.attempt = cpu_to_le16(4); + cp.timeout = cpu_to_le16(1); + hci_send_cmd(hdev, HCI_OP_SNIFF_MODE, sizeof(cp), &cp); + } +} + static void hci_conn_idle(unsigned long arg) { struct hci_conn *conn = (void *) arg; @@ -767,42 +803,6 @@ timer: jiffies + msecs_to_jiffies(hdev->idle_timeout)); } -/* Enter sniff mode */ -void hci_conn_enter_sniff_mode(struct hci_conn *conn) -{ - struct hci_dev *hdev = conn->hdev; - - BT_DBG("conn %p mode %d", conn, conn->mode); - - if (test_bit(HCI_RAW, &hdev->flags)) - return; - - if (!lmp_sniff_capable(hdev) || !lmp_sniff_capable(conn)) - return; - - if (conn->mode != HCI_CM_ACTIVE || !(conn->link_policy & HCI_LP_SNIFF)) - return; - - if (lmp_sniffsubr_capable(hdev) && lmp_sniffsubr_capable(conn)) { - struct hci_cp_sniff_subrate cp; - cp.handle = cpu_to_le16(conn->handle); - cp.max_latency = cpu_to_le16(0); - cp.min_remote_timeout = cpu_to_le16(0); - cp.min_local_timeout = cpu_to_le16(0); - hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp); - } - - if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { - struct hci_cp_sniff_mode cp; - cp.handle = cpu_to_le16(conn->handle); - cp.max_interval = cpu_to_le16(hdev->sniff_max_interval); - cp.min_interval = cpu_to_le16(hdev->sniff_min_interval); - cp.attempt = cpu_to_le16(4); - cp.timeout = cpu_to_le16(1); - hci_send_cmd(hdev, HCI_OP_SNIFF_MODE, sizeof(cp), &cp); - } -} - /* Drop all connection on the device */ void hci_conn_hash_flush(struct hci_dev *hdev) { -- cgit v1.2.3 From b78752cc71d86998d3b77d873c61d6ffdb7a2142 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 8 Aug 2010 23:06:53 -0400 Subject: Bluetooth: Process recv path in a workqueue instead of a tasklet Run recv process in workqueue helps a lot with our processing as the recv path will also be in the process context, i.e., now all our tx and rx are in process context. Signed-off-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 3 ++- net/bluetooth/hci_core.c | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 6a1ac2c2489..1e28be45c4f 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -194,8 +194,9 @@ struct hci_dev { struct delayed_work discov_off; struct timer_list cmd_timer; + + struct work_struct rx_work; struct tasklet_struct cmd_task; - struct tasklet_struct rx_task; struct tasklet_struct tx_task; struct sk_buff_head rx_q; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 700d0abdf2b..4f15722c56d 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -56,8 +56,8 @@ int enable_hs; +static void hci_rx_work(struct work_struct *work); static void hci_cmd_task(unsigned long arg); -static void hci_rx_task(unsigned long arg); static void hci_tx_task(unsigned long arg); static DEFINE_RWLOCK(hci_task_lock); @@ -547,9 +547,9 @@ int hci_dev_open(__u16 dev) } } else { /* Init failed, cleanup */ - tasklet_kill(&hdev->rx_task); tasklet_kill(&hdev->tx_task); tasklet_kill(&hdev->cmd_task); + flush_work(&hdev->rx_work); skb_queue_purge(&hdev->cmd_q); skb_queue_purge(&hdev->rx_q); @@ -586,8 +586,8 @@ static int hci_dev_do_close(struct hci_dev *hdev) } /* Kill RX and TX tasks */ - tasklet_kill(&hdev->rx_task); tasklet_kill(&hdev->tx_task); + flush_work(&hdev->rx_work); if (hdev->discov_timeout > 0) { cancel_delayed_work(&hdev->discov_off); @@ -1456,8 +1456,9 @@ int hci_register_dev(struct hci_dev *hdev) hdev->sniff_max_interval = 800; hdev->sniff_min_interval = 80; - tasklet_init(&hdev->cmd_task, hci_cmd_task, (unsigned long) hdev); - tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev); + INIT_WORK(&hdev->rx_work, hci_rx_work); + + tasklet_init(&hdev->cmd_task, hci_cmd_task,(unsigned long) hdev); tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev); skb_queue_head_init(&hdev->rx_q); @@ -1623,9 +1624,8 @@ int hci_recv_frame(struct sk_buff *skb) /* Time stamp */ __net_timestamp(skb); - /* Queue frame for rx task */ skb_queue_tail(&hdev->rx_q, skb); - tasklet_schedule(&hdev->rx_task); + queue_work(hdev->workqueue, &hdev->rx_work); return 0; } @@ -2486,9 +2486,9 @@ static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb) kfree_skb(skb); } -static void hci_rx_task(unsigned long arg) +static void hci_rx_work(struct work_struct *work) { - struct hci_dev *hdev = (struct hci_dev *) arg; + struct hci_dev *hdev = container_of(work, struct hci_dev, rx_work); struct sk_buff *skb; BT_DBG("%s", hdev->name); @@ -2519,6 +2519,7 @@ static void hci_rx_task(unsigned long arg) /* Process frame */ switch (bt_cb(skb)->pkt_type) { case HCI_EVENT_PKT: + BT_DBG("%s Event packet", hdev->name); hci_event_packet(hdev, skb); break; -- cgit v1.2.3 From 09fd0de5bd8f8ef3317e5365f92f1a13dcd89aa9 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 17 Jun 2011 13:03:21 -0300 Subject: Bluetooth: Replace spin_lock by mutex in hci_dev Now we run everything in HCI in process context, so it's a better idea use mutex instead spin_lock. The macro remains hci_dev_lock() (and I got rid of hci_dev_lock_bh()), of course. Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 8 ++- net/bluetooth/hci_conn.c | 12 ++--- net/bluetooth/hci_core.c | 38 +++++++------- net/bluetooth/hci_sock.c | 8 +-- net/bluetooth/hci_sysfs.c | 20 ++++---- net/bluetooth/hidp/core.c | 4 +- net/bluetooth/l2cap_core.c | 4 +- net/bluetooth/mgmt.c | 104 +++++++++++++++++++-------------------- net/bluetooth/sco.c | 4 +- 9 files changed, 100 insertions(+), 102 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 1e28be45c4f..e7dbe597a4b 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -117,7 +117,7 @@ struct adv_entry { #define NUM_REASSEMBLY 4 struct hci_dev { struct list_head list; - spinlock_t lock; + struct mutex lock; atomic_t refcnt; char name[8]; @@ -566,10 +566,8 @@ static inline struct hci_dev *hci_dev_hold(struct hci_dev *d) return NULL; } -#define hci_dev_lock(d) spin_lock(&d->lock) -#define hci_dev_unlock(d) spin_unlock(&d->lock) -#define hci_dev_lock_bh(d) spin_lock_bh(&d->lock) -#define hci_dev_unlock_bh(d) spin_unlock_bh(&d->lock) +#define hci_dev_lock(d) mutex_lock(&d->lock) +#define hci_dev_unlock(d) mutex_unlock(&d->lock) struct hci_dev *hci_dev_get(int index); struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 3131a99dd5f..d45783de5e2 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -876,7 +876,7 @@ int hci_get_conn_list(void __user *arg) ci = cl->conn_info; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); list_for_each_entry(c, &hdev->conn_hash.list, list) { bacpy(&(ci + n)->bdaddr, &c->dst); (ci + n)->handle = c->handle; @@ -887,7 +887,7 @@ int hci_get_conn_list(void __user *arg) if (++n >= req.conn_num) break; } - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); cl->dev_id = hdev->id; cl->conn_num = n; @@ -911,7 +911,7 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg) if (copy_from_user(&req, arg, sizeof(req))) return -EFAULT; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); conn = hci_conn_hash_lookup_ba(hdev, req.type, &req.bdaddr); if (conn) { bacpy(&ci.bdaddr, &conn->dst); @@ -921,7 +921,7 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg) ci.state = conn->state; ci.link_mode = conn->link_mode; } - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); if (!conn) return -ENOENT; @@ -937,11 +937,11 @@ int hci_get_auth_info(struct hci_dev *hdev, void __user *arg) if (copy_from_user(&req, arg, sizeof(req))) return -EFAULT; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &req.bdaddr); if (conn) req.type = conn->auth_type; - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); if (!conn) return -ENOENT; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 4f15722c56d..ec1019178f8 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -433,14 +433,14 @@ int hci_inquiry(void __user *arg) if (!hdev) return -ENODEV; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX || inquiry_cache_empty(hdev) || ir.flags & IREQ_CACHE_FLUSH) { inquiry_cache_flush(hdev); do_inquiry = 1; } - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); timeo = ir.length * msecs_to_jiffies(2000); @@ -462,9 +462,9 @@ int hci_inquiry(void __user *arg) goto done; } - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); ir.num_rsp = inquiry_cache_dump(hdev, max_rsp, buf); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); BT_DBG("num_rsp %d", ir.num_rsp); @@ -541,9 +541,9 @@ int hci_dev_open(__u16 dev) set_bit(HCI_UP, &hdev->flags); hci_notify(hdev, HCI_DEV_UP); if (!test_bit(HCI_SETUP, &hdev->flags)) { - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); mgmt_powered(hdev, 1); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); } } else { /* Init failed, cleanup */ @@ -597,10 +597,10 @@ static int hci_dev_do_close(struct hci_dev *hdev) if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags)) cancel_delayed_work(&hdev->power_off); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); inquiry_cache_flush(hdev); hci_conn_hash_flush(hdev); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_notify(hdev, HCI_DEV_DOWN); @@ -636,9 +636,9 @@ static int hci_dev_do_close(struct hci_dev *hdev) * and no tasks are scheduled. */ hdev->close(hdev); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); mgmt_powered(hdev, 0); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); /* Clear flags */ hdev->flags = 0; @@ -681,10 +681,10 @@ int hci_dev_reset(__u16 dev) skb_queue_purge(&hdev->rx_q); skb_queue_purge(&hdev->cmd_q); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); inquiry_cache_flush(hdev); hci_conn_hash_flush(hdev); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); if (hdev->flush) hdev->flush(hdev); @@ -967,13 +967,13 @@ static void hci_discov_off(struct work_struct *work) BT_DBG("%s", hdev->name); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan); hdev->discov_timeout = 0; - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); } int hci_uuids_clear(struct hci_dev *hdev) @@ -1443,7 +1443,7 @@ int hci_register_dev(struct hci_dev *hdev) list_add_tail(&hdev->list, head); atomic_set(&hdev->refcnt, 1); - spin_lock_init(&hdev->lock); + mutex_init(&hdev->lock); hdev->flags = 0; hdev->dev_flags = 0; @@ -1558,9 +1558,9 @@ void hci_unregister_dev(struct hci_dev *hdev) if (!test_bit(HCI_INIT, &hdev->flags) && !test_bit(HCI_SETUP, &hdev->flags)) { - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); mgmt_index_removed(hdev); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); } /* mgmt_index_removed should take care of emptying the @@ -1580,13 +1580,13 @@ void hci_unregister_dev(struct hci_dev *hdev) destroy_workqueue(hdev->workqueue); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); hci_blacklist_clear(hdev); hci_uuids_clear(hdev); hci_link_keys_clear(hdev); hci_remote_oob_data_clear(hdev); hci_adv_entries_clear(hdev); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); __hci_dev_put(hdev); } diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index f6afe3d76a6..399be345ea2 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -188,11 +188,11 @@ static int hci_sock_blacklist_add(struct hci_dev *hdev, void __user *arg) if (copy_from_user(&bdaddr, arg, sizeof(bdaddr))) return -EFAULT; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); err = hci_blacklist_add(hdev, &bdaddr); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); return err; } @@ -205,11 +205,11 @@ static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg) if (copy_from_user(&bdaddr, arg, sizeof(bdaddr))) return -EFAULT; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); err = hci_blacklist_del(hdev, &bdaddr); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); return err; } diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index f8e6aa386ce..c3c1ec871d4 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -402,7 +402,7 @@ static int inquiry_cache_show(struct seq_file *f, void *p) struct inquiry_cache *cache = &hdev->inq_cache; struct inquiry_entry *e; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); for (e = cache->list; e; e = e->next) { struct inquiry_data *data = &e->data; @@ -415,7 +415,7 @@ static int inquiry_cache_show(struct seq_file *f, void *p) data->rssi, data->ssp_mode, e->timestamp); } - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); return 0; } @@ -437,12 +437,12 @@ static int blacklist_show(struct seq_file *f, void *p) struct hci_dev *hdev = f->private; struct bdaddr_list *b; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); list_for_each_entry(b, &hdev->blacklist, list) seq_printf(f, "%s\n", batostr(&b->bdaddr)); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); return 0; } @@ -481,12 +481,12 @@ static int uuids_show(struct seq_file *f, void *p) struct hci_dev *hdev = f->private; struct bt_uuid *uuid; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); list_for_each_entry(uuid, &hdev->uuids, list) print_bt_uuid(f, uuid->uuid); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); return 0; } @@ -507,11 +507,11 @@ static int auto_accept_delay_set(void *data, u64 val) { struct hci_dev *hdev = data; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); hdev->auto_accept_delay = val; - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); return 0; } @@ -520,11 +520,11 @@ static int auto_accept_delay_get(void *data, u64 *val) { struct hci_dev *hdev = data; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); *val = hdev->auto_accept_delay; - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); return 0; } diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 3c2d888925d..d478be11d56 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -795,11 +795,11 @@ static struct hci_conn *hidp_get_connection(struct hidp_session *session) if (!hdev) return NULL; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); if (conn) hci_conn_hold_device(conn); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 014fdec1711..0369a9bf60c 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1171,7 +1171,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan) if (!hdev) return -EHOSTUNREACH; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); auth_type = l2cap_get_auth_type(chan); @@ -1214,7 +1214,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan) err = 0; done: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 7a23f211d60..ad4817c9ef2 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -257,7 +257,7 @@ static int read_controller_info(struct sock *sk, u16 index) if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags)) cancel_delayed_work_sync(&hdev->power_off); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); set_bit(HCI_MGMT, &hdev->flags); @@ -286,7 +286,7 @@ static int read_controller_info(struct sock *sk, u16 index) memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name)); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp)); @@ -394,7 +394,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) return cmd_status(sk, index, MGMT_OP_SET_POWERED, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); up = test_bit(HCI_UP, &hdev->flags); if ((cp->val && up) || (!cp->val && !up)) { @@ -422,7 +422,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) err = 0; failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; } @@ -449,7 +449,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, @@ -492,7 +492,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data, hdev->discov_timeout = get_unaligned_le16(&cp->timeout); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -520,7 +520,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, @@ -557,7 +557,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data, mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -612,7 +612,7 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (cp->val) set_bit(HCI_PAIRABLE, &hdev->flags); @@ -628,7 +628,7 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data, err = mgmt_event(MGMT_EV_PAIRABLE, hdev, &ev, sizeof(ev), sk); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -827,7 +827,7 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) return cmd_status(sk, index, MGMT_OP_ADD_UUID, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC); if (!uuid) { @@ -851,7 +851,7 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -878,7 +878,7 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) { err = hci_uuids_clear(hdev); @@ -914,7 +914,7 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0); unlock: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -940,7 +940,7 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); hdev->major_class = cp->major; hdev->minor_class = cp->minor; @@ -950,7 +950,7 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data, if (err == 0) err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -974,7 +974,7 @@ static int set_service_cache(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); BT_DBG("hci%u enable %d", index, cp->enable); @@ -995,7 +995,7 @@ static int set_service_cache(struct sock *sk, u16 index, unsigned char *data, cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, -err); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1034,7 +1034,7 @@ static int load_link_keys(struct sock *sk, u16 index, unsigned char *data, BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys, key_count); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); hci_link_keys_clear(hdev); @@ -1054,7 +1054,7 @@ static int load_link_keys(struct sock *sk, u16 index, unsigned char *data, cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, NULL, 0); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return 0; @@ -1082,7 +1082,7 @@ static int remove_keys(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); memset(&rp, 0, sizeof(rp)); bacpy(&rp.bdaddr, &cp->bdaddr); @@ -1123,7 +1123,7 @@ unlock: if (err < 0) err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp, sizeof(rp)); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1151,7 +1151,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len) return cmd_status(sk, index, MGMT_OP_DISCONNECT, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_DISCONNECT, @@ -1189,7 +1189,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len) mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1231,7 +1231,7 @@ static int get_connections(struct sock *sk, u16 index) return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); count = 0; list_for_each(p, &hdev->conn_hash.list) { @@ -1263,7 +1263,7 @@ static int get_connections(struct sock *sk, u16 index) unlock: kfree(rp); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; } @@ -1311,7 +1311,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, @@ -1354,7 +1354,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data, mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1380,7 +1380,7 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, @@ -1391,7 +1391,7 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data, err = send_pin_code_neg_reply(sk, index, hdev, cp); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1416,14 +1416,14 @@ static int set_io_capability(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); hdev->io_capability = cp->io_capability; BT_DBG("%s IO capability set to 0x%02x", hdev->name, hdev->io_capability); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0); @@ -1504,7 +1504,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); sec_level = BT_SECURITY_MEDIUM; if (cp->io_cap == 0x03) @@ -1561,7 +1561,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) err = 0; unlock: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1580,7 +1580,7 @@ static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr, return cmd_status(sk, index, mgmt_op, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED); @@ -1631,7 +1631,7 @@ static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr, mgmt_pending_remove(cmd); done: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1719,7 +1719,7 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len); if (!cmd) { @@ -1734,7 +1734,7 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data, mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1753,7 +1753,7 @@ static int read_local_oob_data(struct sock *sk, u16 index) return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, @@ -1784,7 +1784,7 @@ static int read_local_oob_data(struct sock *sk, u16 index) mgmt_pending_remove(cmd); unlock: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1808,7 +1808,7 @@ static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash, cp->randomizer); @@ -1819,7 +1819,7 @@ static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data, err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL, 0); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1843,7 +1843,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); err = hci_remove_remote_oob_data(hdev, &cp->bdaddr); if (err < 0) @@ -1853,7 +1853,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, NULL, 0); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1878,7 +1878,7 @@ static int start_discovery(struct sock *sk, u16 index, return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, @@ -1897,7 +1897,7 @@ static int start_discovery(struct sock *sk, u16 index, mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1916,7 +1916,7 @@ static int stop_discovery(struct sock *sk, u16 index) return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0); if (!cmd) { @@ -1929,7 +1929,7 @@ static int stop_discovery(struct sock *sk, u16 index) mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1953,7 +1953,7 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); err = hci_blacklist_add(hdev, &cp->bdaddr); if (err < 0) @@ -1963,7 +1963,7 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data, err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, NULL, 0); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1987,7 +1987,7 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, MGMT_STATUS_INVALID_PARAMS); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); err = hci_blacklist_del(hdev, &cp->bdaddr); @@ -1998,7 +1998,7 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data, err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, NULL, 0); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index a324b009e34..725e10d487f 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -189,7 +189,7 @@ static int sco_connect(struct sock *sk) if (!hdev) return -EHOSTUNREACH; - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (lmp_esco_capable(hdev) && !disable_esco) type = ESCO_LINK; @@ -225,7 +225,7 @@ static int sco_connect(struct sock *sk) } done: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; } -- cgit v1.2.3 From 19c40e3bcaf2d969f5d4ee85bbe1330b54d36d9c Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 17 Jun 2011 13:03:21 -0300 Subject: Bluetooth: Use delayed_work for connection timeout Bluetooth rx task runs now in a workqueue, so it a good approach run any timer that share locking with process context code also in a workqueue. Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 8 +++++--- net/bluetooth/hci_conn.c | 9 +++++---- 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index e7dbe597a4b..d9159085042 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -297,7 +297,7 @@ struct hci_conn { struct sk_buff_head data_q; struct list_head chan_list; - struct timer_list disc_timer; + struct delayed_work disc_work; struct timer_list idle_timer; struct timer_list auto_accept_timer; @@ -517,7 +517,7 @@ void hci_conn_put_device(struct hci_conn *conn); static inline void hci_conn_hold(struct hci_conn *conn) { atomic_inc(&conn->refcnt); - del_timer(&conn->disc_timer); + cancel_delayed_work_sync(&conn->disc_work); } static inline void hci_conn_put(struct hci_conn *conn) @@ -536,7 +536,9 @@ static inline void hci_conn_put(struct hci_conn *conn) } else { timeo = msecs_to_jiffies(10); } - mod_timer(&conn->disc_timer, jiffies + timeo); + cancel_delayed_work_sync(&conn->disc_work); + queue_delayed_work(conn->hdev->workqueue, + &conn->disc_work, jiffies + timeo); } } diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index d45783de5e2..7d88a614209 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -275,9 +275,10 @@ void hci_sco_setup(struct hci_conn *conn, __u8 status) } } -static void hci_conn_timeout(unsigned long arg) +static void hci_conn_timeout(struct work_struct *work) { - struct hci_conn *conn = (void *) arg; + struct hci_conn *conn = container_of(work, struct hci_conn, + disc_work.work); struct hci_dev *hdev = conn->hdev; __u8 reason; @@ -412,7 +413,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) INIT_LIST_HEAD(&conn->chan_list);; - setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn); + INIT_DELAYED_WORK(&conn->disc_work, hci_conn_timeout); setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn); setup_timer(&conn->auto_accept_timer, hci_conn_auto_accept, (unsigned long) conn); @@ -444,7 +445,7 @@ int hci_conn_del(struct hci_conn *conn) del_timer(&conn->idle_timer); - del_timer(&conn->disc_timer); + cancel_delayed_work_sync(&conn->disc_work); del_timer(&conn->auto_accept_timer); -- cgit v1.2.3 From db323f2fff0ded058f033df6235e8c2be4146bfd Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 20 Jun 2011 16:39:29 -0300 Subject: Bluetooth: Use delayed work for advertisiment cache timeout As HCI rx path is now done in process context it makes sense to do all the timer in process context as well. Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_core.c | 10 +++++----- net/bluetooth/hci_event.c | 6 ++++-- 3 files changed, 10 insertions(+), 8 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index d9159085042..14b200b08d8 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -226,7 +226,7 @@ struct hci_dev { struct list_head remote_oob_data; struct list_head adv_entries; - struct timer_list adv_timer; + struct delayed_work adv_work; struct hci_dev_stats stat; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index ec1019178f8..6f5bb3cbf6f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1340,9 +1340,10 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr) return mgmt_device_unblocked(hdev, bdaddr); } -static void hci_clear_adv_cache(unsigned long arg) +static void hci_clear_adv_cache(struct work_struct *work) { - struct hci_dev *hdev = (void *) arg; + struct hci_dev *hdev = container_of(work, struct hci_dev, + adv_work.work); hci_dev_lock(hdev); @@ -1488,9 +1489,8 @@ int hci_register_dev(struct hci_dev *hdev) INIT_LIST_HEAD(&hdev->remote_oob_data); INIT_LIST_HEAD(&hdev->adv_entries); - setup_timer(&hdev->adv_timer, hci_clear_adv_cache, - (unsigned long) hdev); + INIT_DELAYED_WORK(&hdev->adv_work, hci_clear_adv_cache); INIT_WORK(&hdev->power_on, hci_power_on); INIT_DELAYED_WORK(&hdev->power_off, hci_power_off); @@ -1576,7 +1576,7 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_del_sysfs(hdev); - del_timer(&hdev->adv_timer); + cancel_delayed_work_sync(&hdev->adv_work); destroy_workqueue(hdev->workqueue); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 35cb56ed3b0..0a9501f1736 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1017,7 +1017,7 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, if (cp->enable == 0x01) { set_bit(HCI_LE_SCAN, &hdev->dev_flags); - del_timer(&hdev->adv_timer); + cancel_delayed_work_sync(&hdev->adv_work); hci_dev_lock(hdev); hci_adv_entries_clear(hdev); @@ -1025,7 +1025,9 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, } else if (cp->enable == 0x00) { clear_bit(HCI_LE_SCAN, &hdev->dev_flags); - mod_timer(&hdev->adv_timer, jiffies + ADV_CLEAR_TIMEOUT); + cancel_delayed_work_sync(&hdev->adv_work); + queue_delayed_work(hdev->workqueue, &hdev->adv_work, + jiffies + ADV_CLEAR_TIMEOUT); } } -- cgit v1.2.3 From b9cc553f12d14b692d0fcb607d28db783da68139 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 17 Jun 2011 12:58:41 -0300 Subject: Bluetooth: hci_conn_auto_accept() doesn't need locking It doesn't really touch any sensitive information about hdev. So no need to lock here. Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_conn.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 7d88a614209..e6d8a220b5d 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -362,12 +362,8 @@ static void hci_conn_auto_accept(unsigned long arg) struct hci_conn *conn = (void *) arg; struct hci_dev *hdev = conn->hdev; - hci_dev_lock(hdev); - hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY, sizeof(conn->dst), &conn->dst); - - hci_dev_unlock(hdev); } struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) -- cgit v1.2.3 From 721c41812daf7b38759942563773a7832e3c990d Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 23 Jun 2011 19:29:58 -0300 Subject: Bluetooth: Move L2CAP timers to workqueue L2CAP timers also need to run in process context. As the works in l2cap are small we are using the system worqueue. Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 17 ++++++----- net/bluetooth/l2cap_core.c | 70 +++++++++++++++++++------------------------ 2 files changed, 40 insertions(+), 47 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 30719eb2e77..03be9111dc5 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -482,10 +482,11 @@ struct l2cap_chan { __u32 remote_acc_lat; __u32 remote_flush_to; - struct timer_list chan_timer; - struct timer_list retrans_timer; - struct timer_list monitor_timer; - struct timer_list ack_timer; + struct delayed_work chan_timer; + struct delayed_work retrans_timer; + struct delayed_work monitor_timer; + struct delayed_work ack_timer; + struct sk_buff *tx_send_head; struct sk_buff_head tx_q; struct sk_buff_head srej_q; @@ -595,16 +596,16 @@ enum { }; #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t)) -#define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer) +#define __clear_chan_timer(c) l2cap_clear_timer(&c->chan_timer) #define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \ L2CAP_DEFAULT_RETRANS_TO); -#define __clear_retrans_timer(c) l2cap_clear_timer(c, &c->retrans_timer) +#define __clear_retrans_timer(c) l2cap_clear_timer(&c->retrans_timer) #define __set_monitor_timer(c) l2cap_set_timer(c, &c->monitor_timer, \ L2CAP_DEFAULT_MONITOR_TO); -#define __clear_monitor_timer(c) l2cap_clear_timer(c, &c->monitor_timer) +#define __clear_monitor_timer(c) l2cap_clear_timer(&c->monitor_timer) #define __set_ack_timer(c) l2cap_set_timer(c, &chan->ack_timer, \ L2CAP_DEFAULT_ACK_TO); -#define __clear_ack_timer(c) l2cap_clear_timer(c, &c->ack_timer) +#define __clear_ack_timer(c) l2cap_clear_timer(&c->ack_timer) static inline int __seq_offset(struct l2cap_chan *chan, __u16 seq1, __u16 seq2) { diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 0369a9bf60c..89cda6d82d0 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -213,20 +213,18 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn) return 0; } -static void l2cap_set_timer(struct l2cap_chan *chan, struct timer_list *timer, long timeout) +static void l2cap_set_timer(struct l2cap_chan *chan, struct delayed_work *work, long timeout) { BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout); - if (!mod_timer(timer, jiffies + msecs_to_jiffies(timeout))) - chan_hold(chan); + cancel_delayed_work_sync(work); + + schedule_delayed_work(work, timeout); } -static void l2cap_clear_timer(struct l2cap_chan *chan, struct timer_list *timer) +static void l2cap_clear_timer(struct delayed_work *work) { - BT_DBG("chan %p state %d", chan, chan->state); - - if (timer_pending(timer) && del_timer(timer)) - chan_put(chan); + cancel_delayed_work_sync(work); } static char *state_to_string(int state) @@ -264,23 +262,16 @@ static void l2cap_state_change(struct l2cap_chan *chan, int state) chan->ops->state_change(chan->data, state); } -static void l2cap_chan_timeout(unsigned long arg) +static void l2cap_chan_timeout(struct work_struct *work) { - struct l2cap_chan *chan = (struct l2cap_chan *) arg; + struct l2cap_chan *chan = container_of(work, struct l2cap_chan, + chan_timer.work); struct sock *sk = chan->sk; int reason; BT_DBG("chan %p state %d", chan, chan->state); - bh_lock_sock(sk); - - if (sock_owned_by_user(sk)) { - /* sk is owned by user. Try again later */ - __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); - bh_unlock_sock(sk); - chan_put(chan); - return; - } + lock_sock(sk); if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG) reason = ECONNREFUSED; @@ -292,7 +283,7 @@ static void l2cap_chan_timeout(unsigned long arg) l2cap_chan_close(chan, reason); - bh_unlock_sock(sk); + release_sock(sk); chan->ops->close(chan->data); chan_put(chan); @@ -312,7 +303,7 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk) list_add(&chan->global_l, &chan_list); write_unlock_bh(&chan_list_lock); - setup_timer(&chan->chan_timer, l2cap_chan_timeout, (unsigned long) chan); + INIT_DELAYED_WORK(&chan->chan_timer, l2cap_chan_timeout); chan->state = BT_OPEN; @@ -1251,17 +1242,18 @@ int __l2cap_wait_ack(struct sock *sk) return err; } -static void l2cap_monitor_timeout(unsigned long arg) +static void l2cap_monitor_timeout(struct work_struct *work) { - struct l2cap_chan *chan = (void *) arg; + struct l2cap_chan *chan = container_of(work, struct l2cap_chan, + monitor_timer.work); struct sock *sk = chan->sk; BT_DBG("chan %p", chan); - bh_lock_sock(sk); + lock_sock(sk); if (chan->retry_count >= chan->remote_max_tx) { l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); - bh_unlock_sock(sk); + release_sock(sk); return; } @@ -1269,24 +1261,25 @@ static void l2cap_monitor_timeout(unsigned long arg) __set_monitor_timer(chan); l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); - bh_unlock_sock(sk); + release_sock(sk); } -static void l2cap_retrans_timeout(unsigned long arg) +static void l2cap_retrans_timeout(struct work_struct *work) { - struct l2cap_chan *chan = (void *) arg; + struct l2cap_chan *chan = container_of(work, struct l2cap_chan, + retrans_timer.work); struct sock *sk = chan->sk; BT_DBG("chan %p", chan); - bh_lock_sock(sk); + lock_sock(sk); chan->retry_count = 1; __set_monitor_timer(chan); set_bit(CONN_WAIT_F, &chan->conn_state); l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); - bh_unlock_sock(sk); + release_sock(sk); } static void l2cap_drop_acked_frames(struct l2cap_chan *chan) @@ -1955,13 +1948,14 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan) (unsigned long) &efs); } -static void l2cap_ack_timeout(unsigned long arg) +static void l2cap_ack_timeout(struct work_struct *work) { - struct l2cap_chan *chan = (void *) arg; + struct l2cap_chan *chan = container_of(work, struct l2cap_chan, + ack_timer.work); - bh_lock_sock(chan->sk); + lock_sock(chan->sk); l2cap_send_ack(chan); - bh_unlock_sock(chan->sk); + release_sock(chan->sk); } static inline void l2cap_ertm_init(struct l2cap_chan *chan) @@ -1974,11 +1968,9 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan) chan->num_acked = 0; chan->frames_sent = 0; - setup_timer(&chan->retrans_timer, l2cap_retrans_timeout, - (unsigned long) chan); - setup_timer(&chan->monitor_timer, l2cap_monitor_timeout, - (unsigned long) chan); - setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan); + INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout); + INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout); + INIT_DELAYED_WORK(&chan->ack_timer, l2cap_ack_timeout); skb_queue_head_init(&chan->srej_q); -- cgit v1.2.3 From aa2ac881ba1e4e9f878be2ece80001ae8563955c Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 24 Jun 2011 01:53:01 -0300 Subject: Bluetooth: Don't use spin_lock socket lock anymore We now run everything in process context, so the mutex lock is the best option. But in some places we still need the bh_lock_sock() Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_core.c | 66 ++++++++++++++-------------------------------- 1 file changed, 20 insertions(+), 46 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 89cda6d82d0..ed67ac0ca21 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -118,7 +118,7 @@ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 ci read_lock(&conn->chan_lock); c = __l2cap_get_chan_by_scid(conn, cid); if (c) - bh_lock_sock(c->sk); + lock_sock(c->sk); read_unlock(&conn->chan_lock); return c; } @@ -141,7 +141,7 @@ static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn read_lock(&conn->chan_lock); c = __l2cap_get_chan_by_ident(conn, ident); if (c) - bh_lock_sock(c->sk); + lock_sock(c->sk); read_unlock(&conn->chan_lock); return c; } @@ -889,7 +889,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) parent = pchan->sk; - bh_lock_sock(parent); + lock_sock(parent); /* Check for backlog size */ if (sk_acceptq_is_full(parent)) { @@ -922,7 +922,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) write_unlock_bh(&conn->chan_lock); clean: - bh_unlock_sock(parent); + release_sock(parent); } static void l2cap_chan_ready(struct sock *sk) @@ -1024,9 +1024,9 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) /* Kill channels */ list_for_each_entry_safe(chan, l, &conn->chan_l, list) { sk = chan->sk; - bh_lock_sock(sk); + lock_sock(sk); l2cap_chan_del(chan, err); - bh_unlock_sock(sk); + release_sock(sk); chan->ops->close(chan->data); } @@ -2568,7 +2568,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd parent = pchan->sk; - bh_lock_sock(parent); + lock_sock(parent); /* Check if the ACL is secure enough (if not SDP) */ if (psm != cpu_to_le16(0x0001) && @@ -2645,7 +2645,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd write_unlock_bh(&conn->chan_lock); response: - bh_unlock_sock(parent); + release_sock(parent); sendresp: rsp.scid = cpu_to_le16(scid); @@ -2727,19 +2727,11 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd break; default: - /* don't delete l2cap channel if sk is owned by user */ - if (sock_owned_by_user(sk)) { - l2cap_state_change(chan, BT_DISCONN); - __clear_chan_timer(chan); - __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); - break; - } - l2cap_chan_del(chan, ECONNREFUSED); break; } - bh_unlock_sock(sk); + release_sock(sk); return 0; } @@ -2861,7 +2853,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr } unlock: - bh_unlock_sock(sk); + release_sock(sk); return 0; } @@ -2968,7 +2960,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr } done: - bh_unlock_sock(sk); + release_sock(sk); return 0; } @@ -2997,17 +2989,8 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd sk->sk_shutdown = SHUTDOWN_MASK; - /* don't delete l2cap channel if sk is owned by user */ - if (sock_owned_by_user(sk)) { - l2cap_state_change(chan, BT_DISCONN); - __clear_chan_timer(chan); - __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); - bh_unlock_sock(sk); - return 0; - } - l2cap_chan_del(chan, ECONNRESET); - bh_unlock_sock(sk); + release_sock(sk); chan->ops->close(chan->data); return 0; @@ -3031,17 +3014,8 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd sk = chan->sk; - /* don't delete l2cap channel if sk is owned by user */ - if (sock_owned_by_user(sk)) { - l2cap_state_change(chan, BT_DISCONN); - __clear_chan_timer(chan); - __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); - bh_unlock_sock(sk); - return 0; - } - l2cap_chan_del(chan, 0); - bh_unlock_sock(sk); + release_sock(sk); chan->ops->close(chan->data); return 0; @@ -4284,7 +4258,7 @@ drop: done: if (sk) - bh_unlock_sock(sk); + release_sock(sk); return 0; } @@ -4300,7 +4274,7 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str sk = chan->sk; - bh_lock_sock(sk); + lock_sock(sk); BT_DBG("sk %p, len %d", sk, skb->len); @@ -4318,7 +4292,7 @@ drop: done: if (sk) - bh_unlock_sock(sk); + release_sock(sk); return 0; } @@ -4333,7 +4307,7 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk = chan->sk; - bh_lock_sock(sk); + lock_sock(sk); BT_DBG("sk %p, len %d", sk, skb->len); @@ -4351,7 +4325,7 @@ drop: done: if (sk) - bh_unlock_sock(sk); + release_sock(sk); return 0; } @@ -4656,11 +4630,11 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl BT_ERR("Frame exceeding recv MTU (len %d, " "MTU %d)", len, chan->imtu); - bh_unlock_sock(sk); + release_sock(sk); l2cap_conn_unreliable(conn, ECOMM); goto drop; } - bh_unlock_sock(sk); + release_sock(sk); } /* Allocate skb for the complete frame (with header) */ -- cgit v1.2.3 From eb403a1b7eea9d736c55f78407dccb42b72757a4 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 24 Jun 2011 01:54:50 -0300 Subject: Bluetooth: Remove sk_backlog usage from L2CAP We run everything in the same lock now. The backlog queue is useless now Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_core.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index ed67ac0ca21..31c94fd3161 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1960,8 +1960,6 @@ static void l2cap_ack_timeout(struct work_struct *work) static inline void l2cap_ertm_init(struct l2cap_chan *chan) { - struct sock *sk = chan->sk; - chan->expected_ack_seq = 0; chan->unacked_frames = 0; chan->buffer_seq = 0; @@ -1975,9 +1973,6 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan) skb_queue_head_init(&chan->srej_q); INIT_LIST_HEAD(&chan->srej_l); - - - sk->sk_backlog_rcv = l2cap_ertm_data_rcv; } static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) @@ -4203,12 +4198,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk break; case L2CAP_MODE_ERTM: - if (!sock_owned_by_user(sk)) { - l2cap_ertm_data_rcv(sk, skb); - } else { - if (sk_add_backlog(sk, skb)) - goto drop; - } + l2cap_ertm_data_rcv(sk, skb); goto done; -- cgit v1.2.3 From 67d0dfb5ec781e9fe030e4e61359ee6eed66ff92 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 9 Dec 2011 04:41:30 -0200 Subject: Bluetooth: move hci_task_lock to mutex Now we can sleep in any path inside Bluetooth core, so mutex can make sense here. Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_core.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 6f5bb3cbf6f..36763aa59ea 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -60,7 +60,7 @@ static void hci_rx_work(struct work_struct *work); static void hci_cmd_task(unsigned long arg); static void hci_tx_task(unsigned long arg); -static DEFINE_RWLOCK(hci_task_lock); +static DEFINE_MUTEX(hci_task_lock); /* HCI device list */ LIST_HEAD(hci_dev_list); @@ -1808,14 +1808,14 @@ int hci_register_proto(struct hci_proto *hp) if (hp->id >= HCI_MAX_PROTO) return -EINVAL; - write_lock_bh(&hci_task_lock); + mutex_lock(&hci_task_lock); if (!hci_proto[hp->id]) hci_proto[hp->id] = hp; else err = -EEXIST; - write_unlock_bh(&hci_task_lock); + mutex_unlock(&hci_task_lock); return err; } @@ -1830,14 +1830,14 @@ int hci_unregister_proto(struct hci_proto *hp) if (hp->id >= HCI_MAX_PROTO) return -EINVAL; - write_lock_bh(&hci_task_lock); + mutex_lock(&hci_task_lock); if (hci_proto[hp->id]) hci_proto[hp->id] = NULL; else err = -ENOENT; - write_unlock_bh(&hci_task_lock); + mutex_unlock(&hci_task_lock); return err; } @@ -2386,7 +2386,7 @@ static void hci_tx_task(unsigned long arg) struct hci_dev *hdev = (struct hci_dev *) arg; struct sk_buff *skb; - read_lock(&hci_task_lock); + mutex_lock(&hci_task_lock); BT_DBG("%s acl %d sco %d le %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt, hdev->le_cnt); @@ -2405,7 +2405,7 @@ static void hci_tx_task(unsigned long arg) while ((skb = skb_dequeue(&hdev->raw_q))) hci_send_frame(skb); - read_unlock(&hci_task_lock); + mutex_unlock(&hci_task_lock); } /* ----- HCI RX task (incoming data processing) ----- */ @@ -2493,7 +2493,7 @@ static void hci_rx_work(struct work_struct *work) BT_DBG("%s", hdev->name); - read_lock(&hci_task_lock); + mutex_lock(&hci_task_lock); while ((skb = skb_dequeue(&hdev->rx_q))) { if (atomic_read(&hdev->promisc)) { @@ -2539,7 +2539,7 @@ static void hci_rx_work(struct work_struct *work) } } - read_unlock(&hci_task_lock); + mutex_unlock(&hci_task_lock); } static void hci_cmd_task(unsigned long arg) -- cgit v1.2.3 From d01b2ff4e6496bc48a1917b6340e13263f871a15 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 9 Dec 2011 04:45:12 -0200 Subject: Bluetooth: convert chan_lock to mutex spin lock doesn't fit ok anymore on the new code based on workqueues. Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 2 +- net/bluetooth/l2cap_core.c | 52 +++++++++++++++++++++---------------------- 2 files changed, 27 insertions(+), 27 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 03be9111dc5..a1750912824 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -536,7 +536,7 @@ struct l2cap_conn { struct smp_chan *smp_chan; struct list_head chan_l; - rwlock_t chan_lock; + struct mutex chan_lock; }; #define L2CAP_INFO_CL_MTU_REQ_SENT 0x01 diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 31c94fd3161..5c5948f09a6 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -115,11 +115,11 @@ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 ci { struct l2cap_chan *c; - read_lock(&conn->chan_lock); + mutex_lock(&conn->chan_lock); c = __l2cap_get_chan_by_scid(conn, cid); if (c) lock_sock(c->sk); - read_unlock(&conn->chan_lock); + mutex_unlock(&conn->chan_lock); return c; } @@ -138,11 +138,11 @@ static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn { struct l2cap_chan *c; - read_lock(&conn->chan_lock); + mutex_lock(&conn->chan_lock); c = __l2cap_get_chan_by_ident(conn, ident); if (c) lock_sock(c->sk); - read_unlock(&conn->chan_lock); + mutex_unlock(&conn->chan_lock); return c; } @@ -381,9 +381,9 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) if (conn) { /* Delete from channel list */ - write_lock_bh(&conn->chan_lock); + mutex_lock(&conn->chan_lock); list_del(&chan->list); - write_unlock_bh(&conn->chan_lock); + mutex_unlock(&conn->chan_lock); chan_put(chan); chan->conn = NULL; @@ -754,7 +754,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) BT_DBG("conn %p", conn); - read_lock(&conn->chan_lock); + mutex_lock(&conn->chan_lock); list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { struct sock *sk = chan->sk; @@ -780,9 +780,9 @@ static void l2cap_conn_start(struct l2cap_conn *conn) &chan->conf_state)) { /* l2cap_chan_close() calls list_del(chan) * so release the lock */ - read_unlock(&conn->chan_lock); + mutex_unlock(&conn->chan_lock); l2cap_chan_close(chan, ECONNRESET); - read_lock(&conn->chan_lock); + utex_lock(&conn->chan_lock); bh_unlock_sock(sk); continue; } @@ -838,7 +838,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) bh_unlock_sock(sk); } - read_unlock(&conn->chan_lock); + mutex_unlock(&conn->chan_lock); } /* Find socket with cid and source bdaddr. @@ -903,7 +903,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) sk = chan->sk; - write_lock_bh(&conn->chan_lock); + mutex_lock(&conn->chan_lock); hci_conn_hold(conn->hcon); @@ -919,7 +919,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) l2cap_state_change(chan, BT_CONNECTED); parent->sk_data_ready(parent, 0); - write_unlock_bh(&conn->chan_lock); + mutex_unlock(&conn->chan_lock); clean: release_sock(parent); @@ -954,7 +954,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) if (conn->hcon->out && conn->hcon->type == LE_LINK) smp_conn_security(conn, conn->hcon->pending_sec_level); - read_lock(&conn->chan_lock); + mutex_lock(&conn->chan_lock); list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; @@ -976,7 +976,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) bh_unlock_sock(sk); } - read_unlock(&conn->chan_lock); + mutex_unlock(&conn->chan_lock); } /* Notify sockets that we cannot guaranty reliability anymore */ @@ -986,7 +986,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) BT_DBG("conn %p", conn); - read_lock(&conn->chan_lock); + mutex_lock(&conn->chan_lock); list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; @@ -995,7 +995,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) sk->sk_err = err; } - read_unlock(&conn->chan_lock); + mutex_unlock(&conn->chan_lock); } static void l2cap_info_timeout(unsigned long arg) @@ -1086,7 +1086,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) conn->feat_mask = 0; spin_lock_init(&conn->lock); - rwlock_init(&conn->chan_lock); + mutex_init(&conn->chan_lock); INIT_LIST_HEAD(&conn->chan_l); @@ -1104,9 +1104,9 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { - write_lock_bh(&conn->chan_lock); + mutex_lock(&conn->chan_lock); __l2cap_chan_add(conn, chan); - write_unlock_bh(&conn->chan_lock); + mutex_unlock(&conn->chan_lock); } /* ---- Socket interface ---- */ @@ -1771,7 +1771,7 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("conn %p", conn); - read_lock(&conn->chan_lock); + mutex_lock(&conn->chan_lock); list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; if (chan->chan_type != L2CAP_CHAN_RAW) @@ -1787,7 +1787,7 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) if (chan->ops->recv(chan->data, nskb)) kfree_skb(nskb); } - read_unlock(&conn->chan_lock); + mutex_unlock(&conn->chan_lock); } /* ---- L2CAP signalling commands ---- */ @@ -2587,11 +2587,11 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd sk = chan->sk; - write_lock_bh(&conn->chan_lock); + mutex_lock(&conn->chan_lock); /* Check if we already have channel with that dcid */ if (__l2cap_get_chan_by_dcid(conn, scid)) { - write_unlock_bh(&conn->chan_lock); + mutex_unlock(&conn->chan_lock); sock_set_flag(sk, SOCK_ZAPPED); chan->ops->close(chan->data); goto response; @@ -2637,7 +2637,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd status = L2CAP_CS_NO_INFO; } - write_unlock_bh(&conn->chan_lock); + mutex_unlock(&conn->chan_lock); response: release_sock(parent); @@ -4474,7 +4474,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) del_timer(&conn->security_timer); } - read_lock(&conn->chan_lock); + mutex_lock(&conn->chan_lock); list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; @@ -4554,7 +4554,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) bh_unlock_sock(sk); } - read_unlock(&conn->chan_lock); + mutex_unlock(&conn->chan_lock); return 0; } -- cgit v1.2.3 From 8192edef03f9b47f1cc1120724db525e63e218f3 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 14 Dec 2011 15:08:48 -0200 Subject: Bluetooth: Use RCU to manipulate chan_list Instead of using tasklet_disable() to prevent acess to the channel use, we can use RCU and improve the performance of our code. Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_conn.c | 14 ++++++-------- net/bluetooth/hci_core.c | 12 ++++++++++-- 2 files changed, 16 insertions(+), 10 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index e6d8a220b5d..b04467674a1 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -960,9 +960,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn) chan->conn = conn; skb_queue_head_init(&chan->data_q); - tasklet_disable(&hdev->tx_task); - list_add(&conn->chan_list, &chan->list); - tasklet_enable(&hdev->tx_task); + list_add_rcu(&chan->list, &conn->chan_list); return chan; } @@ -974,9 +972,9 @@ int hci_chan_del(struct hci_chan *chan) BT_DBG("%s conn %p chan %p", hdev->name, conn, chan); - tasklet_disable(&hdev->tx_task); - list_del(&chan->list); - tasklet_enable(&hdev->tx_task); + list_del_rcu(&chan->list); + + synchronize_rcu(); skb_queue_purge(&chan->data_q); kfree(chan); @@ -986,10 +984,10 @@ int hci_chan_del(struct hci_chan *chan) void hci_chan_list_flush(struct hci_conn *conn) { - struct hci_chan *chan, *tmp; + struct hci_chan *chan; BT_DBG("conn %p", conn); - list_for_each_entry_safe(chan, tmp, &conn->chan_list, list) + list_for_each_entry_rcu(chan, &conn->chan_list, list) hci_chan_del(chan); } diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 36763aa59ea..2c4f32f4456 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2135,7 +2135,9 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type, conn_num++; - list_for_each_entry(tmp, &conn->chan_list, list) { + rcu_read_lock(); + + list_for_each_entry_rcu(tmp, &conn->chan_list, list) { struct sk_buff *skb; if (skb_queue_empty(&tmp->data_q)) @@ -2159,6 +2161,8 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type, } } + rcu_read_unlock(); + if (hci_conn_num(hdev, type) == conn_num) break; } @@ -2207,7 +2211,9 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type) num++; - list_for_each_entry(chan, &conn->chan_list, list) { + rcu_read_lock(); + + list_for_each_entry_rcu(chan, &conn->chan_list, list) { struct sk_buff *skb; if (chan->sent) { @@ -2228,6 +2234,8 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type) skb->priority); } + rcu_read_unlock(); + if (hci_conn_num(hdev, type) == num) break; } -- cgit v1.2.3 From bf4c63252490ba78fb833cc7acf1a5b1900c970f Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 14 Dec 2011 22:54:12 -0200 Subject: Bluetooth: convert conn hash to RCU Handling hci_conn_hash with RCU make us avoid some locking and disable tasklets. Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 45 +++++++++++++++++++++++++++------------- net/bluetooth/hci_conn.c | 19 ++++++++--------- net/bluetooth/hci_core.c | 34 +++++++++++++++++++----------- 3 files changed, 62 insertions(+), 36 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 14b200b08d8..e8324331892 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -392,7 +392,7 @@ static inline void hci_conn_hash_init(struct hci_dev *hdev) static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c) { struct hci_conn_hash *h = &hdev->conn_hash; - list_add(&c->list, &h->list); + list_add_rcu(&c->list, &h->list); switch (c->type) { case ACL_LINK: h->acl_num++; @@ -410,7 +410,10 @@ static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c) static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c) { struct hci_conn_hash *h = &hdev->conn_hash; - list_del(&c->list); + + list_del_rcu(&c->list); + synchronize_rcu(); + switch (c->type) { case ACL_LINK: h->acl_num--; @@ -445,14 +448,18 @@ static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev, __u16 handle) { struct hci_conn_hash *h = &hdev->conn_hash; - struct list_head *p; struct hci_conn *c; - list_for_each(p, &h->list) { - c = list_entry(p, struct hci_conn, list); - if (c->handle == handle) + rcu_read_lock(); + + list_for_each_entry_rcu(c, &h->list, list) { + if (c->handle == handle) { + rcu_read_unlock(); return c; + } } + rcu_read_unlock(); + return NULL; } @@ -460,14 +467,19 @@ static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev, __u8 type, bdaddr_t *ba) { struct hci_conn_hash *h = &hdev->conn_hash; - struct list_head *p; struct hci_conn *c; - list_for_each(p, &h->list) { - c = list_entry(p, struct hci_conn, list); - if (c->type == type && !bacmp(&c->dst, ba)) + rcu_read_lock(); + + list_for_each_entry_rcu(c, &h->list, list) { + if (c->type == type && !bacmp(&c->dst, ba)) { + rcu_read_unlock(); return c; + } } + + rcu_read_unlock(); + return NULL; } @@ -475,14 +487,19 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev, __u8 type, __u16 state) { struct hci_conn_hash *h = &hdev->conn_hash; - struct list_head *p; struct hci_conn *c; - list_for_each(p, &h->list) { - c = list_entry(p, struct hci_conn, list); - if (c->type == type && c->state == state) + rcu_read_lock(); + + list_for_each_entry_rcu(c, &h->list, list) { + if (c->type == type && c->state == state) { + rcu_read_unlock(); return c; + } } + + rcu_read_unlock(); + return NULL; } diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index b04467674a1..5e9e193ac71 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -418,18 +418,17 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) hci_dev_hold(hdev); - tasklet_disable(&hdev->tx_task); - hci_conn_hash_add(hdev, conn); - if (hdev->notify) + if (hdev->notify) { + tasklet_disable(&hdev->tx_task); hdev->notify(hdev, HCI_NOTIFY_CONN_ADD); + tasklet_enable(&hdev->tx_task); + } atomic_set(&conn->devref, 0); hci_conn_init_sysfs(conn); - tasklet_enable(&hdev->tx_task); - return conn; } @@ -465,15 +464,15 @@ int hci_conn_del(struct hci_conn *conn) } } - tasklet_disable(&hdev->tx_task); hci_chan_list_flush(conn); hci_conn_hash_del(hdev, conn); - if (hdev->notify) + if (hdev->notify) { + tasklet_disable(&hdev->tx_task); hdev->notify(hdev, HCI_NOTIFY_CONN_DEL); - - tasklet_enable(&hdev->tx_task); + tasklet_enable(&hdev->tx_task); + } skb_queue_purge(&conn->data_q); @@ -808,7 +807,7 @@ void hci_conn_hash_flush(struct hci_dev *hdev) BT_DBG("hdev %s", hdev->name); - list_for_each_entry(c, &h->list, list) { + list_for_each_entry_rcu(c, &h->list, list) { c->state = BT_CLOSED; hci_proto_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 2c4f32f4456..de923ee6009 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2050,7 +2050,10 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int /* We don't have to lock device here. Connections are always * added and removed with TX task disabled. */ - list_for_each_entry(c, &h->list, list) { + + rcu_read_lock(); + + list_for_each_entry_rcu(c, &h->list, list) { if (c->type != type || skb_queue_empty(&c->data_q)) continue; @@ -2068,6 +2071,8 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int break; } + rcu_read_unlock(); + if (conn) { int cnt, q; @@ -2103,14 +2108,18 @@ static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type) BT_ERR("%s link tx timeout", hdev->name); + rcu_read_lock(); + /* Kill stalled connections */ - list_for_each_entry(c, &h->list, list) { + list_for_each_entry_rcu(c, &h->list, list) { if (c->type == type && c->sent) { BT_ERR("%s killing stalled connection %s", hdev->name, batostr(&c->dst)); hci_acl_disconn(c, 0x13); } } + + rcu_read_unlock(); } static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type, @@ -2124,7 +2133,9 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type, BT_DBG("%s", hdev->name); - list_for_each_entry(conn, &h->list, list) { + rcu_read_lock(); + + list_for_each_entry_rcu(conn, &h->list, list) { struct hci_chan *tmp; if (conn->type != type) @@ -2135,8 +2146,6 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type, conn_num++; - rcu_read_lock(); - list_for_each_entry_rcu(tmp, &conn->chan_list, list) { struct sk_buff *skb; @@ -2161,12 +2170,12 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type, } } - rcu_read_unlock(); - if (hci_conn_num(hdev, type) == conn_num) break; } + rcu_read_unlock(); + if (!chan) return NULL; @@ -2200,7 +2209,9 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type) BT_DBG("%s", hdev->name); - list_for_each_entry(conn, &h->list, list) { + rcu_read_lock(); + + list_for_each_entry_rcu(conn, &h->list, list) { struct hci_chan *chan; if (conn->type != type) @@ -2211,8 +2222,6 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type) num++; - rcu_read_lock(); - list_for_each_entry_rcu(chan, &conn->chan_list, list) { struct sk_buff *skb; @@ -2234,11 +2243,12 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type) skb->priority); } - rcu_read_unlock(); - if (hci_conn_num(hdev, type) == num) break; } + + rcu_read_unlock(); + } static inline void hci_sched_acl(struct hci_dev *hdev) -- cgit v1.2.3 From 3c54711c4fd103edf2044ab60726939f1de02b0c Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 14 Dec 2011 22:58:44 -0200 Subject: Bluetooth: Don't disable tasklets to call hdev->notify() It's pointless, we aren't protecting anything since btusb_notify() schedules a work to run, then all it operation happens without protection. If protection is really needed here, we will fix it further. Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_conn.c | 10 ++-------- net/bluetooth/hci_event.c | 10 ++-------- 2 files changed, 4 insertions(+), 16 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 5e9e193ac71..385cccbcafe 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -419,11 +419,8 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) hci_dev_hold(hdev); hci_conn_hash_add(hdev, conn); - if (hdev->notify) { - tasklet_disable(&hdev->tx_task); + if (hdev->notify) hdev->notify(hdev, HCI_NOTIFY_CONN_ADD); - tasklet_enable(&hdev->tx_task); - } atomic_set(&conn->devref, 0); @@ -468,11 +465,8 @@ int hci_conn_del(struct hci_conn *conn) hci_chan_list_flush(conn); hci_conn_hash_del(hdev, conn); - if (hdev->notify) { - tasklet_disable(&hdev->tx_task); + if (hdev->notify) hdev->notify(hdev, HCI_NOTIFY_CONN_DEL); - tasklet_enable(&hdev->tx_task); - } skb_queue_purge(&conn->data_q); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 0a9501f1736..93ecb2dfa17 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -378,11 +378,8 @@ static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s voice setting 0x%04x", hdev->name, setting); - if (hdev->notify) { - tasklet_disable(&hdev->tx_task); + if (hdev->notify) hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING); - tasklet_enable(&hdev->tx_task); - } } static void hci_cc_write_voice_setting(struct hci_dev *hdev, struct sk_buff *skb) @@ -409,11 +406,8 @@ static void hci_cc_write_voice_setting(struct hci_dev *hdev, struct sk_buff *skb BT_DBG("%s voice setting 0x%04x", hdev->name, setting); - if (hdev->notify) { - tasklet_disable(&hdev->tx_task); + if (hdev->notify) hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING); - tasklet_enable(&hdev->tx_task); - } } static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb) -- cgit v1.2.3 From c347b765fe70d718c721cd6d0b979cfbaed83125 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 14 Dec 2011 23:53:47 -0200 Subject: Bluetooth: Move command task to workqueue As part of the moving on all the Bluetooth processing to Process context. Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_core.c | 22 +++++++++++----------- net/bluetooth/hci_event.c | 4 ++-- net/bluetooth/hci_sock.c | 2 +- 4 files changed, 15 insertions(+), 15 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index e8324331892..051fd7fd299 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -196,7 +196,7 @@ struct hci_dev { struct timer_list cmd_timer; struct work_struct rx_work; - struct tasklet_struct cmd_task; + struct work_struct cmd_work; struct tasklet_struct tx_task; struct sk_buff_head rx_q; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index de923ee6009..e2db2551b15 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -57,7 +57,7 @@ int enable_hs; static void hci_rx_work(struct work_struct *work); -static void hci_cmd_task(unsigned long arg); +static void hci_cmd_work(struct work_struct *work); static void hci_tx_task(unsigned long arg); static DEFINE_MUTEX(hci_task_lock); @@ -209,7 +209,7 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) skb->dev = (void *) hdev; skb_queue_tail(&hdev->cmd_q, skb); - tasklet_schedule(&hdev->cmd_task); + queue_work(hdev->workqueue, &hdev->cmd_work); } skb_queue_purge(&hdev->driver_init); @@ -548,7 +548,7 @@ int hci_dev_open(__u16 dev) } else { /* Init failed, cleanup */ tasklet_kill(&hdev->tx_task); - tasklet_kill(&hdev->cmd_task); + flush_work(&hdev->cmd_work); flush_work(&hdev->rx_work); skb_queue_purge(&hdev->cmd_q); @@ -617,8 +617,8 @@ static int hci_dev_do_close(struct hci_dev *hdev) clear_bit(HCI_INIT, &hdev->flags); } - /* Kill cmd task */ - tasklet_kill(&hdev->cmd_task); + /* flush cmd work */ + flush_work(&hdev->cmd_work); /* Drop queues */ skb_queue_purge(&hdev->rx_q); @@ -1207,7 +1207,7 @@ static void hci_cmd_timer(unsigned long arg) BT_ERR("%s command tx timeout", hdev->name); atomic_set(&hdev->cmd_cnt, 1); - tasklet_schedule(&hdev->cmd_task); + queue_work(hdev->workqueue, &hdev->cmd_work); } struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev, @@ -1458,8 +1458,8 @@ int hci_register_dev(struct hci_dev *hdev) hdev->sniff_min_interval = 80; INIT_WORK(&hdev->rx_work, hci_rx_work); + INIT_WORK(&hdev->cmd_work, hci_cmd_work); - tasklet_init(&hdev->cmd_task, hci_cmd_task,(unsigned long) hdev); tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev); skb_queue_head_init(&hdev->rx_q); @@ -1922,7 +1922,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param) hdev->init_last_cmd = opcode; skb_queue_tail(&hdev->cmd_q, skb); - tasklet_schedule(&hdev->cmd_task); + queue_work(hdev->workqueue, &hdev->cmd_work); return 0; } @@ -2560,9 +2560,9 @@ static void hci_rx_work(struct work_struct *work) mutex_unlock(&hci_task_lock); } -static void hci_cmd_task(unsigned long arg) +static void hci_cmd_work(struct work_struct *work) { - struct hci_dev *hdev = (struct hci_dev *) arg; + struct hci_dev *hdev = container_of(work, struct hci_dev, cmd_work); struct sk_buff *skb; BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt)); @@ -2586,7 +2586,7 @@ static void hci_cmd_task(unsigned long arg) jiffies + msecs_to_jiffies(HCI_CMD_TIMEOUT)); } else { skb_queue_head(&hdev->cmd_q, skb); - tasklet_schedule(&hdev->cmd_task); + queue_work(hdev->workqueue, &hdev->cmd_work); } } } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 93ecb2dfa17..23466bb4842 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2112,7 +2112,7 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk if (ev->ncmd) { atomic_set(&hdev->cmd_cnt, 1); if (!skb_queue_empty(&hdev->cmd_q)) - tasklet_schedule(&hdev->cmd_task); + queue_work(hdev->workqueue, &hdev->cmd_work); } } @@ -2194,7 +2194,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) { atomic_set(&hdev->cmd_cnt, 1); if (!skb_queue_empty(&hdev->cmd_q)) - tasklet_schedule(&hdev->cmd_task); + queue_work(hdev->workqueue, &hdev->cmd_work); } } diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 399be345ea2..d10a724810e 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -538,7 +538,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, tasklet_schedule(&hdev->tx_task); } else { skb_queue_tail(&hdev->cmd_q, skb); - tasklet_schedule(&hdev->cmd_task); + queue_work(hdev->workqueue, &hdev->cmd_work); } } else { if (!capable(CAP_NET_RAW)) { -- cgit v1.2.3 From 3eff45eaf81780dad25c167bbaafa7d25ae407da Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 15 Dec 2011 00:50:02 -0200 Subject: Bluetooth: convert tx_task to workqueue This should simplify Bluetooth core processing a lot. Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_core.c | 20 +++++++++----------- net/bluetooth/hci_event.c | 6 +----- net/bluetooth/hci_sock.c | 4 ++-- 4 files changed, 13 insertions(+), 19 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 051fd7fd299..5d1bb51c43c 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -197,7 +197,7 @@ struct hci_dev { struct work_struct rx_work; struct work_struct cmd_work; - struct tasklet_struct tx_task; + struct work_struct tx_work; struct sk_buff_head rx_q; struct sk_buff_head raw_q; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index e2db2551b15..2b20941ebcb 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -58,7 +58,7 @@ int enable_hs; static void hci_rx_work(struct work_struct *work); static void hci_cmd_work(struct work_struct *work); -static void hci_tx_task(unsigned long arg); +static void hci_tx_work(struct work_struct *work); static DEFINE_MUTEX(hci_task_lock); @@ -547,7 +547,7 @@ int hci_dev_open(__u16 dev) } } else { /* Init failed, cleanup */ - tasklet_kill(&hdev->tx_task); + flush_work(&hdev->tx_work); flush_work(&hdev->cmd_work); flush_work(&hdev->rx_work); @@ -585,8 +585,8 @@ static int hci_dev_do_close(struct hci_dev *hdev) return 0; } - /* Kill RX and TX tasks */ - tasklet_kill(&hdev->tx_task); + /* Flush RX and TX works */ + flush_work(&hdev->tx_work); flush_work(&hdev->rx_work); if (hdev->discov_timeout > 0) { @@ -672,7 +672,6 @@ int hci_dev_reset(__u16 dev) return -ENODEV; hci_req_lock(hdev); - tasklet_disable(&hdev->tx_task); if (!test_bit(HCI_UP, &hdev->flags)) goto done; @@ -697,7 +696,6 @@ int hci_dev_reset(__u16 dev) msecs_to_jiffies(HCI_INIT_TIMEOUT)); done: - tasklet_enable(&hdev->tx_task); hci_req_unlock(hdev); hci_dev_put(hdev); return ret; @@ -1459,8 +1457,8 @@ int hci_register_dev(struct hci_dev *hdev) INIT_WORK(&hdev->rx_work, hci_rx_work); INIT_WORK(&hdev->cmd_work, hci_cmd_work); + INIT_WORK(&hdev->tx_work, hci_tx_work); - tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev); skb_queue_head_init(&hdev->rx_q); skb_queue_head_init(&hdev->cmd_q); @@ -2012,7 +2010,7 @@ void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags) hci_queue_acl(conn, &chan->data_q, skb, flags); - tasklet_schedule(&hdev->tx_task); + queue_work(hdev->workqueue, &hdev->tx_work); } EXPORT_SYMBOL(hci_send_acl); @@ -2035,7 +2033,7 @@ void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb) bt_cb(skb)->pkt_type = HCI_SCODATA_PKT; skb_queue_tail(&conn->data_q, skb); - tasklet_schedule(&hdev->tx_task); + queue_work(hdev->workqueue, &hdev->tx_work); } EXPORT_SYMBOL(hci_send_sco); @@ -2399,9 +2397,9 @@ static inline void hci_sched_le(struct hci_dev *hdev) hci_prio_recalculate(hdev, LE_LINK); } -static void hci_tx_task(unsigned long arg) +static void hci_tx_work(struct work_struct *work) { - struct hci_dev *hdev = (struct hci_dev *) arg; + struct hci_dev *hdev = container_of(work, struct hci_dev, tx_work); struct sk_buff *skb; mutex_lock(&hci_task_lock); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 23466bb4842..74f758363c2 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2239,8 +2239,6 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s return; } - tasklet_disable(&hdev->tx_task); - for (i = 0, ptr = (__le16 *) skb->data; i < ev->num_hndl; i++) { struct hci_conn *conn; __u16 handle, count; @@ -2274,9 +2272,7 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s } } - tasklet_schedule(&hdev->tx_task); - - tasklet_enable(&hdev->tx_task); + queue_work(hdev->workqueue, &hdev->tx_work); } static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb) diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index d10a724810e..cd064068d94 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -535,7 +535,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, if (test_bit(HCI_RAW, &hdev->flags) || (ogf == 0x3f)) { skb_queue_tail(&hdev->raw_q, skb); - tasklet_schedule(&hdev->tx_task); + queue_work(hdev->workqueue, &hdev->tx_work); } else { skb_queue_tail(&hdev->cmd_q, skb); queue_work(hdev->workqueue, &hdev->cmd_work); @@ -547,7 +547,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, } skb_queue_tail(&hdev->raw_q, skb); - tasklet_schedule(&hdev->tx_task); + queue_work(hdev->workqueue, &hdev->tx_work); } err = len; -- cgit v1.2.3 From f878fcad1760247c054a9c80964d0b7450d2379b Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 15 Dec 2011 01:16:14 -0200 Subject: Bluetooth: convert info timer to delayed_work Another step of remove interrupt context from Bluetooth Core. Use the system workqueue. Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 2 +- net/bluetooth/l2cap_core.c | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index a1750912824..f79137476cb 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -522,7 +522,7 @@ struct l2cap_conn { __u8 info_state; __u8 info_ident; - struct timer_list info_timer; + struct delayed_work info_work; spinlock_t lock; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 5c5948f09a6..a78cdf7236d 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -698,7 +698,7 @@ static void l2cap_do_start(struct l2cap_chan *chan) conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; conn->info_ident = l2cap_get_ident(conn); - mod_timer(&conn->info_timer, jiffies + + schedule_delayed_work(&conn->info_work, msecs_to_jiffies(L2CAP_INFO_TIMEOUT)); l2cap_send_cmd(conn, conn->info_ident, @@ -998,9 +998,10 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) mutex_unlock(&conn->chan_lock); } -static void l2cap_info_timeout(unsigned long arg) +static void l2cap_info_timeout(struct work_struct *work) { - struct l2cap_conn *conn = (void *) arg; + struct l2cap_conn *conn = container_of(work, struct l2cap_conn, + info_work.work); conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; conn->info_ident = 0; @@ -1033,7 +1034,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) hci_chan_del(conn->hchan); if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) - del_timer_sync(&conn->info_timer); + cancel_delayed_work_sync(&conn->info_work); if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) { del_timer(&conn->security_timer); @@ -1094,8 +1095,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) setup_timer(&conn->security_timer, security_timeout, (unsigned long) conn); else - setup_timer(&conn->info_timer, l2cap_info_timeout, - (unsigned long) conn); + INIT_DELAYED_WORK(&conn->info_work, l2cap_info_timeout); conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM; @@ -2530,7 +2530,7 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) && cmd->ident == conn->info_ident) { - del_timer(&conn->info_timer); + cancel_delayed_work_sync(&conn->info_work); conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; conn->info_ident = 0; @@ -2656,7 +2656,7 @@ sendresp: conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; conn->info_ident = l2cap_get_ident(conn); - mod_timer(&conn->info_timer, jiffies + + schedule_delayed_work(&conn->info_work, msecs_to_jiffies(L2CAP_INFO_TIMEOUT)); l2cap_send_cmd(conn, conn->info_ident, @@ -3081,7 +3081,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) return 0; - del_timer(&conn->info_timer); + cancel_delayed_work_sync(&conn->info_work); if (result != L2CAP_IR_SUCCESS) { conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; -- cgit v1.2.3 From 03a001948166d966d0d580cddb8ae3a23f8b795b Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 9 Dec 2011 04:48:17 -0200 Subject: Bluetooth: invert locking order in connect path This move some checking code that was in l2cap_sock_connect() to l2cap_chan_connect(). Thus we can invert the lock calls, i.e., call lock_sock() before hci_dev_lock() to avoid a deadlock scenario. Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 3 ++- net/bluetooth/l2cap_core.c | 58 ++++++++++++++++++++++++++++++++++++++-- net/bluetooth/l2cap_sock.c | 61 +++---------------------------------------- 3 files changed, 61 insertions(+), 61 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index f79137476cb..c0d168adf9b 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -806,7 +806,8 @@ int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid); struct l2cap_chan *l2cap_chan_create(struct sock *sk); void l2cap_chan_close(struct l2cap_chan *chan, int reason); void l2cap_chan_destroy(struct l2cap_chan *chan); -int l2cap_chan_connect(struct l2cap_chan *chan); +inline int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, + bdaddr_t *dst); int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u32 priority); void l2cap_chan_busy(struct l2cap_chan *chan, int busy); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a78cdf7236d..d6165199fc8 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1144,11 +1144,10 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr return c1; } -int l2cap_chan_connect(struct l2cap_chan *chan) +inline int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst) { struct sock *sk = chan->sk; bdaddr_t *src = &bt_sk(sk)->src; - bdaddr_t *dst = &bt_sk(sk)->dst; struct l2cap_conn *conn; struct hci_conn *hcon; struct hci_dev *hdev; @@ -1164,6 +1163,61 @@ int l2cap_chan_connect(struct l2cap_chan *chan) hci_dev_lock(hdev); + lock_sock(sk); + + /* PSM must be odd and lsb of upper byte must be 0 */ + if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid && + chan->chan_type != L2CAP_CHAN_RAW) { + err = -EINVAL; + goto done; + } + + if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) { + err = -EINVAL; + goto done; + } + + switch (chan->mode) { + case L2CAP_MODE_BASIC: + break; + case L2CAP_MODE_ERTM: + case L2CAP_MODE_STREAMING: + if (!disable_ertm) + break; + /* fall through */ + default: + err = -ENOTSUPP; + goto done; + } + + switch (sk->sk_state) { + case BT_CONNECT: + case BT_CONNECT2: + case BT_CONFIG: + /* Already connecting */ + err = 0; + goto done; + + case BT_CONNECTED: + /* Already connected */ + err = -EISCONN; + goto done; + + case BT_OPEN: + case BT_BOUND: + /* Can connect */ + break; + + default: + err = -EBADFD; + goto done; + } + + /* Set destination address and psm */ + bacpy(&bt_sk(sk)->dst, src); + chan->psm = psm; + chan->dcid = cid; + auth_type = l2cap_get_auth_type(chan); if (chan->dcid == L2CAP_CID_LE_DATA) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index fbdc8b38d9e..6c7d4323e79 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -121,70 +121,15 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al if (la.l2_cid && la.l2_psm) return -EINVAL; - lock_sock(sk); - - if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED - && !(la.l2_psm || la.l2_cid)) { - err = -EINVAL; - goto done; - } - - switch (chan->mode) { - case L2CAP_MODE_BASIC: - break; - case L2CAP_MODE_ERTM: - case L2CAP_MODE_STREAMING: - if (!disable_ertm) - break; - /* fall through */ - default: - err = -ENOTSUPP; - goto done; - } - - switch (sk->sk_state) { - case BT_CONNECT: - case BT_CONNECT2: - case BT_CONFIG: - /* Already connecting */ - goto wait; - - case BT_CONNECTED: - /* Already connected */ - err = -EISCONN; - goto done; - - case BT_OPEN: - case BT_BOUND: - /* Can connect */ - break; - - default: - err = -EBADFD; - goto done; - } - - /* PSM must be odd and lsb of upper byte must be 0 */ - if ((__le16_to_cpu(la.l2_psm) & 0x0101) != 0x0001 && !la.l2_cid && - chan->chan_type != L2CAP_CHAN_RAW) { - err = -EINVAL; - goto done; - } - - /* Set destination address and psm */ - bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr); - chan->psm = la.l2_psm; - chan->dcid = la.l2_cid; - - err = l2cap_chan_connect(chan); + err = l2cap_chan_connect(chan, la.l2_psm, la.l2_cid, &la.l2_bdaddr); if (err) goto done; -wait: err = bt_sock_wait_state(sk, BT_CONNECTED, sock_sndtimeo(sk, flags & O_NONBLOCK)); done: - release_sock(sk); + if (sock_owned_by_user(sk)) + release_sock(sk); return err; } -- cgit v1.2.3 From 3d57dc6806599ca7d389fc9410eefbc1a7dc32bc Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 17 Dec 2011 10:56:45 -0200 Subject: Bluetooth: Change l2cap chan_list to use RCU This list has much more reads than writes, so RCU makes senses here, also it avoid deadlock against the socket lock. Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_core.c | 119 ++++++++++++++++++++++----------------------- 1 file changed, 58 insertions(+), 61 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d6165199fc8..a1766adee39 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -89,24 +89,36 @@ static inline void chan_put(struct l2cap_chan *c) static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid) { - struct l2cap_chan *c; + struct l2cap_chan *c, *r = NULL; - list_for_each_entry(c, &conn->chan_l, list) { - if (c->dcid == cid) - return c; + rcu_read_lock(); + + list_for_each_entry_rcu(c, &conn->chan_l, list) { + if (c->dcid == cid) { + r = c; + break; + } } - return NULL; + + rcu_read_unlock(); + return r; } static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) { - struct l2cap_chan *c; + struct l2cap_chan *c, *r = NULL; - list_for_each_entry(c, &conn->chan_l, list) { - if (c->scid == cid) - return c; + rcu_read_lock(); + + list_for_each_entry_rcu(c, &conn->chan_l, list) { + if (c->scid == cid) { + r = c; + break; + } } - return NULL; + + rcu_read_unlock(); + return r; } /* Find channel with given SCID. @@ -115,34 +127,36 @@ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 ci { struct l2cap_chan *c; - mutex_lock(&conn->chan_lock); c = __l2cap_get_chan_by_scid(conn, cid); if (c) lock_sock(c->sk); - mutex_unlock(&conn->chan_lock); return c; } static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident) { - struct l2cap_chan *c; + struct l2cap_chan *c, *r = NULL; - list_for_each_entry(c, &conn->chan_l, list) { - if (c->ident == ident) - return c; + rcu_read_lock(); + + list_for_each_entry_rcu(c, &conn->chan_l, list) { + if (c->ident == ident) { + r = c; + break; + } } - return NULL; + + rcu_read_unlock(); + return r; } static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident) { struct l2cap_chan *c; - mutex_lock(&conn->chan_lock); c = __l2cap_get_chan_by_ident(conn, ident); if (c) lock_sock(c->sk); - mutex_unlock(&conn->chan_lock); return c; } @@ -323,7 +337,7 @@ void l2cap_chan_destroy(struct l2cap_chan *chan) chan_put(chan); } -static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) +static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, chan->psm, chan->dcid); @@ -364,7 +378,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) chan_hold(chan); - list_add(&chan->list, &conn->chan_l); + list_add_rcu(&chan->list, &conn->chan_l); } /* Delete channel. @@ -381,9 +395,9 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) if (conn) { /* Delete from channel list */ - mutex_lock(&conn->chan_lock); - list_del(&chan->list); - mutex_unlock(&conn->chan_lock); + list_del_rcu(&chan->list); + synchronize_rcu(); + chan_put(chan); chan->conn = NULL; @@ -750,13 +764,13 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c /* ---- L2CAP connections ---- */ static void l2cap_conn_start(struct l2cap_conn *conn) { - struct l2cap_chan *chan, *tmp; + struct l2cap_chan *chan; BT_DBG("conn %p", conn); - mutex_lock(&conn->chan_lock); + rcu_read_lock(); - list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { + list_for_each_entry_rcu(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; bh_lock_sock(sk); @@ -780,9 +794,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) &chan->conf_state)) { /* l2cap_chan_close() calls list_del(chan) * so release the lock */ - mutex_unlock(&conn->chan_lock); l2cap_chan_close(chan, ECONNRESET); - utex_lock(&conn->chan_lock); bh_unlock_sock(sk); continue; } @@ -838,7 +850,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) bh_unlock_sock(sk); } - mutex_unlock(&conn->chan_lock); + rcu_read_unlock(); } /* Find socket with cid and source bdaddr. @@ -903,8 +915,6 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) sk = chan->sk; - mutex_lock(&conn->chan_lock); - hci_conn_hold(conn->hcon); bacpy(&bt_sk(sk)->src, conn->src); @@ -912,15 +922,13 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) bt_accept_enqueue(parent, sk); - __l2cap_chan_add(conn, chan); + l2cap_chan_add(conn, chan); __set_chan_timer(chan, sk->sk_sndtimeo); l2cap_state_change(chan, BT_CONNECTED); parent->sk_data_ready(parent, 0); - mutex_unlock(&conn->chan_lock); - clean: release_sock(parent); } @@ -954,9 +962,9 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) if (conn->hcon->out && conn->hcon->type == LE_LINK) smp_conn_security(conn, conn->hcon->pending_sec_level); - mutex_lock(&conn->chan_lock); + rcu_read_lock(); - list_for_each_entry(chan, &conn->chan_l, list) { + list_for_each_entry_rcu(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; bh_lock_sock(sk); @@ -976,7 +984,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) bh_unlock_sock(sk); } - mutex_unlock(&conn->chan_lock); + rcu_read_unlock(); } /* Notify sockets that we cannot guaranty reliability anymore */ @@ -986,16 +994,16 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) BT_DBG("conn %p", conn); - mutex_lock(&conn->chan_lock); + rcu_read_lock(); - list_for_each_entry(chan, &conn->chan_l, list) { + list_for_each_entry_rcu(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags)) sk->sk_err = err; } - mutex_unlock(&conn->chan_lock); + rcu_read_unlock(); } static void l2cap_info_timeout(struct work_struct *work) @@ -1087,7 +1095,6 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) conn->feat_mask = 0; spin_lock_init(&conn->lock); - mutex_init(&conn->chan_lock); INIT_LIST_HEAD(&conn->chan_l); @@ -1102,13 +1109,6 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) return conn; } -static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) -{ - mutex_lock(&conn->chan_lock); - __l2cap_chan_add(conn, chan); - mutex_unlock(&conn->chan_lock); -} - /* ---- Socket interface ---- */ /* Find socket with psm and source bdaddr. @@ -1825,8 +1825,9 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("conn %p", conn); - mutex_lock(&conn->chan_lock); - list_for_each_entry(chan, &conn->chan_l, list) { + rcu_read_lock(); + + list_for_each_entry_rcu(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; if (chan->chan_type != L2CAP_CHAN_RAW) continue; @@ -1841,7 +1842,8 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) if (chan->ops->recv(chan->data, nskb)) kfree_skb(nskb); } - mutex_unlock(&conn->chan_lock); + + rcu_read_unlock(); } /* ---- L2CAP signalling commands ---- */ @@ -2641,11 +2643,8 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd sk = chan->sk; - mutex_lock(&conn->chan_lock); - /* Check if we already have channel with that dcid */ if (__l2cap_get_chan_by_dcid(conn, scid)) { - mutex_unlock(&conn->chan_lock); sock_set_flag(sk, SOCK_ZAPPED); chan->ops->close(chan->data); goto response; @@ -2660,7 +2659,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd bt_accept_enqueue(parent, sk); - __l2cap_chan_add(conn, chan); + l2cap_chan_add(conn, chan); dcid = chan->scid; @@ -2691,8 +2690,6 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd status = L2CAP_CS_NO_INFO; } - mutex_unlock(&conn->chan_lock); - response: release_sock(parent); @@ -4528,9 +4525,9 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) del_timer(&conn->security_timer); } - mutex_lock(&conn->chan_lock); + rcu_read_lock(); - list_for_each_entry(chan, &conn->chan_l, list) { + list_for_each_entry_rcu(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; bh_lock_sock(sk); @@ -4608,7 +4605,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) bh_unlock_sock(sk); } - mutex_unlock(&conn->chan_lock); + rcu_read_unlock(); return 0; } -- cgit v1.2.3 From 80b7ab33414beeb3c17600af9b69d903f5cf8a7d Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 17 Dec 2011 14:52:27 -0200 Subject: Bluetooth: move power_off to system workqueue hdev->workqueue will be only for for rx/tx/cmd processing, all other small works should go to the system workqueue for now. Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_core.c | 2 +- net/bluetooth/mgmt.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 2b20941ebcb..a14a60d5890 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -937,7 +937,7 @@ static void hci_power_on(struct work_struct *work) return; if (test_bit(HCI_AUTO_OFF, &hdev->flags)) - queue_delayed_work(hdev->workqueue, &hdev->power_off, + schedule_delayed_work(&hdev->power_off, msecs_to_jiffies(AUTO_OFF_TIMEOUT)); if (test_and_clear_bit(HCI_SETUP, &hdev->flags)) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ad4817c9ef2..f4af6593c43 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -417,7 +417,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) if (cp->val) queue_work(hdev->workqueue, &hdev->power_on); else - queue_work(hdev->workqueue, &hdev->power_off.work); + schedule_work(&hdev->power_off.work); err = 0; -- cgit v1.2.3 From 32845eb1242e4c862de8d27c19ae9b3011f89291 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 17 Dec 2011 17:47:30 -0200 Subject: Bluetooth: Use new alloc_workqueue() Update hdev workqueue API usage to use the new interface, this new interface also allow us to mark this workqueue as WQ_HIGHPRI, so now rx and tx work gets higher priority when running. Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index a14a60d5890..dcbb7655d77 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1500,7 +1500,8 @@ int hci_register_dev(struct hci_dev *hdev) write_unlock_bh(&hci_dev_list_lock); - hdev->workqueue = create_singlethread_workqueue(hdev->name); + hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI | WQ_UNBOUND | + WQ_MEM_RECLAIM, 1); if (!hdev->workqueue) { error = -ENOMEM; goto err; -- cgit v1.2.3 From 6d438e335ce83ff0528415a58632dc6508e4fde1 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 17 Dec 2011 18:53:02 -0200 Subject: Bluetooth: Remove work_add and work_del from hci_sysfs As we run in process context now we don't need worqueue to add e del from sysfs. Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 3 -- net/bluetooth/hci_sysfs.c | 71 +++++++++++++++------------------------- 2 files changed, 27 insertions(+), 47 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 5d1bb51c43c..72f84d6d4d3 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -301,9 +301,6 @@ struct hci_conn { struct timer_list idle_timer; struct timer_list auto_accept_timer; - struct work_struct work_add; - struct work_struct work_del; - struct device dev; atomic_t devref; diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index c3c1ec871d4..db6af705f8f 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -88,11 +88,35 @@ static struct device_type bt_link = { .release = bt_link_release, }; -static void add_conn(struct work_struct *work) +/* + * The rfcomm tty device will possibly retain even when conn + * is down, and sysfs doesn't support move zombie device, + * so we should move the device before conn device is destroyed. + */ +static int __match_tty(struct device *dev, void *data) +{ + return !strncmp(dev_name(dev), "rfcomm", 6); +} + +void hci_conn_init_sysfs(struct hci_conn *conn) +{ + struct hci_dev *hdev = conn->hdev; + + BT_DBG("conn %p", conn); + + conn->dev.type = &bt_link; + conn->dev.class = bt_class; + conn->dev.parent = &hdev->dev; + + device_initialize(&conn->dev); +} + +void hci_conn_add_sysfs(struct hci_conn *conn) { - struct hci_conn *conn = container_of(work, struct hci_conn, work_add); struct hci_dev *hdev = conn->hdev; + BT_DBG("conn %p", conn); + dev_set_name(&conn->dev, "%s:%d", hdev->name, conn->handle); dev_set_drvdata(&conn->dev, conn); @@ -105,19 +129,8 @@ static void add_conn(struct work_struct *work) hci_dev_hold(hdev); } -/* - * The rfcomm tty device will possibly retain even when conn - * is down, and sysfs doesn't support move zombie device, - * so we should move the device before conn device is destroyed. - */ -static int __match_tty(struct device *dev, void *data) -{ - return !strncmp(dev_name(dev), "rfcomm", 6); -} - -static void del_conn(struct work_struct *work) +void hci_conn_del_sysfs(struct hci_conn *conn) { - struct hci_conn *conn = container_of(work, struct hci_conn, work_del); struct hci_dev *hdev = conn->hdev; if (!device_is_registered(&conn->dev)) @@ -139,36 +152,6 @@ static void del_conn(struct work_struct *work) hci_dev_put(hdev); } -void hci_conn_init_sysfs(struct hci_conn *conn) -{ - struct hci_dev *hdev = conn->hdev; - - BT_DBG("conn %p", conn); - - conn->dev.type = &bt_link; - conn->dev.class = bt_class; - conn->dev.parent = &hdev->dev; - - device_initialize(&conn->dev); - - INIT_WORK(&conn->work_add, add_conn); - INIT_WORK(&conn->work_del, del_conn); -} - -void hci_conn_add_sysfs(struct hci_conn *conn) -{ - BT_DBG("conn %p", conn); - - queue_work(conn->hdev->workqueue, &conn->work_add); -} - -void hci_conn_del_sysfs(struct hci_conn *conn) -{ - BT_DBG("conn %p", conn); - - queue_work(conn->hdev->workqueue, &conn->work_del); -} - static inline char *host_bustostr(int bus) { switch (bus) { -- cgit v1.2.3 From 7f971041cf591d8cf3b289c9d78739638ca7e629 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sun, 18 Dec 2011 12:40:32 -0200 Subject: Bluetooth: Use system workqueue to schedule power_on hdev->workqueue should be only for rx/tx, so move this one out. Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_core.c | 2 +- net/bluetooth/mgmt.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index dcbb7655d77..b250685d59a 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1522,7 +1522,7 @@ int hci_register_dev(struct hci_dev *hdev) set_bit(HCI_AUTO_OFF, &hdev->flags); set_bit(HCI_SETUP, &hdev->flags); - queue_work(hdev->workqueue, &hdev->power_on); + schedule_work(&hdev->power_on); hci_notify(hdev, HCI_DEV_REG); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f4af6593c43..ffd1c01c7d0 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -415,7 +415,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) } if (cp->val) - queue_work(hdev->workqueue, &hdev->power_on); + schedule_work(&hdev->power_on); else schedule_work(&hdev->power_off.work); -- cgit v1.2.3 From 590051de5ce54f7ae02997ed0a2532f08c7b7866 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sun, 18 Dec 2011 13:39:33 -0200 Subject: Bluetooth: Add ProFUSION's copyright Add ProFUSION's copyright to some files I've been touching recently. Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_core.c | 1 + net/bluetooth/l2cap_core.c | 1 + net/bluetooth/l2cap_sock.c | 1 + 3 files changed, 3 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index b250685d59a..82d1d9e6b7c 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1,6 +1,7 @@ /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2000-2001 Qualcomm Incorporated + Copyright (C) 2011 ProFUSION Embedded Systems Written 2000,2001 by Maxim Krasnyansky diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a1766adee39..ea36d1dea76 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -3,6 +3,7 @@ Copyright (C) 2000-2001 Qualcomm Incorporated Copyright (C) 2009-2010 Gustavo F. Padovan Copyright (C) 2010 Google Inc. + Copyright (C) 2011 ProFUSION Embedded Systems Written 2000,2001 by Maxim Krasnyansky diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 6c7d4323e79..5e0976670b9 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -3,6 +3,7 @@ Copyright (C) 2000-2001 Qualcomm Incorporated Copyright (C) 2009-2010 Gustavo F. Padovan Copyright (C) 2010 Google Inc. + Copyright (C) 2011 ProFUSION Embedded Systems Written 2000,2001 by Maxim Krasnyansky -- cgit v1.2.3 From 69ab39ea5da03e632a51b31534da713aff8d1e3b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 15 Dec 2011 00:47:35 +0200 Subject: Bluetooth: Update mgmt_read_info and related mgmt messages This patch updates the mgmt_read_info and related messages to the latest management API which uses a bitfield of settings instead of individual boolean values. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci.h | 1 + include/net/bluetooth/mgmt.h | 29 +++++---- net/bluetooth/mgmt.c | 146 ++++++++++++++++++++++++++++--------------- 3 files changed, 113 insertions(+), 63 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 67ad9843034..c9ad56fe58f 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -210,6 +210,7 @@ enum { #define LMP_EV4 0x01 #define LMP_EV5 0x02 +#define LMP_NO_BREDR 0x20 #define LMP_LE 0x40 #define LMP_SNIFF_SUBR 0x02 diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 3b6880690a7..85e9c6e9d22 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -61,22 +61,29 @@ struct mgmt_rp_read_index_list { /* Reserve one extra byte for names in management messages so that they * are always guaranteed to be nul-terminated */ #define MGMT_MAX_NAME_LENGTH (HCI_MAX_NAME_LENGTH + 1) +#define MGMT_MAX_SHORT_NAME_LENGTH (10 + 1) + +#define MGMT_SETTING_POWERED 0x00000001 +#define MGMT_SETTING_CONNECTABLE 0x00000002 +#define MGMT_SETTING_FAST_CONNECTABLE 0x00000004 +#define MGMT_SETTING_DISCOVERABLE 0x00000008 +#define MGMT_SETTING_PAIRABLE 0x00000010 +#define MGMT_SETTING_LINK_SECURITY 0x00000020 +#define MGMT_SETTING_SSP 0x00000040 +#define MGMT_SETTING_BREDR 0x00000080 +#define MGMT_SETTING_HS 0x00000100 +#define MGMT_SETTING_LE 0x00000200 #define MGMT_OP_READ_INFO 0x0004 struct mgmt_rp_read_info { - __u8 type; - __u8 powered; - __u8 connectable; - __u8 discoverable; - __u8 pairable; - __u8 sec_mode; bdaddr_t bdaddr; + __u8 version; + __le16 manufacturer; + __le32 supported_settings; + __le32 current_settings; __u8 dev_class[3]; - __u8 features[8]; - __u16 manufacturer; - __u8 hci_ver; - __u16 hci_rev; __u8 name[MGMT_MAX_NAME_LENGTH]; + __u8 short_name[MGMT_MAX_SHORT_NAME_LENGTH]; } __packed; struct mgmt_mode { @@ -285,7 +292,7 @@ struct mgmt_ev_controller_error { #define MGMT_EV_INDEX_REMOVED 0x0005 -#define MGMT_EV_POWERED 0x0006 +#define MGMT_EV_NEW_SETTINGS 0x0006 #define MGMT_EV_DISCOVERABLE 0x0007 diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ffd1c01c7d0..087cf00a443 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -242,6 +242,63 @@ static int read_index_list(struct sock *sk) return err; } +static u32 get_supported_settings(struct hci_dev *hdev) +{ + u32 settings = 0; + + settings |= MGMT_SETTING_POWERED; + settings |= MGMT_SETTING_CONNECTABLE; + settings |= MGMT_SETTING_FAST_CONNECTABLE; + settings |= MGMT_SETTING_DISCOVERABLE; + settings |= MGMT_SETTING_PAIRABLE; + + if (hdev->features[6] & LMP_SIMPLE_PAIR) + settings |= MGMT_SETTING_SSP; + + if (!(hdev->features[4] & LMP_NO_BREDR)) { + settings |= MGMT_SETTING_BREDR; + settings |= MGMT_SETTING_LINK_SECURITY; + } + + if (hdev->features[4] & LMP_LE) + settings |= MGMT_SETTING_LE; + + return settings; +} + +static u32 get_current_settings(struct hci_dev *hdev) +{ + u32 settings = 0; + + if (test_bit(HCI_UP, &hdev->flags)) + settings |= MGMT_SETTING_POWERED; + else + return settings; + + if (test_bit(HCI_PSCAN, &hdev->flags)) + settings |= MGMT_SETTING_CONNECTABLE; + + if (test_bit(HCI_ISCAN, &hdev->flags)) + settings |= MGMT_SETTING_DISCOVERABLE; + + if (test_bit(HCI_PAIRABLE, &hdev->flags)) + settings |= MGMT_SETTING_PAIRABLE; + + if (!(hdev->features[4] & LMP_NO_BREDR)) + settings |= MGMT_SETTING_BREDR; + + if (hdev->extfeatures[0] & LMP_HOST_LE) + settings |= MGMT_SETTING_LE; + + if (test_bit(HCI_AUTH, &hdev->flags)) + settings |= MGMT_SETTING_LINK_SECURITY; + + if (hdev->ssp_mode > 0) + settings |= MGMT_SETTING_SSP; + + return settings; +} + static int read_controller_info(struct sock *sk, u16 index) { struct mgmt_rp_read_info rp; @@ -263,26 +320,16 @@ static int read_controller_info(struct sock *sk, u16 index) memset(&rp, 0, sizeof(rp)); - rp.type = hdev->dev_type; + bacpy(&rp.bdaddr, &hdev->bdaddr); - rp.powered = test_bit(HCI_UP, &hdev->flags); - rp.connectable = test_bit(HCI_PSCAN, &hdev->flags); - rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags); - rp.pairable = test_bit(HCI_PSCAN, &hdev->flags); + rp.version = hdev->hci_ver; - if (test_bit(HCI_AUTH, &hdev->flags)) - rp.sec_mode = 3; - else if (hdev->ssp_mode > 0) - rp.sec_mode = 4; - else - rp.sec_mode = 2; + put_unaligned_le16(hdev->manufacturer, &rp.manufacturer); + + rp.supported_settings = cpu_to_le32(get_supported_settings(hdev)); + rp.current_settings = cpu_to_le32(get_current_settings(hdev)); - bacpy(&rp.bdaddr, &hdev->bdaddr); - memcpy(rp.features, hdev->features, 8); memcpy(rp.dev_class, hdev->dev_class, 3); - put_unaligned_le16(hdev->manufacturer, &rp.manufacturer); - rp.hci_ver = hdev->hci_ver; - put_unaligned_le16(hdev->hci_rev, &rp.hci_rev); memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name)); @@ -365,13 +412,11 @@ static void mgmt_pending_remove(struct pending_cmd *cmd) mgmt_pending_free(cmd); } -static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val) +static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev) { - struct mgmt_mode rp; + __le32 settings = cpu_to_le32(get_current_settings(hdev)); - rp.val = val; - - return cmd_complete(sk, index, opcode, &rp, sizeof(rp)); + return cmd_complete(sk, hdev->id, opcode, &settings, sizeof(settings)); } static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) @@ -398,7 +443,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) up = test_bit(HCI_UP, &hdev->flags); if ((cp->val && up) || (!cp->val && !up)) { - err = send_mode_rsp(sk, index, MGMT_OP_SET_POWERED, cp->val); + err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev); goto failed; } @@ -466,8 +511,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data, if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) && test_bit(HCI_PSCAN, &hdev->flags)) { - err = send_mode_rsp(sk, index, MGMT_OP_SET_DISCOVERABLE, - cp->val); + err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev); goto failed; } @@ -536,8 +580,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data, } if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) { - err = send_mode_rsp(sk, index, MGMT_OP_SET_CONNECTABLE, - cp->val); + err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev); goto failed; } @@ -595,8 +638,9 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, static int set_pairable(struct sock *sk, u16 index, unsigned char *data, u16 len) { - struct mgmt_mode *cp, ev; + struct mgmt_mode *cp; struct hci_dev *hdev; + __le32 ev; int err; cp = (void *) data; @@ -619,13 +663,13 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data, else clear_bit(HCI_PAIRABLE, &hdev->flags); - err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val); + err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev); if (err < 0) goto failed; - ev.val = cp->val; + ev = cpu_to_le32(get_current_settings(hdev)); - err = mgmt_event(MGMT_EV_PAIRABLE, hdev, &ev, sizeof(ev), sk); + err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk); failed: hci_dev_unlock(hdev); @@ -2234,17 +2278,14 @@ int mgmt_index_removed(struct hci_dev *hdev) struct cmd_lookup { u8 val; struct sock *sk; + struct hci_dev *hdev; }; -static void mode_rsp(struct pending_cmd *cmd, void *data) +static void settings_rsp(struct pending_cmd *cmd, void *data) { - struct mgmt_mode *cp = cmd->param; struct cmd_lookup *match = data; - if (cp->val != match->val) - return; - - send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val); + send_settings_rsp(cmd->sk, cmd->opcode, match->hdev); list_del(&cmd->list); @@ -2258,20 +2299,21 @@ static void mode_rsp(struct pending_cmd *cmd, void *data) int mgmt_powered(struct hci_dev *hdev, u8 powered) { - struct mgmt_mode ev; - struct cmd_lookup match = { powered, NULL }; + struct cmd_lookup match = { powered, NULL, hdev }; + __le32 ev; int ret; - mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, mode_rsp, &match); + mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); if (!powered) { u8 status = ENETDOWN; mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); } - ev.val = powered; + ev = cpu_to_le32(get_current_settings(hdev)); - ret = mgmt_event(MGMT_EV_POWERED, hdev, &ev, sizeof(ev), match.sk); + ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), + match.sk); if (match.sk) sock_put(match.sk); @@ -2281,17 +2323,16 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) { - struct mgmt_mode ev; - struct cmd_lookup match = { discoverable, NULL }; + struct cmd_lookup match = { discoverable, NULL, hdev }; + __le32 ev; int ret; - mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, mode_rsp, &match); + mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match); - ev.val = discoverable; + ev = cpu_to_le32(get_current_settings(hdev)); - ret = mgmt_event(MGMT_EV_DISCOVERABLE, hdev, &ev, sizeof(ev), + ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk); - if (match.sk) sock_put(match.sk); @@ -2300,15 +2341,16 @@ int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) int mgmt_connectable(struct hci_dev *hdev, u8 connectable) { - struct mgmt_mode ev; - struct cmd_lookup match = { connectable, NULL }; + __le32 ev; + struct cmd_lookup match = { connectable, NULL, hdev }; int ret; - mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, mode_rsp, &match); + mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp, + &match); - ev.val = connectable; + ev = cpu_to_le32(get_current_settings(hdev)); - ret = mgmt_event(MGMT_EV_CONNECTABLE, hdev, &ev, sizeof(ev), match.sk); + ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk); if (match.sk) sock_put(match.sk); -- cgit v1.2.3 From f7c6869cebe631582fdc2ac57459ee217ce9b015 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 15 Dec 2011 00:47:36 +0200 Subject: Bluetooth: Move mgmt_set_fast_connectable to the right location Fast connectable is logically after the connectable property so that's where it should show up in the code as well (it's also after connectable in the settings bitfield). Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/mgmt.h | 7 ++----- net/bluetooth/mgmt.c | 12 ++++++------ 2 files changed, 8 insertions(+), 11 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 85e9c6e9d22..bf217ccb86b 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -100,6 +100,8 @@ struct mgmt_cp_set_discoverable { #define MGMT_OP_SET_CONNECTABLE 0x0007 +#define MGMT_OP_SET_FAST_CONNECTABLE 0x001F + #define MGMT_OP_SET_PAIRABLE 0x0008 #define MGMT_OP_ADD_UUID 0x0009 @@ -255,11 +257,6 @@ struct mgmt_cp_unblock_device { bdaddr_t bdaddr; } __packed; -#define MGMT_OP_SET_FAST_CONNECTABLE 0x001F -struct mgmt_cp_set_fast_connectable { - __u8 enable; -} __packed; - #define MGMT_OP_USER_PASSKEY_REPLY 0x0020 struct mgmt_cp_user_passkey_reply { bdaddr_t bdaddr; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 087cf00a443..34e48101339 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2052,7 +2052,7 @@ static int set_fast_connectable(struct sock *sk, u16 index, unsigned char *data, u16 len) { struct hci_dev *hdev; - struct mgmt_cp_set_fast_connectable *cp = (void *) data; + struct mgmt_mode *cp = (void *) data; struct hci_cp_write_page_scan_activity acp; u8 type; int err; @@ -2070,7 +2070,7 @@ static int set_fast_connectable(struct sock *sk, u16 index, hci_dev_lock(hdev); - if (cp->enable) { + if (cp->val) { type = PAGE_SCAN_TYPE_INTERLACED; acp.interval = 0x0024; /* 22.5 msec page scan interval */ } else { @@ -2154,6 +2154,10 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_SET_CONNECTABLE: err = set_connectable(sk, index, buf + sizeof(*hdr), len); break; + case MGMT_OP_SET_FAST_CONNECTABLE: + err = set_fast_connectable(sk, index, buf + sizeof(*hdr), + len); + break; case MGMT_OP_SET_PAIRABLE: err = set_pairable(sk, index, buf + sizeof(*hdr), len); break; @@ -2232,10 +2236,6 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_UNBLOCK_DEVICE: err = unblock_device(sk, index, buf + sizeof(*hdr), len); break; - case MGMT_OP_SET_FAST_CONNECTABLE: - err = set_fast_connectable(sk, index, buf + sizeof(*hdr), - len); - break; default: BT_DBG("Unknown op %u", opcode); err = cmd_status(sk, index, opcode, -- cgit v1.2.3 From 14c0b60829751135346d71e7d11649c4f72dc9af Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 15 Dec 2011 00:47:37 +0200 Subject: Bluetooth: Remove mgmt_set_service_cache Instead of having an explicit service cache command we can make the mgmt API simpler by implicitly enabling the cache when mgmt_read_info is called for the first time and disabling it when mgmt_set_dev_class is called. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 4 +++ include/net/bluetooth/mgmt.h | 5 ---- net/bluetooth/hci_sock.c | 7 +++-- net/bluetooth/mgmt.c | 56 +++++----------------------------------- 4 files changed, 16 insertions(+), 56 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 72f84d6d4d3..cc17f739dff 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -943,12 +943,16 @@ int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr); /* 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/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index bf217ccb86b..bdb0a581149 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -121,11 +121,6 @@ struct mgmt_cp_set_dev_class { __u8 minor; } __packed; -#define MGMT_OP_SET_SERVICE_CACHE 0x000C -struct mgmt_cp_set_service_cache { - __u8 enable; -} __packed; - struct mgmt_link_key_info { bdaddr_t bdaddr; u8 type; diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index cd064068d94..189a667c293 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -343,8 +343,11 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le if (haddr.hci_channel > HCI_CHANNEL_CONTROL) return -EINVAL; - if (haddr.hci_channel == HCI_CHANNEL_CONTROL && !enable_mgmt) - 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); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 34e48101339..559b938f504 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -316,7 +316,10 @@ static int read_controller_info(struct sock *sk, u16 index) hci_dev_lock(hdev); - set_bit(HCI_MGMT, &hdev->flags); + if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags)) { + set_bit(HCI_MGMT, &hdev->flags); + set_bit(HCI_SERVICE_CACHE, &hdev->flags); + } memset(&rp, 0, sizeof(rp)); @@ -989,6 +992,9 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data, hdev->major_class = cp->major; hdev->minor_class = cp->minor; + if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags)) + update_eir(hdev); + err = update_class(hdev); if (err == 0) @@ -1000,51 +1006,6 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data, return err; } -static int set_service_cache(struct sock *sk, u16 index, unsigned char *data, - u16 len) -{ - struct hci_dev *hdev; - struct mgmt_cp_set_service_cache *cp; - int err; - - cp = (void *) data; - - if (len != sizeof(*cp)) - return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, - MGMT_STATUS_INVALID_PARAMS); - - hdev = hci_dev_get(index); - if (!hdev) - return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, - MGMT_STATUS_INVALID_PARAMS); - - hci_dev_lock(hdev); - - BT_DBG("hci%u enable %d", index, cp->enable); - - if (cp->enable) { - set_bit(HCI_SERVICE_CACHE, &hdev->flags); - err = 0; - } else { - clear_bit(HCI_SERVICE_CACHE, &hdev->flags); - err = update_class(hdev); - if (err == 0) - err = update_eir(hdev); - } - - if (err == 0) - err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL, - 0); - else - cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, -err); - - - hci_dev_unlock(hdev); - hci_dev_put(hdev); - - return err; -} - static int load_link_keys(struct sock *sk, u16 index, unsigned char *data, u16 len) { @@ -2170,9 +2131,6 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_SET_DEV_CLASS: err = set_dev_class(sk, index, buf + sizeof(*hdr), len); break; - case MGMT_OP_SET_SERVICE_CACHE: - err = set_service_cache(sk, index, buf + sizeof(*hdr), len); - break; case MGMT_OP_LOAD_LINK_KEYS: err = load_link_keys(sk, index, buf + sizeof(*hdr), len); break; -- cgit v1.2.3 From ef5803729c2323204f7372617ad97e55e94153b9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 15 Dec 2011 00:47:38 +0200 Subject: Bluetooth: Move EIR and CoD update functions to a better position Due to the upcoming addition of a service cache timer the functions to update the EIR and CoD need to be higher up in mgmt.c in order to avoid unnecessary forward-declarations. This patch simply moves code around without any other changes in order to make subsequent patches more readable. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/mgmt.c | 346 +++++++++++++++++++++++++-------------------------- 1 file changed, 173 insertions(+), 173 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 559b938f504..cc4ea392ac6 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -299,6 +299,179 @@ static u32 get_current_settings(struct hci_dev *hdev) return settings; } +#define EIR_FLAGS 0x01 /* flags */ +#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */ +#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */ +#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */ +#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */ +#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */ +#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */ +#define EIR_NAME_SHORT 0x08 /* shortened local name */ +#define EIR_NAME_COMPLETE 0x09 /* complete local name */ +#define EIR_TX_POWER 0x0A /* transmit power level */ +#define EIR_DEVICE_ID 0x10 /* device ID */ + +#define PNP_INFO_SVCLASS_ID 0x1200 + +static u8 bluetooth_base_uuid[] = { + 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static u16 get_uuid16(u8 *uuid128) +{ + u32 val; + int i; + + for (i = 0; i < 12; i++) { + if (bluetooth_base_uuid[i] != uuid128[i]) + return 0; + } + + memcpy(&val, &uuid128[12], 4); + + val = le32_to_cpu(val); + if (val > 0xffff) + return 0; + + return (u16) val; +} + +static void create_eir(struct hci_dev *hdev, u8 *data) +{ + u8 *ptr = data; + u16 eir_len = 0; + u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)]; + int i, truncated = 0; + struct bt_uuid *uuid; + size_t name_len; + + name_len = strlen(hdev->dev_name); + + if (name_len > 0) { + /* EIR Data type */ + if (name_len > 48) { + name_len = 48; + ptr[1] = EIR_NAME_SHORT; + } else + ptr[1] = EIR_NAME_COMPLETE; + + /* EIR Data length */ + ptr[0] = name_len + 1; + + memcpy(ptr + 2, hdev->dev_name, name_len); + + eir_len += (name_len + 2); + ptr += (name_len + 2); + } + + memset(uuid16_list, 0, sizeof(uuid16_list)); + + /* Group all UUID16 types */ + list_for_each_entry(uuid, &hdev->uuids, list) { + u16 uuid16; + + uuid16 = get_uuid16(uuid->uuid); + if (uuid16 == 0) + return; + + if (uuid16 < 0x1100) + continue; + + if (uuid16 == PNP_INFO_SVCLASS_ID) + continue; + + /* Stop if not enough space to put next UUID */ + if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) { + truncated = 1; + break; + } + + /* Check for duplicates */ + for (i = 0; uuid16_list[i] != 0; i++) + if (uuid16_list[i] == uuid16) + break; + + if (uuid16_list[i] == 0) { + uuid16_list[i] = uuid16; + eir_len += sizeof(u16); + } + } + + if (uuid16_list[0] != 0) { + u8 *length = ptr; + + /* EIR Data type */ + ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL; + + ptr += 2; + eir_len += 2; + + for (i = 0; uuid16_list[i] != 0; i++) { + *ptr++ = (uuid16_list[i] & 0x00ff); + *ptr++ = (uuid16_list[i] & 0xff00) >> 8; + } + + /* EIR Data length */ + *length = (i * sizeof(u16)) + 1; + } +} + +static int update_eir(struct hci_dev *hdev) +{ + struct hci_cp_write_eir cp; + + if (!(hdev->features[6] & LMP_EXT_INQ)) + return 0; + + if (hdev->ssp_mode == 0) + return 0; + + if (test_bit(HCI_SERVICE_CACHE, &hdev->flags)) + return 0; + + memset(&cp, 0, sizeof(cp)); + + create_eir(hdev, cp.data); + + if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0) + return 0; + + memcpy(hdev->eir, cp.data, sizeof(cp.data)); + + return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp); +} + +static u8 get_service_classes(struct hci_dev *hdev) +{ + struct bt_uuid *uuid; + u8 val = 0; + + list_for_each_entry(uuid, &hdev->uuids, list) + val |= uuid->svc_hint; + + return val; +} + +static int update_class(struct hci_dev *hdev) +{ + u8 cod[3]; + + BT_DBG("%s", hdev->name); + + if (test_bit(HCI_SERVICE_CACHE, &hdev->flags)) + return 0; + + cod[0] = hdev->minor_class; + cod[1] = hdev->major_class; + cod[2] = get_service_classes(hdev); + + if (memcmp(cod, hdev->dev_class, 3) == 0) + return 0; + + return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod); +} + static int read_controller_info(struct sock *sk, u16 index) { struct mgmt_rp_read_info rp; @@ -681,179 +854,6 @@ failed: return err; } -#define EIR_FLAGS 0x01 /* flags */ -#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */ -#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */ -#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */ -#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */ -#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */ -#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */ -#define EIR_NAME_SHORT 0x08 /* shortened local name */ -#define EIR_NAME_COMPLETE 0x09 /* complete local name */ -#define EIR_TX_POWER 0x0A /* transmit power level */ -#define EIR_DEVICE_ID 0x10 /* device ID */ - -#define PNP_INFO_SVCLASS_ID 0x1200 - -static u8 bluetooth_base_uuid[] = { - 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, - 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - -static u16 get_uuid16(u8 *uuid128) -{ - u32 val; - int i; - - for (i = 0; i < 12; i++) { - if (bluetooth_base_uuid[i] != uuid128[i]) - return 0; - } - - memcpy(&val, &uuid128[12], 4); - - val = le32_to_cpu(val); - if (val > 0xffff) - return 0; - - return (u16) val; -} - -static void create_eir(struct hci_dev *hdev, u8 *data) -{ - u8 *ptr = data; - u16 eir_len = 0; - u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)]; - int i, truncated = 0; - struct bt_uuid *uuid; - size_t name_len; - - name_len = strlen(hdev->dev_name); - - if (name_len > 0) { - /* EIR Data type */ - if (name_len > 48) { - name_len = 48; - ptr[1] = EIR_NAME_SHORT; - } else - ptr[1] = EIR_NAME_COMPLETE; - - /* EIR Data length */ - ptr[0] = name_len + 1; - - memcpy(ptr + 2, hdev->dev_name, name_len); - - eir_len += (name_len + 2); - ptr += (name_len + 2); - } - - memset(uuid16_list, 0, sizeof(uuid16_list)); - - /* Group all UUID16 types */ - list_for_each_entry(uuid, &hdev->uuids, list) { - u16 uuid16; - - uuid16 = get_uuid16(uuid->uuid); - if (uuid16 == 0) - return; - - if (uuid16 < 0x1100) - continue; - - if (uuid16 == PNP_INFO_SVCLASS_ID) - continue; - - /* Stop if not enough space to put next UUID */ - if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) { - truncated = 1; - break; - } - - /* Check for duplicates */ - for (i = 0; uuid16_list[i] != 0; i++) - if (uuid16_list[i] == uuid16) - break; - - if (uuid16_list[i] == 0) { - uuid16_list[i] = uuid16; - eir_len += sizeof(u16); - } - } - - if (uuid16_list[0] != 0) { - u8 *length = ptr; - - /* EIR Data type */ - ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL; - - ptr += 2; - eir_len += 2; - - for (i = 0; uuid16_list[i] != 0; i++) { - *ptr++ = (uuid16_list[i] & 0x00ff); - *ptr++ = (uuid16_list[i] & 0xff00) >> 8; - } - - /* EIR Data length */ - *length = (i * sizeof(u16)) + 1; - } -} - -static int update_eir(struct hci_dev *hdev) -{ - struct hci_cp_write_eir cp; - - if (!(hdev->features[6] & LMP_EXT_INQ)) - return 0; - - if (hdev->ssp_mode == 0) - return 0; - - if (test_bit(HCI_SERVICE_CACHE, &hdev->flags)) - return 0; - - memset(&cp, 0, sizeof(cp)); - - create_eir(hdev, cp.data); - - if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0) - return 0; - - memcpy(hdev->eir, cp.data, sizeof(cp.data)); - - return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp); -} - -static u8 get_service_classes(struct hci_dev *hdev) -{ - struct bt_uuid *uuid; - u8 val = 0; - - list_for_each_entry(uuid, &hdev->uuids, list) - val |= uuid->svc_hint; - - return val; -} - -static int update_class(struct hci_dev *hdev) -{ - u8 cod[3]; - - BT_DBG("%s", hdev->name); - - if (test_bit(HCI_SERVICE_CACHE, &hdev->flags)) - return 0; - - cod[0] = hdev->minor_class; - cod[1] = hdev->major_class; - cod[2] = get_service_classes(hdev); - - if (memcmp(cod, hdev->dev_class, 3) == 0) - return 0; - - return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod); -} - static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) { struct mgmt_cp_add_uuid *cp; -- cgit v1.2.3 From 7d78525dcf5c6fe5e6e73d22776ed5f960e3153e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 15 Dec 2011 00:47:39 +0200 Subject: Bluetooth: Add timer for automatically disabling the service cache We do not want the service cache to be enabled indefinitely after mgmt_read_info is called. To solve this a timer is added which will automatically disable the cache if mgmt_set_dev_class isn't called within 5 seconds of calling mgmt_read_info. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_core.c | 3 +++ net/bluetooth/mgmt.c | 40 +++++++++++++++++++++++++++++++++++----- 3 files changed, 40 insertions(+), 5 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index cc17f739dff..105eaa25103 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -193,6 +193,8 @@ struct hci_dev { __u16 discov_timeout; struct delayed_work discov_off; + struct delayed_work service_cache; + struct timer_list cmd_timer; struct work_struct rx_work; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 82d1d9e6b7c..b5ba42db056 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -598,6 +598,9 @@ static int hci_dev_do_close(struct hci_dev *hdev) if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags)) cancel_delayed_work(&hdev->power_off); + if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags)) + cancel_delayed_work(&hdev->service_cache); + hci_dev_lock(hdev); inquiry_cache_flush(hdev); hci_conn_hash_flush(hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index cc4ea392ac6..6cb8c7f708b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -35,6 +35,8 @@ #define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */ +#define SERVICE_CACHE_TIMEOUT (5 * 1000) + struct pending_cmd { struct list_head list; u16 opcode; @@ -472,6 +474,32 @@ static int update_class(struct hci_dev *hdev) return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod); } +static void service_cache_off(struct work_struct *work) +{ + struct hci_dev *hdev = container_of(work, struct hci_dev, + service_cache.work); + + if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags)) + return; + + hci_dev_lock(hdev); + + update_eir(hdev); + update_class(hdev); + + hci_dev_unlock(hdev); +} + +static void mgmt_init_hdev(struct hci_dev *hdev) +{ + if (!test_and_set_bit(HCI_MGMT, &hdev->flags)) + INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off); + + if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->flags)) + schedule_delayed_work(&hdev->service_cache, + msecs_to_jiffies(SERVICE_CACHE_TIMEOUT)); +} + static int read_controller_info(struct sock *sk, u16 index) { struct mgmt_rp_read_info rp; @@ -489,10 +517,8 @@ static int read_controller_info(struct sock *sk, u16 index) hci_dev_lock(hdev); - if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags)) { - set_bit(HCI_MGMT, &hdev->flags); - set_bit(HCI_SERVICE_CACHE, &hdev->flags); - } + if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags)) + mgmt_init_hdev(hdev); memset(&rp, 0, sizeof(rp)); @@ -992,8 +1018,12 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data, hdev->major_class = cp->major; hdev->minor_class = cp->minor; - if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags)) + if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags)) { + hci_dev_unlock(hdev); + cancel_delayed_work_sync(&hdev->service_cache); + hci_dev_lock(hdev); update_eir(hdev); + } err = update_class(hdev); -- cgit v1.2.3 From c9c2659f1ea84f860af82cac504cc58f17067523 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 15 Dec 2011 00:47:41 +0200 Subject: Bluetooth: Use correct struct for user_confirm_neg_reply This patch fixes user_confirm_neg_reply to use the appropriate struct for accessing the call parameters. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 6cb8c7f708b..8413f55cc13 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1690,7 +1690,7 @@ static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len) static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data, u16 len) { - struct mgmt_cp_user_confirm_reply *cp = (void *) data; + struct mgmt_cp_user_confirm_neg_reply *cp = data; BT_DBG(""); -- cgit v1.2.3 From 350ee4cfc0ea620bd1126ad4daa295586d6aa3a9 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 7 Dec 2011 15:56:51 +0200 Subject: Bluetooth: Add HCI Read Data Block Size function Implement block size read function. Use different variables for packet-based and block-based flow control. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci.h | 8 ++++++++ include/net/bluetooth/hci_core.h | 5 +++++ net/bluetooth/hci_event.c | 26 ++++++++++++++++++++++++++ 3 files changed, 39 insertions(+) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index c9ad56fe58f..2e48d326e36 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -746,6 +746,14 @@ struct hci_rp_read_bd_addr { bdaddr_t bdaddr; } __packed; +#define HCI_OP_READ_DATA_BLOCK_SIZE 0x100a +struct hci_rp_read_data_block_size { + __u8 status; + __le16 max_acl_len; + __le16 block_len; + __le16 num_blocks; +} __packed; + #define HCI_OP_WRITE_PAGE_SCAN_ACTIVITY 0x0c1c struct hci_cp_write_page_scan_activity { __le16 interval; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 105eaa25103..74f8356b9ff 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -181,6 +181,11 @@ struct hci_dev { unsigned int sco_pkts; unsigned int le_pkts; + __u16 block_len; + __u16 block_mtu; + __u16 num_blocks; + __u16 block_cnt; + unsigned long acl_last_tx; unsigned long sco_last_tx; unsigned long le_last_tx; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 74f758363c2..48796832fdf 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -767,6 +767,28 @@ static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb) hci_req_complete(hdev, HCI_OP_READ_BD_ADDR, rp->status); } +static void hci_cc_read_data_block_size(struct hci_dev *hdev, + struct sk_buff *skb) +{ + struct hci_rp_read_data_block_size *rp = (void *) skb->data; + + BT_DBG("%s status 0x%x", hdev->name, rp->status); + + if (rp->status) + return; + + hdev->block_mtu = __le16_to_cpu(rp->max_acl_len); + hdev->block_len = __le16_to_cpu(rp->block_len); + hdev->num_blocks = __le16_to_cpu(rp->num_blocks); + + hdev->block_cnt = hdev->num_blocks; + + BT_DBG("%s blk mtu %d cnt %d len %d", hdev->name, hdev->block_mtu, + hdev->block_cnt, hdev->block_len); + + hci_req_complete(hdev, HCI_OP_READ_DATA_BLOCK_SIZE, rp->status); +} + static void hci_cc_write_ca_timeout(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); @@ -2018,6 +2040,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk hci_cc_read_bd_addr(hdev, skb); break; + case HCI_OP_READ_DATA_BLOCK_SIZE: + hci_cc_read_data_block_size(hdev, skb); + break; + case HCI_OP_WRITE_CA_TIMEOUT: hci_cc_write_ca_timeout(hdev, skb); break; -- cgit v1.2.3 From f42809185896296d5662778e4ec63e084cfa5f2b Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 7 Dec 2011 15:56:52 +0200 Subject: Bluetooth: Simplify num_comp_pkts_evt function Simplify function and remove fourth level of indentation. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_event.c | 47 +++++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 18 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 48796832fdf..fc5338fc2a6 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2273,28 +2273,39 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s count = get_unaligned_le16(ptr++); conn = hci_conn_hash_lookup_handle(hdev, handle); - if (conn) { - conn->sent -= count; - - if (conn->type == ACL_LINK) { + if (!conn) + continue; + + conn->sent -= count; + + switch (conn->type) { + case ACL_LINK: + hdev->acl_cnt += count; + if (hdev->acl_cnt > hdev->acl_pkts) + hdev->acl_cnt = hdev->acl_pkts; + break; + + case LE_LINK: + if (hdev->le_pkts) { + hdev->le_cnt += count; + if (hdev->le_cnt > hdev->le_pkts) + hdev->le_cnt = hdev->le_pkts; + } else { hdev->acl_cnt += count; if (hdev->acl_cnt > hdev->acl_pkts) hdev->acl_cnt = hdev->acl_pkts; - } else if (conn->type == LE_LINK) { - if (hdev->le_pkts) { - hdev->le_cnt += count; - if (hdev->le_cnt > hdev->le_pkts) - hdev->le_cnt = hdev->le_pkts; - } else { - hdev->acl_cnt += count; - if (hdev->acl_cnt > hdev->acl_pkts) - hdev->acl_cnt = hdev->acl_pkts; - } - } else { - hdev->sco_cnt += count; - if (hdev->sco_cnt > hdev->sco_pkts) - hdev->sco_cnt = hdev->sco_pkts; } + break; + + case SCO_LINK: + hdev->sco_cnt += count; + if (hdev->sco_cnt > hdev->sco_pkts) + hdev->sco_cnt = hdev->sco_pkts; + break; + + default: + BT_ERR("Unknown type %d conn %p", conn->type, conn); + break; } } -- cgit v1.2.3 From 65983fc7bb8df655706cb6e8353b6561b633ee4d Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Tue, 13 Dec 2011 15:06:02 -0800 Subject: Bluetooth: Incoming ACL packets do not force active mode Incoming sk_buffs always have bt_cb(skb)->force_active set to 0, so it's misleading to use that value from the control block when calling hci_conn_enter_active_mode() for incoming data. The destination socket is not known in the HCI layer, so the force_active setting for each socket isn't known either. Hard-coding the force_active parameter does not change any behavior, but makes it obvious that incoming ACL data never exits sniff mode. Signed-off-by: Mat Martineau Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index b5ba42db056..d6382dbb7b7 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2455,7 +2455,7 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb) if (conn) { register struct hci_proto *hp; - hci_conn_enter_active_mode(conn, bt_cb(skb)->force_active); + hci_conn_enter_active_mode(conn, BT_POWER_FORCE_ACTIVE_OFF); /* Send to upper protocol */ hp = hci_proto[HCI_PROTO_L2CAP]; -- cgit v1.2.3 From 36e999a83a4a4badd389901eb6d23a30e199b8db Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Thu, 8 Dec 2011 17:23:21 -0800 Subject: Bluetooth: Prevent uninitialized data access in L2CAP configuration When configuring an ERTM or streaming mode connection, remote devices are expected to send an RFC option in a successful config response. A misbehaving remote device might not send an RFC option, and the L2CAP code should not access uninitialized data in this case. Signed-off-by: Mat Martineau Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_core.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 5ea94a1eecf..17b5b1cd965 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2152,7 +2152,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi void *ptr = req->data; int type, olen; unsigned long val; - struct l2cap_conf_rfc rfc; + struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC }; BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data); @@ -2271,6 +2271,16 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len) } } + /* Use sane default values in case a misbehaving remote device + * did not send an RFC option. + */ + rfc.mode = chan->mode; + rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); + rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); + rfc.max_pdu_size = cpu_to_le16(chan->imtu); + + BT_ERR("Expected RFC option was not found, using defaults"); + done: switch (rfc.mode) { case L2CAP_MODE_ERTM: -- cgit v1.2.3 From 79e654787c67f6b05f73366ff8ccac72ba7249e6 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Tue, 6 Dec 2011 16:23:26 -0800 Subject: Bluetooth: Clear RFCOMM session timer when disconnecting last channel When the last RFCOMM data channel is closed, a timer is normally set up to disconnect the control channel at a later time. If the control channel disconnect command is sent with the timer pending, the timer needs to be cancelled. If the timer is not cancelled in this situation, the reference counting logic for the RFCOMM session does not work correctly when the remote device closes the L2CAP connection. The session is freed at the wrong time, leading to a kernel panic. Signed-off-by: Mat Martineau Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/rfcomm/core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 4e32e18211f..2d28dfe9838 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -1146,6 +1146,7 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci) if (list_empty(&s->dlcs)) { s->state = BT_DISCONN; rfcomm_send_disc(s, 0); + rfcomm_session_clear_timer(s); } break; -- cgit v1.2.3 From d7660918fce210f421cc58c060ca3de71e4ffd37 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sun, 18 Dec 2011 22:33:30 -0200 Subject: Revert "Bluetooth: Revert: Fix L2CAP connection establishment" This reverts commit 4dff523a913197e3314c7b0d08734ab037709093. It was reported that this patch cause issues when trying to connect to legacy devices so reverting it. Reported-by: David Fries Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_conn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index e0af7237cd9..c1c597e3e19 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -673,7 +673,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) goto encrypt; auth: - if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) + if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) return 0; if (!hci_conn_auth(conn, sec_level, auth_type)) -- cgit v1.2.3