aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndre Guedes <andre.guedes@openbossa.org>2014-02-26 18:21:48 -0500
committerMarcel Holtmann <marcel@holtmann.org>2014-02-26 22:41:34 -0500
commit9fcb18ef3acb51e54b6bca6d2d803676ac86813d (patch)
treec19f7f9d5fcca619785894898fb08522bb2b95e0
parenta4790dbd43d1617b09d57e96494fde5a4b01980a (diff)
Bluetooth: Introduce LE auto connect options
This patch introduces the LE auto connection options: HCI_AUTO_CONN_ ALWAYS and HCI_AUTO_CONN_LINK_LOSS. Their working mechanism are described as follows: The HCI_AUTO_CONN_ALWAYS option configures the kernel to always re- establish the connection, no matter the reason the connection was terminated. This feature is required by some LE profiles such as HID over GATT, Health Thermometer and Blood Pressure. These profiles require the host autonomously connect to the device as soon as it enters in connectable mode (start advertising) so the device is able to delivery notifications or indications. The BT_AUTO_CONN_LINK_LOSS option configures the kernel to re- establish the connection in case the connection was terminated due to a link loss. This feature is required by the majority of LE profiles such as Proximity, Find Me, Cycling Speed and Cadence and Time. Signed-off-by: Andre Guedes <andre.guedes@openbossa.org> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r--include/net/bluetooth/hci_core.h9
-rw-r--r--net/bluetooth/hci_core.c11
-rw-r--r--net/bluetooth/hci_event.c18
3 files changed, 33 insertions, 5 deletions
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 617cf495a449..b159810f67a6 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -402,6 +402,12 @@ struct hci_conn_params {
402 402
403 u16 conn_min_interval; 403 u16 conn_min_interval;
404 u16 conn_max_interval; 404 u16 conn_max_interval;
405
406 enum {
407 HCI_AUTO_CONN_DISABLED,
408 HCI_AUTO_CONN_ALWAYS,
409 HCI_AUTO_CONN_LINK_LOSS,
410 } auto_connect;
405}; 411};
406 412
407extern struct list_head hci_dev_list; 413extern struct list_head hci_dev_list;
@@ -796,7 +802,8 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
796struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev, 802struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev,
797 bdaddr_t *addr, u8 addr_type); 803 bdaddr_t *addr, u8 addr_type);
798void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, 804void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type,
799 u16 conn_min_interval, u16 conn_max_interval); 805 u8 auto_connect, u16 conn_min_interval,
806 u16 conn_max_interval);
800void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); 807void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type);
801void hci_conn_params_clear(struct hci_dev *hdev); 808void hci_conn_params_clear(struct hci_dev *hdev);
802 809
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 9a08f341f0a4..f4224dc58e4d 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3202,7 +3202,8 @@ struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev,
3202 3202
3203/* This function requires the caller holds hdev->lock */ 3203/* This function requires the caller holds hdev->lock */
3204void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, 3204void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type,
3205 u16 conn_min_interval, u16 conn_max_interval) 3205 u8 auto_connect, u16 conn_min_interval,
3206 u16 conn_max_interval)
3206{ 3207{
3207 struct hci_conn_params *params; 3208 struct hci_conn_params *params;
3208 3209
@@ -3210,6 +3211,7 @@ void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type,
3210 if (params) { 3211 if (params) {
3211 params->conn_min_interval = conn_min_interval; 3212 params->conn_min_interval = conn_min_interval;
3212 params->conn_max_interval = conn_max_interval; 3213 params->conn_max_interval = conn_max_interval;
3214 params->auto_connect = auto_connect;
3213 return; 3215 return;
3214 } 3216 }
3215 3217
@@ -3223,12 +3225,13 @@ void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type,
3223 params->addr_type = addr_type; 3225 params->addr_type = addr_type;
3224 params->conn_min_interval = conn_min_interval; 3226 params->conn_min_interval = conn_min_interval;
3225 params->conn_max_interval = conn_max_interval; 3227 params->conn_max_interval = conn_max_interval;
3228 params->auto_connect = auto_connect;
3226 3229
3227 list_add(&params->list, &hdev->le_conn_params); 3230 list_add(&params->list, &hdev->le_conn_params);
3228 3231
3229 BT_DBG("addr %pMR (type %u) conn_min_interval 0x%.4x " 3232 BT_DBG("addr %pMR (type %u) auto_connect %u conn_min_interval 0x%.4x "
3230 "conn_max_interval 0x%.4x", addr, addr_type, conn_min_interval, 3233 "conn_max_interval 0x%.4x", addr, addr_type, auto_connect,
3231 conn_max_interval); 3234 conn_min_interval, conn_max_interval);
3232} 3235}
3233 3236
3234/* This function requires the caller holds hdev->lock */ 3237/* This function requires the caller holds hdev->lock */
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index b6631d7e2ddf..46da8b6f4368 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1841,6 +1841,7 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
1841{ 1841{
1842 struct hci_ev_disconn_complete *ev = (void *) skb->data; 1842 struct hci_ev_disconn_complete *ev = (void *) skb->data;
1843 u8 reason = hci_to_mgmt_reason(ev->reason); 1843 u8 reason = hci_to_mgmt_reason(ev->reason);
1844 struct hci_conn_params *params;
1844 struct hci_conn *conn; 1845 struct hci_conn *conn;
1845 bool mgmt_connected; 1846 bool mgmt_connected;
1846 u8 type; 1847 u8 type;
@@ -1868,6 +1869,23 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
1868 if (conn->type == ACL_LINK && conn->flush_key) 1869 if (conn->type == ACL_LINK && conn->flush_key)
1869 hci_remove_link_key(hdev, &conn->dst); 1870 hci_remove_link_key(hdev, &conn->dst);
1870 1871
1872 params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
1873 if (params) {
1874 switch (params->auto_connect) {
1875 case HCI_AUTO_CONN_LINK_LOSS:
1876 if (ev->reason != HCI_ERROR_CONNECTION_TIMEOUT)
1877 break;
1878 /* Fall through */
1879
1880 case HCI_AUTO_CONN_ALWAYS:
1881 hci_pend_le_conn_add(hdev, &conn->dst, conn->dst_type);
1882 break;
1883
1884 default:
1885 break;
1886 }
1887 }
1888
1871 type = conn->type; 1889 type = conn->type;
1872 1890
1873 hci_proto_disconn_cfm(conn, ev->reason); 1891 hci_proto_disconn_cfm(conn, ev->reason);