The TX and RX PHYs will always be 1M if the established LE connection is a legacy connection. These values may differ in case of LE Extended connection. This change will read and update the connection PHYs and autonomously send LE PHY Update event if the connection is LE Extended. < HCI Command: LE Read PHY (0x08|0x0030) plen 2 Handle: 0 > HCI Event: Command Complete (0x0e) plen 8 LE Read PHY (0x08|0x0030) ncmd 1 Status: Success (0x00) Handle: 0 TX PHY: LE 1M (0x01) RX PHY: LE 1M (0x01) @ MGMT Event: LE PHY Update Complete (0x002f) plen 12 LE Address: 45:18:F8:CF:23:7E (Resolvable) Status: Success (0x00) Updated PHYs: 0x0600 LE 1M TX LE 1M RX Reviewed-by: Anupam Roy <anupam.r@xxxxxxxxxxx> Signed-off-by: Ayush Garg <ayush.garg@xxxxxxxxxxx> --- include/net/bluetooth/hci.h | 12 +++++++++ net/bluetooth/hci_event.c | 51 +++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 06e10ccf2a1c..6073e8431ed5 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1670,6 +1670,18 @@ struct hci_rp_le_read_max_data_len { __le16 rx_time; } __packed; +#define HCI_OP_LE_READ_PHY 0x2030 +struct hci_cp_le_read_phy { + __le16 handle; +} __packed; + +struct hci_rp_le_read_phy { + __u8 status; + __le16 handle; + __u8 tx_phy; + __u8 rx_phy; +} __packed; + #define HCI_OP_LE_SET_DEFAULT_PHY 0x2031 struct hci_cp_le_set_default_phy { __u8 all_phys; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index effe525e5272..37ab2f2a1d06 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1196,6 +1196,31 @@ static void hci_cc_le_set_default_phy(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_unlock(hdev); } +static void hci_cc_le_read_phy(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_rp_le_read_phy *rp = (void *)skb->data; + struct hci_conn *conn; + + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); + + if (rp->status) + return; + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle)); + if (!conn) + goto unlock; + + conn->le_tx_phy = rp->tx_phy; + conn->le_rx_phy = rp->rx_phy; + + mgmt_le_phy_update(hdev, conn, 0); + +unlock: + hci_dev_unlock(hdev); +} + static void hci_cc_le_set_adv_set_random_addr(struct hci_dev *hdev, struct sk_buff *skb) { @@ -3642,6 +3667,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb, hci_cc_le_read_transmit_power(hdev, skb); break; + case HCI_OP_LE_READ_PHY: + hci_cc_le_read_phy(hdev, skb); + break; + default: BT_DBG("%s opcode 0x%4.4x", hdev->name, *opcode); break; @@ -5229,6 +5258,17 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status, goto unlock; } + /* If this LE connection is not an extended connection, then LE + * PHYs will always be 1M at the time of connection establishment. + * So, set 1M as initial LE PHY values. + * But if this is LE Extended connection, then the PHY values + * can be 1M, 2M or CODED. So, In this case, read and update + * the values after the conn->state becomes connected and + * then, send the LE_PHY_UPDATE_COMPLETE event. + */ + conn->le_tx_phy = HCI_LE_SET_PHY_1M; + conn->le_rx_phy = HCI_LE_SET_PHY_1M; + if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) mgmt_device_connected(hdev, conn, NULL, 0); @@ -5267,6 +5307,17 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status, hci_connect_cfm(conn, status); } + /* If this is LE Extended connection and HCI_LE_READ_PHY + * command is supported, then update the LE PHYs. + */ + if (use_ext_conn(hdev) && hdev->commands[35] & 0x10) { + struct hci_cp_le_read_phy cp; + + cp.handle = __cpu_to_le16(conn->handle); + + hci_send_cmd(hdev, HCI_OP_LE_READ_PHY, sizeof(cp), &cp); + } + params = hci_pend_le_action_lookup(&hdev->pend_le_conns, &conn->dst, conn->dst_type); if (params) { -- 2.17.1