mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 03:27:30 -04:00
Bluetooth: mgmt: Translate HCI reason in Device Disconnected event
MGMT_EV_DEVICE_DISCONNECTED carries a reason field which is defined to
be one of MGMT_DEV_DISCONN_* (0x00..0x05). hci_disconn_complete_evt()
converts the HCI error with hci_to_mgmt_reason(), but two other paths
pass the raw HCI error straight through:
hci_cs_disconnect() -> cp->reason
mgmt_connect_failed() -> status
The latter is reached whenever the adapter is powered off or suspended:
hci_disconnect_all_sync() aborts every link with
HCI_ERROR_REMOTE_POWER_OFF, hci_disconnect_sync() deliberately does not
wait for HCI_EV_DISCONN_COMPLETE for that reason, so that
hci_abort_conn_sync() finishes the connection off through
hci_conn_failed() instead.
As a result userspace sees an out of range reason:
@ MGMT Event: Device Disconnected (0x000c) plen 8
BR/EDR Address: 8C:A9:6F:2C:51:46
Reason: Reserved (0x15)
bluetoothd: btd_bearer_disconnected() Unknown disconnection value: 21
bluetoothd: device_disconnected() Unknown disconnection value: 21
Export hci_to_mgmt_reason() and use it in both places, so that a power
off is reported as MGMT_DEV_DISCONN_REMOTE rather than as the raw
HCI_ERROR_REMOTE_POWER_OFF (0x15).
Fixes: d47da6bd4c ("Bluetooth: hci_core: Fix sending MGMT_EV_CONNECT_FAILED")
Fixes: 182ee45da0 ("Bluetooth: hci_sync: Rework hci_suspend_notifier")
Signed-off-by: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
committed by
Luiz Augusto von Dentz
parent
bf587a10c3
commit
c1cec2bbbe
@@ -2430,6 +2430,7 @@ void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
|
||||
bool persistent);
|
||||
void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
|
||||
u8 *name, u8 name_len);
|
||||
u8 hci_to_mgmt_reason(u8 err);
|
||||
void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 link_type, u8 addr_type, u8 reason,
|
||||
bool mgmt_connected);
|
||||
|
||||
@@ -2763,7 +2763,7 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
|
||||
}
|
||||
|
||||
mgmt_device_disconnected(hdev, &conn->dst, conn->type, conn->dst_type,
|
||||
cp->reason, mgmt_conn);
|
||||
hci_to_mgmt_reason(cp->reason), mgmt_conn);
|
||||
|
||||
hci_disconn_cfm(conn, cp->reason);
|
||||
|
||||
@@ -3381,22 +3381,6 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data,
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static u8 hci_to_mgmt_reason(u8 err)
|
||||
{
|
||||
switch (err) {
|
||||
case HCI_ERROR_CONNECTION_TIMEOUT:
|
||||
return MGMT_DEV_DISCONN_TIMEOUT;
|
||||
case HCI_ERROR_REMOTE_USER_TERM:
|
||||
case HCI_ERROR_REMOTE_LOW_RESOURCES:
|
||||
case HCI_ERROR_REMOTE_POWER_OFF:
|
||||
return MGMT_DEV_DISCONN_REMOTE;
|
||||
case HCI_ERROR_LOCAL_HOST_TERM:
|
||||
return MGMT_DEV_DISCONN_LOCAL_HOST;
|
||||
default:
|
||||
return MGMT_DEV_DISCONN_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static void hci_disconn_complete_evt(struct hci_dev *hdev, void *data,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
|
||||
@@ -9908,6 +9908,22 @@ bool mgmt_powering_down(struct hci_dev *hdev)
|
||||
return false;
|
||||
}
|
||||
|
||||
u8 hci_to_mgmt_reason(u8 err)
|
||||
{
|
||||
switch (err) {
|
||||
case HCI_ERROR_CONNECTION_TIMEOUT:
|
||||
return MGMT_DEV_DISCONN_TIMEOUT;
|
||||
case HCI_ERROR_REMOTE_USER_TERM:
|
||||
case HCI_ERROR_REMOTE_LOW_RESOURCES:
|
||||
case HCI_ERROR_REMOTE_POWER_OFF:
|
||||
return MGMT_DEV_DISCONN_REMOTE;
|
||||
case HCI_ERROR_LOCAL_HOST_TERM:
|
||||
return MGMT_DEV_DISCONN_LOCAL_HOST;
|
||||
default:
|
||||
return MGMT_DEV_DISCONN_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 link_type, u8 addr_type, u8 reason,
|
||||
bool mgmt_connected)
|
||||
@@ -9969,7 +9985,8 @@ void mgmt_connect_failed(struct hci_dev *hdev, struct hci_conn *conn, u8 status)
|
||||
|
||||
if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) {
|
||||
mgmt_device_disconnected(hdev, &conn->dst, conn->type,
|
||||
conn->dst_type, status, true);
|
||||
conn->dst_type,
|
||||
hci_to_mgmt_reason(status), true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user