From: johan.hedberg@gmail.com
To: linux-bluetooth@vger.kernel.org
Subject: [PATCH v2 23/32] Bluetooth: Add LE L2CAP segmentation support for outgoing data
Date: Thu, 5 Dec 2013 15:11:21 +0200 [thread overview]
Message-ID: <1386249090-10236-24-git-send-email-johan.hedberg@gmail.com> (raw)
In-Reply-To: <1386249090-10236-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@intel.com>
This patch adds segmentation support for outgoing data packets. Packets
are segmented based on the MTU and MPS values. The l2cap_chan struct
already contains many helpful variables from BR/EDR Enhanced L2CAP which
can be used for this.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
net/bluetooth/l2cap_core.c | 127 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 126 insertions(+), 1 deletion(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index ef9d22a3689a..9869faa2904d 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -607,6 +607,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
break;
case L2CAP_MODE_LE_FLOWCTL:
+ skb_queue_purge(&chan->tx_q);
break;
case L2CAP_MODE_ERTM:
@@ -1194,12 +1195,24 @@ static void l2cap_move_done(struct l2cap_chan *chan)
}
}
+static void l2cap_le_flowctl_start(struct l2cap_chan *chan)
+{
+ chan->sdu = NULL;
+ chan->sdu_last_frag = NULL;
+ chan->sdu_len = 0;
+
+ skb_queue_head_init(&chan->tx_q);
+}
+
static void l2cap_chan_ready(struct l2cap_chan *chan)
{
/* This clears all conf flags, including CONF_NOT_COMPLETE */
chan->conf_state = 0;
__clear_chan_timer(chan);
+ if (chan->mode == L2CAP_MODE_LE_FLOWCTL)
+ l2cap_le_flowctl_start(chan);
+
chan->state = BT_CONNECTED;
chan->ops->ready(chan);
@@ -2521,6 +2534,89 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan,
return 0;
}
+static struct sk_buff *l2cap_create_le_flowctl_pdu(struct l2cap_chan *chan,
+ struct msghdr *msg,
+ size_t len, u16 sdulen)
+{
+ struct l2cap_conn *conn = chan->conn;
+ struct sk_buff *skb;
+ int err, count, hlen;
+ struct l2cap_hdr *lh;
+
+ BT_DBG("chan %p len %zu", chan, len);
+
+ if (!conn)
+ return ERR_PTR(-ENOTCONN);
+
+ hlen = L2CAP_HDR_SIZE;
+
+ if (sdulen)
+ hlen += L2CAP_SDULEN_SIZE;
+
+ count = min_t(unsigned int, (conn->mtu - hlen), len);
+
+ skb = chan->ops->alloc_skb(chan, count + hlen,
+ msg->msg_flags & MSG_DONTWAIT);
+ if (IS_ERR(skb))
+ return skb;
+
+ /* Create L2CAP header */
+ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
+ lh->cid = cpu_to_le16(chan->dcid);
+ lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
+
+ if (sdulen)
+ put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
+
+ err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
+ if (unlikely(err < 0)) {
+ kfree_skb(skb);
+ return ERR_PTR(err);
+ }
+
+ return skb;
+}
+
+static int l2cap_segment_le_sdu(struct l2cap_chan *chan,
+ struct sk_buff_head *seg_queue,
+ struct msghdr *msg, size_t len)
+{
+ struct sk_buff *skb;
+ size_t pdu_len;
+ u16 sdu_len;
+
+ BT_DBG("chan %p, msg %p, len %zu", chan, msg, len);
+
+ pdu_len = chan->conn->mtu - L2CAP_HDR_SIZE;
+
+ pdu_len = min_t(size_t, pdu_len, chan->remote_mps);
+
+ sdu_len = len;
+ pdu_len -= L2CAP_SDULEN_SIZE;
+
+ while (len > 0) {
+ if (len <= pdu_len)
+ pdu_len = len;
+
+ skb = l2cap_create_le_flowctl_pdu(chan, msg, pdu_len, sdu_len);
+ if (IS_ERR(skb)) {
+ __skb_queue_purge(seg_queue);
+ return PTR_ERR(skb);
+ }
+
+ __skb_queue_tail(seg_queue, skb);
+
+ len -= pdu_len;
+
+ if (sdu_len) {
+ sdu_len = 0;
+ pdu_len += L2CAP_SDULEN_SIZE;
+ }
+ }
+
+ return 0;
+}
+
int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
u32 priority)
{
@@ -2543,10 +2639,39 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
switch (chan->mode) {
case L2CAP_MODE_LE_FLOWCTL:
+ /* Check outgoing MTU */
+ if (len > chan->omtu)
+ return -EMSGSIZE;
+
if (!chan->tx_credits)
return -EAGAIN;
- /* fall through */
+ __skb_queue_head_init(&seg_queue);
+
+ err = l2cap_segment_le_sdu(chan, &seg_queue, msg, len);
+
+ if (chan->state != BT_CONNECTED) {
+ __skb_queue_purge(&seg_queue);
+ err = -ENOTCONN;
+ }
+
+ if (err)
+ return err;
+
+ skb_queue_splice_tail_init(&seg_queue, &chan->tx_q);
+
+ while (chan->tx_credits && !skb_queue_empty(&chan->tx_q)) {
+ l2cap_do_send(chan, skb_dequeue(&chan->tx_q));
+ chan->tx_credits--;
+ }
+
+ if (!chan->tx_credits)
+ chan->ops->suspend(chan);
+
+ err = len;
+
+ break;
+
case L2CAP_MODE_BASIC:
/* Check outgoing MTU */
if (len > chan->omtu)
--
1.8.4.2
next prev parent reply other threads:[~2013-12-05 13:11 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-12-05 13:10 [PATCH v2 00/32] Bluetooth: LE CoC support johan.hedberg
2013-12-05 13:10 ` [PATCH v2 01/32] Bluetooth: Remove unnecessary braces from one-line if-statement johan.hedberg
2013-12-05 13:11 ` [PATCH v2 02/32] Bluetooth: Add module parameter to enable LE CoC support johan.hedberg
2013-12-05 13:11 ` [PATCH v2 03/32] Bluetooth: Update l2cap_global_chan_by_psm() to take a link type johan.hedberg
2013-12-05 13:11 ` [PATCH v2 04/32] Bluetooth: Allow l2cap_chan_check_security() to be used for LE links johan.hedberg
2013-12-05 13:11 ` [PATCH v2 05/32] Bluetooth: Pass command length to LE signaling channel handlers johan.hedberg
2013-12-05 13:11 ` [PATCH v2 06/32] Bluetooth: Move LE L2CAP initiator procedure to its own function johan.hedberg
2013-12-05 13:11 ` [PATCH v2 07/32] Bluetooth: Add definitions for LE connection oriented channels johan.hedberg
2013-12-05 13:11 ` [PATCH v2 08/32] Bluetooth: Add initial code for LE L2CAP Connect Request johan.hedberg
2013-12-05 13:11 ` [PATCH v2 09/32] Bluetooth: Add smp_sufficient_security helper function johan.hedberg
2013-12-05 13:11 ` [PATCH v2 10/32] Bluetooth: Refactor L2CAP connect rejection to its own function johan.hedberg
2013-12-05 13:11 ` [PATCH v2 11/32] Bluetooth: Add basic LE L2CAP connect request receiving support johan.hedberg
2013-12-05 13:11 ` [PATCH v2 12/32] Bluetooth: Fix L2CAP channel closing for LE connections johan.hedberg
2013-12-05 13:11 ` [PATCH v2 13/32] Bluetooth: Add L2CAP Disconnect suppport for LE johan.hedberg
2013-12-05 13:11 ` [PATCH v2 14/32] Bluetooth: Make l2cap_le_sig_cmd logic consistent johan.hedberg
2013-12-05 13:11 ` [PATCH v2 15/32] Bluetooth: Add LE L2CAP flow control mode johan.hedberg
2013-12-05 13:11 ` [PATCH v2 16/32] Bluetooth: Track LE L2CAP credits in l2cap_chan johan.hedberg
2013-12-05 13:11 ` [PATCH v2 17/32] Bluetooth: Limit L2CAP_OPTIONS socket option usage with LE johan.hedberg
2013-12-05 13:11 ` [PATCH v2 18/32] Bluetooth: Add new BT_SNDMTU and BT_RCVMTU socket options johan.hedberg
2013-12-05 13:11 ` [PATCH v2 19/32] Bluetooth: Implement returning of LE L2CAP credits johan.hedberg
2013-12-05 13:11 ` [PATCH v2 20/32] Bluetooth: Add LE flow control discipline johan.hedberg
2013-12-05 13:11 ` [PATCH v2 21/32] Bluetooth: Reject LE CoC commands when the feature is not enabled johan.hedberg
2013-12-05 13:11 ` [PATCH v2 22/32] Bluetooth: Introduce L2CAP channel callback for suspending johan.hedberg
2013-12-05 13:11 ` johan.hedberg [this message]
2013-12-05 13:11 ` [PATCH v2 24/32] Bluetooth: Implement LE L2CAP reassembly johan.hedberg
2013-12-05 13:11 ` [PATCH v2 25/32] Bluetooth: Fix LE L2CAP Connect Request handling together with SMP johan.hedberg
2013-12-05 13:11 ` [PATCH v2 26/32] Bluetooth: Fix suspending the L2CAP socket if we start with 0 credits johan.hedberg
2013-12-05 13:11 ` [PATCH v2 27/32] Bluetooth: Limit LE MPS to the MTU value johan.hedberg
2013-12-05 13:11 ` [PATCH v2 28/32] Bluetooth: Fix clearing of chan->omtu for LE CoC channels johan.hedberg
2013-12-05 13:11 ` [PATCH v2 29/32] Bluetooth: Fix CID ranges for LE CoC CID allocations johan.hedberg
2013-12-05 13:11 ` [PATCH v2 30/32] Bluetooth: Fix validating LE PSM values johan.hedberg
2013-12-06 0:02 ` Anderson Lizardo
2013-12-06 5:05 ` Johan Hedberg
2013-12-05 13:11 ` [PATCH v2 31/32] Bluetooth: Add debugfs controls for LE CoC MPS and Credits johan.hedberg
2013-12-05 13:11 ` [PATCH v2 32/32] Bluetooth: Simplify l2cap_chan initialization for LE CoC johan.hedberg
2013-12-05 15:06 ` [PATCH v2 00/32] Bluetooth: LE CoC support Marcel Holtmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1386249090-10236-24-git-send-email-johan.hedberg@gmail.com \
--to=johan.hedberg@gmail.com \
--cc=linux-bluetooth@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).