Skip to content

Commit

Permalink
Bluetooth: Refactor l2cap_ertm_send
Browse files Browse the repository at this point in the history
The new implementation is aware of the new transmit state machine, and
uses struct l2cap_ctrl to compose ERTM headers.  It also has improved
error handling for allocation failures, and does not send the packet
until after all skb and channel data structures are updated.

Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
  • Loading branch information
Mat Martineau authored and Johan Hedberg committed Jun 5, 2012
1 parent 3733937 commit 18a48e7
Showing 1 changed file with 39 additions and 40 deletions.
79 changes: 39 additions & 40 deletions net/bluetooth/l2cap_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1741,71 +1741,68 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
static int l2cap_ertm_send(struct l2cap_chan *chan)
{
struct sk_buff *skb, *tx_skb;
u16 fcs;
u32 control;
int nsent = 0;
struct l2cap_ctrl *control;
int sent = 0;

BT_DBG("chan %p", chan);

if (chan->state != BT_CONNECTED)
return -ENOTCONN;

if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
return 0;

while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {

if (bt_cb(skb)->control.retries == chan->remote_max_tx &&
chan->remote_max_tx) {
l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
break;
}
while (chan->tx_send_head &&
chan->unacked_frames < chan->remote_tx_win &&
chan->tx_state == L2CAP_TX_STATE_XMIT) {

tx_skb = skb_clone(skb, GFP_ATOMIC);
skb = chan->tx_send_head;

bt_cb(skb)->control.retries++;

control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
control &= __get_sar_mask(chan);
bt_cb(skb)->control.retries = 1;
control = &bt_cb(skb)->control;

if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
control |= __set_ctrl_final(chan);
control->final = 1;

control |= __set_reqseq(chan, chan->buffer_seq);
control |= __set_txseq(chan, chan->next_tx_seq);
control |= __set_ctrl_sar(chan, bt_cb(skb)->control.sar);
control->reqseq = chan->buffer_seq;
chan->last_acked_seq = chan->buffer_seq;
control->txseq = chan->next_tx_seq;

__put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
__pack_control(chan, control, skb);

if (chan->fcs == L2CAP_FCS_CRC16) {
fcs = crc16(0, (u8 *)skb->data,
tx_skb->len - L2CAP_FCS_SIZE);
put_unaligned_le16(fcs, skb->data +
tx_skb->len - L2CAP_FCS_SIZE);
u16 fcs = crc16(0, (u8 *) skb->data, skb->len);
put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
}

l2cap_do_send(chan, tx_skb);
/* Clone after data has been modified. Data is assumed to be
read-only (for locking purposes) on cloned sk_buffs.
*/
tx_skb = skb_clone(skb, GFP_KERNEL);

__set_retrans_timer(chan);
if (!tx_skb)
break;

bt_cb(skb)->control.txseq = chan->next_tx_seq;
__set_retrans_timer(chan);

chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);

if (bt_cb(skb)->control.retries == 1) {
chan->unacked_frames++;

if (!nsent++)
__clear_ack_timer(chan);
}

chan->unacked_frames++;
chan->frames_sent++;
sent++;

if (skb_queue_is_last(&chan->tx_q, skb))
chan->tx_send_head = NULL;
else
chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);

l2cap_do_send(chan, tx_skb);
BT_DBG("Sent txseq %d", (int)control->txseq);
}

return nsent;
BT_DBG("Sent %d, %d unacked, %d in ERTM queue", sent,
(int) chan->unacked_frames, skb_queue_len(&chan->tx_q));

return sent;
}

static int l2cap_retransmit_frames(struct l2cap_chan *chan)
Expand Down Expand Up @@ -2009,7 +2006,11 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
lh->cid = cpu_to_le16(chan->dcid);
lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));

__put_control(chan, 0, skb_put(skb, __ctrl_size(chan)));
/* Control header is populated later */
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
put_unaligned_le32(0, skb_put(skb, L2CAP_EXT_CTRL_SIZE));
else
put_unaligned_le16(0, skb_put(skb, L2CAP_ENH_CTRL_SIZE));

if (sdulen)
put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
Expand All @@ -2020,9 +2021,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
return ERR_PTR(err);
}

if (chan->fcs == L2CAP_FCS_CRC16)
put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));

bt_cb(skb)->control.fcs = chan->fcs;
bt_cb(skb)->control.retries = 0;
return skb;
}
Expand Down

0 comments on commit 18a48e7

Please sign in to comment.