From: Luiz Augusto von Dentz <[email protected]>
This uses SO_PRIORITY to set the skbuffer priority field
Signed-off-by: Luiz Augusto von Dentz <[email protected]>
---
include/net/bluetooth/hci_core.h | 3 +++
include/net/bluetooth/l2cap.h | 3 ++-
net/bluetooth/l2cap_core.c | 27 ++++++++++++++++++++-------
net/bluetooth/l2cap_sock.c | 2 +-
4 files changed, 26 insertions(+), 9 deletions(-)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index e2ba4d6..0742828 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -32,6 +32,9 @@
#define HCI_PROTO_L2CAP 0
#define HCI_PROTO_SCO 1
+/* HCI priority */
+#define HCI_PRIO_MAX 7
+
/* HCI Core structures */
struct inquiry_data {
bdaddr_t bdaddr;
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 4f34ad2..f018e5d 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -511,7 +511,8 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk);
void l2cap_chan_close(struct l2cap_chan *chan, int reason);
void l2cap_chan_destroy(struct l2cap_chan *chan);
int l2cap_chan_connect(struct l2cap_chan *chan);
-int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len);
+int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
+ u32 priority);
void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
#endif /* __L2CAP_H */
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index b3bdb48..0b6e1ae 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -556,6 +556,7 @@ static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
flags = ACL_START;
bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
+ skb->priority = HCI_PRIO_MAX;
hci_send_acl(conn->hcon, skb, flags);
}
@@ -1245,7 +1246,8 @@ void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
struct hci_conn *hcon = chan->conn->hcon;
u16 flags;
- BT_DBG("chan %p, skb %p len %d", chan, skb, skb->len);
+ BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,
+ skb->priority);
if (!chan->flushable && lmp_no_flush_capable(hcon->hdev))
flags = ACL_START_NO_FLUSH;
@@ -1451,6 +1453,8 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in
if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
return -EFAULT;
+ (*frag)->priority = skb->priority;
+
sent += count;
len -= count;
@@ -1460,7 +1464,9 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in
return sent;
}
-struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
+static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
+ struct msghdr *msg, size_t len,
+ u32 priority)
{
struct sock *sk = chan->sk;
struct l2cap_conn *conn = chan->conn;
@@ -1468,7 +1474,7 @@ struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr
int err, count, hlen = L2CAP_HDR_SIZE + 2;
struct l2cap_hdr *lh;
- BT_DBG("sk %p len %d", sk, (int)len);
+ BT_DBG("sk %p len %d priority %u", sk, (int)len, priority);
count = min_t(unsigned int, (conn->mtu - hlen), len);
skb = bt_skb_send_alloc(sk, count + hlen,
@@ -1476,6 +1482,8 @@ struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr
if (!skb)
return ERR_PTR(err);
+ skb->priority = priority;
+
/* Create L2CAP header */
lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
lh->cid = cpu_to_le16(chan->dcid);
@@ -1490,7 +1498,9 @@ struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr
return skb;
}
-struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
+static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
+ struct msghdr *msg, size_t len,
+ u32 priority)
{
struct sock *sk = chan->sk;
struct l2cap_conn *conn = chan->conn;
@@ -1506,6 +1516,8 @@ struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *m
if (!skb)
return ERR_PTR(err);
+ skb->priority = priority;
+
/* Create L2CAP header */
lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
lh->cid = cpu_to_le16(chan->dcid);
@@ -1610,7 +1622,8 @@ int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t le
return size;
}
-int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
+int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
+ u32 priority)
{
struct sk_buff *skb;
u16 control;
@@ -1618,7 +1631,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
/* Connectionless channel */
if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
- skb = l2cap_create_connless_pdu(chan, msg, len);
+ skb = l2cap_create_connless_pdu(chan, msg, len, priority);
if (IS_ERR(skb))
return PTR_ERR(skb);
@@ -1633,7 +1646,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
return -EMSGSIZE;
/* Create a basic PDU */
- skb = l2cap_create_basic_pdu(chan, msg, len);
+ skb = l2cap_create_basic_pdu(chan, msg, len, priority);
if (IS_ERR(skb))
return PTR_ERR(skb);
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 61f1f62..7fb0404 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -706,7 +706,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
return -ENOTCONN;
}
- err = l2cap_chan_send(chan, msg, len);
+ err = l2cap_chan_send(chan, msg, len, sk->sk_priority);
release_sock(sk);
return err;
--
1.7.6.1
Hi Gustavo,
On Tue, Sep 20, 2011 at 12:36 AM, Gustavo Padovan
<[email protected]> wrote:
> Hi Luiz,
>
> * Luiz Augusto von Dentz <[email protected]> [2011-09-12 20:00:49 +0300]:
>
>> From: Luiz Augusto von Dentz <[email protected]>
>>
>> This uses SO_PRIORITY to set the skbuffer priority field
>>
>> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
>> ---
>> ?include/net/bluetooth/hci_core.h | ? ?3 +++
>> ?include/net/bluetooth/l2cap.h ? ?| ? ?3 ++-
>> ?net/bluetooth/l2cap_core.c ? ? ? | ? 27 ++++++++++++++++++++-------
>> ?net/bluetooth/l2cap_sock.c ? ? ? | ? ?2 +-
>> ?4 files changed, 26 insertions(+), 9 deletions(-)
>>
>> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
>> index e2ba4d6..0742828 100644
>> --- a/include/net/bluetooth/hci_core.h
>> +++ b/include/net/bluetooth/hci_core.h
>> @@ -32,6 +32,9 @@
>> ?#define HCI_PROTO_L2CAP ? ? ?0
>> ?#define HCI_PROTO_SCO ? ? ? ?1
>>
>> +/* HCI priority */
>> +#define HCI_PRIO_MAX 7
>> +
>> ?/* HCI Core structures */
>> ?struct inquiry_data {
>> ? ? ? bdaddr_t ? ? ? ?bdaddr;
>> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
>> index 4f34ad2..f018e5d 100644
>> --- a/include/net/bluetooth/l2cap.h
>> +++ b/include/net/bluetooth/l2cap.h
>> @@ -511,7 +511,8 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk);
>> ?void l2cap_chan_close(struct l2cap_chan *chan, int reason);
>> ?void l2cap_chan_destroy(struct l2cap_chan *chan);
>> ?int l2cap_chan_connect(struct l2cap_chan *chan);
>> -int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len);
>> +int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? u32 priority);
>> ?void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
>>
>> ?#endif /* __L2CAP_H */
>> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
>> index b3bdb48..0b6e1ae 100644
>> --- a/net/bluetooth/l2cap_core.c
>> +++ b/net/bluetooth/l2cap_core.c
>> @@ -556,6 +556,7 @@ static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
>> ? ? ? ? ? ? ? flags = ACL_START;
>>
>> ? ? ? bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
>> + ? ? skb->priority = HCI_PRIO_MAX;
>
> As Mat pointed out we can't prioritize commands over data, this could to
> misbehaviours and loss of data. However, if the command is not related to any
> cid, like the information request/reponse we can put HCI_PRIO_MAX on it.
Yep, I got it fixed already so we don't have a separated queue for
commands anymore, this alone should already guarantee packet ordering
of the channel, but Im afraid we need to keep HCI_PRIO_MAX for
commands since those may have a timer associated to them (either
locally or remotely) so if the priority is not set according the timer
may expire before the frame is even sent, actually I already faced
this a couple of times when trying to connect to multiple devices
simultaneously a high priority socket prevented other channels
commands to be sent causing a disconnection (connect timeout even
though we succeed to page and create an ACL link).
The key problem here is that priority may increase latency and that is
not something we want to happen for commands because it may cause IOP
problems, so the use of HCI_PRIO_MAX is to minimize the latency.
--
Luiz Augusto von Dentz
Hi Luiz,
* Luiz Augusto von Dentz <[email protected]> [2011-09-12 20:00:49 +0300]:
> From: Luiz Augusto von Dentz <[email protected]>
>
> This uses SO_PRIORITY to set the skbuffer priority field
>
> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
> ---
> include/net/bluetooth/hci_core.h | 3 +++
> include/net/bluetooth/l2cap.h | 3 ++-
> net/bluetooth/l2cap_core.c | 27 ++++++++++++++++++++-------
> net/bluetooth/l2cap_sock.c | 2 +-
> 4 files changed, 26 insertions(+), 9 deletions(-)
>
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index e2ba4d6..0742828 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -32,6 +32,9 @@
> #define HCI_PROTO_L2CAP 0
> #define HCI_PROTO_SCO 1
>
> +/* HCI priority */
> +#define HCI_PRIO_MAX 7
> +
> /* HCI Core structures */
> struct inquiry_data {
> bdaddr_t bdaddr;
> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> index 4f34ad2..f018e5d 100644
> --- a/include/net/bluetooth/l2cap.h
> +++ b/include/net/bluetooth/l2cap.h
> @@ -511,7 +511,8 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk);
> void l2cap_chan_close(struct l2cap_chan *chan, int reason);
> void l2cap_chan_destroy(struct l2cap_chan *chan);
> int l2cap_chan_connect(struct l2cap_chan *chan);
> -int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len);
> +int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
> + u32 priority);
> void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
>
> #endif /* __L2CAP_H */
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index b3bdb48..0b6e1ae 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -556,6 +556,7 @@ static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
> flags = ACL_START;
>
> bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
> + skb->priority = HCI_PRIO_MAX;
As Mat pointed out we can't prioritize commands over data, this could to
misbehaviours and loss of data. However, if the command is not related to any
cid, like the information request/reponse we can put HCI_PRIO_MAX on it.
Gustavo
Hi Luiz,
* Luiz Augusto von Dentz <[email protected]> [2011-09-12 20:00:50 +0300]:
> From: Luiz Augusto von Dentz <[email protected]>
>
> l2cap_create_iframe_pdu is only used in l2cap_core.c
>
> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
> ---
> net/bluetooth/l2cap_core.c | 4 +++-
> 1 files changed, 3 insertions(+), 1 deletions(-)
Applied, thanks.
Gustavo
Hi Mat,
On Fri, Sep 16, 2011 at 2:34 AM, Mat Martineau <[email protected]> wrote:
>
>
> On Mon, 12 Sep 2011, Luiz Augusto von Dentz wrote:
>
>> From: Luiz Augusto von Dentz <[email protected]>
>>
>> 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.
>>
>> Each connection continue to have a queue but it is only used for time
>> critical packets such the L2CAP commands and it is always processed
>> before the channels thus it can be considered the highest priority.
>
> For a given L2CAP channel, I think we want commands and data to use the same
> queue.
Yep, I forgot to remove the old hci_chan from l2cap_chan, but the idea
is to use only one queue per channel to maintain ordering.
> With AMP channel move signaling, it's important to maintain ordering between
> L2CAP commands and data. ?This ensures that data gets flushed out of the
> queues and is not being sent during the channel move process and AMP link
> establishment. ?You also want to make sure queued data is sent before a
> disconnect request.
Yep.
>
>>
>> -static inline void hci_sched_acl(struct hci_dev *hdev)
>> +static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8
>> type,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int *quote)
>> {
>> + ? ? ? struct hci_conn_hash *h = &hdev->conn_hash;
>> + ? ? ? struct hci_chan *chan = NULL;
>> + ? ? ? int num = 0, min = ~0, cur_prio = 0;
>> ? ? ? ?struct hci_conn *conn;
>> + ? ? ? int cnt, q, conn_num = 0;
>> +
>> + ? ? ? 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)
>> + ? ? ? ? ? ? ? ? ? ? ? continue;
>> +
>> + ? ? ? ? ? ? ? if (conn->state != BT_CONNECTED && conn->state !=
>> BT_CONFIG)
>> + ? ? ? ? ? ? ? ? ? ? ? continue;
>> +
>> + ? ? ? ? ? ? ? conn_num++;
>> +
>> + ? ? ? ? ? ? ? ch = &conn->chan_hash;
>> +
>> + ? ? ? ? ? ? ? list_for_each_entry(tmp, &ch->list, list) {
>> + ? ? ? ? ? ? ? ? ? ? ? struct sk_buff *skb;
>> +
>> + ? ? ? ? ? ? ? ? ? ? ? if (skb_queue_empty(&tmp->data_q))
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? continue;
>> +
>> + ? ? ? ? ? ? ? ? ? ? ? skb = skb_peek(&tmp->data_q);
>> + ? ? ? ? ? ? ? ? ? ? ? if (skb->priority < cur_prio)
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? continue;
>> +
>> + ? ? ? ? ? ? ? ? ? ? ? if (skb->priority > cur_prio) {
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? num = 0;
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? min = ~0;
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? cur_prio = skb->priority;
>> + ? ? ? ? ? ? ? ? ? ? ? }
>> +
>> + ? ? ? ? ? ? ? ? ? ? ? num++;
>> +
>> + ? ? ? ? ? ? ? ? ? ? ? if (conn->sent < min) {
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? min ?= conn->sent;
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? chan = tmp;
>> + ? ? ? ? ? ? ? ? ? ? ? }
>> + ? ? ? ? ? ? ? }
>> +
>> + ? ? ? ? ? ? ? if (hci_conn_num(hdev, type) == conn_num)
>> + ? ? ? ? ? ? ? ? ? ? ? break;
>> + ? ? ? }
>
>
> Only the priority of the first skb in each queue is considered. ?What if
> there's a higher priority skb deeper in a queue?
Can be done at cost of redoing the quote calculation every time
skb>priority < quote priority, but I considered that too expensive for
the little impact it cause as priority inversion, also note that it
will not handle the case you have presented that a higher priority is
deeper in the queue because it is not really a problem since we have
to maintain the ordering we cannot sent it before the low priority skb
so it has to wait until those are sent.
> Would it work to track priority in hci_chan instead of the skb? ?That would
> simplify patch 1 of this series.
Nope, because RFCOMM connections share the same L2CAP channel, so
currently Im afraid it has to be per skb.
>
>> +
>> + ? ? ? if (!chan)
>> + ? ? ? ? ? ? ? return NULL;
>> +
>> + ? ? ? switch (chan->conn->type) {
>> + ? ? ? case ACL_LINK:
>> + ? ? ? ? ? ? ? cnt = hdev->acl_cnt;
>> + ? ? ? ? ? ? ? break;
>> + ? ? ? case SCO_LINK:
>> + ? ? ? case ESCO_LINK:
>> + ? ? ? ? ? ? ? cnt = hdev->sco_cnt;
>> + ? ? ? ? ? ? ? break;
>> + ? ? ? case LE_LINK:
>> + ? ? ? ? ? ? ? cnt = hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt;
>> + ? ? ? ? ? ? ? break;
>> + ? ? ? default:
>> + ? ? ? ? ? ? ? cnt = 0;
>> + ? ? ? ? ? ? ? BT_ERR("Unknown link type");
>> + ? ? ? }
>> +
>> + ? ? ? q = cnt / num;
>> + ? ? ? *quote = q ? q : 1;
>> + ? ? ? BT_DBG("chan %p quote %d", chan, *quote);
>> + ? ? ? return chan;
>> +}
>> +
>> +static inline void hci_sched_acl(struct hci_dev *hdev)
>> +{
>> + ? ? ? struct hci_chan *chan;
>> ? ? ? ?struct sk_buff *skb;
>> ? ? ? ?int quote;
>> + ? ? ? unsigned int cnt;
>>
>> ? ? ? ?BT_DBG("%s", hdev->name);
>>
>> @@ -2122,17 +2226,23 @@ static inline void hci_sched_acl(struct hci_dev
>> *hdev)
>> ? ? ? ? ? ? ? ? ? ? ? ?hci_link_tx_to(hdev, ACL_LINK);
>> ? ? ? ?}
>>
>> - ? ? ? while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK,
>> "e))) {
>> - ? ? ? ? ? ? ? while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
>> - ? ? ? ? ? ? ? ? ? ? ? BT_DBG("skb %p len %d", skb, skb->len);
>> + ? ? ? cnt = hdev->acl_cnt;
>>
>> - ? ? ? ? ? ? ? ? ? ? ? hci_conn_enter_active_mode(conn,
>> bt_cb(skb)->force_active);
>> + ? ? ? while (hdev->acl_cnt &&
>> + ? ? ? ? ? ? ? ? ? ? ? (chan = hci_chan_sent(hdev, ACL_LINK, "e))) {
>> + ? ? ? ? ? ? ? while (quote-- && (skb = skb_dequeue(&chan->data_q))) {
>> + ? ? ? ? ? ? ? ? ? ? ? BT_DBG("chan %p skb %p len %d priority %u", chan,
>> skb,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? skb->len, skb->priority);
>> +
>> + ? ? ? ? ? ? ? ? ? ? ? hci_conn_enter_active_mode(chan->conn,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? bt_cb(skb)->force_active);
>
>
> Where are conn->data_q skbs dequeued now?
Ive removed as suggested by Gustavo to unify the algorithm used for
ACL, SCO/ESCO still use it, gonna update the commit message to reflect
it.
--
Luiz Augusto von Dentz
On Mon, 12 Sep 2011, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <[email protected]>
>
> 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.
>
> Each connection continue to have a queue but it is only used for time
> critical packets such the L2CAP commands and it is always processed
> before the channels thus it can be considered the highest priority.
For a given L2CAP channel, I think we want commands and data to use
the same queue.
With AMP channel move signaling, it's important to maintain ordering
between L2CAP commands and data. This ensures that data gets flushed
out of the queues and is not being sent during the channel move
process and AMP link establishment. You also want to make sure queued
data is sent before a disconnect request.
>
> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
> ---
> include/net/bluetooth/hci_core.h | 42 ++++++++++
> include/net/bluetooth/l2cap.h | 2 +
> net/bluetooth/hci_conn.c | 59 ++++++++++++++
> net/bluetooth/hci_core.c | 163 ++++++++++++++++++++++++++++++++------
> net/bluetooth/l2cap_core.c | 21 ++++-
> 5 files changed, 258 insertions(+), 29 deletions(-)
>
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index 0742828..e0d29eb 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -67,6 +67,12 @@ struct hci_conn_hash {
> unsigned int le_num;
> };
>
> +struct hci_chan_hash {
> + struct list_head list;
> + spinlock_t lock;
> + unsigned int num;
> +};
> +
> struct bdaddr_list {
> struct list_head list;
> bdaddr_t bdaddr;
> @@ -278,6 +284,7 @@ struct hci_conn {
> unsigned int sent;
>
> struct sk_buff_head data_q;
> + struct hci_chan_hash chan_hash;
>
> struct timer_list disc_timer;
> struct timer_list idle_timer;
> @@ -300,6 +307,14 @@ struct hci_conn {
> void (*disconn_cfm_cb) (struct hci_conn *conn, u8 reason);
> };
>
> +struct hci_chan {
> + struct list_head list;
> +
> + struct hci_conn *conn;
> + struct sk_buff_head data_q;
> + unsigned int sent;
> +};
> +
> extern struct hci_proto *hci_proto[];
> extern struct list_head hci_dev_list;
> extern struct list_head hci_cb_list;
> @@ -459,6 +474,28 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
> return NULL;
> }
>
> +static inline void hci_chan_hash_init(struct hci_conn *c)
> +{
> + struct hci_chan_hash *h = &c->chan_hash;
> + INIT_LIST_HEAD(&h->list);
> + spin_lock_init(&h->lock);
> + h->num = 0;
> +}
> +
> +static inline void hci_chan_hash_add(struct hci_conn *c, struct hci_chan *chan)
> +{
> + struct hci_chan_hash *h = &c->chan_hash;
> + list_add(&chan->list, &h->list);
> + h->num++;
> +}
> +
> +static inline void hci_chan_hash_del(struct hci_conn *c, struct hci_chan *chan)
> +{
> + struct hci_chan_hash *h = &c->chan_hash;
> + list_del(&chan->list);
> + h->num--;
> +}
> +
> void hci_acl_connect(struct hci_conn *conn);
> void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
> void hci_add_sco(struct hci_conn *conn, __u16 handle);
> @@ -470,6 +507,10 @@ int hci_conn_del(struct hci_conn *conn);
> void hci_conn_hash_flush(struct hci_dev *hdev);
> void hci_conn_check_pending(struct hci_dev *hdev);
>
> +struct hci_chan *hci_chan_create(struct hci_conn *conn);
> +int hci_chan_del(struct hci_chan *chan);
> +void hci_chan_hash_flush(struct hci_conn *conn);
> +
> struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
> __u8 sec_level, __u8 auth_type);
> int hci_conn_check_link_mode(struct hci_conn *conn);
> @@ -839,6 +880,7 @@ int hci_unregister_notifier(struct notifier_block *nb);
>
> int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param);
> void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
> +void hci_chan_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags);
> void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
>
> void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> index f018e5d..0899f96 100644
> --- a/include/net/bluetooth/l2cap.h
> +++ b/include/net/bluetooth/l2cap.h
> @@ -301,6 +301,7 @@ struct srej_list {
> struct l2cap_chan {
> struct sock *sk;
>
> + struct hci_chan *hchan;
> struct l2cap_conn *conn;
>
> __u8 state;
> @@ -388,6 +389,7 @@ struct l2cap_ops {
>
> struct l2cap_conn {
> struct hci_conn *hcon;
> + struct hci_chan *hchan;
>
> bdaddr_t *dst;
> bdaddr_t *src;
> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
> index 581cc42..1dc8c38 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,58 @@ 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 list_head *p;
> +
> + BT_DBG("conn %p", conn);
> + p = h->list.next;
> + while (p != &h->list) {
> + struct hci_chan *chan;
> +
> + chan = list_entry(p, struct hci_chan, list);
> + p = p->next;
> +
> + hci_chan_del(chan);
> + }
> +}
> diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
> index 94e916d..821b69b 100644
> --- a/net/bluetooth/hci_core.c
> +++ b/net/bluetooth/hci_core.c
> @@ -1958,23 +1958,18 @@ static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
> hdr->dlen = cpu_to_le16(len);
> }
>
> -void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
> +static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
> + struct sk_buff *skb, __u16 flags)
> {
> struct hci_dev *hdev = conn->hdev;
> struct sk_buff *list;
>
> - BT_DBG("%s conn %p flags 0x%x", hdev->name, conn, flags);
> -
> - skb->dev = (void *) hdev;
> - bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
> - hci_add_acl_hdr(skb, conn->handle, flags);
> -
> list = skb_shinfo(skb)->frag_list;
> if (!list) {
> /* Non fragmented */
> BT_DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len);
>
> - skb_queue_tail(&conn->data_q, skb);
> + skb_queue_tail(queue, skb);
> } else {
> /* Fragmented */
> BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
> @@ -1982,9 +1977,9 @@ void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
> skb_shinfo(skb)->frag_list = NULL;
>
> /* Queue all fragments atomically */
> - spin_lock_bh(&conn->data_q.lock);
> + spin_lock_bh(&queue->lock);
>
> - __skb_queue_tail(&conn->data_q, skb);
> + __skb_queue_tail(queue, skb);
>
> flags &= ~ACL_START;
> flags |= ACL_CONT;
> @@ -1997,16 +1992,46 @@ void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
>
> BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
>
> - __skb_queue_tail(&conn->data_q, skb);
> + __skb_queue_tail(queue, skb);
> } while (list);
>
> - spin_unlock_bh(&conn->data_q.lock);
> + spin_unlock_bh(&queue->lock);
> }
> +}
> +
> +void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
> +{
> + struct hci_dev *hdev = conn->hdev;
> +
> + BT_DBG("%s conn %p flags 0x%x", hdev->name, conn, flags);
> +
> + skb->dev = (void *) hdev;
> + bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
> + hci_add_acl_hdr(skb, conn->handle, flags);
> +
> + hci_queue_acl(conn, &conn->data_q, skb, flags);
>
> tasklet_schedule(&hdev->tx_task);
> }
> EXPORT_SYMBOL(hci_send_acl);
>
> +void hci_chan_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags)
> +{
> + struct hci_conn *conn = chan->conn;
> + struct hci_dev *hdev = conn->hdev;
> +
> + BT_DBG("%s chan %p flags 0x%x", hdev->name, chan, flags);
> +
> + skb->dev = (void *) hdev;
> + bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
> + hci_add_acl_hdr(skb, conn->handle, flags);
> +
> + hci_queue_acl(conn, &chan->data_q, skb, flags);
> +
> + tasklet_schedule(&hdev->tx_task);
> +}
> +EXPORT_SYMBOL(hci_chan_send_acl);
> +
> /* Send SCO data */
> void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
> {
> @@ -2104,11 +2129,90 @@ static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
> }
> }
>
> -static inline void hci_sched_acl(struct hci_dev *hdev)
> +static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
> + int *quote)
> {
> + struct hci_conn_hash *h = &hdev->conn_hash;
> + struct hci_chan *chan = NULL;
> + int num = 0, min = ~0, cur_prio = 0;
> struct hci_conn *conn;
> + int cnt, q, conn_num = 0;
> +
> + 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)
> + continue;
> +
> + if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG)
> + continue;
> +
> + conn_num++;
> +
> + ch = &conn->chan_hash;
> +
> + list_for_each_entry(tmp, &ch->list, list) {
> + struct sk_buff *skb;
> +
> + if (skb_queue_empty(&tmp->data_q))
> + continue;
> +
> + skb = skb_peek(&tmp->data_q);
> + if (skb->priority < cur_prio)
> + continue;
> +
> + if (skb->priority > cur_prio) {
> + num = 0;
> + min = ~0;
> + cur_prio = skb->priority;
> + }
> +
> + num++;
> +
> + if (conn->sent < min) {
> + min = conn->sent;
> + chan = tmp;
> + }
> + }
> +
> + if (hci_conn_num(hdev, type) == conn_num)
> + break;
> + }
Only the priority of the first skb in each queue is considered. What
if there's a higher priority skb deeper in a queue?
Would it work to track priority in hci_chan instead of the skb? That
would simplify patch 1 of this series.
> +
> + if (!chan)
> + return NULL;
> +
> + switch (chan->conn->type) {
> + case ACL_LINK:
> + cnt = hdev->acl_cnt;
> + break;
> + case SCO_LINK:
> + case ESCO_LINK:
> + cnt = hdev->sco_cnt;
> + break;
> + case LE_LINK:
> + cnt = hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt;
> + break;
> + default:
> + cnt = 0;
> + BT_ERR("Unknown link type");
> + }
> +
> + q = cnt / num;
> + *quote = q ? q : 1;
> + BT_DBG("chan %p quote %d", chan, *quote);
> + return chan;
> +}
> +
> +static inline void hci_sched_acl(struct hci_dev *hdev)
> +{
> + struct hci_chan *chan;
> struct sk_buff *skb;
> int quote;
> + unsigned int cnt;
>
> BT_DBG("%s", hdev->name);
>
> @@ -2122,17 +2226,23 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
> hci_link_tx_to(hdev, ACL_LINK);
> }
>
> - while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, "e))) {
> - while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
> - BT_DBG("skb %p len %d", skb, skb->len);
> + cnt = hdev->acl_cnt;
>
> - hci_conn_enter_active_mode(conn, bt_cb(skb)->force_active);
> + while (hdev->acl_cnt &&
> + (chan = hci_chan_sent(hdev, ACL_LINK, "e))) {
> + while (quote-- && (skb = skb_dequeue(&chan->data_q))) {
> + BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
> + skb->len, skb->priority);
> +
> + hci_conn_enter_active_mode(chan->conn,
> + bt_cb(skb)->force_active);
Where are conn->data_q skbs dequeued now?
>
> hci_send_frame(skb);
> hdev->acl_last_tx = jiffies;
>
> hdev->acl_cnt--;
> - conn->sent++;
> + chan->sent++;
> + chan->conn->sent++;
> }
> }
> }
> @@ -2151,7 +2261,7 @@ static inline void hci_sched_sco(struct hci_dev *hdev)
>
> while (hdev->sco_cnt && (conn = hci_low_sent(hdev, SCO_LINK, "e))) {
> while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
> - BT_DBG("skb %p len %d", skb, skb->len);
> + BT_DBG("conn %p skb %p len %d", conn, skb, skb->len);
> hci_send_frame(skb);
>
> conn->sent++;
> @@ -2174,7 +2284,7 @@ static inline void hci_sched_esco(struct hci_dev *hdev)
>
> while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK, "e))) {
> while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
> - BT_DBG("skb %p len %d", skb, skb->len);
> + BT_DBG("conn %p skb %p len %d", conn, skb, skb->len);
> hci_send_frame(skb);
>
> conn->sent++;
> @@ -2186,7 +2296,7 @@ static inline void hci_sched_esco(struct hci_dev *hdev)
>
> static inline void hci_sched_le(struct hci_dev *hdev)
> {
> - struct hci_conn *conn;
> + struct hci_chan *chan;
> struct sk_buff *skb;
> int quote, cnt;
>
> @@ -2204,17 +2314,20 @@ static inline void hci_sched_le(struct hci_dev *hdev)
> }
>
> cnt = hdev->le_pkts ? hdev->le_cnt : hdev->acl_cnt;
> - while (cnt && (conn = hci_low_sent(hdev, LE_LINK, "e))) {
> - while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
> - BT_DBG("skb %p len %d", skb, skb->len);
> + while (cnt && (chan = hci_chan_sent(hdev, LE_LINK, "e))) {
> + while (quote-- && (skb = skb_dequeue(&chan->data_q))) {
> + BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
> + skb->len, skb->priority);
>
> hci_send_frame(skb);
> hdev->le_last_tx = jiffies;
>
> cnt--;
> - conn->sent++;
> + chan->sent++;
> + chan->conn->sent++;
> }
> }
> +
> if (hdev->le_pkts)
> hdev->le_cnt = cnt;
> else
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index afd5455..28994b7 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -313,6 +313,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
> conn->disc_reason = 0x13;
>
> chan->conn = conn;
> + chan->hchan = hci_chan_create(conn->hcon);
>
> if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) {
> if (conn->hcon->type == LE_LINK) {
> @@ -357,6 +358,8 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
> if (conn) {
> /* Delete from channel list */
> write_lock_bh(&conn->chan_lock);
> + hci_chan_del(chan->hchan);
> + chan->hchan = NULL;
> list_del(&chan->list);
> write_unlock_bh(&conn->chan_lock);
> chan_put(chan);
> @@ -558,7 +561,7 @@ static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
> bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
> skb->priority = HCI_PRIO_MAX;
>
> - hci_send_acl(conn->hcon, skb, flags);
> + hci_chan_send_acl(conn->hchan, skb, flags);
> }
>
> static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
> @@ -984,6 +987,8 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
> chan->ops->close(chan->data);
> }
>
> + hci_chan_del(conn->hchan);
> +
> if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
> del_timer_sync(&conn->info_timer);
>
> @@ -1004,18 +1009,26 @@ static void security_timeout(unsigned long arg)
> static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
> {
> struct l2cap_conn *conn = hcon->l2cap_data;
> + struct hci_chan *hchan;
>
> if (conn || status)
> return conn;
>
> + hchan = hci_chan_create(hcon);
> + if (!hchan)
> + return NULL;
> +
> conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
> - if (!conn)
> + if (!conn) {
> + hci_chan_del(hchan);
> return NULL;
> + }
>
> hcon->l2cap_data = conn;
> conn->hcon = hcon;
> + conn->hchan = hchan;
>
> - BT_DBG("hcon %p conn %p", hcon, conn);
> + BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
>
> if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
> conn->mtu = hcon->hdev->le_mtu;
> @@ -1255,7 +1268,7 @@ void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
> flags = ACL_START;
>
> bt_cb(skb)->force_active = chan->force_active;
> - hci_send_acl(hcon, skb, flags);
> + hci_chan_send_acl(chan->hchan, skb, flags);
> }
>
> void l2cap_streaming_send(struct l2cap_chan *chan)
> --
> 1.7.6.1
Thanks for looking at improving the HCI scheduler. Will you be at the
Bluetooth summit in Prague? That might be a good chance to talk about
overall changes to the HCI layer.
--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
From: Luiz Augusto von Dentz <[email protected]>
To avoid starvation the priority is recalculated so that the starving
channels are promoted to HCI_PRIO_MAX - 1 (6).
HCI_PRIO_MAX (7) is considered special, because it requires CAP_NET_ADMIN
capability which can be used to provide more guaranties, so it is not used
when promoting.
Signed-off-by: Luiz Augusto von Dentz <[email protected]>
---
net/bluetooth/hci_core.c | 56 +++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 55 insertions(+), 1 deletions(-)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 821b69b..0fd4fc3 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2207,6 +2207,53 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
return chan;
}
+static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
+{
+ struct hci_conn_hash *h = &hdev->conn_hash;
+ struct hci_conn *conn;
+ int num = 0;
+
+ 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)
+ continue;
+
+ if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG)
+ continue;
+
+ num++;
+
+ ch = &conn->chan_hash;
+ list_for_each_entry(chan, &ch->list, list) {
+ struct sk_buff *skb;
+
+ if (chan->sent) {
+ chan->sent = 0;
+ continue;
+ }
+
+ if (skb_queue_empty(&chan->data_q))
+ continue;
+
+ skb = skb_peek(&chan->data_q);
+ if (skb->priority >= HCI_PRIO_MAX - 1)
+ continue;
+
+ skb->priority = HCI_PRIO_MAX - 1;
+
+ BT_DBG("chan %p skb %p promoted to %d", chan, skb,
+ skb->priority);
+ }
+
+ if (hci_conn_num(hdev, type) == num)
+ break;
+ }
+}
+
static inline void hci_sched_acl(struct hci_dev *hdev)
{
struct hci_chan *chan;
@@ -2245,6 +2292,9 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
chan->conn->sent++;
}
}
+
+ if (cnt != hdev->acl_cnt)
+ hci_prio_recalculate(hdev, ACL_LINK);
}
/* Schedule SCO */
@@ -2298,7 +2348,7 @@ static inline void hci_sched_le(struct hci_dev *hdev)
{
struct hci_chan *chan;
struct sk_buff *skb;
- int quote, cnt;
+ int quote, cnt, tmp;
BT_DBG("%s", hdev->name);
@@ -2314,6 +2364,7 @@ static inline void hci_sched_le(struct hci_dev *hdev)
}
cnt = hdev->le_pkts ? hdev->le_cnt : hdev->acl_cnt;
+ tmp = cnt;
while (cnt && (chan = hci_chan_sent(hdev, LE_LINK, "e))) {
while (quote-- && (skb = skb_dequeue(&chan->data_q))) {
BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
@@ -2332,6 +2383,9 @@ static inline void hci_sched_le(struct hci_dev *hdev)
hdev->le_cnt = cnt;
else
hdev->acl_cnt = cnt;
+
+ if (cnt != tmp)
+ hci_prio_recalculate(hdev, LE_LINK);
}
static void hci_tx_task(unsigned long arg)
--
1.7.6.1
From: Luiz Augusto von Dentz <[email protected]>
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.
Each connection continue to have a queue but it is only used for time
critical packets such the L2CAP commands and it is always processed
before the channels thus it can be considered the highest priority.
Signed-off-by: Luiz Augusto von Dentz <[email protected]>
---
include/net/bluetooth/hci_core.h | 42 ++++++++++
include/net/bluetooth/l2cap.h | 2 +
net/bluetooth/hci_conn.c | 59 ++++++++++++++
net/bluetooth/hci_core.c | 163 ++++++++++++++++++++++++++++++++------
net/bluetooth/l2cap_core.c | 21 ++++-
5 files changed, 258 insertions(+), 29 deletions(-)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 0742828..e0d29eb 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -67,6 +67,12 @@ struct hci_conn_hash {
unsigned int le_num;
};
+struct hci_chan_hash {
+ struct list_head list;
+ spinlock_t lock;
+ unsigned int num;
+};
+
struct bdaddr_list {
struct list_head list;
bdaddr_t bdaddr;
@@ -278,6 +284,7 @@ struct hci_conn {
unsigned int sent;
struct sk_buff_head data_q;
+ struct hci_chan_hash chan_hash;
struct timer_list disc_timer;
struct timer_list idle_timer;
@@ -300,6 +307,14 @@ struct hci_conn {
void (*disconn_cfm_cb) (struct hci_conn *conn, u8 reason);
};
+struct hci_chan {
+ struct list_head list;
+
+ struct hci_conn *conn;
+ struct sk_buff_head data_q;
+ unsigned int sent;
+};
+
extern struct hci_proto *hci_proto[];
extern struct list_head hci_dev_list;
extern struct list_head hci_cb_list;
@@ -459,6 +474,28 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
return NULL;
}
+static inline void hci_chan_hash_init(struct hci_conn *c)
+{
+ struct hci_chan_hash *h = &c->chan_hash;
+ INIT_LIST_HEAD(&h->list);
+ spin_lock_init(&h->lock);
+ h->num = 0;
+}
+
+static inline void hci_chan_hash_add(struct hci_conn *c, struct hci_chan *chan)
+{
+ struct hci_chan_hash *h = &c->chan_hash;
+ list_add(&chan->list, &h->list);
+ h->num++;
+}
+
+static inline void hci_chan_hash_del(struct hci_conn *c, struct hci_chan *chan)
+{
+ struct hci_chan_hash *h = &c->chan_hash;
+ list_del(&chan->list);
+ h->num--;
+}
+
void hci_acl_connect(struct hci_conn *conn);
void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
void hci_add_sco(struct hci_conn *conn, __u16 handle);
@@ -470,6 +507,10 @@ int hci_conn_del(struct hci_conn *conn);
void hci_conn_hash_flush(struct hci_dev *hdev);
void hci_conn_check_pending(struct hci_dev *hdev);
+struct hci_chan *hci_chan_create(struct hci_conn *conn);
+int hci_chan_del(struct hci_chan *chan);
+void hci_chan_hash_flush(struct hci_conn *conn);
+
struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
__u8 sec_level, __u8 auth_type);
int hci_conn_check_link_mode(struct hci_conn *conn);
@@ -839,6 +880,7 @@ int hci_unregister_notifier(struct notifier_block *nb);
int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param);
void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
+void hci_chan_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags);
void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index f018e5d..0899f96 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -301,6 +301,7 @@ struct srej_list {
struct l2cap_chan {
struct sock *sk;
+ struct hci_chan *hchan;
struct l2cap_conn *conn;
__u8 state;
@@ -388,6 +389,7 @@ struct l2cap_ops {
struct l2cap_conn {
struct hci_conn *hcon;
+ struct hci_chan *hchan;
bdaddr_t *dst;
bdaddr_t *src;
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 581cc42..1dc8c38 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,58 @@ 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 list_head *p;
+
+ BT_DBG("conn %p", conn);
+ p = h->list.next;
+ while (p != &h->list) {
+ struct hci_chan *chan;
+
+ chan = list_entry(p, struct hci_chan, list);
+ p = p->next;
+
+ hci_chan_del(chan);
+ }
+}
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 94e916d..821b69b 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1958,23 +1958,18 @@ static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
hdr->dlen = cpu_to_le16(len);
}
-void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
+static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
+ struct sk_buff *skb, __u16 flags)
{
struct hci_dev *hdev = conn->hdev;
struct sk_buff *list;
- BT_DBG("%s conn %p flags 0x%x", hdev->name, conn, flags);
-
- skb->dev = (void *) hdev;
- bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
- hci_add_acl_hdr(skb, conn->handle, flags);
-
list = skb_shinfo(skb)->frag_list;
if (!list) {
/* Non fragmented */
BT_DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len);
- skb_queue_tail(&conn->data_q, skb);
+ skb_queue_tail(queue, skb);
} else {
/* Fragmented */
BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
@@ -1982,9 +1977,9 @@ void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
skb_shinfo(skb)->frag_list = NULL;
/* Queue all fragments atomically */
- spin_lock_bh(&conn->data_q.lock);
+ spin_lock_bh(&queue->lock);
- __skb_queue_tail(&conn->data_q, skb);
+ __skb_queue_tail(queue, skb);
flags &= ~ACL_START;
flags |= ACL_CONT;
@@ -1997,16 +1992,46 @@ void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
- __skb_queue_tail(&conn->data_q, skb);
+ __skb_queue_tail(queue, skb);
} while (list);
- spin_unlock_bh(&conn->data_q.lock);
+ spin_unlock_bh(&queue->lock);
}
+}
+
+void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
+{
+ struct hci_dev *hdev = conn->hdev;
+
+ BT_DBG("%s conn %p flags 0x%x", hdev->name, conn, flags);
+
+ skb->dev = (void *) hdev;
+ bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
+ hci_add_acl_hdr(skb, conn->handle, flags);
+
+ hci_queue_acl(conn, &conn->data_q, skb, flags);
tasklet_schedule(&hdev->tx_task);
}
EXPORT_SYMBOL(hci_send_acl);
+void hci_chan_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags)
+{
+ struct hci_conn *conn = chan->conn;
+ struct hci_dev *hdev = conn->hdev;
+
+ BT_DBG("%s chan %p flags 0x%x", hdev->name, chan, flags);
+
+ skb->dev = (void *) hdev;
+ bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
+ hci_add_acl_hdr(skb, conn->handle, flags);
+
+ hci_queue_acl(conn, &chan->data_q, skb, flags);
+
+ tasklet_schedule(&hdev->tx_task);
+}
+EXPORT_SYMBOL(hci_chan_send_acl);
+
/* Send SCO data */
void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
{
@@ -2104,11 +2129,90 @@ static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
}
}
-static inline void hci_sched_acl(struct hci_dev *hdev)
+static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
+ int *quote)
{
+ struct hci_conn_hash *h = &hdev->conn_hash;
+ struct hci_chan *chan = NULL;
+ int num = 0, min = ~0, cur_prio = 0;
struct hci_conn *conn;
+ int cnt, q, conn_num = 0;
+
+ 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)
+ continue;
+
+ if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG)
+ continue;
+
+ conn_num++;
+
+ ch = &conn->chan_hash;
+
+ list_for_each_entry(tmp, &ch->list, list) {
+ struct sk_buff *skb;
+
+ if (skb_queue_empty(&tmp->data_q))
+ continue;
+
+ skb = skb_peek(&tmp->data_q);
+ if (skb->priority < cur_prio)
+ continue;
+
+ if (skb->priority > cur_prio) {
+ num = 0;
+ min = ~0;
+ cur_prio = skb->priority;
+ }
+
+ num++;
+
+ if (conn->sent < min) {
+ min = conn->sent;
+ chan = tmp;
+ }
+ }
+
+ if (hci_conn_num(hdev, type) == conn_num)
+ break;
+ }
+
+ if (!chan)
+ return NULL;
+
+ switch (chan->conn->type) {
+ case ACL_LINK:
+ cnt = hdev->acl_cnt;
+ break;
+ case SCO_LINK:
+ case ESCO_LINK:
+ cnt = hdev->sco_cnt;
+ break;
+ case LE_LINK:
+ cnt = hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt;
+ break;
+ default:
+ cnt = 0;
+ BT_ERR("Unknown link type");
+ }
+
+ q = cnt / num;
+ *quote = q ? q : 1;
+ BT_DBG("chan %p quote %d", chan, *quote);
+ return chan;
+}
+
+static inline void hci_sched_acl(struct hci_dev *hdev)
+{
+ struct hci_chan *chan;
struct sk_buff *skb;
int quote;
+ unsigned int cnt;
BT_DBG("%s", hdev->name);
@@ -2122,17 +2226,23 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
hci_link_tx_to(hdev, ACL_LINK);
}
- while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, "e))) {
- while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
- BT_DBG("skb %p len %d", skb, skb->len);
+ cnt = hdev->acl_cnt;
- hci_conn_enter_active_mode(conn, bt_cb(skb)->force_active);
+ while (hdev->acl_cnt &&
+ (chan = hci_chan_sent(hdev, ACL_LINK, "e))) {
+ while (quote-- && (skb = skb_dequeue(&chan->data_q))) {
+ BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
+ skb->len, skb->priority);
+
+ hci_conn_enter_active_mode(chan->conn,
+ bt_cb(skb)->force_active);
hci_send_frame(skb);
hdev->acl_last_tx = jiffies;
hdev->acl_cnt--;
- conn->sent++;
+ chan->sent++;
+ chan->conn->sent++;
}
}
}
@@ -2151,7 +2261,7 @@ static inline void hci_sched_sco(struct hci_dev *hdev)
while (hdev->sco_cnt && (conn = hci_low_sent(hdev, SCO_LINK, "e))) {
while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
- BT_DBG("skb %p len %d", skb, skb->len);
+ BT_DBG("conn %p skb %p len %d", conn, skb, skb->len);
hci_send_frame(skb);
conn->sent++;
@@ -2174,7 +2284,7 @@ static inline void hci_sched_esco(struct hci_dev *hdev)
while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK, "e))) {
while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
- BT_DBG("skb %p len %d", skb, skb->len);
+ BT_DBG("conn %p skb %p len %d", conn, skb, skb->len);
hci_send_frame(skb);
conn->sent++;
@@ -2186,7 +2296,7 @@ static inline void hci_sched_esco(struct hci_dev *hdev)
static inline void hci_sched_le(struct hci_dev *hdev)
{
- struct hci_conn *conn;
+ struct hci_chan *chan;
struct sk_buff *skb;
int quote, cnt;
@@ -2204,17 +2314,20 @@ static inline void hci_sched_le(struct hci_dev *hdev)
}
cnt = hdev->le_pkts ? hdev->le_cnt : hdev->acl_cnt;
- while (cnt && (conn = hci_low_sent(hdev, LE_LINK, "e))) {
- while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
- BT_DBG("skb %p len %d", skb, skb->len);
+ while (cnt && (chan = hci_chan_sent(hdev, LE_LINK, "e))) {
+ while (quote-- && (skb = skb_dequeue(&chan->data_q))) {
+ BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
+ skb->len, skb->priority);
hci_send_frame(skb);
hdev->le_last_tx = jiffies;
cnt--;
- conn->sent++;
+ chan->sent++;
+ chan->conn->sent++;
}
}
+
if (hdev->le_pkts)
hdev->le_cnt = cnt;
else
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index afd5455..28994b7 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -313,6 +313,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
conn->disc_reason = 0x13;
chan->conn = conn;
+ chan->hchan = hci_chan_create(conn->hcon);
if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) {
if (conn->hcon->type == LE_LINK) {
@@ -357,6 +358,8 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
if (conn) {
/* Delete from channel list */
write_lock_bh(&conn->chan_lock);
+ hci_chan_del(chan->hchan);
+ chan->hchan = NULL;
list_del(&chan->list);
write_unlock_bh(&conn->chan_lock);
chan_put(chan);
@@ -558,7 +561,7 @@ static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
skb->priority = HCI_PRIO_MAX;
- hci_send_acl(conn->hcon, skb, flags);
+ hci_chan_send_acl(conn->hchan, skb, flags);
}
static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
@@ -984,6 +987,8 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
chan->ops->close(chan->data);
}
+ hci_chan_del(conn->hchan);
+
if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
del_timer_sync(&conn->info_timer);
@@ -1004,18 +1009,26 @@ static void security_timeout(unsigned long arg)
static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
{
struct l2cap_conn *conn = hcon->l2cap_data;
+ struct hci_chan *hchan;
if (conn || status)
return conn;
+ hchan = hci_chan_create(hcon);
+ if (!hchan)
+ return NULL;
+
conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
- if (!conn)
+ if (!conn) {
+ hci_chan_del(hchan);
return NULL;
+ }
hcon->l2cap_data = conn;
conn->hcon = hcon;
+ conn->hchan = hchan;
- BT_DBG("hcon %p conn %p", hcon, conn);
+ BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
conn->mtu = hcon->hdev->le_mtu;
@@ -1255,7 +1268,7 @@ void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
flags = ACL_START;
bt_cb(skb)->force_active = chan->force_active;
- hci_send_acl(hcon, skb, flags);
+ hci_chan_send_acl(chan->hchan, skb, flags);
}
void l2cap_streaming_send(struct l2cap_chan *chan)
--
1.7.6.1
From: Luiz Augusto von Dentz <[email protected]>
Signed-off-by: Luiz Augusto von Dentz <[email protected]>
---
net/bluetooth/rfcomm/core.c | 51 +++++++++++++++++++++++++++++-------------
net/bluetooth/rfcomm/sock.c | 2 +
2 files changed, 37 insertions(+), 16 deletions(-)
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 85580f2..bfc6bce 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -65,7 +65,8 @@ static DEFINE_MUTEX(rfcomm_mutex);
static LIST_HEAD(session_list);
-static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len);
+static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len,
+ u32 priority);
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);
@@ -747,19 +748,34 @@ 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)
+static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len,
+ u32 priority)
{
struct socket *sock = s->sock;
+ struct sock *sk = sock->sk;
struct kvec iv = { data, len };
struct msghdr msg;
- BT_DBG("session %p len %d", s, len);
+ 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);
+ }
memset(&msg, 0, sizeof(msg));
return kernel_sendmsg(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);
+}
+
static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci)
{
struct rfcomm_cmd cmd;
@@ -771,7 +787,7 @@ static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci)
cmd.len = __len8(0);
cmd.fcs = __fcs2((u8 *) &cmd);
- return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
+ return rfcomm_send_cmd(s, &cmd);
}
static int rfcomm_send_ua(struct rfcomm_session *s, u8 dlci)
@@ -785,7 +801,7 @@ static int rfcomm_send_ua(struct rfcomm_session *s, u8 dlci)
cmd.len = __len8(0);
cmd.fcs = __fcs2((u8 *) &cmd);
- return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
+ return rfcomm_send_cmd(s, &cmd);
}
static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci)
@@ -799,7 +815,7 @@ static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci)
cmd.len = __len8(0);
cmd.fcs = __fcs2((u8 *) &cmd);
- return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
+ return rfcomm_send_cmd(s, &cmd);
}
static int rfcomm_queue_disc(struct rfcomm_dlc *d)
@@ -813,6 +829,8 @@ 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);
@@ -835,7 +853,7 @@ static int rfcomm_send_dm(struct rfcomm_session *s, u8 dlci)
cmd.len = __len8(0);
cmd.fcs = __fcs2((u8 *) &cmd);
- return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
+ return rfcomm_send_cmd(s, &cmd);
}
static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type)
@@ -860,7 +878,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);
+ return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
}
static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d)
@@ -902,7 +920,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);
+ return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
}
int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
@@ -940,7 +958,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);
+ return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
}
static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status)
@@ -967,7 +985,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);
+ return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
}
static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig)
@@ -994,7 +1012,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);
+ return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
}
static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr)
@@ -1016,7 +1034,7 @@ static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr)
*ptr = __fcs(buf); ptr++;
- return rfcomm_send_frame(s, buf, ptr - buf);
+ return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
}
static int rfcomm_send_fcon(struct rfcomm_session *s, int cr)
@@ -1038,7 +1056,7 @@ static int rfcomm_send_fcon(struct rfcomm_session *s, int cr)
*ptr = __fcs(buf); ptr++;
- return rfcomm_send_frame(s, buf, ptr - buf);
+ return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
}
static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len)
@@ -1089,7 +1107,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);
+ return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
}
static void rfcomm_make_uih(struct sk_buff *skb, u8 addr)
@@ -1767,7 +1785,8 @@ 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);
+ err = rfcomm_send_frame(d->session, skb->data, skb->len,
+ skb->priority);
if (err < 0) {
skb_queue_head(&d->tx_queue, skb);
break;
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 482722b..40988e2 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -597,6 +597,8 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
break;
}
+ skb->priority = sk->sk_priority;
+
err = rfcomm_dlc_send(d, skb);
if (err < 0) {
kfree_skb(skb);
--
1.7.6.1
From: Luiz Augusto von Dentz <[email protected]>
l2cap_create_iframe_pdu is only used in l2cap_core.c
Signed-off-by: Luiz Augusto von Dentz <[email protected]>
---
net/bluetooth/l2cap_core.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 0b6e1ae..afd5455 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1531,7 +1531,9 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
return skb;
}
-struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u16 control, u16 sdulen)
+static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
+ struct msghdr *msg, size_t len,
+ u16 control, u16 sdulen)
{
struct sock *sk = chan->sk;
struct l2cap_conn *conn = chan->conn;
--
1.7.6.1