From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=209.85.221.177 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1794087979; b=cXYoX/30OXhS7+Q91TpB+LCVSoCS6vcv03AOdeVUbDWdwaYraqBXUJQ/SsMVTfMd+1Ql gMfhR48ElXhWpfmTu3nXOh6gVXYh/1RuNePy0bxaUl5mPvaXk/fKr+Bw1vE70+LodTMLO WdvPfhRmNORUMy6DfJHmdhwikCSSPgT27MWGK+fK5iE9IDkkYA7v8tvTdNALcqMbCjwFH pGuCu/Om/nNIqGU7ZH5WSW4ZbPd5HS76tRjOcs+9kZSbzO7kEHH+1FMdwsZlZ8cr2GZaR McL8PcutG41Y2CBqkvHEO6lpsEuhO2Qr81tlnN+1kBWqThFONjIbtqfODMcYIIrnCug== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794087979; h=DMARC-Filter:Received:DKIM-Signature:X-Google-DKIM-Signature: X-Gm-Message-State:X-Gm-Gg:X-Received:Received:From:To:Subject:Date: Message-ID:X-Mailer:In-Reply-To:References:MIME-Version: Content-Transfer-Encoding; bh=mXuBDqXYFekIMnZ/s4W0ulTP+MzS9DTQLSUo8AX/8bM=; b=zMsgR8wFXdTttM4GopRNhOpdwtG8dFlq/kBk7r9P4Nfr6+4BcaY1mwc+xrmVy3+aDdwn /XVJoMDMEERB2C6NoFQvNtTarrTH9+GcXoA4m9WTDAeuO4T2qGzSmI7Qe+3AHIZvmyldt xOuZiFJAgOWy/e1Fy9ny+/UOGQn2tDCI5u1CmFQcG1kMIop1qu2U6+m/o92bQMG4RH3C6 qIoAquNdEE7vdk05RrphoF8dt5mQgmkFuHLM4aR2YuT/+pLgTxIH8pRRpX+ybe0JfSw2H uph7+N6IATrWP4RPPIKBhuLvnlqcH/rUR4RQEH1l0tgCXXYBFeKcyxP9KkJ2AYUzYKQ== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20260707 header.b=txAMgsaW; arc=none smtp.remote-ip=209.85.221.177 Received: from mail-vk1-f177.google.com (mail-vk1-f177.google.com [209.85.221.177]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2EE37606A326 for ; Sat, 7 Nov 2026 21:46:19 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.2 smtp.subspace.kernel.org 2EE37606A326 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20260707 header.b=txAMgsaW Received: by mail-vk1-f177.google.com with SMTP id 71dfb90a1353d-5ecd9a400cbso26954e0c.0 for ; Sat, 07 Nov 2026 13:46:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1794087978; x=1794692778; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to:content-type; bh=mXuBDqXYFekIMnZ/s4W0ulTP+MzS9DTQLSUo8AX/8bM=; b=txAMgsaW4dLstyPwje6mQe6keBhS65i9F0c/cHVRx35SiXfJ1oQWZMzQq/J7lGlyHI IAzezK2E3RXO6sVMbiyhuuy53F8xa/uXv57LgK8OF7bM5zLKcvkjjsSCK/zsHZ5gfhlU ggTmcsi4m24SdNzl2MCQqjN2ikt6E0akl6aUlpqezBy65sCmz4ZztixUpz6GocsY9ENo ZmXjoaIb/P81KzCB3nd5IcdnJYhO0PASTbYId+iuAHQ9LZFacSEvGHcrYkrLUObg9yc4 YDIdUm6zjJZL6DfYH1BAT0ZQXdnu/SNzBrqQWBFpd/VVTLFUKdZ6W5lKMbp3iqBifhmj UXsw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1794087978; x=1794692778; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to:content-type; bh=mXuBDqXYFekIMnZ/s4W0ulTP+MzS9DTQLSUo8AX/8bM=; b=XsgUSkIDRJ4W3W0GLx8MXXPE8hIv2uDN+aRFowPyU9kipvUzF2uknkT6uH8IyQaWA3 EnFzL8whf7xrfX7f0CrmmBguWjmKd7QA/YIR11jQyuDQpllCAC1xRsZEt7ViEs99p9zU VQ+jrtFGSqQuM9nOxrLsKtEhPuz9E0Kq56y6tg0rutqC+iANf33/lqsBZvbtp8jjt+G7 mGiHLUwv59gjejoRZRP5H4UwybczkAkkKMgG/rVxjzt15H1dXOQznTQQfjuuYyp5JFlx 4BevediJRa1ibePgc02j+VsdmCkF3Axc5LR3BvhepD3DZDVgeGgJu6HL4dQrh0M2XDQ2 YWeA== X-Gm-Message-State: APuU4Z8WT0j1/6RSU8ICvs6HO/wjcOKJ3oIiqpWp3OHjtIE7vBiZwiCH T0aPb7KqhwIqzWPm2jf+PKMDB8sp2A1JeIEa1o4Dnn/l0CYgDfokcD7RrT4j4Q== X-Gm-Gg: AYBFou1F/arLKVkvuuEOdmlDfJNDi0ayLYFBKsNBsJuGCV1MM87g0Xlc4lkFOOc0+33 nNtRlzs3xWLojQ4jwIQo1bPJLRQ4MK//Zq94Pp2QG3jF3KnbsUpxbXS82mrJ6r58mzb4Fsmwlwa tWLNgZiOqlgpah/GVZPIQocplTeFBxXU6jI1pRJW+AgvY/B8+AVHVvMKsmuMxAsDI83MsyGAfRX PFSua/arMXofFZ8gwCHN2KqUZ7h7WHunvarK7PPIZb0M3qIan9+flU3YVxLFTJxhv+JdfdVIBo2 8mKLWYybdytN3su9xQMWQbaA1SlIlIoznxzpKkfmkUf0WiA8mDg+Q2/VJsEOxIZhx0+2N0dwF61 0Yx7PbG5uvDvQ2ylu6kXowHUxeRZ2HA4tYgw/hnhYaeq4o0zHblok7tzNdYC5+WOYco9Im3W3vI iLdIKZ6g+uSUJ32chcWv/F+JIV0E0Sr/3OdtM956e8M3dnp9IIdbH9DE9Mb3a3E0fR/IXeTuusV SSl6+9Ss/0WU9Na9X+EANbHe+ukeD/os4dEZ+joMMq7oyLIGMoPsJ4oRknUxkW0cuOvuSGn+Svl Izu2augGvbGH65IGk67f7ePaFkJTqag3HdRlnHglDLMysWV/+/GnXMPKDCFwFdlYr75QCaM1Bnr vSWIr2n4rJ6ciSqMjQatlgfmCOuVWNfBgjQ49YjuVl2BS+w/IzguZHVaI6KfK2AHeBpTYIiz4lS OkVvk= X-Received: by 2002:a05:6122:786:b0:5ea:dc36:245b with SMTP id 71dfb90a1353d-5ece735529amr58631e0c.18.1794087977984; Sat, 07 Nov 2026 13:46:17 -0800 (PST) Received: from lvondent-mobl5.taila91cb8.ts.net ([72.188.211.115]) by smtp.gmail.com with ESMTPSA id 71dfb90a1353d-5ece6418de3sm382617e0c.13.2026.11.07.13.46.17 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 07 Nov 2026 13:46:17 -0800 (PST) From: Luiz Augusto von Dentz To: linux-bluetooth@vger.kernel.org Subject: [PATCH BlueZ v6 03/11] doc/iso-protocol: Document BT_ISO_QOS Date: Sat, 7 Nov 2026 16:46:02 -0500 Message-ID: <20261107214611.388705-4-luiz.dentz@gmail.com> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261107214611.388705-1-luiz.dentz@gmail.com> References: <20261107214611.388705-1-luiz.dentz@gmail.com> X-Mailing-List: linux-bluetooth@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: Luiz Augusto von Dentz Document BT_ISO_QOS with struct bt_iso_qos_ext, its version and type fields and why they exist, the PHY values and the HDT rates, with examples for unicast and broadcast with the LE HDT PHY and reading the QoS in use. --- doc/iso-protocol.rst | 207 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) diff --git a/doc/iso-protocol.rst b/doc/iso-protocol.rst index 4d315132f911..8d8aebc3af2f 100644 --- a/doc/iso-protocol.rst +++ b/doc/iso-protocol.rst @@ -241,6 +241,213 @@ Example: } } +BT_ISO_QOS +---------- + +Isochronous channel QoS, used by **connect(2)** and **listen(2)** to set up a +CIS (unicast) or BIS (broadcast). It is read back with **getsockopt(2)**, which +reports the parameters in use once the channel is connected. Two forms are +accepted, told apart by the option length: + +- ``struct bt_iso_qos``: the original form, kept for existing applications. +- ``struct bt_iso_qos_ext``: the extended form, required + for the fields added after the original one, such as the HDT rates. + +.. code-block:: + + struct bt_iso_io_qos_ext { + uint32_t interval; + uint16_t latency; + uint16_t sdu; + uint8_t phys; + uint8_t rtn; + uint16_t rates; /* Version 1 */ + }; + + struct bt_iso_ucast_qos_ext { + uint8_t cig; + uint8_t cis; + uint8_t sca; + uint8_t packing; + uint8_t framing; + struct bt_iso_io_qos_ext in; + struct bt_iso_io_qos_ext out; + }; + + struct bt_iso_bcast_qos_ext { + uint8_t big; + uint8_t bis; + uint8_t sync_factor; + uint8_t packing; + uint8_t framing; + struct bt_iso_io_qos_ext in; + struct bt_iso_io_qos_ext out; + uint8_t encryption; + uint8_t bcode[16]; + uint8_t options; + uint16_t skip; + uint16_t sync_timeout; + uint8_t sync_cte_type; + uint8_t mse; + uint16_t timeout; + }; + + struct bt_iso_qos_ext { + uint16_t version; + uint16_t type; + union { /* Shall be the last member */ + struct bt_iso_ucast_qos_ext ucast; + struct bt_iso_bcast_qos_ext bcast; + }; + }; + +``struct bt_iso_qos`` has the same fields without ``version``, ``type`` and +``rates``. + +The extended form is meant to grow, by extending it rather than adding new +socket options or structs, which is what its first two fields are for: + +- ``version`` tells which fields are valid. Later versions add fields, while + applications built for an earlier version keep working with the fields + they know. +- ``type`` tells which member of the union is in use. The QoS is usually set + before **bind(2)** or **connect(2)**, when the socket can't tell unicast + from broadcast, so with ``type`` ``ucast`` and ``bcast`` can each grow on + their own, by adding fields at their end, without the kernel having to + guess which one it was given. That is also why the union is the last + member. + +version: + +.. csv-table:: + :header: "Value", "Description" + :widths: auto + + **BT_ISO_QOS_VERSION_1 (0x0001)**, Adds ``rates`` to each direction + +type: + +.. csv-table:: + :header: "Value", "Description" + :widths: auto + + **BT_ISO_QOS_ANY (0x0000)**, "Set by **connect(2)** or **listen(2)**, + possible with version 1 fields since the unicast ones are a prefix of the + broadcast ones" + **BT_ISO_QOS_UCAST (0x0001)**, Unicast (CIS) uses ``ucast`` + **BT_ISO_QOS_BCAST (0x0002)**, Broadcast (BIS) uses ``bcast`` + +**setsockopt(2)** fails with ``EINVAL`` for an unknown ``version`` or +``type``, and **connect(2)** or **listen(2)** fail with ``EINVAL`` if +``type`` doesn't match how the socket is used. A socket that already has a +connection, such as an accepted one with ``BT_DEFER_SETUP`` or a PA sync, +knows its type, so there **setsockopt(2)** fails instead. **getsockopt(2)** returns +``struct bt_iso_qos`` if the buffer is shorter than ``struct bt_iso_qos_ext``, +otherwise ``struct bt_iso_qos_ext`` with the version and, once known, the type +in use. + +phys, in each direction: + +.. csv-table:: + :header: "Value", "Description" + :widths: auto + + **BT_ISO_PHY_1M (0x01)**, LE 1M + **BT_ISO_PHY_2M (0x02)**, LE 2M + **BT_ISO_PHY_CODED (0x04)**, LE Coded + **BT_ISO_PHY_HDT (0x10)**, "LE HDT, if supported by the controller, using + ``rates``" + +rates, in each direction, used with ``BT_ISO_PHY_HDT``; 0 selects every rate +the controller supports: + +.. csv-table:: + :header: "Value", "Description" + :widths: auto + + **BT_ISO_HDT_RATE_2M (0x0001)**, HDT 2M + **BT_ISO_HDT_RATE_3M (0x0002)**, HDT 3M + **BT_ISO_HDT_RATE_4M (0x0004)**, HDT 4M + **BT_ISO_HDT_RATE_6M (0x0008)**, "HDT 6M, if supported in that direction" + **BT_ISO_HDT_RATE_7_5M (0x0010)**, "HDT 7.5M, if supported in that + direction" + +Example (Unicast with the LE HDT PHY): + +.. code-block:: + + struct bt_iso_qos_ext qos; + + memset(&qos, 0, sizeof(qos)); + qos.version = BT_ISO_QOS_VERSION_1; + qos.type = BT_ISO_QOS_UCAST; + qos.ucast.cig = BT_ISO_QOS_CIG_UNSET; + qos.ucast.cis = BT_ISO_QOS_CIS_UNSET; + + qos.ucast.out.interval = 10000; + qos.ucast.out.latency = 10; + qos.ucast.out.sdu = 40; + qos.ucast.out.phys = BT_ISO_PHY_HDT; + qos.ucast.out.rtn = 2; + qos.ucast.out.rates = BT_ISO_HDT_RATE_4M | BT_ISO_HDT_RATE_6M; + + /* The input direction uses the same settings */ + qos.ucast.in = qos.ucast.out; + + err = setsockopt(iso_socket, SOL_BLUETOOTH, BT_ISO_QOS, &qos, + sizeof(qos)); + if (err == -1) { + perror("setsockopt"); + return err; + } + + /* connect(2) sets up the CIS */ + +Example (Broadcast with the LE HDT PHY at any supported rate): + +.. code-block:: + + struct bt_iso_qos_ext qos; + + memset(&qos, 0, sizeof(qos)); + qos.version = BT_ISO_QOS_VERSION_1; + qos.type = BT_ISO_QOS_BCAST; + qos.bcast.big = BT_ISO_QOS_BIG_UNSET; + qos.bcast.bis = BT_ISO_QOS_BIS_UNSET; + qos.bcast.sync_factor = 0x01; + qos.bcast.sync_timeout = BT_ISO_SYNC_TIMEOUT; + qos.bcast.timeout = BT_ISO_SYNC_TIMEOUT; + + qos.bcast.out.interval = 10000; + qos.bcast.out.latency = 10; + qos.bcast.out.sdu = 40; + qos.bcast.out.phys = BT_ISO_PHY_HDT; + qos.bcast.out.rtn = 2; + qos.bcast.out.rates = 0; /* Every rate the controller supports */ + + err = setsockopt(iso_socket, SOL_BLUETOOTH, BT_ISO_QOS, &qos, + sizeof(qos)); + +Example (Read the QoS in use, including the rates selected): + +.. code-block:: + + struct bt_iso_qos_ext qos; + socklen_t len = sizeof(qos); + + err = getsockopt(iso_socket, SOL_BLUETOOTH, BT_ISO_QOS, &qos, &len); + if (err == -1) { + perror("getsockopt"); + return err; + } + + if (len < sizeof(qos)) { + /* Older kernel, only struct bt_iso_qos was returned */ + } else if (qos.type == BT_ISO_QOS_UCAST && + qos.ucast.out.phys == BT_ISO_PHY_HDT) { + printf("Output HDT rates 0x%4.4x\n", qos.ucast.out.rates); + } + BT_PKT_STATUS ------------- -- 2.56.0