@@ -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);
@@ -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
@@ -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);
@@ -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)
{