Bluetooth: hci_conn: Fix using conn->le_{tx,rx}_phy as supported PHYs

conn->le_{tx,rx}_phy is not actually a bitfield as it set by
HCI_EV_LE_PHY_UPDATE_COMPLETE it is actually correspond to the current
PHY in use not what is supported by the controller, so this introduces
different fields (conn->le_{tx,rx}_def_phys) to track what PHYs are
supported by the connection.

Fixes: eab2404ba7 ("Bluetooth: Add BT_PHY socket option")
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
Luiz Augusto von Dentz
2025-12-10 11:38:08 -05:00
parent fce1a9244a
commit 129d1ef3c5
3 changed files with 40 additions and 9 deletions

View File

@@ -730,6 +730,8 @@ struct hci_conn {
__u16 le_per_adv_data_offset;
__u8 le_adv_phy;
__u8 le_adv_sec_phy;
__u8 le_tx_def_phys;
__u8 le_rx_def_phys;
__u8 le_tx_phy;
__u8 le_rx_phy;
__s8 rssi;

View File

@@ -1008,6 +1008,11 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type,
/* conn->src should reflect the local identity address */
hci_copy_identity_address(hdev, &conn->src, &conn->src_type);
conn->mtu = hdev->le_mtu ? hdev->le_mtu : hdev->acl_mtu;
/* Use the controller supported PHYS as default until the
* remote features are resolved.
*/
conn->le_tx_def_phys = hdev->le_tx_def_phys;
conn->le_rx_def_phys = hdev->le_tx_def_phys;
break;
case CIS_LINK:
/* conn->src should reflect the local identity address */
@@ -2928,22 +2933,22 @@ u32 hci_conn_get_phy(struct hci_conn *conn)
break;
case LE_LINK:
if (conn->le_tx_phy & HCI_LE_SET_PHY_1M)
if (conn->le_tx_def_phys & HCI_LE_SET_PHY_1M)
phys |= BT_PHY_LE_1M_TX;
if (conn->le_rx_phy & HCI_LE_SET_PHY_1M)
if (conn->le_rx_def_phys & HCI_LE_SET_PHY_1M)
phys |= BT_PHY_LE_1M_RX;
if (conn->le_tx_phy & HCI_LE_SET_PHY_2M)
if (conn->le_tx_def_phys & HCI_LE_SET_PHY_2M)
phys |= BT_PHY_LE_2M_TX;
if (conn->le_rx_phy & HCI_LE_SET_PHY_2M)
if (conn->le_rx_def_phys & HCI_LE_SET_PHY_2M)
phys |= BT_PHY_LE_2M_RX;
if (conn->le_tx_phy & HCI_LE_SET_PHY_CODED)
if (conn->le_tx_def_phys & HCI_LE_SET_PHY_CODED)
phys |= BT_PHY_LE_CODED_TX;
if (conn->le_rx_phy & HCI_LE_SET_PHY_CODED)
if (conn->le_rx_def_phys & HCI_LE_SET_PHY_CODED)
phys |= BT_PHY_LE_CODED_RX;
break;

View File

@@ -6607,8 +6607,20 @@ static void hci_le_remote_feat_complete_evt(struct hci_dev *hdev, void *data,
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
if (conn) {
if (!ev->status)
memcpy(conn->features[0], ev->features, 8);
if (!ev->status) {
memcpy(conn->le_features, ev->features, 8);
/* Update supported PHYs */
if (!(conn->le_features[1] & HCI_LE_PHY_2M)) {
conn->le_tx_def_phys &= ~HCI_LE_SET_PHY_2M;
conn->le_rx_def_phys &= ~HCI_LE_SET_PHY_2M;
}
if (!(conn->le_features[1] & HCI_LE_PHY_CODED)) {
conn->le_tx_def_phys &= ~HCI_LE_SET_PHY_CODED;
conn->le_rx_def_phys &= ~HCI_LE_SET_PHY_CODED;
}
}
if (conn->state == BT_CONFIG) {
__u8 status;
@@ -7221,9 +7233,21 @@ static void hci_le_read_all_remote_features_evt(struct hci_dev *hdev,
if (!conn)
goto unlock;
if (!ev->status)
if (!ev->status) {
memcpy(conn->le_features, ev->features, 248);
/* Update supported PHYs */
if (!(conn->le_features[1] & HCI_LE_PHY_2M)) {
conn->le_tx_def_phys &= ~HCI_LE_SET_PHY_2M;
conn->le_rx_def_phys &= ~HCI_LE_SET_PHY_2M;
}
if (!(conn->le_features[1] & HCI_LE_PHY_CODED)) {
conn->le_tx_def_phys &= ~HCI_LE_SET_PHY_CODED;
conn->le_rx_def_phys &= ~HCI_LE_SET_PHY_CODED;
}
}
if (conn->state == BT_CONFIG) {
__u8 status;