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') 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') 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') 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 --- net/bluetooth/hci_conn.c | 72 ++++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 36 deletions(-) (limited to 'net') 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 --- net/bluetooth/hci_core.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'net') 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 --- 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 +- 8 files changed, 97 insertions(+), 97 deletions(-) (limited to 'net') 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 --- net/bluetooth/hci_conn.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'net') 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 --- net/bluetooth/hci_core.c | 10 +++++----- net/bluetooth/hci_event.c | 6 ++++-- 2 files changed, 9 insertions(+), 7 deletions(-) (limited to 'net') 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') 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 --- net/bluetooth/l2cap_core.c | 70 ++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 39 deletions(-) (limited to 'net') 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') 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') 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') 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 --- net/bluetooth/l2cap_core.c | 52 +++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 26 deletions(-) (limited to 'net') 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') 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 --- net/bluetooth/hci_conn.c | 19 +++++++++---------- net/bluetooth/hci_core.c | 34 ++++++++++++++++++++++------------ 2 files changed, 31 insertions(+), 22 deletions(-) (limited to 'net') 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') 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 --- net/bluetooth/hci_core.c | 22 +++++++++++----------- net/bluetooth/hci_event.c | 4 ++-- net/bluetooth/hci_sock.c | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) (limited to 'net') 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 --- net/bluetooth/hci_core.c | 20 +++++++++----------- net/bluetooth/hci_event.c | 6 +----- net/bluetooth/hci_sock.c | 4 ++-- 3 files changed, 12 insertions(+), 18 deletions(-) (limited to 'net') 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 --- net/bluetooth/l2cap_core.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'net') 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 --- net/bluetooth/l2cap_core.c | 58 +++++++++++++++++++++++++++++++++++++++++-- net/bluetooth/l2cap_sock.c | 61 +++------------------------------------------- 2 files changed, 59 insertions(+), 60 deletions(-) (limited to 'net') 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') 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') 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') 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 --- net/bluetooth/hci_sysfs.c | 71 ++++++++++++++++++----------------------------- 1 file changed, 27 insertions(+), 44 deletions(-) (limited to 'net') 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') 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') 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 --- net/bluetooth/mgmt.c | 146 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 94 insertions(+), 52 deletions(-) (limited to 'net') 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 --- net/bluetooth/mgmt.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'net') 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 --- net/bluetooth/hci_sock.c | 7 ++++-- net/bluetooth/mgmt.c | 56 ++++++------------------------------------------ 2 files changed, 12 insertions(+), 51 deletions(-) (limited to 'net') 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') 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 --- net/bluetooth/hci_core.c | 3 +++ net/bluetooth/mgmt.c | 40 +++++++++++++++++++++++++++++++++++----- 2 files changed, 38 insertions(+), 5 deletions(-) (limited to 'net') 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') 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 --- net/bluetooth/hci_event.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'net') 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') 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') 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 84381b4ed58498e1e3d49a4a306fec9894b8e00c Mon Sep 17 00:00:00 2001 From: Nikolay Martynov Date: Sat, 17 Dec 2011 19:39:35 -0500 Subject: mac80211: split addba retries in time Currently code allows three (HT_AGG_MAX_RETRIES) unanswered addba requests. When this limit is reached aggregation is turned off for given TID permanently. This doesn't seem right: three requests is not that much, some 'blackout' can happen, but effect of it affects whole connection indefinitely. This patch increases number of retries to 15. Also, when there have been 3 or more retries it splits further retries apart by 15 seconds instead of sending them in very short period of time. Signed-off-by: Nikolay Martynov Signed-off-by: John W. Linville --- net/mac80211/agg-tx.c | 19 +++++++++++++++++++ net/mac80211/sta_info.h | 6 +++++- 2 files changed, 24 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index e92f98d3274..76be6174419 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -392,6 +392,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) #endif spin_lock_bh(&sta->lock); + sta->ampdu_mlme.last_addba_req_time[tid] = jiffies; sta->ampdu_mlme.addba_req_num[tid]++; spin_unlock_bh(&sta->lock); @@ -492,6 +493,24 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, goto err_unlock_sta; } + /* + * if we have tried more than HT_AGG_BURST_RETRIES times we + * will spread our requests in time to avoid stalling connection + * for too long + */ + if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_BURST_RETRIES && + time_before(jiffies, sta->ampdu_mlme.last_addba_req_time[tid] + + HT_AGG_RETRIES_PERIOD)) { +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "BA request denied - " + "waiting a grace period after %d failed requests " + "on tid %u\n", + sta->ampdu_mlme.addba_req_num[tid], tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + ret = -EBUSY; + goto err_unlock_sta; + } + tid_tx = rcu_dereference_protected_tid_tx(sta, tid); /* check if the TID is not in aggregation flow already */ if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) { diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 15b3bb7d862..dee28429046 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -83,7 +83,9 @@ enum ieee80211_sta_state { #define STA_TID_NUM 16 #define ADDBA_RESP_INTERVAL HZ -#define HT_AGG_MAX_RETRIES 0x3 +#define HT_AGG_MAX_RETRIES 15 +#define HT_AGG_BURST_RETRIES 3 +#define HT_AGG_RETRIES_PERIOD (15 * HZ) #define HT_AGG_STATE_DRV_READY 0 #define HT_AGG_STATE_RESPONSE_RECEIVED 1 @@ -179,6 +181,7 @@ struct tid_ampdu_rx { * @tid_tx: aggregation info for Tx per TID * @tid_start_tx: sessions where start was requested * @addba_req_num: number of times addBA request has been sent. + * @last_addba_req_time: timestamp of the last addBA request. * @dialog_token_allocator: dialog token enumerator for each new session; * @work: work struct for starting/stopping aggregation * @tid_rx_timer_expired: bitmap indicating on which TIDs the @@ -198,6 +201,7 @@ struct sta_ampdu_mlme { struct work_struct work; struct tid_ampdu_tx __rcu *tid_tx[STA_TID_NUM]; struct tid_ampdu_tx *tid_start_tx[STA_TID_NUM]; + unsigned long last_addba_req_time[STA_TID_NUM]; u8 addba_req_num[STA_TID_NUM]; u8 dialog_token_allocator; }; -- cgit v1.2.3 From a85e1d55974646a442d95911e3f7d7a891ea9ac5 Mon Sep 17 00:00:00 2001 From: Paul Stewart Date: Fri, 9 Dec 2011 11:01:49 -0800 Subject: cfg80211: Return beacon loss count in station If station info contains a beacon loss count, return it to userspace. Signed-off-by: Paul Stewart Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 4 +++- net/mac80211/mlme.c | 8 ++++++++ net/mac80211/sta_info.h | 2 ++ net/wireless/nl80211.c | 3 +++ 4 files changed, 16 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 66ad9d9af87..850bb96bd68 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -355,7 +355,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) STATION_INFO_RX_DROP_MISC | STATION_INFO_BSS_PARAM | STATION_INFO_CONNECTED_TIME | - STATION_INFO_STA_FLAGS; + STATION_INFO_STA_FLAGS | + STATION_INFO_BEACON_LOSS_COUNT; do_posix_clock_monotonic_gettime(&uptime); sinfo->connected_time = uptime.tv_sec - sta->last_connected; @@ -368,6 +369,7 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) sinfo->tx_retries = sta->tx_retry_count; sinfo->tx_failed = sta->tx_retry_failed; sinfo->rx_dropped_misc = sta->rx_dropped; + sinfo->beacon_loss_count = sta->beacon_loss_count; if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index a984f1f60dd..57989a046fc 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1381,6 +1381,14 @@ void ieee80211_beacon_connection_loss_work(struct work_struct *work) struct ieee80211_sub_if_data *sdata = container_of(work, struct ieee80211_sub_if_data, u.mgd.beacon_connection_loss_work); + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct sta_info *sta; + + if (ifmgd->associated) { + sta = sta_info_get(sdata, ifmgd->bssid); + if (sta) + sta->beacon_loss_count++; + } if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) __ieee80211_connection_loss(sdata); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index dee28429046..6f77f12dc3f 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -275,6 +275,7 @@ struct sta_ampdu_mlme { * EAP frames before association * @sta: station information we share with the driver * @sta_state: duplicates information about station state (for debug) + * @beacon_loss_count: number of times beacon loss has triggered */ struct sta_info { /* General information, mostly static */ @@ -367,6 +368,7 @@ struct sta_info { #endif unsigned int lost_packets; + unsigned int beacon_loss_count; /* should be right in front of sta to be in the same cache line */ bool dummy; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b07c4fc4ae2..b3d3cf8931c 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2390,6 +2390,9 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, if (sinfo->filled & STATION_INFO_TX_FAILED) NLA_PUT_U32(msg, NL80211_STA_INFO_TX_FAILED, sinfo->tx_failed); + if (sinfo->filled & STATION_INFO_BEACON_LOSS_COUNT) + NLA_PUT_U32(msg, NL80211_STA_INFO_BEACON_LOSS, + sinfo->beacon_loss_count); if (sinfo->filled & STATION_INFO_BSS_PARAM) { bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM); if (!bss_param) -- cgit v1.2.3 From 645d35902c8f05a1b12fa838aa9052d8eeaf161e Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 16 Dec 2011 15:03:36 +0100 Subject: NFC: Fix LLCP related build failure llcp_mac routines should be static and inlined or build will fail with NFC selected without LLCP. This patch fixes: LD [M] net/nfc/nfc.o net/nfc/netlink.o: In function `nfc_llcp_mac_is_down': netlink.c:(.text+0x0): multiple definition of `nfc_llcp_mac_is_down' net/nfc/core.o:(.text+0x0): first defined here net/nfc/netlink.o: In function `nfc_llcp_mac_is_up': netlink.c:(.text+0x10): multiple definition of `nfc_llcp_mac_is_up' net/nfc/core.o:(.text+0x10): first defined here net/nfc/af_nfc.o: In function `nfc_llcp_mac_is_down': (.text+0x0): multiple definition of `nfc_llcp_mac_is_down' net/nfc/core.o:(.text+0x0): first defined here net/nfc/af_nfc.o: In function `nfc_llcp_mac_is_up': (.text+0x10): multiple definition of `nfc_llcp_mac_is_up' net/nfc/core.o:(.text+0x10): first defined here net/nfc/rawsock.o: In function `nfc_llcp_mac_is_down': rawsock.c:(.text+0x0): multiple definition of `nfc_llcp_mac_is_down' net/nfc/core.o:(.text+0x0): first defined here net/nfc/rawsock.o: In function `nfc_llcp_mac_is_up': rawsock.c:(.text+0x10): multiple definition of `nfc_llcp_mac_is_up' net/nfc/core.o:(.text+0x10): first defined here Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/nfc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h index 2c2c4015c68..6d28d75995b 100644 --- a/net/nfc/nfc.h +++ b/net/nfc/nfc.h @@ -60,11 +60,11 @@ void nfc_llcp_exit(void); #else -void nfc_llcp_mac_is_down(struct nfc_dev *dev) +static inline void nfc_llcp_mac_is_down(struct nfc_dev *dev) { } -void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx, +static inline void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx, u8 comm_mode, u8 rf_mode) { } -- cgit v1.2.3 From 1d8d3dec5fbba15864f25c734a7fda5703234091 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 16 Dec 2011 15:28:57 +0100 Subject: mac80211: handle SMPS action frames When a peer changes SMPS state we should update rate control so it doesn't have to detect it by itself. It can't detect "dynamic" mode anyway since that just requires rts-cts handshaking. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rx.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) (limited to 'net') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 2be5b7d69ad..57832eb44f3 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -28,6 +28,7 @@ #include "wpa.h" #include "tkip.h" #include "wme.h" +#include "rate.h" /* * monitor mode reception @@ -2233,6 +2234,63 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) return RX_DROP_UNUSABLE; switch (mgmt->u.action.category) { + case WLAN_CATEGORY_HT: + /* reject HT action frames from stations not supporting HT */ + if (!rx->sta->sta.ht_cap.ht_supported) + goto invalid; + + if (sdata->vif.type != NL80211_IFTYPE_STATION && + sdata->vif.type != NL80211_IFTYPE_MESH_POINT && + sdata->vif.type != NL80211_IFTYPE_AP_VLAN && + sdata->vif.type != NL80211_IFTYPE_AP && + sdata->vif.type != NL80211_IFTYPE_ADHOC) + break; + + /* verify action & smps_control are present */ + if (len < IEEE80211_MIN_ACTION_SIZE + 2) + goto invalid; + + switch (mgmt->u.action.u.ht_smps.action) { + case WLAN_HT_ACTION_SMPS: { + struct ieee80211_supported_band *sband; + u8 smps; + + /* convert to HT capability */ + switch (mgmt->u.action.u.ht_smps.smps_control) { + case WLAN_HT_SMPS_CONTROL_DISABLED: + smps = WLAN_HT_CAP_SM_PS_DISABLED; + break; + case WLAN_HT_SMPS_CONTROL_STATIC: + smps = WLAN_HT_CAP_SM_PS_STATIC; + break; + case WLAN_HT_SMPS_CONTROL_DYNAMIC: + smps = WLAN_HT_CAP_SM_PS_DYNAMIC; + break; + default: + goto invalid; + } + smps <<= IEEE80211_HT_CAP_SM_PS_SHIFT; + + /* if no change do nothing */ + if ((rx->sta->sta.ht_cap.cap & + IEEE80211_HT_CAP_SM_PS) == smps) + goto handled; + + rx->sta->sta.ht_cap.cap &= ~IEEE80211_HT_CAP_SM_PS; + rx->sta->sta.ht_cap.cap |= smps; + + sband = rx->local->hw.wiphy->bands[status->band]; + + rate_control_rate_update(local, sband, rx->sta, + IEEE80211_RC_SMPS_CHANGED, + local->_oper_channel_type); + goto handled; + } + default: + goto invalid; + } + + break; case WLAN_CATEGORY_BACK: if (sdata->vif.type != NL80211_IFTYPE_STATION && sdata->vif.type != NL80211_IFTYPE_MESH_POINT && -- cgit v1.2.3 From 341ee4349f31e42fb0eb20d340d15309ac760308 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 16 Dec 2011 23:25:29 +0300 Subject: NFC: double unlock in nfc_llcp_recv_connect() We unlock inside the if block on the other side of this if else statement. It could result in calling mutex_unlock() twice. Signed-off-by: Dan Carpenter Acked-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/llcp/llcp.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'net') diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 67756b23eac..f99d6b4658e 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -554,11 +554,9 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local, goto enqueue; } } - + mutex_unlock(&local->socket_lock); } - mutex_unlock(&local->socket_lock); - reason = LLCP_DM_NOBOUND; goto fail; -- cgit v1.2.3 From 5b68a7ca32194e238a1dcbb24ae0a4cf61e67047 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 16 Dec 2011 23:26:00 +0300 Subject: NFC: use kfree_skb() for sk_buffs This is a struct sk_buff pointer and it should be freed with kfree_skb() instead of kfree(). Signed-off-by: Dan Carpenter Acked-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/llcp/llcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index f99d6b4658e..1d32680807d 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -954,7 +954,7 @@ void nfc_llcp_unregister_device(struct nfc_dev *dev) skb_queue_purge(&local->tx_queue); destroy_workqueue(local->tx_wq); destroy_workqueue(local->rx_wq); - kfree(local->rx_pending); + kfree_skb(local->rx_pending); kfree(local); } -- cgit v1.2.3 From 27bf88829f50cf1af2b052ecee2f6f0dbe4a5141 Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Fri, 16 Dec 2011 11:47:15 +0530 Subject: mac80211: Fixing sparse warning at sta_info.c The commit 42624d4913a00219a8fdbb4bafd634d1d843be85 created following sparse warning >net/mac80211/sta_info.c:965:24: warning: incorrect type in assignment (different address spaces) >net/mac80211/sta_info.c:965:24: expected struct tid_ampdu_tx *tid_tx >net/mac80211/sta_info.c:965:24: got struct tid_ampdu_tx [noderef] * Making use of rcu_dereference_protected to fix the problem. V2: - Replacing rcu_dereference with rcu_dereference_protected as suggested by Johannes. - Adding mutex_lock/unlock to satisfy the condition at rcu_dereference_protected Cc: Nishant Sarmukadam Reported-by: Johannes Berg Signed-off-by: Yogesh Ashok Powar Signed-off-by: John W. Linville --- net/mac80211/sta_info.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 2db01e9541e..3d01abb2b81 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -822,10 +822,13 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) * until the aggregation stop completes. Refer * http://thread.gmane.org/gmane.linux.kernel.wireless.general/81936 */ + + mutex_lock(&sta->ampdu_mlme.mtx); + for (i = 0; i < STA_TID_NUM; i++) { - if (!sta->ampdu_mlme.tid_tx[i]) + tid_tx = rcu_dereference_protected_tid_tx(sta, i); + if (!tid_tx) continue; - tid_tx = sta->ampdu_mlme.tid_tx[i]; if (skb_queue_len(&tid_tx->pending)) { #ifdef CONFIG_MAC80211_HT_DEBUG wiphy_debug(local->hw.wiphy, "TX A-MPDU purging %d " @@ -837,6 +840,8 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) kfree_rcu(tid_tx, rcu_head); } + mutex_unlock(&sta->ampdu_mlme.mtx); + sta_info_free(local, sta); return 0; -- cgit v1.2.3 From e61ef49966777defa84b04159ea23cdeb2c7cd4c Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 19 Dec 2011 16:31:27 +0200 Subject: Bluetooth: Split ctrl init to BREDR and AMP parts Current controller initialization is moved tp bredr_init and new function added amp_init to handle later AMP init sequence. Current AMP init sequence include Reset and Read Local Version. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_core.c | 64 ++++++++++++++++++++++++++++++++++------------- net/bluetooth/hci_event.c | 3 +++ 2 files changed, 49 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index d6382dbb7b7..bb089e3bcce 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -193,33 +193,18 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt) hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL); } -static void hci_init_req(struct hci_dev *hdev, unsigned long opt) +static void bredr_init(struct hci_dev *hdev) { struct hci_cp_delete_stored_link_key cp; - struct sk_buff *skb; __le16 param; __u8 flt_type; - BT_DBG("%s %ld", hdev->name, opt); - - /* Driver initialization */ - - /* Special commands */ - while ((skb = skb_dequeue(&hdev->driver_init))) { - bt_cb(skb)->pkt_type = HCI_COMMAND_PKT; - skb->dev = (void *) hdev; - - skb_queue_tail(&hdev->cmd_q, skb); - queue_work(hdev->workqueue, &hdev->cmd_work); - } - skb_queue_purge(&hdev->driver_init); - /* Mandatory initialization */ /* Reset */ if (!test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) { - set_bit(HCI_RESET, &hdev->flags); - hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL); + set_bit(HCI_RESET, &hdev->flags); + hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL); } /* Read Local Supported Features */ @@ -258,6 +243,49 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp); } +static void amp_init(struct hci_dev *hdev) +{ + /* Reset */ + hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL); + + /* Read Local Version */ + hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL); +} + +static void hci_init_req(struct hci_dev *hdev, unsigned long opt) +{ + struct sk_buff *skb; + + BT_DBG("%s %ld", hdev->name, opt); + + /* Driver initialization */ + + /* Special commands */ + while ((skb = skb_dequeue(&hdev->driver_init))) { + bt_cb(skb)->pkt_type = HCI_COMMAND_PKT; + skb->dev = (void *) hdev; + + skb_queue_tail(&hdev->cmd_q, skb); + queue_work(hdev->workqueue, &hdev->cmd_work); + } + skb_queue_purge(&hdev->driver_init); + + switch (hdev->dev_type) { + case HCI_BREDR: + bredr_init(hdev); + break; + + case HCI_AMP: + amp_init(hdev); + break; + + default: + BT_ERR("Unknown device type %d", hdev->dev_type); + break; + } + +} + static void hci_le_init_req(struct hci_dev *hdev, unsigned long opt) { BT_DBG("%s", hdev->name); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index fc5338fc2a6..da4e17f4a7c 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -556,6 +556,9 @@ static void hci_set_le_support(struct hci_dev *hdev) static void hci_setup(struct hci_dev *hdev) { + if (hdev->dev_type != HCI_BREDR) + return; + hci_setup_event_mask(hdev); if (hdev->hci_ver > BLUETOOTH_VER_1_1) -- cgit v1.2.3 From 2455a3ea0c0235fe3c32b67649ff7db3fb892d90 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 19 Dec 2011 16:31:28 +0200 Subject: Bluetooth: Initialize default flow control mode Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_core.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index bb089e3bcce..884eb85a136 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -199,6 +199,8 @@ static void bredr_init(struct hci_dev *hdev) __le16 param; __u8 flt_type; + hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_PACKET_BASED; + /* Mandatory initialization */ /* Reset */ @@ -245,6 +247,8 @@ static void bredr_init(struct hci_dev *hdev) static void amp_init(struct hci_dev *hdev) { + hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_BLOCK_BASED; + /* Reset */ hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL); -- cgit v1.2.3 From 32ac5b9b57ef521470f930fd00849be4705bc134 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 19 Dec 2011 16:31:29 +0200 Subject: Bluetooth: Check for flow control mode Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_event.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index da4e17f4a7c..5a204aefc03 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2263,6 +2263,11 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s BT_DBG("%s num_hndl %d", hdev->name, ev->num_hndl); + if (hdev->flow_ctl_mode != HCI_FLOW_CTL_MODE_PACKET_BASED) { + BT_ERR("Wrong event for mode %d", hdev->flow_ctl_mode); + return; + } + if (skb->len < ev->num_hndl * 4) { BT_DBG("%s bad parameters", hdev->name); return; -- cgit v1.2.3 From 613a1c0c595fe2f2d9148a705f140a53bc9f56e1 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 19 Dec 2011 16:31:30 +0200 Subject: Bluetooth: Clean up magic pointers Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_event.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 5a204aefc03..b9d77be92d3 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2256,7 +2256,6 @@ static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_num_comp_pkts *ev = (void *) skb->data; - __le16 *ptr; int i; skb_pull(skb, sizeof(*ev)); @@ -2273,12 +2272,13 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s return; } - for (i = 0, ptr = (__le16 *) skb->data; i < ev->num_hndl; i++) { + for (i = 0; i < ev->num_hndl; i++) { + struct hci_comp_pkts_info *info = &ev->handles[i]; struct hci_conn *conn; __u16 handle, count; - handle = get_unaligned_le16(ptr++); - count = get_unaligned_le16(ptr++); + handle = __le16_to_cpu(info->handle); + count = __le16_to_cpu(info->count); conn = hci_conn_hash_lookup_handle(hdev, handle); if (!conn) -- cgit v1.2.3 From c2ec9c1bbd17cdd1fc962f000b4ecb98c1dad830 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 20 Dec 2011 10:57:26 -0200 Subject: Bluetooth: Move l2cap_{set,clear}_timer to l2cap.h It is the only place where it is used. Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_core.c | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index ffa2f6b8408..5978d69f3d8 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -228,20 +228,6 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn) return 0; } -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); - - cancel_delayed_work_sync(work); - - schedule_delayed_work(work, timeout); -} - -static void l2cap_clear_timer(struct delayed_work *work) -{ - cancel_delayed_work_sync(work); -} - static char *state_to_string(int state) { switch(state) { -- cgit v1.2.3 From 6c9d42a1615c6dc19c4a57a77d9c4b3d779bb741 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 20 Dec 2011 10:57:27 -0200 Subject: Bluetooth: convert security timer to delayed_work This one also needs to run in process context Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_core.c | 12 ++++++------ net/bluetooth/smp.c | 7 ++++--- 2 files changed, 10 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 5978d69f3d8..d0064550d83 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1032,7 +1032,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) cancel_delayed_work_sync(&conn->info_work); if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) { - del_timer(&conn->security_timer); + cancel_delayed_work_sync(&conn->security_timer); smp_chan_destroy(conn); } @@ -1040,9 +1040,10 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) kfree(conn); } -static void security_timeout(unsigned long arg) +static void security_timeout(struct work_struct *work) { - struct l2cap_conn *conn = (void *) arg; + struct l2cap_conn *conn = container_of(work, struct l2cap_conn, + security_timer.work); l2cap_conn_del(conn->hcon, ETIMEDOUT); } @@ -1086,8 +1087,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) INIT_LIST_HEAD(&conn->chan_l); if (hcon->type == LE_LINK) - setup_timer(&conn->security_timer, security_timeout, - (unsigned long) conn); + INIT_DELAYED_WORK(&conn->security_timer, security_timeout); else INIT_DELAYED_WORK(&conn->info_work, l2cap_info_timeout); @@ -4519,7 +4519,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) if (hcon->type == LE_LINK) { smp_distribute_keys(conn, 0); - del_timer(&conn->security_timer); + cancel_delayed_work_sync(&conn->security_timer); } rcu_read_lock(); diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 0b96737d0ad..0ee2905a617 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -184,7 +184,8 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data) skb->priority = HCI_PRIO_MAX; hci_send_acl(conn->hchan, skb, 0); - mod_timer(&conn->security_timer, jiffies + + cancel_delayed_work_sync(&conn->security_timer); + schedule_delayed_work(&conn->security_timer, msecs_to_jiffies(SMP_TIMEOUT)); } @@ -240,7 +241,7 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send) clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->pend); mgmt_auth_failed(conn->hcon->hdev, conn->dst, reason); - del_timer(&conn->security_timer); + cancel_delayed_work_sync(&conn->security_timer); smp_chan_destroy(conn); } @@ -800,7 +801,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) if (conn->hcon->out || force) { clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend); - del_timer(&conn->security_timer); + cancel_delayed_work_sync(&conn->security_timer); smp_chan_destroy(conn); } -- cgit v1.2.3 From 030013d8585bfc9479bb367bf771d96ef8e289a4 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 20 Dec 2011 10:57:28 -0200 Subject: Bluetooth: Rename info_work to info_timer It makes more sense this way, since info_timer is a timer using delayed work API. Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_core.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d0064550d83..a898285e3ea 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -699,7 +699,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); - schedule_delayed_work(&conn->info_work, + schedule_delayed_work(&conn->info_timer, msecs_to_jiffies(L2CAP_INFO_TIMEOUT)); l2cap_send_cmd(conn, conn->info_ident, @@ -996,7 +996,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) static void l2cap_info_timeout(struct work_struct *work) { struct l2cap_conn *conn = container_of(work, struct l2cap_conn, - info_work.work); + info_timer.work); conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; conn->info_ident = 0; @@ -1029,7 +1029,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) - cancel_delayed_work_sync(&conn->info_work); + cancel_delayed_work_sync(&conn->info_timer); if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) { cancel_delayed_work_sync(&conn->security_timer); @@ -1089,7 +1089,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) if (hcon->type == LE_LINK) INIT_DELAYED_WORK(&conn->security_timer, security_timeout); else - INIT_DELAYED_WORK(&conn->info_work, l2cap_info_timeout); + INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout); conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM; @@ -2583,7 +2583,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) { - cancel_delayed_work_sync(&conn->info_work); + cancel_delayed_work_sync(&conn->info_timer); conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; conn->info_ident = 0; @@ -2704,7 +2704,7 @@ sendresp: conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; conn->info_ident = l2cap_get_ident(conn); - schedule_delayed_work(&conn->info_work, + schedule_delayed_work(&conn->info_timer, msecs_to_jiffies(L2CAP_INFO_TIMEOUT)); l2cap_send_cmd(conn, conn->info_ident, @@ -3129,7 +3129,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; - cancel_delayed_work_sync(&conn->info_work); + cancel_delayed_work_sync(&conn->info_timer); if (result != L2CAP_IR_SUCCESS) { conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; -- cgit v1.2.3 From f2d64f6aa6c681ca00a71c2b3304ed80dc317752 Mon Sep 17 00:00:00 2001 From: Ulisses Furquim Date: Tue, 20 Dec 2011 17:10:51 -0200 Subject: Bluetooth: Remove global mutex hci_task_lock The hci_task_lock mutex (previously a lock) was supposed to protect the register/unregister of HCI protocols against RX/TX tasks. This will not be needed anymore because SCO and L2CAP will always be compiled. Moreover, with the recent move of RX/TX to workqueues per device the global hci_task_lock was causing starvation between different HCI devices. Signed-off-by: Ulisses Furquim Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_core.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 884eb85a136..fea8dad72e3 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -61,8 +61,6 @@ static void hci_rx_work(struct work_struct *work); static void hci_cmd_work(struct work_struct *work); static void hci_tx_work(struct work_struct *work); -static DEFINE_MUTEX(hci_task_lock); - /* HCI device list */ LIST_HEAD(hci_dev_list); DEFINE_RWLOCK(hci_dev_list_lock); @@ -1832,8 +1830,7 @@ EXPORT_SYMBOL(hci_recv_stream_fragment); /* ---- Interface to upper protocols ---- */ -/* Register/Unregister protocols. - * hci_task_lock is used to ensure that no tasks are running. */ +/* Register/Unregister protocols. */ int hci_register_proto(struct hci_proto *hp) { int err = 0; @@ -1843,15 +1840,11 @@ int hci_register_proto(struct hci_proto *hp) if (hp->id >= HCI_MAX_PROTO) return -EINVAL; - mutex_lock(&hci_task_lock); - if (!hci_proto[hp->id]) hci_proto[hp->id] = hp; else err = -EEXIST; - mutex_unlock(&hci_task_lock); - return err; } EXPORT_SYMBOL(hci_register_proto); @@ -1865,15 +1858,11 @@ int hci_unregister_proto(struct hci_proto *hp) if (hp->id >= HCI_MAX_PROTO) return -EINVAL; - mutex_lock(&hci_task_lock); - if (hci_proto[hp->id]) hci_proto[hp->id] = NULL; else err = -ENOENT; - mutex_unlock(&hci_task_lock); - return err; } EXPORT_SYMBOL(hci_unregister_proto); @@ -2439,8 +2428,6 @@ static void hci_tx_work(struct work_struct *work) struct hci_dev *hdev = container_of(work, struct hci_dev, tx_work); struct sk_buff *skb; - 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); @@ -2457,8 +2444,6 @@ static void hci_tx_work(struct work_struct *work) /* Send next queued raw (unknown type) packet */ while ((skb = skb_dequeue(&hdev->raw_q))) hci_send_frame(skb); - - mutex_unlock(&hci_task_lock); } /* ----- HCI RX task (incoming data processing) ----- */ @@ -2546,8 +2531,6 @@ static void hci_rx_work(struct work_struct *work) BT_DBG("%s", hdev->name); - mutex_lock(&hci_task_lock); - while ((skb = skb_dequeue(&hdev->rx_q))) { if (atomic_read(&hdev->promisc)) { /* Send copy to the sockets */ @@ -2591,8 +2574,6 @@ static void hci_rx_work(struct work_struct *work) break; } } - - mutex_unlock(&hci_task_lock); } static void hci_cmd_work(struct work_struct *work) -- cgit v1.2.3 From f1e91e1640d808d332498a6b09b2bcd01462eff9 Mon Sep 17 00:00:00 2001 From: Ulisses Furquim Date: Wed, 21 Dec 2011 01:32:09 -0200 Subject: Bluetooth: Always compile SCO and L2CAP in Bluetooth Core The handling of SCO audio links and the L2CAP protocol are essential to any system with Bluetooth thus are always compiled in from now on. Signed-off-by: Ulisses Furquim Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/Kconfig | 37 +++++++++---------------------------- net/bluetooth/Makefile | 5 ++--- net/bluetooth/bnep/Kconfig | 2 +- net/bluetooth/cmtp/Kconfig | 2 +- net/bluetooth/hidp/Kconfig | 2 +- net/bluetooth/rfcomm/Kconfig | 2 +- 6 files changed, 15 insertions(+), 35 deletions(-) (limited to 'net') diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index bfb3dc03c9d..9ec85eb8853 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -6,7 +6,11 @@ menuconfig BT tristate "Bluetooth subsystem support" depends on NET && !S390 depends on RFKILL || !RFKILL + select CRC16 select CRYPTO + select CRYPTO_BLKCIPHER + select CRYPTO_AES + select CRYPTO_ECB help Bluetooth is low-cost, low-power, short-range wireless technology. It was designed as a replacement for cables and other short-range @@ -15,10 +19,12 @@ menuconfig BT Bluetooth can be found at . Linux Bluetooth subsystem consist of several layers: - Bluetooth Core (HCI device and connection manager, scheduler) + Bluetooth Core + HCI device and connection manager, scheduler + SCO audio links + L2CAP (Logical Link Control and Adaptation Protocol) + SMP (Security Manager Protocol) on LE (Low Energy) links HCI Device drivers (Interface to the hardware) - SCO Module (SCO audio links) - L2CAP Module (Logical Link Control and Adaptation Protocol) RFCOMM Module (RFCOMM Protocol) BNEP Module (Bluetooth Network Encapsulation Protocol) CMTP Module (CAPI Message Transport Protocol) @@ -33,31 +39,6 @@ menuconfig BT to Bluetooth kernel modules are provided in the BlueZ packages. For more information, see . -if BT != n - -config BT_L2CAP - bool "L2CAP protocol support" - select CRC16 - select CRYPTO - select CRYPTO_BLKCIPHER - select CRYPTO_AES - select CRYPTO_ECB - help - L2CAP (Logical Link Control and Adaptation Protocol) provides - connection oriented and connection-less data transport. L2CAP - support is required for most Bluetooth applications. - - Also included is support for SMP (Security Manager Protocol) which - is the security layer on top of LE (Low Energy) links. - -config BT_SCO - bool "SCO links support" - help - SCO link provides voice transport over Bluetooth. SCO support is - required for voice applications like Headset and Audio. - -endif - source "net/bluetooth/rfcomm/Kconfig" source "net/bluetooth/bnep/Kconfig" diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile index 9b67f3d08fa..2dc5a5700f5 100644 --- a/net/bluetooth/Makefile +++ b/net/bluetooth/Makefile @@ -8,6 +8,5 @@ obj-$(CONFIG_BT_BNEP) += bnep/ obj-$(CONFIG_BT_CMTP) += cmtp/ obj-$(CONFIG_BT_HIDP) += hidp/ -bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o hci_sock.o hci_sysfs.o lib.o -bluetooth-$(CONFIG_BT_L2CAP) += l2cap_core.o l2cap_sock.o smp.o -bluetooth-$(CONFIG_BT_SCO) += sco.o +bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \ + hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o diff --git a/net/bluetooth/bnep/Kconfig b/net/bluetooth/bnep/Kconfig index 35158b036d5..71791fc9f6b 100644 --- a/net/bluetooth/bnep/Kconfig +++ b/net/bluetooth/bnep/Kconfig @@ -1,6 +1,6 @@ config BT_BNEP tristate "BNEP protocol support" - depends on BT && BT_L2CAP + depends on BT select CRC32 help BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet diff --git a/net/bluetooth/cmtp/Kconfig b/net/bluetooth/cmtp/Kconfig index d6b0382f6f3..94cbf42ce15 100644 --- a/net/bluetooth/cmtp/Kconfig +++ b/net/bluetooth/cmtp/Kconfig @@ -1,6 +1,6 @@ config BT_CMTP tristate "CMTP protocol support" - depends on BT && BT_L2CAP && ISDN_CAPI + depends on BT && ISDN_CAPI help CMTP (CAPI Message Transport Protocol) is a transport layer for CAPI messages. CMTP is required for the Bluetooth Common diff --git a/net/bluetooth/hidp/Kconfig b/net/bluetooth/hidp/Kconfig index 86a91543172..4deaca78e91 100644 --- a/net/bluetooth/hidp/Kconfig +++ b/net/bluetooth/hidp/Kconfig @@ -1,6 +1,6 @@ config BT_HIDP tristate "HIDP protocol support" - depends on BT && BT_L2CAP && INPUT && HID_SUPPORT + depends on BT && INPUT && HID_SUPPORT select HID help HIDP (Human Interface Device Protocol) is a transport layer diff --git a/net/bluetooth/rfcomm/Kconfig b/net/bluetooth/rfcomm/Kconfig index 405a0e61e7d..22e718b554e 100644 --- a/net/bluetooth/rfcomm/Kconfig +++ b/net/bluetooth/rfcomm/Kconfig @@ -1,6 +1,6 @@ config BT_RFCOMM tristate "RFCOMM protocol support" - depends on BT && BT_L2CAP + depends on BT help RFCOMM provides connection oriented stream transport. RFCOMM support is required for Dialup Networking, OBEX and other Bluetooth -- cgit v1.2.3 From ec2b774e7c91094d8c00de579646f1162b87b01e Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Tue, 20 Dec 2011 23:16:52 +0800 Subject: mac80211: ibss should not purge clients it is not responsible for The IBSS merge code calls ieee80211_sta_expire() with a relatively short expire timeout that purges other clients prematurely. The expire function has to check that only the clients belonging to the vif in question are purged. Signed-off-by: Marek Lindner Signed-off-by: John W. Linville --- net/mac80211/sta_info.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net') diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 3d01abb2b81..f0d3b483dab 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -946,6 +946,9 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, mutex_lock(&local->sta_mtx); list_for_each_entry_safe(sta, tmp, &local->sta_list, list) + if (sdata != sta->sdata) + continue; + if (time_after(jiffies, sta->last_rx + exp_time)) { #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "%s: expiring inactive STA %pM\n", -- cgit v1.2.3 From aef6c928a92481f75fbd548eb8c1e840912444b8 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Wed, 21 Dec 2011 09:11:35 +0100 Subject: mac80211: Keep skb->piority for relayed frames in AP mode When mac80211 relays a frame from STA1 to STA2 in AP mode it will get re-classified in the tx path. Unfortunately the frame protocol field is always set to ETH_P_8023 while the classification only kicks in for ETH_P_IP. Hence, a high priority frame from STA1 will be send to STA2 as best effort. Instead of running classification on the frame just use the same priority as STA1 did. Do this by adding 256 to the skb->priority to allow cfg80211_classify8021d to shortcut frame classification. Signed-off-by: Helmut Schaa Signed-off-by: John W. Linville --- net/mac80211/rx.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 57832eb44f3..59f124c5833 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1827,7 +1827,12 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) } if (xmit_skb) { - /* send to wireless media */ + /* + * Send to wireless media and increase priority by 256 to + * keep the received priority instead of reclassifying + * the frame (see cfg80211_classify8021d). + */ + xmit_skb->priority += 256; xmit_skb->protocol = htons(ETH_P_802_3); skb_reset_network_header(xmit_skb); skb_reset_mac_header(xmit_skb); -- cgit v1.2.3 From 8a154a8feb805394d1fd46281becaf876e18860a Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 20 Dec 2011 17:15:56 -0200 Subject: Bluetooth: fix bt_accept_dequeue() to work in process context No local_bh_disable is needed there once we run everything in process context. The same goes for the replacement of bh_lock_sock() by lock_sock(). Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/af_bluetooth.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 062124cd89c..cdcfcabb34a 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -199,15 +199,14 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock) BT_DBG("parent %p", parent); - local_bh_disable(); list_for_each_safe(p, n, &bt_sk(parent)->accept_q) { sk = (struct sock *) list_entry(p, struct bt_sock, accept_q); - bh_lock_sock(sk); + lock_sock(sk); /* FIXME: Is this check still needed */ if (sk->sk_state == BT_CLOSED) { - bh_unlock_sock(sk); + release_sock(sk); bt_accept_unlink(sk); continue; } @@ -218,14 +217,12 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock) if (newsock) sock_graft(sk, newsock); - bh_unlock_sock(sk); - local_bh_enable(); + release_sock(sk); return sk; } - bh_unlock_sock(sk); + release_sock(sk); } - local_bh_enable(); return NULL; } -- cgit v1.2.3 From 68a8aea45973c8d0bc05f58389ce9e82e04bb5f6 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 19 Dec 2011 16:14:18 +0200 Subject: Bluetooth: Remove magic numbers from le scan cmd Make code readable by removing magic numbers. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_event.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index b9d77be92d3..919e3c0e74a 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1033,7 +1033,8 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, if (!cp) return; - if (cp->enable == 0x01) { + switch (cp->enable) { + case LE_SCANNING_ENABLED: set_bit(HCI_LE_SCAN, &hdev->dev_flags); cancel_delayed_work_sync(&hdev->adv_work); @@ -1041,12 +1042,19 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, hci_dev_lock(hdev); hci_adv_entries_clear(hdev); hci_dev_unlock(hdev); - } else if (cp->enable == 0x00) { + break; + + case LE_SCANNING_DISABLED: clear_bit(HCI_LE_SCAN, &hdev->dev_flags); cancel_delayed_work_sync(&hdev->adv_work); queue_delayed_work(hdev->workqueue, &hdev->adv_work, jiffies + ADV_CLEAR_TIMEOUT); + break; + + default: + BT_ERR("Used reserved LE_Scan_Enable param %d", cp->enable); + break; } } -- cgit v1.2.3 From 686ebf283ba19f82abd8aaec023cd124749be9ec Mon Sep 17 00:00:00 2001 From: Ulisses Furquim Date: Wed, 21 Dec 2011 10:11:33 -0200 Subject: Bluetooth: Make HCI call directly into SCO and L2CAP event functions The struct hci_proto and all related register/unregister and dispatching code was removed. HCI core code now call directly the SCO and L2CAP event functions. Signed-off-by: Ulisses Furquim Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_core.c | 59 ++++------------------------------------------ net/bluetooth/l2cap_core.c | 51 ++++++--------------------------------- net/bluetooth/sco.c | 38 ++++------------------------- 3 files changed, 15 insertions(+), 133 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index fea8dad72e3..22c8331cd0d 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -69,10 +69,6 @@ DEFINE_RWLOCK(hci_dev_list_lock); LIST_HEAD(hci_cb_list); DEFINE_RWLOCK(hci_cb_list_lock); -/* HCI protocols */ -#define HCI_MAX_PROTO 2 -struct hci_proto *hci_proto[HCI_MAX_PROTO]; - /* HCI notifiers list */ static ATOMIC_NOTIFIER_HEAD(hci_notifier); @@ -1830,43 +1826,6 @@ EXPORT_SYMBOL(hci_recv_stream_fragment); /* ---- Interface to upper protocols ---- */ -/* Register/Unregister protocols. */ -int hci_register_proto(struct hci_proto *hp) -{ - int err = 0; - - BT_DBG("%p name %s id %d", hp, hp->name, hp->id); - - if (hp->id >= HCI_MAX_PROTO) - return -EINVAL; - - if (!hci_proto[hp->id]) - hci_proto[hp->id] = hp; - else - err = -EEXIST; - - return err; -} -EXPORT_SYMBOL(hci_register_proto); - -int hci_unregister_proto(struct hci_proto *hp) -{ - int err = 0; - - BT_DBG("%p name %s id %d", hp, hp->name, hp->id); - - if (hp->id >= HCI_MAX_PROTO) - return -EINVAL; - - if (hci_proto[hp->id]) - hci_proto[hp->id] = NULL; - else - err = -ENOENT; - - return err; -} -EXPORT_SYMBOL(hci_unregister_proto); - int hci_register_cb(struct hci_cb *cb) { BT_DBG("%p name %s", cb, cb->name); @@ -2470,16 +2429,11 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_unlock(hdev); if (conn) { - register struct hci_proto *hp; - hci_conn_enter_active_mode(conn, BT_POWER_FORCE_ACTIVE_OFF); /* Send to upper protocol */ - hp = hci_proto[HCI_PROTO_L2CAP]; - if (hp && hp->recv_acldata) { - hp->recv_acldata(conn, skb, flags); - return; - } + l2cap_recv_acldata(conn, skb, flags); + return; } else { BT_ERR("%s ACL packet for unknown connection handle %d", hdev->name, handle); @@ -2508,14 +2462,9 @@ static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_unlock(hdev); if (conn) { - register struct hci_proto *hp; - /* Send to upper protocol */ - hp = hci_proto[HCI_PROTO_SCO]; - if (hp && hp->recv_scodata) { - hp->recv_scodata(conn, skb); - return; - } + sco_recv_scodata(conn, skb); + return; } else { BT_ERR("%s SCO packet for unknown connection handle %d", hdev->name, handle); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a898285e3ea..173218345a1 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -4413,14 +4413,11 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) /* ---- L2CAP interface with lower layer (HCI) ---- */ -static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) +int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr) { int exact = 0, lm1 = 0, lm2 = 0; struct l2cap_chan *c; - if (type != ACL_LINK) - return -EINVAL; - BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr)); /* Find listening sockets and check their link_mode */ @@ -4447,15 +4444,12 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) return exact ? lm1 : lm2; } -static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status) +int l2cap_connect_cfm(struct hci_conn *hcon, u8 status) { struct l2cap_conn *conn; BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status); - if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK)) - return -EINVAL; - if (!status) { conn = l2cap_conn_add(hcon, status); if (conn) @@ -4466,27 +4460,22 @@ static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status) return 0; } -static int l2cap_disconn_ind(struct hci_conn *hcon) +int l2cap_disconn_ind(struct hci_conn *hcon) { struct l2cap_conn *conn = hcon->l2cap_data; BT_DBG("hcon %p", hcon); - if ((hcon->type != ACL_LINK && hcon->type != LE_LINK) || !conn) + if (!conn) return HCI_ERROR_REMOTE_USER_TERM; - return conn->disc_reason; } -static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason) +int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason) { BT_DBG("hcon %p reason %d", hcon, reason); - if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK)) - return -EINVAL; - l2cap_conn_del(hcon, bt_to_errno(reason)); - return 0; } @@ -4507,7 +4496,7 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt) } } -static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) +int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) { struct l2cap_conn *conn = hcon->l2cap_data; struct l2cap_chan *chan; @@ -4607,7 +4596,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) return 0; } -static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) +int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) { struct l2cap_conn *conn = hcon->l2cap_data; @@ -4754,17 +4743,6 @@ static const struct file_operations l2cap_debugfs_fops = { static struct dentry *l2cap_debugfs; -static struct hci_proto l2cap_hci_proto = { - .name = "L2CAP", - .id = HCI_PROTO_L2CAP, - .connect_ind = l2cap_connect_ind, - .connect_cfm = l2cap_connect_cfm, - .disconn_ind = l2cap_disconn_ind, - .disconn_cfm = l2cap_disconn_cfm, - .security_cfm = l2cap_security_cfm, - .recv_acldata = l2cap_recv_acldata -}; - int __init l2cap_init(void) { int err; @@ -4773,13 +4751,6 @@ int __init l2cap_init(void) if (err < 0) return err; - err = hci_register_proto(&l2cap_hci_proto); - if (err < 0) { - BT_ERR("L2CAP protocol registration failed"); - bt_sock_unregister(BTPROTO_L2CAP); - goto error; - } - if (bt_debugfs) { l2cap_debugfs = debugfs_create_file("l2cap", 0444, bt_debugfs, NULL, &l2cap_debugfs_fops); @@ -4788,19 +4759,11 @@ int __init l2cap_init(void) } return 0; - -error: - l2cap_cleanup_sockets(); - return err; } void l2cap_exit(void) { debugfs_remove(l2cap_debugfs); - - if (hci_unregister_proto(&l2cap_hci_proto) < 0) - BT_ERR("L2CAP protocol unregistration failed"); - l2cap_cleanup_sockets(); } diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 725e10d487f..0d59e61d782 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -893,15 +893,12 @@ done: } /* ----- SCO interface with lower layer (HCI) ----- */ -static int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type) +int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr) { register struct sock *sk; struct hlist_node *node; int lm = 0; - if (type != SCO_LINK && type != ESCO_LINK) - return -EINVAL; - BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr)); /* Find listening sockets */ @@ -921,13 +918,9 @@ static int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type) return lm; } -static int sco_connect_cfm(struct hci_conn *hcon, __u8 status) +int sco_connect_cfm(struct hci_conn *hcon, __u8 status) { BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status); - - if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK) - return -EINVAL; - if (!status) { struct sco_conn *conn; @@ -940,19 +933,15 @@ static int sco_connect_cfm(struct hci_conn *hcon, __u8 status) return 0; } -static int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason) +int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason) { BT_DBG("hcon %p reason %d", hcon, reason); - if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK) - return -EINVAL; - sco_conn_del(hcon, bt_to_errno(reason)); - return 0; } -static int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb) +int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb) { struct sco_conn *conn = hcon->sco_data; @@ -1028,15 +1017,6 @@ static const struct net_proto_family sco_sock_family_ops = { .create = sco_sock_create, }; -static struct hci_proto sco_hci_proto = { - .name = "SCO", - .id = HCI_PROTO_SCO, - .connect_ind = sco_connect_ind, - .connect_cfm = sco_connect_cfm, - .disconn_cfm = sco_disconn_cfm, - .recv_scodata = sco_recv_scodata -}; - int __init sco_init(void) { int err; @@ -1051,13 +1031,6 @@ int __init sco_init(void) goto error; } - err = hci_register_proto(&sco_hci_proto); - if (err < 0) { - BT_ERR("SCO protocol registration failed"); - bt_sock_unregister(BTPROTO_SCO); - goto error; - } - if (bt_debugfs) { sco_debugfs = debugfs_create_file("sco", 0444, bt_debugfs, NULL, &sco_debugfs_fops); @@ -1081,9 +1054,6 @@ void __exit sco_exit(void) if (bt_sock_unregister(BTPROTO_SCO) < 0) BT_ERR("SCO socket unregistration failed"); - if (hci_unregister_proto(&sco_hci_proto) < 0) - BT_ERR("SCO protocol unregistration failed"); - proto_unregister(&sco_proto); } -- cgit v1.2.3 From 371fd83563252f550ce59476a7366d0b5171d316 Mon Sep 17 00:00:00 2001 From: Ulisses Furquim Date: Wed, 21 Dec 2011 20:02:36 -0200 Subject: Bluetooth: Fix deadlocks with sock lock and L2CAP timers locks When cancelling a delayed work (timer) in L2CAP we can not sleep holding the sock mutex otherwise we might deadlock with an L2CAP timer handler. This is possible because RX/TX and L2CAP timers run in different workqueues. The scenario below illustrates the problem. Thus we are now avoiding to sleep on the timers locks. ====================================================== [ INFO: possible circular locking dependency detected ] 3.1.0-05270-ga978dc7-dirty #239 ------------------------------------------------------- kworker/1:1/873 is trying to acquire lock: (sk_lock-AF_BLUETOOTH-BTPROTO_L2CAP){+.+...}, at: [] l2cap_chan_timeout+0x3c/0xe0 [bluetooth] but task is already holding lock: ((&(&chan->chan_timer)->work)){+.+...}, at: [] process_one_work+0x126/0x450 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 ((&(&chan->chan_timer)->work)){+.+...}: [] check_prevs_add+0xf6/0x170 [] validate_chain+0x613/0x790 [] __lock_acquire+0x4be/0xac0 [] lock_acquire+0x8d/0xb0 [] wait_on_work+0x4f/0x160 [] __cancel_work_timer+0x73/0x80 [] cancel_delayed_work_sync+0xd/0x10 [] l2cap_chan_connect+0x22d/0x470 [bluetooth] [] l2cap_sock_connect+0xb1/0x140 [bluetooth] [] kernel_connect+0xb/0x10 [] rfcomm_session_create+0x12a/0x1c0 [rfcomm] [] __rfcomm_dlc_open+0x1c7/0x240 [rfcomm] [] rfcomm_dlc_open+0x42/0x70 [rfcomm] [] rfcomm_sock_connect+0x103/0x150 [rfcomm] [] sys_connect+0xae/0xc0 [] compat_sys_socketcall+0xb2/0x220 [] sysenter_dispatch+0x7/0x30 -> #0 (sk_lock-AF_BLUETOOTH-BTPROTO_L2CAP){+.+...}: [] check_prev_add+0x6cd/0x6e0 [] check_prevs_add+0xf6/0x170 [] validate_chain+0x613/0x790 [] __lock_acquire+0x4be/0xac0 [] lock_acquire+0x8d/0xb0 [] lock_sock_nested+0x8a/0xa0 [] l2cap_chan_timeout+0x3c/0xe0 [bluetooth] [] process_one_work+0x184/0x450 [] worker_thread+0x15e/0x340 [] kthread+0x96/0xa0 [] kernel_thread_helper+0x4/0x10 other info that might help us debug this: Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock((&(&chan->chan_timer)->work)); lock(sk_lock-AF_BLUETOOTH-BTPROTO_L2CAP); lock((&(&chan->chan_timer)->work)); lock(sk_lock-AF_BLUETOOTH-BTPROTO_L2CAP); *** DEADLOCK *** 2 locks held by kworker/1:1/873: #0: (events){.+.+.+}, at: [] process_one_work+0x126/0x450 #1: ((&(&chan->chan_timer)->work)){+.+...}, at: [] process_one_work+0x126/0x450 stack backtrace: Pid: 873, comm: kworker/1:1 Not tainted 3.1.0-05270-ga978dc7-dirty #239 Call Trace: [] print_circular_bug+0xd2/0xe3 [] check_prev_add+0x6cd/0x6e0 [] check_prevs_add+0xf6/0x170 [] validate_chain+0x613/0x790 [] __lock_acquire+0x4be/0xac0 [] ? lock_sock_nested+0x66/0xa0 [] ? lock_release_nested+0x100/0x110 [] ? lock_sock_nested+0x66/0xa0 [] lock_acquire+0x8d/0xb0 [] ? l2cap_chan_timeout+0x3c/0xe0 [bluetooth] [] lock_sock_nested+0x8a/0xa0 [] ? l2cap_chan_timeout+0x3c/0xe0 [bluetooth] [] ? process_one_work+0x126/0x450 [] l2cap_chan_timeout+0x3c/0xe0 [bluetooth] [] process_one_work+0x184/0x450 [] ? process_one_work+0x126/0x450 [] ? l2cap_security_cfm+0x4e0/0x4e0 [bluetooth] [] worker_thread+0x15e/0x340 [] ? manage_workers+0x110/0x110 [] kthread+0x96/0xa0 [] kernel_thread_helper+0x4/0x10 [] ? retint_restore_args+0xe/0xe [] ? __init_kthread_worker+0x70/0x70 [] ? gs_change+0xb/0xb Signed-off-by: Ulisses Furquim Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_core.c | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 173218345a1..944c18913ca 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -77,17 +77,6 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb); /* ---- L2CAP channels ---- */ -static inline void chan_hold(struct l2cap_chan *c) -{ - atomic_inc(&c->refcnt); -} - -static inline void chan_put(struct l2cap_chan *c) -{ - if (atomic_dec_and_test(&c->refcnt)) - kfree(c); -} - static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid) { struct l2cap_chan *c, *r = NULL; @@ -287,7 +276,7 @@ static void l2cap_chan_timeout(struct work_struct *work) release_sock(sk); chan->ops->close(chan->data); - chan_put(chan); + l2cap_chan_put(chan); } struct l2cap_chan *l2cap_chan_create(struct sock *sk) @@ -321,7 +310,7 @@ void l2cap_chan_destroy(struct l2cap_chan *chan) list_del(&chan->global_l); write_unlock_bh(&chan_list_lock); - chan_put(chan); + l2cap_chan_put(chan); } static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) @@ -363,7 +352,7 @@ static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) chan->local_acc_lat = L2CAP_DEFAULT_ACC_LAT; chan->local_flush_to = L2CAP_DEFAULT_FLUSH_TO; - chan_hold(chan); + l2cap_chan_hold(chan); list_add_rcu(&chan->list, &conn->chan_l); } @@ -385,7 +374,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) list_del_rcu(&chan->list); synchronize_rcu(); - chan_put(chan); + l2cap_chan_put(chan); chan->conn = NULL; hci_conn_put(conn->hcon); @@ -1029,10 +1018,10 @@ 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) - cancel_delayed_work_sync(&conn->info_timer); + __cancel_delayed_work(&conn->info_timer); if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) { - cancel_delayed_work_sync(&conn->security_timer); + __cancel_delayed_work(&conn->security_timer); smp_chan_destroy(conn); } @@ -2583,7 +2572,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) { - cancel_delayed_work_sync(&conn->info_timer); + __cancel_delayed_work(&conn->info_timer); conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; conn->info_ident = 0; @@ -3129,7 +3118,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; - cancel_delayed_work_sync(&conn->info_timer); + __cancel_delayed_work(&conn->info_timer); if (result != L2CAP_IR_SUCCESS) { conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; @@ -4508,7 +4497,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) if (hcon->type == LE_LINK) { smp_distribute_keys(conn, 0); - cancel_delayed_work_sync(&conn->security_timer); + __cancel_delayed_work(&conn->security_timer); } rcu_read_lock(); -- cgit v1.2.3 From 2b64d153a0cc9d2b60e47be013cde8490f16e0a5 Mon Sep 17 00:00:00 2001 From: Brian Gix Date: Wed, 21 Dec 2011 16:12:12 -0800 Subject: Bluetooth: Add MITM mechanism to LE-SMP To achive Man-In-The-Middle (MITM) level security with Low Energy, we have to enable User Passkey Comparison. This commit modifies the hard-coded JUST-WORKS pairing mechanism to support query via the MGMT interface of Passkey comparison and User Confirmation. Signed-off-by: Brian Gix Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/smp.c | 226 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 204 insertions(+), 22 deletions(-) (limited to 'net') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 0ee2905a617..9fea4bfd0eb 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -189,24 +190,45 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data) msecs_to_jiffies(SMP_TIMEOUT)); } +static __u8 authreq_to_seclevel(__u8 authreq) +{ + if (authreq & SMP_AUTH_MITM) + return BT_SECURITY_HIGH; + else + return BT_SECURITY_MEDIUM; +} + +static __u8 seclevel_to_authreq(__u8 sec_level) +{ + switch (sec_level) { + case BT_SECURITY_HIGH: + return SMP_AUTH_MITM | SMP_AUTH_BONDING; + case BT_SECURITY_MEDIUM: + return SMP_AUTH_BONDING; + default: + return SMP_AUTH_NONE; + } +} + static void build_pairing_cmd(struct l2cap_conn *conn, struct smp_cmd_pairing *req, struct smp_cmd_pairing *rsp, __u8 authreq) { - u8 dist_keys; + u8 dist_keys = 0; - dist_keys = 0; if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->flags)) { dist_keys = SMP_DIST_ENC_KEY; authreq |= SMP_AUTH_BONDING; + } else { + authreq &= ~SMP_AUTH_BONDING; } if (rsp == NULL) { req->io_capability = conn->hcon->io_capability; req->oob_flag = SMP_OOB_NOT_PRESENT; req->max_key_size = SMP_MAX_ENC_KEY_SIZE; - req->init_key_dist = dist_keys; + req->init_key_dist = 0; req->resp_key_dist = dist_keys; req->auth_req = authreq; return; @@ -215,7 +237,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, rsp->io_capability = conn->hcon->io_capability; rsp->oob_flag = SMP_OOB_NOT_PRESENT; rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE; - rsp->init_key_dist = req->init_key_dist & dist_keys; + rsp->init_key_dist = 0; rsp->resp_key_dist = req->resp_key_dist & dist_keys; rsp->auth_req = authreq; } @@ -245,6 +267,95 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send) smp_chan_destroy(conn); } +#define JUST_WORKS 0x00 +#define JUST_CFM 0x01 +#define REQ_PASSKEY 0x02 +#define CFM_PASSKEY 0x03 +#define REQ_OOB 0x04 +#define OVERLAP 0xFF + +static const u8 gen_method[5][5] = { + { JUST_WORKS, JUST_CFM, REQ_PASSKEY, JUST_WORKS, REQ_PASSKEY }, + { JUST_WORKS, JUST_CFM, REQ_PASSKEY, JUST_WORKS, REQ_PASSKEY }, + { CFM_PASSKEY, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, CFM_PASSKEY }, + { JUST_WORKS, JUST_CFM, JUST_WORKS, JUST_WORKS, JUST_CFM }, + { CFM_PASSKEY, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, OVERLAP }, +}; + +static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, + u8 local_io, u8 remote_io) +{ + struct hci_conn *hcon = conn->hcon; + struct smp_chan *smp = conn->smp_chan; + u8 method; + u32 passkey = 0; + int ret = 0; + + /* Initialize key for JUST WORKS */ + memset(smp->tk, 0, sizeof(smp->tk)); + clear_bit(SMP_FLAG_TK_VALID, &smp->smp_flags); + + BT_DBG("tk_request: auth:%d lcl:%d rem:%d", auth, local_io, remote_io); + + /* If neither side wants MITM, use JUST WORKS */ + /* If either side has unknown io_caps, use JUST WORKS */ + /* Otherwise, look up method from the table */ + if (!(auth & SMP_AUTH_MITM) || + local_io > SMP_IO_KEYBOARD_DISPLAY || + remote_io > SMP_IO_KEYBOARD_DISPLAY) + method = JUST_WORKS; + else + method = gen_method[local_io][remote_io]; + + /* If not bonding, don't ask user to confirm a Zero TK */ + if (!(auth & SMP_AUTH_BONDING) && method == JUST_CFM) + method = JUST_WORKS; + + /* If Just Works, Continue with Zero TK */ + if (method == JUST_WORKS) { + set_bit(SMP_FLAG_TK_VALID, &smp->smp_flags); + return 0; + } + + /* Not Just Works/Confirm results in MITM Authentication */ + if (method != JUST_CFM) + set_bit(SMP_FLAG_MITM_AUTH, &smp->smp_flags); + + /* If both devices have Keyoard-Display I/O, the master + * Confirms and the slave Enters the passkey. + */ + if (method == OVERLAP) { + if (hcon->link_mode & HCI_LM_MASTER) + method = CFM_PASSKEY; + else + method = REQ_PASSKEY; + } + + /* Generate random passkey. Not valid until confirmed. */ + if (method == CFM_PASSKEY) { + u8 key[16]; + + memset(key, 0, sizeof(key)); + get_random_bytes(&passkey, sizeof(passkey)); + passkey %= 1000000; + put_unaligned_le32(passkey, key); + swap128(key, smp->tk); + BT_DBG("PassKey: %d", passkey); + } + + hci_dev_lock(hcon->hdev); + + if (method == REQ_PASSKEY) + ret = mgmt_user_passkey_request(hcon->hdev, conn->dst); + else + ret = mgmt_user_confirm_request(hcon->hdev, conn->dst, + cpu_to_le32(passkey), 0); + + hci_dev_unlock(hcon->hdev); + + return ret; +} + static void confirm_work(struct work_struct *work) { struct smp_chan *smp = container_of(work, struct smp_chan, confirm); @@ -277,6 +388,8 @@ static void confirm_work(struct work_struct *work) goto error; } + clear_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags); + swap128(res, cp.confirm_val); smp_send_cmd(smp->conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp); @@ -382,6 +495,7 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) smp->conn = conn; conn->smp_chan = smp; + conn->hcon->smp_conn = conn; hci_conn_hold(conn->hcon); @@ -399,18 +513,64 @@ void smp_chan_destroy(struct l2cap_conn *conn) kfree(smp); conn->smp_chan = NULL; + conn->hcon->smp_conn = NULL; hci_conn_put(conn->hcon); } +int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey) +{ + struct l2cap_conn *conn = hcon->smp_conn; + struct smp_chan *smp; + u32 value; + u8 key[16]; + + BT_DBG(""); + + if (!conn) + return -ENOTCONN; + + smp = conn->smp_chan; + + switch (mgmt_op) { + case MGMT_OP_USER_PASSKEY_REPLY: + value = le32_to_cpu(passkey); + memset(key, 0, sizeof(key)); + BT_DBG("PassKey: %d", value); + put_unaligned_le32(value, key); + swap128(key, smp->tk); + /* Fall Through */ + case MGMT_OP_USER_CONFIRM_REPLY: + set_bit(SMP_FLAG_TK_VALID, &smp->smp_flags); + break; + case MGMT_OP_USER_PASSKEY_NEG_REPLY: + case MGMT_OP_USER_CONFIRM_NEG_REPLY: + smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED, 1); + return 0; + default: + smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED, 1); + return -EOPNOTSUPP; + } + + /* If it is our turn to send Pairing Confirm, do so now */ + if (test_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags)) + queue_work(hcon->hdev->workqueue, &smp->confirm); + + return 0; +} + static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_pairing rsp, *req = (void *) skb->data; struct smp_chan *smp; u8 key_size; + u8 auth = SMP_AUTH_NONE; int ret; BT_DBG("conn %p", conn); + if (conn->hcon->link_mode & HCI_LM_MASTER) + return SMP_CMD_NOTSUPP; + if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend)) smp = smp_chan_create(conn); @@ -420,19 +580,16 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) memcpy(&smp->preq[1], req, sizeof(*req)); skb_pull(skb, sizeof(*req)); - if (req->oob_flag) - return SMP_OOB_NOT_AVAIL; + /* We didn't start the pairing, so match remote */ + if (req->auth_req & SMP_AUTH_BONDING) + auth = req->auth_req; - /* We didn't start the pairing, so no requirements */ - build_pairing_cmd(conn, req, &rsp, SMP_AUTH_NONE); + build_pairing_cmd(conn, req, &rsp, auth); key_size = min(req->max_key_size, rsp.max_key_size); if (check_enc_key_size(conn, key_size)) return SMP_ENC_KEY_SIZE; - /* Just works */ - memset(smp->tk, 0, sizeof(smp->tk)); - ret = smp_rand(smp->prnd); if (ret) return SMP_UNSPECIFIED; @@ -442,6 +599,11 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp); + /* Request setup of TK */ + ret = tk_request(conn, 0, auth, rsp.io_capability, req->io_capability); + if (ret) + return SMP_UNSPECIFIED; + return 0; } @@ -450,11 +612,14 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) struct smp_cmd_pairing *req, *rsp = (void *) skb->data; struct smp_chan *smp = conn->smp_chan; struct hci_dev *hdev = conn->hcon->hdev; - u8 key_size; + u8 key_size, auth = SMP_AUTH_NONE; int ret; BT_DBG("conn %p", conn); + if (!(conn->hcon->link_mode & HCI_LM_MASTER)) + return SMP_CMD_NOTSUPP; + skb_pull(skb, sizeof(*rsp)); req = (void *) &smp->preq[1]; @@ -463,12 +628,6 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) if (check_enc_key_size(conn, key_size)) return SMP_ENC_KEY_SIZE; - if (rsp->oob_flag) - return SMP_OOB_NOT_AVAIL; - - /* Just works */ - memset(smp->tk, 0, sizeof(smp->tk)); - ret = smp_rand(smp->prnd); if (ret) return SMP_UNSPECIFIED; @@ -476,6 +635,22 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) smp->prsp[0] = SMP_CMD_PAIRING_RSP; memcpy(&smp->prsp[1], rsp, sizeof(*rsp)); + if ((req->auth_req & SMP_AUTH_BONDING) && + (rsp->auth_req & SMP_AUTH_BONDING)) + auth = SMP_AUTH_BONDING; + + auth |= (req->auth_req | rsp->auth_req) & SMP_AUTH_MITM; + + ret = tk_request(conn, 0, auth, rsp->io_capability, req->io_capability); + if (ret) + return SMP_UNSPECIFIED; + + set_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags); + + /* Can't compose response until we have been confirmed */ + if (!test_bit(SMP_FLAG_TK_VALID, &smp->smp_flags)) + return 0; + queue_work(hdev->workqueue, &smp->confirm); return 0; @@ -497,8 +672,10 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb) swap128(smp->prnd, random); smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(random), random); - } else { + } else if (test_bit(SMP_FLAG_TK_VALID, &smp->smp_flags)) { queue_work(hdev->workqueue, &smp->confirm); + } else { + set_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags); } return 0; @@ -551,7 +728,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("conn %p", conn); - hcon->pending_sec_level = BT_SECURITY_MEDIUM; + hcon->pending_sec_level = authreq_to_seclevel(rp->auth_req); if (smp_ltk_encrypt(conn)) return 0; @@ -578,6 +755,7 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) { struct hci_conn *hcon = conn->hcon; struct smp_chan *smp = conn->smp_chan; + __u8 authreq; BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level); @@ -598,18 +776,22 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) return 0; smp = smp_chan_create(conn); + if (!smp) + return 1; + + authreq = seclevel_to_authreq(sec_level); if (hcon->link_mode & HCI_LM_MASTER) { struct smp_cmd_pairing cp; - build_pairing_cmd(conn, &cp, NULL, SMP_AUTH_NONE); + build_pairing_cmd(conn, &cp, NULL, authreq); smp->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&smp->preq[1], &cp, sizeof(cp)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); } else { struct smp_cmd_security_req cp; - cp.auth_req = SMP_AUTH_NONE; + cp.auth_req = authreq; smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp); } -- cgit v1.2.3 From 5fe57d9e9edb9182d1fa941b94902444c3174ccd Mon Sep 17 00:00:00 2001 From: Brian Gix Date: Wed, 21 Dec 2011 16:12:13 -0800 Subject: Bluetooth: Add SMP to User Passkey and Confirm Low Energy pairing is performed through the SMP (Security Manager Protocol) mechanism rather than HCI. Signed-off-by: Brian Gix Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/mgmt.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index fbcbef6ecce..2540944d871 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -30,6 +30,7 @@ #include #include #include +#include #define MGMT_VERSION 0 #define MGMT_REVISION 1 @@ -1642,8 +1643,15 @@ static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr, } /* Continue with pairing via SMP */ + err = smp_user_confirm_reply(conn, mgmt_op, passkey); + + if (!err) + err = cmd_status(sk, index, mgmt_op, + MGMT_STATUS_SUCCESS); + else + err = cmd_status(sk, index, mgmt_op, + MGMT_STATUS_FAILED); - err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_SUCCESS); goto done; } -- cgit v1.2.3 From 5436538fb5f2a12e5328dcaa2e3a1742be25c2e0 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 20 Dec 2011 16:30:44 -0200 Subject: Bluetooth: Remove l2cap priority from inside RFCOMM. RFCOMM needs a proper priority mechanism inside itself and not try to use l2cap priority to fix its own problem. Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/rfcomm/core.c | 44 +++++++++++++++++--------------------------- 1 file changed, 17 insertions(+), 27 deletions(-) (limited to 'net') diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index be6288cf854..1524418f39e 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -65,8 +65,7 @@ static DEFINE_MUTEX(rfcomm_mutex); static LIST_HEAD(session_list); -static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len, - u32 priority); +static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len); static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci); static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci); static int rfcomm_queue_disc(struct rfcomm_dlc *d); @@ -748,32 +747,23 @@ void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *d } /* ---- RFCOMM frame sending ---- */ -static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len, - u32 priority) +static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len) { - struct socket *sock = s->sock; - struct sock *sk = sock->sk; struct kvec iv = { data, len }; struct msghdr msg; - BT_DBG("session %p len %d priority %u", s, len, priority); - - if (sk->sk_priority != priority) { - lock_sock(sk); - sk->sk_priority = priority; - release_sock(sk); - } + BT_DBG("session %p len %d", s, len); memset(&msg, 0, sizeof(msg)); - return kernel_sendmsg(sock, &msg, &iv, 1, len); + return kernel_sendmsg(s->sock, &msg, &iv, 1, len); } static int rfcomm_send_cmd(struct rfcomm_session *s, struct rfcomm_cmd *cmd) { BT_DBG("%p cmd %u", s, cmd->ctrl); - return rfcomm_send_frame(s, (void *) cmd, sizeof(*cmd), HCI_PRIO_MAX); + return rfcomm_send_frame(s, (void *) cmd, sizeof(*cmd)); } static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci) @@ -829,8 +819,6 @@ static int rfcomm_queue_disc(struct rfcomm_dlc *d) if (!skb) return -ENOMEM; - skb->priority = HCI_PRIO_MAX; - cmd = (void *) __skb_put(skb, sizeof(*cmd)); cmd->addr = d->addr; cmd->ctrl = __ctrl(RFCOMM_DISC, 1); @@ -878,7 +866,7 @@ static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type) *ptr = __fcs(buf); ptr++; - return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX); + return rfcomm_send_frame(s, buf, ptr - buf); } static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d) @@ -920,7 +908,7 @@ static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d *ptr = __fcs(buf); ptr++; - return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX); + return rfcomm_send_frame(s, buf, ptr - buf); } int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci, @@ -958,7 +946,7 @@ int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci, *ptr = __fcs(buf); ptr++; - return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX); + return rfcomm_send_frame(s, buf, ptr - buf); } static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status) @@ -985,7 +973,7 @@ static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status) *ptr = __fcs(buf); ptr++; - return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX); + return rfcomm_send_frame(s, buf, ptr - buf); } static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig) @@ -1012,7 +1000,7 @@ static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig *ptr = __fcs(buf); ptr++; - return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX); + return rfcomm_send_frame(s, buf, ptr - buf); } static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr) @@ -1034,7 +1022,7 @@ static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr) *ptr = __fcs(buf); ptr++; - return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX); + return rfcomm_send_frame(s, buf, ptr - buf); } static int rfcomm_send_fcon(struct rfcomm_session *s, int cr) @@ -1056,7 +1044,7 @@ static int rfcomm_send_fcon(struct rfcomm_session *s, int cr) *ptr = __fcs(buf); ptr++; - return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX); + return rfcomm_send_frame(s, buf, ptr - buf); } static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len) @@ -1107,7 +1095,7 @@ static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits) *ptr = __fcs(buf); ptr++; - return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX); + return rfcomm_send_frame(s, buf, ptr - buf); } static void rfcomm_make_uih(struct sk_buff *skb, u8 addr) @@ -1786,8 +1774,10 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d) return skb_queue_len(&d->tx_queue); while (d->tx_credits && (skb = skb_dequeue(&d->tx_queue))) { - err = rfcomm_send_frame(d->session, skb->data, skb->len, - skb->priority); + struct socket *sock = d->session->sock; + struct sock *sk = sock->sk; + + err = rfcomm_send_frame(d->session, skb->data, skb->len); if (err < 0) { skb_queue_head(&d->tx_queue, skb); break; -- cgit v1.2.3 From 2fb9b3d4e5d720d4033461519af0d3f789924015 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 22 Dec 2011 16:56:05 -0200 Subject: Bluetooth: add debug output to l2cap_ack_timeout() Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 944c18913ca..cd7bb3d7f2b 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1985,6 +1985,8 @@ static void l2cap_ack_timeout(struct work_struct *work) struct l2cap_chan *chan = container_of(work, struct l2cap_chan, ack_timer.work); + BT_DBG("chan %p", chan); + lock_sock(chan->sk); l2cap_send_ack(chan); release_sock(chan->sk); -- cgit v1.2.3 From f20d09d5f7093e5dc5f231c65835e2d04739bd5e Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 22 Dec 2011 16:30:27 -0200 Subject: Bluetooth: remove *_bh usage from hci_dev_list and hci_cb_list They don't need to disable interrupts anymore, we only run in process context now. Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_conn.c | 4 ++-- net/bluetooth/hci_core.c | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 401d8ea266a..3db432473ad 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -487,7 +487,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src) BT_DBG("%s -> %s", batostr(src), batostr(dst)); - read_lock_bh(&hci_dev_list_lock); + read_lock(&hci_dev_list_lock); list_for_each_entry(d, &hci_dev_list, list) { if (!test_bit(HCI_UP, &d->flags) || test_bit(HCI_RAW, &d->flags)) @@ -512,7 +512,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src) if (hdev) hdev = hci_dev_hold(hdev); - read_unlock_bh(&hci_dev_list_lock); + read_unlock(&hci_dev_list_lock); return hdev; } EXPORT_SYMBOL(hci_get_route); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 22c8331cd0d..4f0ff01dc68 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -844,7 +844,7 @@ int hci_get_dev_list(void __user *arg) dr = dl->dev_req; - read_lock_bh(&hci_dev_list_lock); + read_lock(&hci_dev_list_lock); list_for_each_entry(hdev, &hci_dev_list, list) { if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags)) cancel_delayed_work(&hdev->power_off); @@ -858,7 +858,7 @@ int hci_get_dev_list(void __user *arg) if (++n >= dev_num) break; } - read_unlock_bh(&hci_dev_list_lock); + read_unlock(&hci_dev_list_lock); dl->dev_num = n; size = sizeof(*dl) + n * sizeof(*dr); @@ -1458,7 +1458,7 @@ int hci_register_dev(struct hci_dev *hdev) */ id = (hdev->dev_type == HCI_BREDR) ? 0 : 1; - write_lock_bh(&hci_dev_list_lock); + write_lock(&hci_dev_list_lock); /* Find first available device id */ list_for_each(p, &hci_dev_list) { @@ -1528,7 +1528,7 @@ int hci_register_dev(struct hci_dev *hdev) atomic_set(&hdev->promisc, 0); - write_unlock_bh(&hci_dev_list_lock); + write_unlock(&hci_dev_list_lock); hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI | WQ_UNBOUND | WQ_MEM_RECLAIM, 1); @@ -1561,9 +1561,9 @@ int hci_register_dev(struct hci_dev *hdev) err_wqueue: destroy_workqueue(hdev->workqueue); err: - write_lock_bh(&hci_dev_list_lock); + write_lock(&hci_dev_list_lock); list_del(&hdev->list); - write_unlock_bh(&hci_dev_list_lock); + write_unlock(&hci_dev_list_lock); return error; } @@ -1576,9 +1576,9 @@ void hci_unregister_dev(struct hci_dev *hdev) BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus); - write_lock_bh(&hci_dev_list_lock); + write_lock(&hci_dev_list_lock); list_del(&hdev->list); - write_unlock_bh(&hci_dev_list_lock); + write_unlock(&hci_dev_list_lock); hci_dev_do_close(hdev); @@ -1830,9 +1830,9 @@ int hci_register_cb(struct hci_cb *cb) { BT_DBG("%p name %s", cb, cb->name); - write_lock_bh(&hci_cb_list_lock); + write_lock(&hci_cb_list_lock); list_add(&cb->list, &hci_cb_list); - write_unlock_bh(&hci_cb_list_lock); + write_unlock(&hci_cb_list_lock); return 0; } @@ -1842,9 +1842,9 @@ int hci_unregister_cb(struct hci_cb *cb) { BT_DBG("%p name %s", cb, cb->name); - write_lock_bh(&hci_cb_list_lock); + write_lock(&hci_cb_list_lock); list_del(&cb->list); - write_unlock_bh(&hci_cb_list_lock); + write_unlock(&hci_cb_list_lock); return 0; } -- cgit v1.2.3 From af3e6359a2b52970c63c3c9f73d52be281a162ad Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 22 Dec 2011 16:35:05 -0200 Subject: Bluetooth: Don't disable interrupt when locking the queue We run everything in process context now. Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 4f0ff01dc68..6d38d80195c 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1960,7 +1960,7 @@ static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue, skb_shinfo(skb)->frag_list = NULL; /* Queue all fragments atomically */ - spin_lock_bh(&queue->lock); + spin_lock(&queue->lock); __skb_queue_tail(queue, skb); @@ -1978,7 +1978,7 @@ static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue, __skb_queue_tail(queue, skb); } while (list); - spin_unlock_bh(&queue->lock); + spin_unlock(&queue->lock); } } -- cgit v1.2.3 From 3573b80c42e88c2a43c068c86bcd1a753cf6e1a0 Mon Sep 17 00:00:00 2001 From: Hemant Gupta Date: Fri, 23 Dec 2011 11:07:24 +0530 Subject: Bluetooth: Incorrect address while storing LTK. This patch fixes incorrect address storage while storing Long Term Key for LE Devices using SMP (Security Manager Protocol). The address stored should be of remote device and not of source device. Signed-off-by: Hemant Gupta Acked-by: Marcel Holtmann Signed-off-by: Gustavo F. Padovan --- net/bluetooth/smp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 9fea4bfd0eb..32c47de3034 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -820,7 +820,7 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) skb_pull(skb, sizeof(*rp)); - hci_add_ltk(conn->hcon->hdev, 1, conn->src, smp->smp_key_size, + hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->smp_key_size, rp->ediv, rp->rand, smp->tk); smp_distribute_keys(conn, 1); -- cgit v1.2.3 From 4ae1652ef1bf38e07caa5d1d86ffd3b31103b55a Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 27 Dec 2011 14:43:41 -0200 Subject: Bluetooth: Fix a compile warning in RFCOMM sock and sk were leftover from another change. Signed-off-by: Gustavo F. Padovan --- net/bluetooth/rfcomm/core.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'net') diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 1524418f39e..09a3cbcf794 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -1774,9 +1774,6 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d) return skb_queue_len(&d->tx_queue); while (d->tx_credits && (skb = skb_dequeue(&d->tx_queue))) { - struct socket *sock = d->session->sock; - struct sock *sk = sock->sk; - err = rfcomm_send_frame(d->session, skb->data, skb->len); if (err < 0) { skb_queue_head(&d->tx_queue, skb); -- cgit v1.2.3