]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
Bluetooth: ISO: add socket option to report packet seqnum via CMSG
authorPauli Virtanen <pav@iki.fi>
Mon, 14 Jul 2025 16:40:37 +0000 (19:40 +0300)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Wed, 23 Jul 2025 14:31:19 +0000 (10:31 -0400)
User applications need a way to track which ISO interval a given SDU
belongs to, to properly detect packet loss. All controllers do not set
timestamps, and it's not guaranteed user application receives all packet
reports (small socket buffer, or controller doesn't send all reports
like Intel AX210 is doing).

Add socket option BT_PKT_SEQNUM that enables reporting of received
packet ISO sequence number in BT_SCM_PKT_SEQNUM CMSG.

Use BT_PKT_SEQNUM == 22 for the socket option, as 21 was used earlier
for a removed experimental feature that never got into mainline.

Signed-off-by: Pauli Virtanen <pav@iki.fi>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
include/net/bluetooth/bluetooth.h
net/bluetooth/af_bluetooth.c
net/bluetooth/iso.c

index 114299bd8b9878f70ca0286ccec1df2cd31735fe..ada5b56a441350399810075254606d3c57196150 100644 (file)
@@ -244,6 +244,12 @@ struct bt_codecs {
 
 #define BT_ISO_BASE            20
 
+/* Socket option value 21 reserved */
+
+#define BT_PKT_SEQNUM          22
+
+#define BT_SCM_PKT_SEQNUM      0x05
+
 __printf(1, 2)
 void bt_info(const char *fmt, ...);
 __printf(1, 2)
@@ -391,7 +397,8 @@ struct bt_sock {
 enum {
        BT_SK_DEFER_SETUP,
        BT_SK_SUSPEND,
-       BT_SK_PKT_STATUS
+       BT_SK_PKT_STATUS,
+       BT_SK_PKT_SEQNUM,
 };
 
 struct bt_sock_list {
@@ -475,6 +482,7 @@ struct bt_skb_cb {
        u8 pkt_type;
        u8 force_active;
        u16 expect;
+       u16 pkt_seqnum;
        u8 incoming:1;
        u8 pkt_status:2;
        union {
@@ -488,6 +496,7 @@ struct bt_skb_cb {
 
 #define hci_skb_pkt_type(skb) bt_cb((skb))->pkt_type
 #define hci_skb_pkt_status(skb) bt_cb((skb))->pkt_status
+#define hci_skb_pkt_seqnum(skb) bt_cb((skb))->pkt_seqnum
 #define hci_skb_expect(skb) bt_cb((skb))->expect
 #define hci_skb_opcode(skb) bt_cb((skb))->hci.opcode
 #define hci_skb_event(skb) bt_cb((skb))->hci.req_event
index ee9bf84c88a70bd926ec5aaceb3a326817e48c5f..2b94e20772038f1d90228d214f57ab334ca01a50 100644 (file)
@@ -364,6 +364,13 @@ int bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
                        put_cmsg(msg, SOL_BLUETOOTH, BT_SCM_PKT_STATUS,
                                 sizeof(pkt_status), &pkt_status);
                }
+
+               if (test_bit(BT_SK_PKT_SEQNUM, &bt_sk(sk)->flags)) {
+                       u16 pkt_seqnum = hci_skb_pkt_seqnum(skb);
+
+                       put_cmsg(msg, SOL_BLUETOOTH, BT_SCM_PKT_SEQNUM,
+                                sizeof(pkt_seqnum), &pkt_seqnum);
+               }
        }
 
        skb_free_datagram(sk, skb);
index 5e752950e266ecee6ae5cf23542542ca13dc6e6b..2f229f2077e831750eeca6923298f82ed6a51355 100644 (file)
@@ -1687,6 +1687,17 @@ static int iso_sock_setsockopt(struct socket *sock, int level, int optname,
                        clear_bit(BT_SK_PKT_STATUS, &bt_sk(sk)->flags);
                break;
 
+       case BT_PKT_SEQNUM:
+               err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
+               if (err)
+                       break;
+
+               if (opt)
+                       set_bit(BT_SK_PKT_SEQNUM, &bt_sk(sk)->flags);
+               else
+                       clear_bit(BT_SK_PKT_SEQNUM, &bt_sk(sk)->flags);
+               break;
+
        case BT_ISO_QOS:
                if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND &&
                    sk->sk_state != BT_CONNECT2 &&
@@ -2278,7 +2289,7 @@ static void iso_disconn_cfm(struct hci_conn *hcon, __u8 reason)
 void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
 {
        struct iso_conn *conn = hcon->iso_data;
-       __u16 pb, ts, len;
+       __u16 pb, ts, len, sn;
 
        if (!conn)
                goto drop;
@@ -2308,6 +2319,7 @@ void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
                                goto drop;
                        }
 
+                       sn = __le16_to_cpu(hdr->sn);
                        len = __le16_to_cpu(hdr->slen);
                } else {
                        struct hci_iso_data_hdr *hdr;
@@ -2318,18 +2330,20 @@ void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
                                goto drop;
                        }
 
+                       sn = __le16_to_cpu(hdr->sn);
                        len = __le16_to_cpu(hdr->slen);
                }
 
                flags  = hci_iso_data_flags(len);
                len    = hci_iso_data_len(len);
 
-               BT_DBG("Start: total len %d, frag len %d flags 0x%4.4x", len,
-                      skb->len, flags);
+               BT_DBG("Start: total len %d, frag len %d flags 0x%4.4x sn %d",
+                      len, skb->len, flags, sn);
 
                if (len == skb->len) {
                        /* Complete frame received */
                        hci_skb_pkt_status(skb) = flags & 0x03;
+                       hci_skb_pkt_seqnum(skb) = sn;
                        iso_recv_frame(conn, skb);
                        return;
                }
@@ -2352,6 +2366,7 @@ void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
                        goto drop;
 
                hci_skb_pkt_status(conn->rx_skb) = flags & 0x03;
+               hci_skb_pkt_seqnum(conn->rx_skb) = sn;
                skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
                                          skb->len);
                conn->rx_len = len - skb->len;