]> www.infradead.org Git - users/hch/misc.git/commitdiff
Bluetooth: L2CAP: add TX timestamping
authorPauli Virtanen <pav@iki.fi>
Tue, 18 Mar 2025 19:06:45 +0000 (21:06 +0200)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Tue, 25 Mar 2025 16:50:35 +0000 (12:50 -0400)
Support TX timestamping in L2CAP sockets.

Support MSG_ERRQUEUE recvmsg.

For other than SOCK_STREAM L2CAP sockets, if a packet from sendmsg() is
fragmented, only the first ACL fragment is timestamped.

For SOCK_STREAM L2CAP sockets, use the bytestream convention and
timestamp the last fragment and count bytes in tskey.

Timestamps are not generated in the Enhanced Retransmission mode, as
meaning of COMPLETION stamp is unclear if L2CAP layer retransmits.

Signed-off-by: Pauli Virtanen <pav@iki.fi>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
include/net/bluetooth/l2cap.h
net/bluetooth/6lowpan.c
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_sock.c
net/bluetooth/smp.c

index 0bf8cb17a6e864793f84a4bc8620414a7a396b2f..4bb0eaedda180fd003913f0914eb4b729e96f19c 100644 (file)
@@ -955,7 +955,8 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason);
 int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
                       bdaddr_t *dst, u8 dst_type, u16 timeout);
 int l2cap_chan_reconfigure(struct l2cap_chan *chan, __u16 mtu);
-int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len);
+int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
+                   const struct sockcm_cookie *sockc);
 void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
 void l2cap_chan_rx_avail(struct l2cap_chan *chan, ssize_t rx_avail);
 int l2cap_chan_check_security(struct l2cap_chan *chan, bool initiator);
index 73530b8e1eaee2495963a504fe1b849635d369d7..f0c862091bff20c16dd7d1230e66b5f7a5a1ae00 100644 (file)
@@ -444,7 +444,7 @@ static int send_pkt(struct l2cap_chan *chan, struct sk_buff *skb,
        memset(&msg, 0, sizeof(msg));
        iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, &iv, 1, skb->len);
 
-       err = l2cap_chan_send(chan, &msg, skb->len);
+       err = l2cap_chan_send(chan, &msg, skb->len, NULL);
        if (err > 0) {
                netdev->stats.tx_bytes += err;
                netdev->stats.tx_packets++;
index 7b4adab353cf2c6f4d2e79a4ab9d6db2c0f14c04..c7b66b2ea9f2102bd6dfde0ffa818cbf2f34d481 100644 (file)
@@ -2515,7 +2515,33 @@ static void l2cap_le_flowctl_send(struct l2cap_chan *chan)
               skb_queue_len(&chan->tx_q));
 }
 
-int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
+static void l2cap_tx_timestamp(struct sk_buff *skb,
+                              const struct sockcm_cookie *sockc,
+                              size_t len)
+{
+       struct sock *sk = skb ? skb->sk : NULL;
+
+       if (sk && sk->sk_type == SOCK_STREAM)
+               hci_setup_tx_timestamp(skb, len, sockc);
+       else
+               hci_setup_tx_timestamp(skb, 1, sockc);
+}
+
+static void l2cap_tx_timestamp_seg(struct sk_buff_head *queue,
+                                  const struct sockcm_cookie *sockc,
+                                  size_t len)
+{
+       struct sk_buff *skb = skb_peek(queue);
+       struct sock *sk = skb ? skb->sk : NULL;
+
+       if (sk && sk->sk_type == SOCK_STREAM)
+               l2cap_tx_timestamp(skb_peek_tail(queue), sockc, len);
+       else
+               l2cap_tx_timestamp(skb, sockc, len);
+}
+
+int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
+                   const struct sockcm_cookie *sockc)
 {
        struct sk_buff *skb;
        int err;
@@ -2530,6 +2556,8 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
                if (IS_ERR(skb))
                        return PTR_ERR(skb);
 
+               l2cap_tx_timestamp(skb, sockc, len);
+
                l2cap_do_send(chan, skb);
                return len;
        }
@@ -2553,6 +2581,8 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
                if (err)
                        return err;
 
+               l2cap_tx_timestamp_seg(&seg_queue, sockc, len);
+
                skb_queue_splice_tail_init(&seg_queue, &chan->tx_q);
 
                l2cap_le_flowctl_send(chan);
@@ -2574,6 +2604,8 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
                if (IS_ERR(skb))
                        return PTR_ERR(skb);
 
+               l2cap_tx_timestamp(skb, sockc, len);
+
                l2cap_do_send(chan, skb);
                err = len;
                break;
@@ -2597,10 +2629,13 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
                if (err)
                        break;
 
-               if (chan->mode == L2CAP_MODE_ERTM)
+               if (chan->mode == L2CAP_MODE_ERTM) {
+                       /* TODO: ERTM mode timestamping */
                        l2cap_tx(chan, NULL, &seg_queue, L2CAP_EV_DATA_REQUEST);
-               else
+               } else {
+                       l2cap_tx_timestamp_seg(&seg_queue, sockc, len);
                        l2cap_streaming_send(chan, &seg_queue);
+               }
 
                err = len;
 
index acd11b268b98ad8bc6ea3a53915cc5b4e6fbfd9f..5aa55fa695943a79bcdd38e5661af9b637fe18ba 100644 (file)
@@ -1106,6 +1106,7 @@ static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg,
 {
        struct sock *sk = sock->sk;
        struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+       struct sockcm_cookie sockc;
        int err;
 
        BT_DBG("sock %p, sk %p", sock, sk);
@@ -1120,6 +1121,14 @@ static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg,
        if (sk->sk_state != BT_CONNECTED)
                return -ENOTCONN;
 
+       hci_sockcm_init(&sockc, sk);
+
+       if (msg->msg_controllen) {
+               err = sock_cmsg_send(sk, msg, &sockc);
+               if (err)
+                       return err;
+       }
+
        lock_sock(sk);
        err = bt_sock_wait_ready(sk, msg->msg_flags);
        release_sock(sk);
@@ -1127,7 +1136,7 @@ static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg,
                return err;
 
        l2cap_chan_lock(chan);
-       err = l2cap_chan_send(chan, msg, len);
+       err = l2cap_chan_send(chan, msg, len, &sockc);
        l2cap_chan_unlock(chan);
 
        return err;
@@ -1168,6 +1177,10 @@ static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg,
        struct l2cap_pinfo *pi = l2cap_pi(sk);
        int err;
 
+       if (unlikely(flags & MSG_ERRQUEUE))
+               return sock_recv_errqueue(sk, msg, len, SOL_BLUETOOTH,
+                                         BT_SCM_ERROR);
+
        lock_sock(sk);
 
        if (sk->sk_state == BT_CONNECT2 && test_bit(BT_SK_DEFER_SETUP,
index a31c6acf1df2bbdc512d1406663ad06069c1f184..47f359f24d1fde2e3d4e44010427f91c030b2253 100644 (file)
@@ -608,7 +608,7 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
 
        iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, iv, 2, 1 + len);
 
-       l2cap_chan_send(chan, &msg, 1 + len);
+       l2cap_chan_send(chan, &msg, 1 + len, NULL);
 
        if (!chan->data)
                return;