linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
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


  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).