The HCI_LE_PHY_Update_Complete event should be sent to upper layers in case of autonomous PHY update made by the controller or HCI_LE_SET_PHY command succeeded. This change will let user know immediately whenever controller change LE PHYs for a particular connection. > HCI Event: LE Meta Event (0x3e) plen 6 LE PHY Update Complete (0x0c) Status: Success (0x00) Handle: 0 TX PHY: LE 2M (0x02) RX PHY: LE 2M (0x02) @ MGMT Event: LE PHY Update Complete (0x002f) plen 12 LE Address: 45:18:F8:CF:23:7E (Resolvable) Status: Success (0x00) Updated PHYs: 0x1800 LE 2M TX LE 2M RX Reviewed-by: Anupam Roy <anupam.r@xxxxxxxxxxx> Signed-off-by: Ayush Garg <ayush.garg@xxxxxxxxxxx> --- include/net/bluetooth/hci_core.h | 1 + include/net/bluetooth/mgmt.h | 7 +++++++ net/bluetooth/hci_event.c | 11 ++++++----- net/bluetooth/mgmt.c | 34 ++++++++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 257467f9d28d..3a5c310ec937 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1835,6 +1835,7 @@ void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev, u8 instance); void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle); int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip); +void mgmt_le_phy_update(struct hci_dev *hdev, struct hci_conn *conn, u8 status); int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status); int mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 23a0524061b7..54800c4883fc 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -1100,6 +1100,13 @@ struct mgmt_ev_controller_resume { struct mgmt_addr_info addr; } __packed; +#define MGMT_EV_LE_PHY_UPDATE_COMPLETE 0x002f +struct mgmt_ev_le_phy_update_complete { + struct mgmt_addr_info addr; + __u8 status; + __le32 phys; +} __packed; + #define MGMT_WAKE_REASON_NON_BT_WAKE 0x0 #define MGMT_WAKE_REASON_UNEXPECTED 0x1 #define MGMT_WAKE_REASON_REMOTE_WAKE 0x2 diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 1c3018202564..effe525e5272 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -5970,17 +5970,18 @@ static void hci_le_phy_update_evt(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); - if (ev->status) - return; - hci_dev_lock(hdev); conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); if (!conn) goto unlock; - conn->le_tx_phy = ev->tx_phy; - conn->le_rx_phy = ev->rx_phy; + if (!ev->status) { + conn->le_tx_phy = ev->tx_phy; + conn->le_rx_phy = ev->rx_phy; + } + + mgmt_le_phy_update(hdev, conn, ev->status); unlock: hci_dev_unlock(hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 3663f880df11..683e4b66f810 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -172,6 +172,7 @@ static const u16 mgmt_events[] = { MGMT_EV_ADV_MONITOR_REMOVED, MGMT_EV_CONTROLLER_SUSPEND, MGMT_EV_CONTROLLER_RESUME, + MGMT_EV_LE_PHY_UPDATE_COMPLETE, }; static const u16 mgmt_untrusted_commands[] = { @@ -3611,6 +3612,39 @@ static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev, return err; } +void mgmt_le_phy_update(struct hci_dev *hdev, struct hci_conn *conn, + u8 status) +{ + struct mgmt_ev_le_phy_update_complete ev; + u32 phys = 0; + + memset(&ev, 0, sizeof(ev)); + + bacpy(&ev.addr.bdaddr, &conn->dst); + ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type); + + ev.status = status; + + if (conn->le_tx_phy == HCI_LE_READ_PHY_1M) + phys |= MGMT_PHY_LE_1M_TX; + else if (conn->le_tx_phy == HCI_LE_READ_PHY_2M) + phys |= MGMT_PHY_LE_2M_TX; + else if (conn->le_tx_phy == HCI_LE_READ_PHY_CODED) + phys |= MGMT_PHY_LE_CODED_TX; + + if (conn->le_rx_phy == HCI_LE_READ_PHY_1M) + phys |= MGMT_PHY_LE_1M_RX; + else if (conn->le_rx_phy == HCI_LE_READ_PHY_2M) + phys |= MGMT_PHY_LE_2M_RX; + else if (conn->le_rx_phy == HCI_LE_READ_PHY_CODED) + phys |= MGMT_PHY_LE_CODED_RX; + + ev.phys = cpu_to_le32(phys); + + mgmt_event(MGMT_EV_LE_PHY_UPDATE_COMPLETE, hdev, &ev, sizeof(ev), + NULL); +} + static int set_blocked_keys(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { -- 2.17.1