summaryrefslogtreecommitdiffstats
path: root/net/bluetooth/l2cap_sock.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/bluetooth/l2cap_sock.c')
-rw-r--r--net/bluetooth/l2cap_sock.c91
1 files changed, 18 insertions, 73 deletions
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 8645461d4..5cc83f906 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -1131,34 +1131,6 @@ static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg,
return err;
}
-static void l2cap_publish_rx_avail(struct l2cap_chan *chan)
-{
- struct sock *sk = chan->data;
- ssize_t avail = sk->sk_rcvbuf - atomic_read(&sk->sk_rmem_alloc);
- int expected_skbs, skb_overhead;
-
- if (avail <= 0) {
- l2cap_chan_rx_avail(chan, 0);
- return;
- }
-
- if (!chan->mps) {
- l2cap_chan_rx_avail(chan, -1);
- return;
- }
-
- /* Correct available memory by estimated sk_buff overhead.
- * This is significant due to small transfer sizes. However, accept
- * at least one full packet if receive space is non-zero.
- */
- expected_skbs = DIV_ROUND_UP(avail, chan->mps);
- skb_overhead = expected_skbs * sizeof(struct sk_buff);
- if (skb_overhead < avail)
- l2cap_chan_rx_avail(chan, avail - skb_overhead);
- else
- l2cap_chan_rx_avail(chan, -1);
-}
-
static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg,
size_t len, int flags)
{
@@ -1195,33 +1167,28 @@ static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg,
else
err = bt_sock_recvmsg(sock, msg, len, flags);
- if (pi->chan->mode != L2CAP_MODE_ERTM &&
- pi->chan->mode != L2CAP_MODE_LE_FLOWCTL &&
- pi->chan->mode != L2CAP_MODE_EXT_FLOWCTL)
+ if (pi->chan->mode != L2CAP_MODE_ERTM)
return err;
+ /* Attempt to put pending rx data in the socket buffer */
+
lock_sock(sk);
- l2cap_publish_rx_avail(pi->chan);
+ if (!test_bit(CONN_LOCAL_BUSY, &pi->chan->conn_state))
+ goto done;
- /* Attempt to put pending rx data in the socket buffer */
- while (!list_empty(&pi->rx_busy)) {
- struct l2cap_rx_busy *rx_busy =
- list_first_entry(&pi->rx_busy,
- struct l2cap_rx_busy,
- list);
- if (__sock_queue_rcv_skb(sk, rx_busy->skb) < 0)
+ if (pi->rx_busy_skb) {
+ if (!__sock_queue_rcv_skb(sk, pi->rx_busy_skb))
+ pi->rx_busy_skb = NULL;
+ else
goto done;
- list_del(&rx_busy->list);
- kfree(rx_busy);
}
/* Restore data flow when half of the receive buffer is
* available. This avoids resending large numbers of
* frames.
*/
- if (test_bit(CONN_LOCAL_BUSY, &pi->chan->conn_state) &&
- atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf >> 1)
+ if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf >> 1)
l2cap_chan_busy(pi->chan, 0);
done:
@@ -1482,20 +1449,17 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan)
static int l2cap_sock_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
{
struct sock *sk = chan->data;
- struct l2cap_pinfo *pi = l2cap_pi(sk);
int err;
lock_sock(sk);
- if (chan->mode == L2CAP_MODE_ERTM && !list_empty(&pi->rx_busy)) {
+ if (l2cap_pi(sk)->rx_busy_skb) {
err = -ENOMEM;
goto done;
}
if (chan->mode != L2CAP_MODE_ERTM &&
- chan->mode != L2CAP_MODE_STREAMING &&
- chan->mode != L2CAP_MODE_LE_FLOWCTL &&
- chan->mode != L2CAP_MODE_EXT_FLOWCTL) {
+ chan->mode != L2CAP_MODE_STREAMING) {
/* Even if no filter is attached, we could potentially
* get errors from security modules, etc.
*/
@@ -1506,9 +1470,7 @@ static int l2cap_sock_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
err = __sock_queue_rcv_skb(sk, skb);
- l2cap_publish_rx_avail(chan);
-
- /* For ERTM and LE, handle a skb that doesn't fit into the recv
+ /* For ERTM, handle one skb that doesn't fit into the recv
* buffer. This is important to do because the data frames
* have already been acked, so the skb cannot be discarded.
*
@@ -1517,18 +1479,8 @@ static int l2cap_sock_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
* acked and reassembled until there is buffer space
* available.
*/
- if (err < 0 &&
- (chan->mode == L2CAP_MODE_ERTM ||
- chan->mode == L2CAP_MODE_LE_FLOWCTL ||
- chan->mode == L2CAP_MODE_EXT_FLOWCTL)) {
- struct l2cap_rx_busy *rx_busy =
- kmalloc(sizeof(*rx_busy), GFP_KERNEL);
- if (!rx_busy) {
- err = -ENOMEM;
- goto done;
- }
- rx_busy->skb = skb;
- list_add_tail(&rx_busy->list, &pi->rx_busy);
+ if (err < 0 && chan->mode == L2CAP_MODE_ERTM) {
+ l2cap_pi(sk)->rx_busy_skb = skb;
l2cap_chan_busy(chan, 1);
err = 0;
}
@@ -1754,8 +1706,6 @@ static const struct l2cap_ops l2cap_chan_ops = {
static void l2cap_sock_destruct(struct sock *sk)
{
- struct l2cap_rx_busy *rx_busy, *next;
-
BT_DBG("sk %p", sk);
if (l2cap_pi(sk)->chan) {
@@ -1763,10 +1713,9 @@ static void l2cap_sock_destruct(struct sock *sk)
l2cap_chan_put(l2cap_pi(sk)->chan);
}
- list_for_each_entry_safe(rx_busy, next, &l2cap_pi(sk)->rx_busy, list) {
- kfree_skb(rx_busy->skb);
- list_del(&rx_busy->list);
- kfree(rx_busy);
+ if (l2cap_pi(sk)->rx_busy_skb) {
+ kfree_skb(l2cap_pi(sk)->rx_busy_skb);
+ l2cap_pi(sk)->rx_busy_skb = NULL;
}
skb_queue_purge(&sk->sk_receive_queue);
@@ -1850,8 +1799,6 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
chan->data = sk;
chan->ops = &l2cap_chan_ops;
-
- l2cap_publish_rx_avail(chan);
}
static struct proto l2cap_proto = {
@@ -1873,8 +1820,6 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
sk->sk_destruct = l2cap_sock_destruct;
sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT;
- INIT_LIST_HEAD(&l2cap_pi(sk)->rx_busy);
-
chan = l2cap_chan_create();
if (!chan) {
sk_free(sk);