diff options
author | Mikel Astiz <mikel.astiz@bmw-carit.de> | 2012-08-09 03:52:30 -0400 |
---|---|---|
committer | Gustavo Padovan <gustavo.padovan@collabora.co.uk> | 2012-08-21 13:54:40 -0400 |
commit | f0d6a0ea330617454032d6e2ed48759858a44427 (patch) | |
tree | d11edf124abaef7d14f39fb9d0678376800fac72 /net/bluetooth | |
parent | fa1bd91809d58b3c183611556219fafd93c08625 (diff) |
Bluetooth: mgmt: Add device disconnect reason
MGMT_EV_DEVICE_DISCONNECTED will now expose the disconnection reason to
userland, distinguishing four possible values:
0x00 Reason not known or unspecified
0x01 Connection timeout
0x02 Connection terminated by local host
0x03 Connection terminated by remote host
Note that the local/remote distinction just determines which side
terminated the low-level connection, regardless of the disconnection of
the higher-level profiles.
This can sometimes be misleading and thus must be used with care. For
example, some hardware combinations would report a locally initiated
disconnection even if the user turned Bluetooth off in the remote side.
Signed-off-by: Mikel Astiz <mikel.astiz@bmw-carit.de>
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Diffstat (limited to 'net/bluetooth')
-rw-r--r-- | net/bluetooth/hci_event.c | 26 | ||||
-rw-r--r-- | net/bluetooth/mgmt.c | 9 |
2 files changed, 28 insertions, 7 deletions
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index bfa9bcc0f5ef..48d730228c2f 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
@@ -29,6 +29,7 @@ | |||
29 | 29 | ||
30 | #include <net/bluetooth/bluetooth.h> | 30 | #include <net/bluetooth/bluetooth.h> |
31 | #include <net/bluetooth/hci_core.h> | 31 | #include <net/bluetooth/hci_core.h> |
32 | #include <net/bluetooth/mgmt.h> | ||
32 | 33 | ||
33 | /* Handle HCI Event packets */ | 34 | /* Handle HCI Event packets */ |
34 | 35 | ||
@@ -1875,6 +1876,22 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
1875 | } | 1876 | } |
1876 | } | 1877 | } |
1877 | 1878 | ||
1879 | static u8 hci_to_mgmt_reason(u8 err) | ||
1880 | { | ||
1881 | switch (err) { | ||
1882 | case HCI_ERROR_CONNECTION_TIMEOUT: | ||
1883 | return MGMT_DEV_DISCONN_TIMEOUT; | ||
1884 | case HCI_ERROR_REMOTE_USER_TERM: | ||
1885 | case HCI_ERROR_REMOTE_LOW_RESOURCES: | ||
1886 | case HCI_ERROR_REMOTE_POWER_OFF: | ||
1887 | return MGMT_DEV_DISCONN_REMOTE; | ||
1888 | case HCI_ERROR_LOCAL_HOST_TERM: | ||
1889 | return MGMT_DEV_DISCONN_LOCAL_HOST; | ||
1890 | default: | ||
1891 | return MGMT_DEV_DISCONN_UNKNOWN; | ||
1892 | } | ||
1893 | } | ||
1894 | |||
1878 | static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | 1895 | static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) |
1879 | { | 1896 | { |
1880 | struct hci_ev_disconn_complete *ev = (void *) skb->data; | 1897 | struct hci_ev_disconn_complete *ev = (void *) skb->data; |
@@ -1893,12 +1910,15 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
1893 | 1910 | ||
1894 | if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) && | 1911 | if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) && |
1895 | (conn->type == ACL_LINK || conn->type == LE_LINK)) { | 1912 | (conn->type == ACL_LINK || conn->type == LE_LINK)) { |
1896 | if (ev->status) | 1913 | if (ev->status) { |
1897 | mgmt_disconnect_failed(hdev, &conn->dst, conn->type, | 1914 | mgmt_disconnect_failed(hdev, &conn->dst, conn->type, |
1898 | conn->dst_type, ev->status); | 1915 | conn->dst_type, ev->status); |
1899 | else | 1916 | } else { |
1917 | u8 reason = hci_to_mgmt_reason(ev->reason); | ||
1918 | |||
1900 | mgmt_device_disconnected(hdev, &conn->dst, conn->type, | 1919 | mgmt_device_disconnected(hdev, &conn->dst, conn->type, |
1901 | conn->dst_type); | 1920 | conn->dst_type, reason); |
1921 | } | ||
1902 | } | 1922 | } |
1903 | 1923 | ||
1904 | if (ev->status == 0) { | 1924 | if (ev->status == 0) { |
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a3329cbd3e4d..05d4b83a0189 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -3077,16 +3077,17 @@ static void unpair_device_rsp(struct pending_cmd *cmd, void *data) | |||
3077 | } | 3077 | } |
3078 | 3078 | ||
3079 | int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, | 3079 | int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, |
3080 | u8 link_type, u8 addr_type) | 3080 | u8 link_type, u8 addr_type, u8 reason) |
3081 | { | 3081 | { |
3082 | struct mgmt_addr_info ev; | 3082 | struct mgmt_ev_device_disconnected ev; |
3083 | struct sock *sk = NULL; | 3083 | struct sock *sk = NULL; |
3084 | int err; | 3084 | int err; |
3085 | 3085 | ||
3086 | mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk); | 3086 | mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk); |
3087 | 3087 | ||
3088 | bacpy(&ev.bdaddr, bdaddr); | 3088 | bacpy(&ev.addr.bdaddr, bdaddr); |
3089 | ev.type = link_to_bdaddr(link_type, addr_type); | 3089 | ev.addr.type = link_to_bdaddr(link_type, addr_type); |
3090 | ev.reason = reason; | ||
3090 | 3091 | ||
3091 | err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), | 3092 | err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), |
3092 | sk); | 3093 | sk); |