summaryrefslogtreecommitdiff
path: root/net/bluetooth/hci_conn.c
diff options
context:
space:
mode:
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2011-11-02 17:52:01 +0400
committerGustavo F. Padovan <padovan@profusion.mobi>2011-11-07 23:24:56 +0400
commit73d80deb7bdf0171f22e76dc2429c1f99eff90e2 (patch)
tree17a65f2bf28e1e5a107503f361a7fb061e2ad2f4 /net/bluetooth/hci_conn.c
parent3c32fa93e5a54cd54e52541892857b0c7164a61e (diff)
downloadlinux-73d80deb7bdf0171f22e76dc2429c1f99eff90e2.tar.xz
Bluetooth: prioritizing data over HCI
This implement priority based scheduler using skbuffer priority set via SO_PRIORITY socket option. It introduces hci_chan_hash (list of HCI Channel/hci_chan) per connection, each item in this list refer to a L2CAP connection and it is used to queue the data for transmission. Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> Acked-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Diffstat (limited to 'net/bluetooth/hci_conn.c')
-rw-r--r--net/bluetooth/hci_conn.c53
1 files changed, 53 insertions, 0 deletions
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 6e98ff3da2a4..e545376379c5 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -374,6 +374,8 @@ 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);
+
setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn);
setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn);
setup_timer(&conn->auto_accept_timer, hci_conn_auto_accept,
@@ -432,6 +434,8 @@ int hci_conn_del(struct hci_conn *conn)
tasklet_disable(&hdev->tx_task);
+ hci_chan_hash_flush(conn);
+
hci_conn_hash_del(hdev, conn);
if (hdev->notify)
hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
@@ -950,3 +954,52 @@ int hci_get_auth_info(struct hci_dev *hdev, void __user *arg)
return copy_to_user(arg, &req, sizeof(req)) ? -EFAULT : 0;
}
+
+struct hci_chan *hci_chan_create(struct hci_conn *conn)
+{
+ struct hci_dev *hdev = conn->hdev;
+ struct hci_chan *chan;
+
+ BT_DBG("%s conn %p", hdev->name, conn);
+
+ chan = kzalloc(sizeof(struct hci_chan), GFP_ATOMIC);
+ if (!chan)
+ return NULL;
+
+ chan->conn = conn;
+ skb_queue_head_init(&chan->data_q);
+
+ tasklet_disable(&hdev->tx_task);
+ hci_chan_hash_add(conn, chan);
+ tasklet_enable(&hdev->tx_task);
+
+ return chan;
+}
+
+int hci_chan_del(struct hci_chan *chan)
+{
+ struct hci_conn *conn = chan->conn;
+ struct hci_dev *hdev = conn->hdev;
+
+ BT_DBG("%s conn %p chan %p", hdev->name, conn, chan);
+
+ tasklet_disable(&hdev->tx_task);
+ hci_chan_hash_del(conn, chan);
+ tasklet_enable(&hdev->tx_task);
+
+ skb_queue_purge(&chan->data_q);
+ kfree(chan);
+
+ return 0;
+}
+
+void hci_chan_hash_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)
+ hci_chan_del(chan);
+}