From 6d03a247468059b0e59c821ef39e6762d4d6fc30 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 19 Jun 2024 23:00:51 +0200 Subject: Merging upstream version 6.9.2. Signed-off-by: Daniel Baumann --- net/bluetooth/l2cap_sock.c | 91 +++++++++------------------------------------- 1 file changed, 18 insertions(+), 73 deletions(-) (limited to 'net/bluetooth/l2cap_sock.c') diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 8645461d45..5cc83f906c 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); -- cgit v1.2.3